diff --git a/.github/workflows/assets.yml b/.github/workflows/assets.yml index b3ec3ae7b..fd77e5b6d 100644 --- a/.github/workflows/assets.yml +++ b/.github/workflows/assets.yml @@ -20,16 +20,12 @@ jobs: fail-fast: false matrix: python: - - '3.7' - '3.8' - '3.9' - '3.10' - '3.11' steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - name: Install dependencies @@ -38,6 +34,8 @@ jobs: echo "/usr/local/opt/bison/bin" >> $GITHUB_PATH echo "/usr/local/opt/flex/bin" >> $GITHUB_PATH python -m pip install --upgrade pip setuptools wheel + - name: Checkout + uses: actions/checkout@v3 - name: Build wheel env: NPROCS: 5 @@ -46,7 +44,7 @@ jobs: id: wheel working-directory: pybuild/dist/ run: echo "##[set-output name=wheel;]$(ls *.whl)" - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: pypi-macos-py${{ matrix.python }} path: pybuild/dist/${{ steps.wheel.outputs.wheel }} @@ -76,7 +74,6 @@ jobs: - 2014 - _2_28 cpython_version: - - 'cp37-cp37m' - 'cp38-cp38' - 'cp39-cp39' - 'cp310-cp310' @@ -90,9 +87,6 @@ jobs: swig_version: 'swig-3.0.12-19.module_el8.3.0+6167+838326ab' steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - name: Install dependencies run: | yum install -y $BISON_VERSION $SWIG_VERSION @@ -105,19 +99,15 @@ jobs: ./configure make -j make install - - name: Install cmake - run: curl -L https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-Linux-x86_64.tar.gz | tar xz --strip-components=1 -C /usr - - name: Build wheel - env: - NPROCS: 5 - run: | - /opt/python/${{ matrix.cpython_version }}/bin/python setup.py bdist_wheel - /opt/python/${{ matrix.cpython_version }}/bin/python -m auditwheel repair pybuild/dist/*.whl + - name: Get latest CMake + uses: lukka/get-cmake@latest + - name: Checkout + uses: actions/checkout@v3 - name: Wheel path id: wheel working-directory: wheelhouse run: echo "##[set-output name=wheel;]$(ls *.whl)" - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: pypi-linux-${{ matrix.cpython_version }} path: wheelhouse/${{ steps.wheel.outputs.wheel }} @@ -138,19 +128,15 @@ jobs: fail-fast: false matrix: python: - - '3.7' - '3.8' - '3.9' - '3.10' - '3.11' steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey key: ${{ runner.os }}-chocolatey-python-1 @@ -162,6 +148,8 @@ jobs: python -m pip install --upgrade pip setuptools wheel choco install winflexbison3 --version 2.5.18.20190508 #choco install swig --version 4.0.1 + - name: Checkout + uses: actions/checkout@v3 - name: Build wheel env: NPROCS: 5 @@ -170,7 +158,7 @@ jobs: id: wheel working-directory: pybuild/dist/ run: echo "##[set-output name=wheel;]$(Get-ChildItem -name *.whl)" - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: pypi-windows-py${{ matrix.python }} path: pybuild/dist/${{ steps.wheel.outputs.wheel }} @@ -184,71 +172,6 @@ jobs: asset_name: ${{ steps.wheel.outputs.wheel }} asset_content_type: application/zip -# NOTE: disabled conda completely because it is INCREDIBLY slow on CI (multiple -# hours!) and occasionally just breaks the runners entirely after ~6 hours. It -# also doesn't appear like anyone is actually using Conda within the lab -# (anymore), as everything goes through pycQED and it is pip-only. -# -# For a release, if conda is really still necessary, it will just have to be -# done manually. -# -# conda: -# name: Conda wheels -# runs-on: ${{ matrix.os }} -# strategy: -# fail-fast: false -# matrix: -# os: -# - ubuntu-latest -# - macos-latest -# - windows-2016 -# python-version: -# - '3.7' -# - '3.8' -# - '3.9' -# - '3.10' -# - '3.11' -# steps: -# - uses: actions/checkout@v2 -# with: -# submodules: recursive -# - name: Set up conda -# uses: conda-incubator/setup-miniconda@v2 -# with: -# auto-update-conda: true -# miniconda-version: "latest" -# channel-priority: strict -# channels: conda-forge -# show-channel-urls: true -# use-only-tar-bz2: true -# - name: Install Windows dependencies -# if: matrix.os == 'windows-2016' -# run: choco install winflexbison3 --version 2.5.18.20190508 -# - name: Install conda dependencies -# run: conda install conda-build conda-verify -y -# - name: Build & test -# env: -# NPROCS: 5 -# run: conda build conda-recipe --python=${{ matrix.python-version }} -# - name: Wheel path -# id: wheel -# run: | -# python -c "import sys,os; print('##[set-output name=path;]' + os.path.abspath(sys.argv[1])); print('##[set-output name=wheel;]' + os.path.basename(sys.argv[1]));" "$(conda build conda-recipe --python=${{ matrix.python-version }} --output)" -# python -c "import sys; print('##[set-output name=os;]' + ('linux' if sys.argv[1].startswith('ubuntu') else 'macos' if sys.argv[1].startswith('macos') else 'windows' if sys.argv[1].startswith('windows') else 0/0))" ${{ matrix.os }} -# - uses: actions/upload-artifact@v2 -# with: -# name: conda-${{ steps.wheel.outputs.os }}-py${{ matrix.python-version }} -# path: ${{ steps.wheel.outputs.path }} -# - uses: actions/upload-release-asset@v1 -# if: ${{ github.event_name == 'release' && github.event.action == 'created' }} -# env: -# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -# with: -# upload_url: ${{ github.event.release.upload_url }} -# asset_path: ${{ steps.wheel.outputs.path }} -# asset_name: ${{ steps.wheel.outputs.wheel }} -# asset_content_type: application/x-bzip2 - publish: name: Publish if: ${{ github.event_name == 'release' && github.event.action == 'created' }} @@ -256,22 +179,14 @@ jobs: - macos - manylinux - windows - #- conda runs-on: ubuntu-latest steps: - name: Download artifacts - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 id: download - #- name: Publish to Anaconda cloud - # run: | - # conda install -c anaconda anaconda-client -y - # conda run anaconda login --username ${{ secrets.ANACONDA_USER }} --password ${{ secrets.ANACONDA_PASSWORD }} - # conda run anaconda upload ${{ steps.download.outputs.download-path }}/conda-*/*.bz2 - # conda run anaconda logout - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@v1.3.1 with: user: __token__ password: ${{ secrets.PYPI_TOKEN }} packages_dir: ${{ steps.download.outputs.download-path }}/pypi-* - diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6408d2a8b..05a898b9d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,59 +7,136 @@ on: pull_request: jobs: - cpp: - name: 'C++ tests' - runs-on: ${{ matrix.os }} + cpp-linux: + name: 'C++ tests (gcc-clang/Linux/x64)' + runs-on: ubuntu-latest strategy: fail-fast: false matrix: - os: - - ubuntu-latest - - macos-latest - - windows-latest + build_type: + - Debug + - Release + compiler: + - clang++ + - g++ steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Install dependencies - if: matrix.os == 'macos-latest' - run: | - brew install bison flex - echo "/usr/local/opt/bison/bin" >> $GITHUB_PATH - echo "/usr/local/opt/flex/bin" >> $GITHUB_PATH - - uses: actions/cache@v2 - if: matrix.os == 'windows-latest' - with: - path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey - key: ${{ runner.os }}-chocolatey-cpp-0 - restore-keys: | - ${{ runner.os }}-chocolatey-cpp- - ${{ runner.os }}-chocolatey- - - name: Install dependencies - if: matrix.os == 'windows-latest' - run: choco install winflexbison3 --version 2.5.18.20190508 - - name: Configure - run: cmake . -DCMAKE_BUILD_TYPE=Debug -DOPENQL_BUILD_TESTS=ON -DBUILD_SHARED_LIBS=OFF -DWITH_UNITARY_DECOMPOSITION=OFF - - name: Build - run: cmake --build . --parallel 5 - - name: Test - run: ctest -C Debug --output-on-failure + - name: Get latest CMake + uses: lukka/get-cmake@latest + - name: Checkout + uses: actions/checkout@v3 + - name: Create build directory + run: mkdir -p build-${{ matrix.compiler }}-${{ matrix.build_type }} + - name: Configure + env: + CXX: ${{ matrix.compiler }} + working-directory: build-${{ matrix.compiler }}-${{ matrix.build_type }} + run: cmake -S .. -B . -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DBUILD_SHARED_LIBS=OFF -DOPENQL_BUILD_TESTS=ON -DWITH_UNITARY_DECOMPOSITION=OFF + - name: Build + working-directory: build-${{ matrix.compiler }}-${{ matrix.build_type }} + run: cmake --build . --parallel 10 + - name: Test + working-directory: build-${{ matrix.compiler }}-${{ matrix.build_type }} + run: ctest -C ${{ matrix.build_type }} --output-on-failure - cpp-standalone: - name: 'C++ standalone program' - runs-on: ubuntu-latest + cpp-macos: + name: 'C++ tests (clang/MacOS/x64)' + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + build_type: + - Debug + - Release steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - name: Configure - run: | - mkdir cbuild - cd cbuild && cmake ../examples/cpp-standalone-example - - name: Build - run: make -C cbuild -j 5 - - name: Test - run: cd tests && ../cbuild/example + - name: Install flex/bison + run: | + brew install flex bison + echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH + echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH + - name: Get latest CMake + uses: lukka/get-cmake@latest + - name: Checkout + uses: actions/checkout@v3 + - name: Create build directory + run: mkdir -p build-${{ matrix.build_type }} + - name: Configure + working-directory: build-${{ matrix.build_type }} + run: cmake -S .. -B . -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DBUILD_SHARED_LIBS=OFF -DOPENQL_BUILD_TESTS=ON -DWITH_UNITARY_DECOMPOSITION=OFF + - name: Build + working-directory: build-${{ matrix.build_type }} + run: cmake --build . --parallel 10 + - name: Test + working-directory: build-${{ matrix.build_type }} + run: ctest -C ${{ matrix.build_type }} --output-on-failure + + cpp-windows: + name: 'C++ tests (msvc/Windows/x64)' + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + build_type: + - Debug + - Release + steps: + - name: Install Winflexbison3 + shell: powershell + run: choco install winflexbison3 --version 2.5.24.20210105 + - name: Get latest CMake + uses: lukka/get-cmake@latest + - name: Checkout + uses: actions/checkout@v3 + - name: Create build directory + run: mkdir -p build + - name: Configure + working-directory: build + run: cmake -S .. -B . -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DBUILD_SHARED_LIBS=OFF -DOPENQL_BUILD_TESTS=ON -DWITH_UNITARY_DECOMPOSITION=OFF + - name: Build + working-directory: build + run: cmake --build . --parallel 10 --config ${{ matrix.build_type }} + - name: Test + working-directory: build + run: ctest -C ${{ matrix.build_type }} --output-on-failure + + cpp-arm64: + name: 'C++ tests (gcc/Linux/ARM64, clang/MacOS/ARM64)' + runs-on: [self-hosted, ARM64, "${{ matrix.os }}"] + strategy: + fail-fast: false + matrix: + os: + - Linux + - macOS + steps: + - if: matrix.os == 'Linux' + name: Install flex/bison, and gcc (Linux) + run: | + sudo apt-get -y update + sudo apt-get -y upgrade + sudo apt-get -y install flex bison gcc + shell: bash + - if: matrix.os == 'macOS' + name: Install flex/bison, and gcc (MacOS) + run: | + brew install flex bison gcc + echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH + echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH + shell: bash + - name: Get latest CMake + uses: lukka/get-cmake@latest + - name: Checkout + uses: actions/checkout@v3 + - name: Create build directory + run: mkdir -p build + - name: Configure + working-directory: build + run: cmake -S .. -B . -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DOPENQL_BUILD_TESTS=ON -DWITH_UNITARY_DECOMPOSITION=OFF + - name: Build + working-directory: build + run: cmake --build . --parallel 10 + - name: Test + working-directory: build + run: ctest -C Release --output-on-failure python: name: Python @@ -68,109 +145,45 @@ jobs: fail-fast: false matrix: os: - - ubuntu-latest - - macos-latest - - windows-latest - python: - - '3.7' - - '3.8' - - '3.9' - - '3.10' - - '3.11' + - ubuntu-latest + - macos-latest + - windows-latest steps: - - uses: actions/checkout@v2 - with: - submodules: recursive - - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python }} - - name: Install dependencies - run: python -m pip install --upgrade pip setuptools wheel pytest numpy qxelarator - - name: Install dependencies - if: matrix.os == 'ubuntu-latest' - run: sudo apt-get install -y swig - - name: Install dependencies - if: matrix.os == 'macos-latest' - run: | - brew install bison flex swig xquartz - echo "/usr/local/opt/bison/bin" >> $GITHUB_PATH - echo "/usr/local/opt/flex/bin" >> $GITHUB_PATH - - uses: actions/cache@v2 - if: matrix.os == 'windows-latest' - with: - path: C:\Users\runneradmin\AppData\Local\Temp\chocolatey - key: ${{ runner.os }}-chocolatey-python-1 - restore-keys: | - ${{ runner.os }}-chocolatey-python- - ${{ runner.os }}-chocolatey- - - name: Install dependencies - if: matrix.os == 'windows-latest' - shell: powershell - run: | - choco install winflexbison3 --version 2.5.18.20190508 - - name: Select build type - if: matrix.os == 'windows-latest' - shell: powershell - run: echo "OPENQL_BUILD_TYPE=Release" >> $GITHUB_ENV - - name: Select build type - if: matrix.os != 'windows-latest' - run: echo "OPENQL_BUILD_TYPE=Debug" >> $GITHUB_ENV - - name: Disable unitary decomposition - if: matrix.os != 'windows-latest' - run: echo "OPENQL_DISABLE_UNITARY=true" >> $GITHUB_ENV - - name: Disable unitary decomposition - if: matrix.os == 'windows-latest' - run: echo "OPENQL_DISABLE_UNITARY=true" >> $env:GITHUB_ENV - - name: Build - env: - NPROCS: 5 - run: python -m pip install --verbose . - - name: Test - run: python -m pytest - -# NOTE: disabled conda completely because it is INCREDIBLY slow on CI (multiple -# hours!) and occasionally just breaks the runners entirely after ~6 hours. It -# also doesn't appear like anyone is actually using Conda within the lab -# (anymore), as everything goes through pycQED and it is pip-only. -# -# conda: -# name: Conda -# runs-on: ${{ matrix.os }} -# strategy: -# fail-fast: false -# matrix: -# os: -# - ubuntu-latest -# - macos-latest -# #- windows-latest -# #- windows-2016 -# steps: -# - uses: actions/checkout@v2 -# with: -# submodules: recursive -# - name: Set up conda -# uses: conda-incubator/setup-miniconda@v2 -# with: -# auto-update-conda: true -# miniconda-version: "latest" -# channel-priority: strict -# channels: conda-forge -# show-channel-urls: true -# use-only-tar-bz2: true -# - name: Install Windows dependencies -# if: matrix.os == 'windows-2016' || matrix.os == 'windows-latest' -# run: choco install winflexbison3 --version 2.5.18.20190508 -# - name: Install conda dependencies -# run: conda install conda-build conda-verify -y -# - name: Build & test -# env: -# NPROCS: 5 -# run: conda build conda-recipe -# - name: Install -# # This doesn't seem to work on Windows in CI because everything appears -# # to build in a non-default environment and conda is broken for that, -# # see https://github.com/conda/conda/issues/7758 -# # Note that conda build already does a test install in a fresh -# # environment, so this is a bit redundant anyway. -# if: matrix.os != 'windows-2016' && matrix.os != 'windows-latest' -# run: conda install openql --use-local + - uses: actions/setup-python@v4 + with: + python-version: "3.11" + - name: Install Python dependencies + run: python -m pip install --upgrade pip setuptools wheel pytest numpy qxelarator + - name: Install flex/bison, and SWIG + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get -y update + sudo apt-get -y upgrade + sudo apt-get -y install flex bison swig + echo "LIBQASM_BUILD_TYPE=Debug" >> $GITHUB_ENV + echo "OPENQL_DISABLE_UNITARY=true" >> $GITHUB_ENV + - name: Install flex/bison, and SWIG + if: matrix.os == 'macos-latest' + run: | + brew install flex bison swig + echo "$(brew --prefix flex)/bin" >> $GITHUB_PATH + echo "$(brew --prefix bison)/bin" >> $GITHUB_PATH + echo "LIBQASM_BUILD_TYPE=Debug" >> $GITHUB_ENV + echo "OPENQL_DISABLE_UNITARY=true" >> $GITHUB_ENV + - name: Install Winflexbison3 + if: matrix.os == 'windows-latest' + shell: powershell + run: | + choco install winflexbison3 --version 2.5.24.20210105 + echo "OPENQL_BUILD_TYPE=Release" >> $env:GITHUB_ENV + echo "OPENQL_DISABLE_UNITARY=true" >> $env:GITHUB_ENV + - name: Get latest CMake + uses: lukka/get-cmake@latest + - name: Checkout + uses: actions/checkout@v3 + - name: Build + env: + NPROCS: 10 + run: python -m pip install --verbose . + - name: Test + run: python -m pytest diff --git a/.gitignore b/.gitignore index dafed2204..874e75bea 100644 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,17 @@ swig/qutechopenql.egg-info # Test files test_output* .ipynb_checkpoints -tests/visualizer/visualizer_example_output/ +test/v1x/python/test_gate_decomposition_cz.cc_backend.map +test/v1x/python/test_gate_decomposition_cz.cc_backend.vcd +test/v1x/python/test_gate_decomposition_cz.cc_backend.vq1asm +test/v1x/python/test_gate_decomposition_cz.initial.cq +test/v1x/python/test_gate_decomposition_cz.scheduled.cq +test/v1x/python/test_qi_example.cc_backend.map +test/v1x/python/test_qi_example.cc_backend.vcd +test/v1x/python/test_qi_example.cc_backend.vq1asm +test/v1x/python/test_qi_example.initial.cq +test/v1x/python/test_qi_example.scheduled.cq +Testing/Temporary/CTestCostData.txt # Diamond Example Files examples/diamond/test_output @@ -41,3 +51,6 @@ docs/_templates /cmake-build-* *.pbm + +# conan +CMakeUserPresets.json diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 42b50ca6b..000000000 --- a/.gitmodules +++ /dev/null @@ -1,22 +0,0 @@ -[submodule "deps/libqasm"] - path = deps/libqasm - url = https://github.com/QuTech-Delft/libqasm.git - branch = develop -[submodule "deps/eigen"] - path = deps/eigen - url = https://gitlab.com/libeigen/eigen.git - shallow = true -[submodule "deps/backward-cpp"] - path = deps/backward-cpp - url = https://github.com/bombela/backward-cpp.git - shallow = true -[submodule "deps/json"] - path = deps/json - url = https://github.com/nlohmann/json.git - shallow = true -[submodule "deps/doctest"] - path = deps/doctest - url = https://github.com/doctest/doctest.git -[submodule "deps/highs"] - path = deps/highs - url = https://github.com/ERGO-Code/HiGHS.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e01ed8ad..f4931349b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,13 @@ -cmake_minimum_required(VERSION 3.1 FATAL_ERROR) +cmake_minimum_required(VERSION 3.25 FATAL_ERROR) # 3.25 needed for add_subdirectory(... SYSTEM) + +# CMake policies +if(POLICY CMP0048) + cmake_policy(SET CMP0048 NEW) +endif() +cmake_policy(SET CMP0077 NEW) +if(POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) +endif() project(OpenQL C CXX) @@ -9,6 +18,9 @@ if(NOT TARGET ql) # Loads up the appropriate directories for installing stuff. include(GNUInstallDirs) +# Packages +include(FetchContent) + #=============================================================================# # Configuration options # @@ -148,8 +160,8 @@ set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) -# Everything needs C++11 support. -set(CMAKE_CXX_STANDARD 11) +# Everything needs C++23 support. +set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) @@ -159,6 +171,75 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) +#=============================================================================# +# Dependencies # +#=============================================================================# + + +message(STATUS "Fetching Backward") +FetchContent_Declare(Backward + GIT_REPOSITORY https://github.com/bombela/backward-cpp.git + GIT_TAG "3bb9240cb15459768adb3e7d963a20e1523a6294" +) +FetchContent_MakeAvailable(Backward) + +message(STATUS "Fetching cqasm") +FetchContent_Declare(cqasm + message(STATUS "Fetching cqasm") + GIT_REPOSITORY https://github.com/QuTech-Delft/libqasm.git + GIT_TAG "8d0b4ed5e3a30aa6fde3b3aaf20a207b5d07876e" +) +FetchContent_MakeAvailable(cqasm) + +message(STATUS "Fetching Eigen3") +FetchContent_Declare(Eigen3 + GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git + GIT_TAG "4e9e493b4abc57dba377fc326082b40d08193619" +) +FetchContent_MakeAvailable(Eigen3) + +# FetchContent_Populate will be deprecated in the future +# The equivalent solution with FetchContent_MakeAvailable consists of +# setting SOURCE_SUBDIR to a non-existent subdirectory in FetchContent_Declare, +# then letting FetchContent_MakeAvailable do the download of the dependency, +# and still add_subdirectory manually +# See: https://discourse.cmake.org/t/fetchcontent-a-directory-but-add-a-subdirectory/8603/13?u=rturrado +message(STATUS "Fetching HiGHS") +FetchContent_Declare(highs + GIT_REPOSITORY https://github.com/ERGO-Code/HiGHS.git + GIT_TAG "45a127b78060942721f75f46a04b274c2bb963d8" + SOURCE_SUBDIR this-directory-does-not-exist +) +FetchContent_MakeAvailable(highs) +# The build system in HiGHS currently doesn't allow to disable HiGHS tests +# thus the following hacks are needed, instead of just add_subdirectory(deps/highs). +set(FAST_BUILD ON) +set(GITHASH "") +set(TODAY "") +set(HIGHS_VERSION_MAJOR 0) +set(HIGHS_VERSION_MINOR 0) +set(HIGHS_VERSION_PATCH 0) +set(HIGHS_SOURCE_DIR "${highs_SOURCE_DIR}") +set(HIGHS_BINARY_DIR "${highs_BINARY_DIR}") +add_subdirectory("${highs_SOURCE_DIR}/src" "${highs_BINARY_DIR}/src" SYSTEM) +configure_file(${highs_SOURCE_DIR}/src/HConfig.h.in ${highs_BINARY_DIR}/HConfig.h) + +# TODO: use Lemon Conan package when it is ready (https://github.com/conan-io/conan-center-index/pull/17338) +# TODO: remove use of Lemon in project? +message(STATUS "Fetching lemon") +FetchContent_Declare(lemon + GIT_REPOSITORY https://github.com/rturrado/lemon.git + GIT_TAG "e70acea5764a97ab3b6d31b883300f3ce1587cde" +) +FetchContent_MakeAvailable(lemon) + +message(STATUS "Fetching nlohmann_json") +FetchContent_Declare(nlohmann_json + URL https://github.com/nlohmann/json/releases/download/v3.11.2/json.tar.xz +) +FetchContent_MakeAvailable(nlohmann_json) + + #=============================================================================# # Compile code generators # #=============================================================================# @@ -185,11 +266,6 @@ function(create_resource fname) add_dependencies(ql ${target_name}) endfunction() -# Add tree-gen. We need to do this *only* to get access to the generate_tree -# CMake function; everything else is handled implicitly because tree-gen is a -# transitive dependency of libqasm. -add_subdirectory(deps/libqasm/src/cqasm/tree-gen deps/tree-gen) - #=============================================================================# # OpenQL library target # @@ -228,6 +304,7 @@ add_library(ql "${CMAKE_CURRENT_SOURCE_DIR}/src/ql/ir/compat/detail/cqasm_reader.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ql/ir/prim.cc" "${CMAKE_CURRENT_BINARY_DIR}/src/ql/ir/ir.gen.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/src/ql/ir/ir_gen_ex.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ql/ir/ops.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ql/ir/operator_info.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ql/ir/describe.cc" @@ -334,6 +411,33 @@ add_library(ql "${CMAKE_CURRENT_SOURCE_DIR}/src/ql/api/kernel.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ql/api/program.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ql/api/cqasm_reader.cc" + ${BACKWARD_ENABLE} +) +add_backward(ql) + +# There is no distinction between public and private header files right now, +# and they're all in the source directory. +# Note the / at the end of the path; +# this is necessary for the header files to be installed in the right location. +target_include_directories(ql + SYSTEM PRIVATE "${cqasm_SOURCE_DIR}/include" + SYSTEM PRIVATE "${eigen3_SOURCE_DIR}/Eigen" + SYSTEM PRIVATE "${eigen3_SOURCE_DIR}/unsupported" + SYSTEM PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/_deps/lemon-src/" + SYSTEM PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/_deps/lemon-build/" + SYSTEM PUBLIC "${nlohmann_json_SOURCE_DIR}/include" + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src/" + PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/src/" + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include/" + PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/include/" +) + +target_link_libraries(ql + PUBLIC cqasm + PRIVATE Eigen3::Eigen + PUBLIC highs + PRIVATE lemon + PRIVATE nlohmann_json::nlohmann_json ) # Specify resources. @@ -360,24 +464,24 @@ configure_file( # https://docs.microsoft.com/en-us/cpp/cpp/declspec?view=vs-2019 target_compile_definitions(ql PRIVATE BUILDING_OPENQL) -# There is no distinction between public and private header files right now, -# and they'r all in the source directory. Note the / at the end of the path; -# this is necessary for the header files to be installed in the right location. -target_include_directories(ql - PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src/" - PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/src/" - PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include/" - PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/include/" -) - # Configure compilation. set_property(TARGET ql PROPERTY POSITION_INDEPENDENT_CODE ON) if(CMAKE_COMPILER_IS_GNUCXX) - target_compile_options(ql PRIVATE -Wall -Wfatal-errors) + target_compile_options(ql PRIVATE + -Wall -Wextra -Werror -Wfatal-errors + -Wno-error=restrict + -Wno-error=deprecated-declarations + ) elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - target_compile_options(ql PRIVATE -Wall -Wfatal-errors -Wno-unused-local-typedef) + target_compile_options(ql PRIVATE + -Wall -Wextra -Werror -Wfatal-errors + -Wno-error=unused-private-field + -Wno-error=unused-but-set-variable + ) elseif(MSVC) - target_compile_options(ql PRIVATE /MP /D_USE_MATH_DEFINES /EHsc /bigobj) + target_compile_options(ql PRIVATE + /MP /D_USE_MATH_DEFINES /EHsc /bigobj + ) else() message(SEND_ERROR "Unknown compiler!") endif() @@ -402,60 +506,6 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Release") target_compile_definitions(ql PRIVATE NDEBUG) endif() -# LEMON ----------------------------------------------------------------------- - -# Configure LEMON. LEMON by itself exposes the "lemon" target to link against, -# but it doesn't use target_include_directories(), so we have to do that here. -add_subdirectory(deps/lemon) -target_include_directories(lemon INTERFACE - "${CMAKE_CURRENT_SOURCE_DIR}/deps/lemon" - "${CMAKE_CURRENT_BINARY_DIR}/deps/lemon" -) -target_link_libraries(ql PUBLIC lemon) - -# Even more annoying stuff: LEMON doesn't install itself in the right place on -# multilib systems (i.e. ones where the libdir is lib64 instead of just lib). -# So to make sure it is found in the install tree, we have to install it in the -# proper place ourselves. That would go something like this, -# -# install( -# TARGETS lemon -# ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" -# LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" -# COMPONENT library -# ) -# -# but until CMake 3.13 the install directive MUST be in the directory where the -# target is created, so we have to insert that piece of code into LEMON's own -# CMakeLists.txt. - - -# Eigen ----------------------------------------------------------------------- - -# Wrap Eigen in an interface library to link against. Note that Eigen is only -# used internally; its headers need not be installed or exposed to programs -# linking against OpenQL. -add_library(eigen INTERFACE) -target_include_directories(eigen INTERFACE - "${CMAKE_CURRENT_SOURCE_DIR}/deps/eigen/Eigen" - "${CMAKE_CURRENT_SOURCE_DIR}/deps/eigen/unsupported" -) -target_link_libraries(ql PRIVATE eigen) - - -# nlohmann::json -------------------------------------------------------------- - -set(JSON_BuildTests OFF CACHE INTERNAL "") -add_subdirectory(deps/json) -target_link_libraries(ql PUBLIC nlohmann_json::nlohmann_json) - - -# libqasm --------------------------------------------------------------------- - -# Load libqasm. libqasm's CMakeLists expose the "cqasm" target to link against. -add_subdirectory(deps/libqasm) -target_link_libraries(ql PUBLIC cqasm) - # X11/CImg --------------------------------------------------------------------- @@ -476,120 +526,48 @@ else() endif() if(QL_VISUALIZER) + message(STATUS "Fetching CImg") + FetchContent_Declare(CImg + GIT_REPOSITORY https://github.com/GreycLab/CImg.git + GIT_TAG "049267da171c50ab48f93c7285f096d7d686e8f3" + ) + FetchContent_MakeAvailable(CImg) + target_compile_definitions(ql PRIVATE WITH_VISUALIZER) - target_include_directories(ql PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/deps/cimg/include/") + target_include_directories(ql SYSTEM PRIVATE "${cimg_SOURCE_DIR}") endif() -# backward-cpp ---------------------------------------------------------------- - -# Stack trace helper library, nothing functional here. -add_subdirectory(deps/backward-cpp) -add_backward(ql) - -# add_backward doesn't set INTERFACE_LINK_LIBRARIES, only LINK_LIBRARIES. That -# goes wrong when we're compiling statically, because said libraries are shared -# and need to be included in the final link. -set_property(TARGET ql APPEND PROPERTY INTERFACE_LINK_LIBRARIES ${BACKWARD_LIBRARIES}) - -# HiGHS ----------------------------------------------------------------------- - -# HiGHS (www.highs.dev) comes as a submodule in deps/highs. It is a linear programming solver that can -# solve Mixed Integer Programming problems efficiently. It is used in the initial placement pass. - -# The build system in HiGHS currently doesn't allow to disable HiGHS tests -# thus the following hacks are needed, instead of just add_subdirectory(deps/highs). -set(FAST_BUILD ON) -set(GITHASH "") -set(TODAY "") -set(HIGHS_VERSION_MAJOR 0) -set(HIGHS_VERSION_MINOR 0) -set(HIGHS_VERSION_PATCH 0) -set(HIGHS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/highs") -set(HIGHS_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/deps/highs") - -add_subdirectory(deps/highs/src) -configure_file(deps/highs/src/HConfig.h.in ${CMAKE_CURRENT_BINARY_DIR}/deps/highs/HConfig.h) -target_link_libraries(ql PUBLIC libhighs) #=============================================================================# # Testing # #=============================================================================# -# Include the tests directory if requested. if(OPENQL_BUILD_TESTS) enable_testing() + include(CTest) + include(GoogleTest) + set(CMAKE_CTEST_ARGUMENTS "--output-on-failure") + add_subdirectory(test) +endif() - # Convenience function to add an integration test. - function(add_openql_test name source workdir) - add_executable("${name}" "${CMAKE_CURRENT_SOURCE_DIR}/${source}") - target_link_libraries("${name}" ql) - add_test( - NAME "${name}" - WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${workdir}" - COMMAND "${name}" - ) - endfunction() - - add_subdirectory(deps/doctest) - - # Include the directories containing integration tests. - add_subdirectory(tests) - add_subdirectory(examples) - - # Convenience function to add a unit test. - function(add_openql_unit_test source) - string(REPLACE "/" "_" name ${source}) - string(REPLACE "_tests_" "_" name ${name}) - string(REPLACE ".cc" "" name ${name}) - set(name test_${name}) - add_executable("${name}" "${CMAKE_CURRENT_SOURCE_DIR}/src/ql/${source}") - target_link_libraries("${name}" ql) - target_link_libraries("${name}" doctest) - get_filename_component(working_dir "${CMAKE_CURRENT_SOURCE_DIR}/src/ql/${source}" DIRECTORY) - add_test( - NAME "${name}" - WORKING_DIRECTORY "${working_dir}" - COMMAND "${name}" - ) - endfunction() - - # Register unit tests. - file( - GLOB_RECURSE unit_tests - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/src/ql - ${CMAKE_CURRENT_SOURCE_DIR}/src/ql/*/tests/*.cc - ) - foreach(unit_test ${unit_tests}) - add_openql_unit_test(${unit_test}) - endforeach() - - # I hate CMake. - file( - GLOB_RECURSE unit_tests - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/src/ql - ${CMAKE_CURRENT_SOURCE_DIR}/src/ql/*/*/tests/*.cc - ) - foreach(unit_test ${unit_tests}) - add_openql_unit_test(${unit_test}) - endforeach() - file( - GLOB_RECURSE unit_tests - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/src/ql - ${CMAKE_CURRENT_SOURCE_DIR}/src/ql/*/*/*/tests/*.cc - ) - foreach(unit_test ${unit_tests}) - add_openql_unit_test(${unit_test}) - endforeach() - file( - GLOB_RECURSE unit_tests - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/src/ql - ${CMAKE_CURRENT_SOURCE_DIR}/src/ql/*/*/*/*/tests/*.cc - ) - foreach(unit_test ${unit_tests}) - add_openql_unit_test(${unit_test}) - endforeach() -endif() +#=============================================================================# +# Debug info # +#=============================================================================# + +message(STATUS + "[${PROJECT_NAME}] Target include directories:\n" + " CImg: ${cimg_SOURCE_DIR}\n" + " cqasm/include: ${cqasm_SOURCE_DIR}/include\n" + " Eigen3/Eigen: ${eigen3_SOURCE_DIR}/Eigen\n" + " Eigen3/unsupported: ${eigen3_SOURCE_DIR}/unsupported\n" + " googletest: ${googletest_SOURCE_DIR}\n" + " highs: ${highs_SOURCE_DIR}\n" + " highs/src: ${highs_SOURCE_DIR}/src\n" + " lemon-src: ${CMAKE_CURRENT_BINARY_DIR}/_deps/lemon-src/\n" + " lemon-build: ${CMAKE_CURRENT_BINARY_DIR}/_deps/lemon-build/\n" + " nlohmann_json/include: ${nlohmann_json_SOURCE_DIR}/include\n" +) #=============================================================================# diff --git a/README.md b/README.md index 8d327dcbd..f7a996334 100644 --- a/README.md +++ b/README.md @@ -17,4 +17,4 @@ can be simulated on the QX simulator. OpenQL's source code is released under the Apache 2.0 license. For detailed user and contributor documentation, visit the -[the ReadTheDocs](https://openql.readthedocs.io) page! +[ReadTheDocs](https://openql.readthedocs.io) page! \ No newline at end of file diff --git a/deps/backward-cpp b/deps/backward-cpp deleted file mode 160000 index 27a89004a..000000000 --- a/deps/backward-cpp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 27a89004a86fe2a665f041c198c7fbab7489e278 diff --git a/deps/cimg/include/CImg.h b/deps/cimg/include/CImg.h deleted file mode 100644 index 5380eb23b..000000000 --- a/deps/cimg/include/CImg.h +++ /dev/null @@ -1,66561 +0,0 @@ -/* - # - # File : CImg.h - # ( C++ header file ) - # - # Description : C++ Template Image Processing Toolkit. - # This file is the main component of the CImg Library project. - # ( http://cimg.eu ) - # - # Project manager : David Tschumperlé - # ( http://tschumperle.users.greyc.fr/ ) - # - # A complete list of contributors is available in file 'README.txt' - # distributed within the CImg package. - # - # Licenses : This file is 'dual-licensed', you have to choose one - # of the two licenses below to apply. - # - # CeCILL-C - # The CeCILL-C license is close to the GNU LGPL. - # ( http://cecill.info/licences/Licence_CeCILL-C_V1-en.html ) - # - # or CeCILL v2.1 - # The CeCILL license is compatible with the GNU GPL. - # ( http://cecill.info/licences/Licence_CeCILL_V2.1-en.html ) - # - # This software is governed either by the CeCILL or the CeCILL-C license - # under French law and abiding by the rules of distribution of free software. - # You can use, modify and or redistribute the software under the terms of - # the CeCILL or CeCILL-C licenses as circulated by CEA, CNRS and INRIA - # at the following URL: "http://cecill.info". - # - # As a counterpart to the access to the source code and rights to copy, - # modify and redistribute granted by the license, users are provided only - # with a limited warranty and the software's author, the holder of the - # economic rights, and the successive licensors have only limited - # liability. - # - # In this respect, the user's attention is drawn to the risks associated - # with loading, using, modifying and/or developing or reproducing the - # software by the user in light of its specific status of free software, - # that may mean that it is complicated to manipulate, and that also - # therefore means that it is reserved for developers and experienced - # professionals having in-depth computer knowledge. Users are therefore - # encouraged to load and test the software's suitability as regards their - # requirements in conditions enabling the security of their systems and/or - # data to be ensured and, more generally, to use and operate it in the - # same conditions as regards security. - # - # The fact that you are presently reading this means that you have had - # knowledge of the CeCILL and CeCILL-C licenses and that you accept its terms. - # -*/ - -// Set version number of the library. -#ifndef cimg_version -#define cimg_version 320 - -/*----------------------------------------------------------- - # - # Test and possibly auto-set CImg configuration variables - # and include required headers. - # - # If you find that the default configuration variables are - # not adapted to your system, you can override their values - # before including the header file "CImg.h" - # (use the #define directive). - # - ------------------------------------------------------------*/ - -// Include standard C++ headers. -// This is the minimal set of required headers to make CImg-based codes compile. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define cimg_str(x) #x -#define cimg_str2(x) cimg_str(x) - -// Detect/configure OS variables. -// -// Define 'cimg_OS' to: '0' for an unknown OS (will try to minize library dependencies). -// '1' for a Unix-like OS (Linux, Solaris, BSD, MacOSX, Irix, ...). -// '2' for Microsoft Windows. -// (auto-detection is performed if 'cimg_OS' is not set by the user). -#ifndef cimg_OS -#if defined(unix) || defined(__unix) || defined(__unix__) \ - || defined(linux) || defined(__linux) || defined(__linux__) \ - || defined(sun) || defined(__sun) \ - || defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) \ - || defined(__FreeBSD__) || defined (__DragonFly__) \ - || defined(sgi) || defined(__sgi) \ - || defined(__OSX__) || defined(__MACOSX__) || defined(__APPLE__) \ - || defined(__CYGWIN__) -#define cimg_OS 1 -#elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \ - || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) -#define cimg_OS 2 -#else -#define cimg_OS 0 -#endif -#elif !(cimg_OS==0 || cimg_OS==1 || cimg_OS==2) -#error CImg Library: Invalid configuration variable 'cimg_OS'. -#error (correct values are '0 = unknown OS', '1 = Unix-like OS', '2 = Microsoft Windows'). -#endif -#ifndef cimg_date -#define cimg_date __DATE__ -#endif -#ifndef cimg_time -#define cimg_time __TIME__ -#endif - -// Disable silly warnings on some Microsoft VC++ compilers. -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4127) -#pragma warning(disable:4244) -#pragma warning(disable:4311) -#pragma warning(disable:4312) -#pragma warning(disable:4319) -#pragma warning(disable:4512) -#pragma warning(disable:4571) -#pragma warning(disable:4640) -#pragma warning(disable:4706) -#pragma warning(disable:4710) -#pragma warning(disable:4800) -#pragma warning(disable:4804) -#pragma warning(disable:4820) -#pragma warning(disable:4996) - -#ifndef _CRT_SECURE_NO_DEPRECATE -#define _CRT_SECURE_NO_DEPRECATE 1 -#endif -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS 1 -#endif -#ifndef _CRT_NONSTDC_NO_DEPRECATE -#define _CRT_NONSTDC_NO_DEPRECATE 1 -#endif -#endif - -// Define correct string functions for each compiler and OS. -#if cimg_OS==2 && defined(_MSC_VER) -#define cimg_sscanf std::sscanf -#define cimg_sprintf std::sprintf -#define cimg_snprintf cimg::_snprintf -#define cimg_vsnprintf cimg::_vsnprintf -#else -#include -#if defined(__MACOSX__) || defined(__APPLE__) -#define cimg_sscanf cimg::_sscanf -#define cimg_sprintf cimg::_sprintf -#define cimg_snprintf cimg::_snprintf -#define cimg_vsnprintf cimg::_vsnprintf -#else -#define cimg_sscanf std::sscanf -#define cimg_sprintf std::sprintf -#define cimg_snprintf snprintf -#define cimg_vsnprintf vsnprintf -#endif -#endif - -// Include OS-specific headers. -#if cimg_OS==1 -#include -#include -#include -#include -#include -#include -#elif cimg_OS==2 -#ifndef NOMINMAX -#define NOMINMAX -#endif -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include -#ifndef _WIN32_IE -#define _WIN32_IE 0x0400 -#endif -#include -#include -#include -enum {FALSE_WIN = 0}; -#endif - -// Look for C++11 features. -#ifndef cimg_use_cpp11 -#if __cplusplus>201100 -#define cimg_use_cpp11 1 -#else -#define cimg_use_cpp11 0 -#endif -#endif -#if cimg_use_cpp11==1 -#include -#include -#endif - -// Convenient macro to define pragma -#ifdef _MSC_VER -#define cimg_pragma(x) __pragma(x) -#else -#define cimg_pragma(x) _Pragma(#x) -#endif - -// Define own datatypes to ensure portability. -// ( 'sizeof(cimg_ulong/cimg_long) = sizeof(void*)' ). -#define cimg_uint8 unsigned char -#if defined(CHAR_MAX) && CHAR_MAX==255 -#define cimg_int8 signed char -#else -#define cimg_int8 char -#endif -#define cimg_uint16 unsigned short -#define cimg_int16 short -#define cimg_uint32 unsigned int -#define cimg_int32 int -#define cimg_float32 float -#define cimg_float64 double - -#if cimg_OS==2 - -#define cimg_uint64 unsigned __int64 -#define cimg_int64 __int64 -#define cimg_ulong UINT_PTR -#define cimg_long INT_PTR -#ifdef _MSC_VER -#define cimg_fuint64 "%I64u" -#define cimg_fint64 "%I64d" -#else -#define cimg_fuint64 "%llu" -#define cimg_fint64 "%lld" -#endif - -#else - -#if UINTPTR_MAX==0xffffffff || defined(__arm__) || defined(_M_ARM) || ((ULONG_MAX)==(UINT_MAX)) -#define cimg_uint64 unsigned long long -#define cimg_int64 long long -#define cimg_fuint64 "%llu" -#define cimg_fint64 "%lld" -#else -#define cimg_uint64 unsigned long -#define cimg_int64 long -#define cimg_fuint64 "%lu" -#define cimg_fint64 "%ld" -#endif - -#if defined(__arm__) || defined(_M_ARM) -#define cimg_ulong unsigned long long -#define cimg_long long long -#else -#define cimg_ulong unsigned long -#define cimg_long long -#endif - -#endif - -#ifndef cimg_max_buf_size -#if UINTPTR_MAX==0xffffffff -#define cimg_max_buf_size ((cimg_ulong)3*1024*1024*1024) -#else -#define cimg_max_buf_size ((cimg_ulong)16*1024*1024*1024) -#endif -#endif - -// Configure filename separator. -// -// Filename separator is set by default to '/', except for Windows where it is '\'. -#ifndef cimg_file_separator -#if cimg_OS==2 -#define cimg_file_separator '\\' -#else -#define cimg_file_separator '/' -#endif -#endif - -// Configure verbosity of output messages. -// -// Define 'cimg_verbosity' to: '0' to hide library messages (quiet mode). -// '1' to output library messages on the console. -// '2' to output library messages on a basic dialog window (default behavior). -// '3' to do as '1' + add extra warnings (may slow down the code!). -// '4' to do as '2' + add extra warnings (may slow down the code!). -// -// Define 'cimg_strict_warnings' to replace warning messages by exception throwns. -// -// Define 'cimg_use_vt100' to allow output of color messages on VT100-compatible terminals. -#ifndef cimg_verbosity -#if cimg_OS==2 -#define cimg_verbosity 2 -#else -#define cimg_verbosity 1 -#endif -#elif !(cimg_verbosity==0 || cimg_verbosity==1 || cimg_verbosity==2 || cimg_verbosity==3 || cimg_verbosity==4) -#error CImg Library: Configuration variable 'cimg_verbosity' is badly defined. -#error (should be { 0=quiet | 1=console | 2=dialog | 3=console+warnings | 4=dialog+warnings }). -#endif - -// Configure OpenMP support. -// (http://www.openmp.org) -// -// Define 'cimg_use_openmp' to enable OpenMP support (requires OpenMP 3.0+). -// -// OpenMP directives are used in many CImg functions to get -// advantages of multi-core CPUs. -#if !defined(cimg_use_openmp) -#ifdef _OPENMP -#define cimg_use_openmp 1 -#else -#define cimg_use_openmp 0 -#endif -#else -#undef cimg_use_openmp -#define cimg_use_openmp 1 -#endif -#if cimg_use_openmp!=0 -#include -#define cimg_pragma_openmp(p) cimg_pragma(omp p) -#else -#define cimg_pragma_openmp(p) -#endif - -// Configure the 'abort' signal handler (does nothing by default). -// A typical signal handler can be defined in your own source like this: -// #define cimg_abort_test if (is_abort) throw CImgAbortException("") -// -// where 'is_abort' is a boolean variable defined somewhere in your code and reachable in the method. -// 'cimg_abort_test2' does the same but is called more often (in inner loops). -#if defined(cimg_abort_test) && cimg_use_openmp!=0 - -// Define abort macros to be used with OpenMP. -#ifndef _cimg_abort_init_openmp -#define _cimg_abort_init_openmp unsigned int _cimg_abort_go_openmp = 1; cimg::unused(_cimg_abort_go_openmp) -#endif -#ifndef _cimg_abort_try_openmp -#define _cimg_abort_try_openmp if (_cimg_abort_go_openmp) try -#endif -#ifndef _cimg_abort_catch_openmp -#define _cimg_abort_catch_openmp catch (CImgAbortException&) { \ - cimg_pragma_openmp(atomic) _cimg_abort_go_openmp&=0; \ -} -#endif -#ifndef _cimg_abort_catch_fill_openmp -#define _cimg_abort_catch_fill_openmp \ - catch (CImgException& e) { cimg_pragma(omp critical(abort)) CImg::string(e._message).move_to(is_error_expr); \ - cimg_pragma_openmp(atomic) _cimg_abort_go_openmp&=0; } -#endif -#ifdef cimg_abort_test2 -#ifndef _cimg_abort_try_openmp2 -#define _cimg_abort_try_openmp2 _cimg_abort_try_openmp -#endif -#ifndef _cimg_abort_catch_openmp2 -#define _cimg_abort_catch_openmp2 _cimg_abort_catch_openmp -#endif -#endif -#endif - -#ifndef _cimg_abort_init_openmp -#define _cimg_abort_init_openmp -#endif -#ifndef _cimg_abort_try_openmp -#define _cimg_abort_try_openmp -#endif -#ifndef _cimg_abort_catch_openmp -#define _cimg_abort_catch_openmp -#endif -#ifndef _cimg_abort_try_openmp2 -#define _cimg_abort_try_openmp2 -#endif -#ifndef _cimg_abort_catch_openmp2 -#define _cimg_abort_catch_openmp2 -#endif -#ifndef _cimg_abort_catch_fill_openmp -#define _cimg_abort_catch_fill_openmp -#endif -#ifndef cimg_abort_init -#define cimg_abort_init -#endif -#ifndef cimg_abort_test -#define cimg_abort_test -#endif -#ifndef cimg_abort_test2 -#define cimg_abort_test2 -#endif - -// Configure display framework. -// -// Define 'cimg_display' to: '0' to disable display capabilities. -// '1' to use the X-Window framework (X11). -// '2' to use the Microsoft GDI32 framework. -#ifndef cimg_display -#if cimg_OS==0 -#define cimg_display 0 -#elif cimg_OS==1 -#define cimg_display 1 -#elif cimg_OS==2 -#define cimg_display 2 -#endif -#elif !(cimg_display==0 || cimg_display==1 || cimg_display==2) -#error CImg Library: Configuration variable 'cimg_display' is badly defined. -#error (should be { 0=none | 1=X-Window (X11) | 2=Microsoft GDI32 }). -#endif - -// Include display-specific headers. -#if cimg_display==1 -#include -#include -#include -#include -#ifdef cimg_use_xshm -#include -#include -#include -#endif -#ifdef cimg_use_xrandr -#include -#endif -#endif -#ifndef cimg_appname -#define cimg_appname "CImg" -#endif - -// Configure OpenCV support. -// (http://opencv.willowgarage.com/wiki/) -// -// Define 'cimg_use_opencv' to enable OpenCV support. -// -// OpenCV library may be used to access images from cameras -// (see method 'CImg::load_camera()'). -#ifdef cimg_use_opencv -#ifdef True -#undef True -#define _cimg_redefine_True -#endif -#ifdef False -#undef False -#define _cimg_redefine_False -#endif -#ifdef Status -#undef Status -#define _cimg_redefine_Status -#endif -#include -#include -#if CV_MAJOR_VERSION>=3 -#define _cimg_fourcc cv::VideoWriter::fourcc -#define _cimg_cap_prop_frame_width cv::VideoCaptureProperties::CAP_PROP_FRAME_WIDTH -#define _cimg_cap_prop_frame_height cv::VideoCaptureProperties::CAP_PROP_FRAME_HEIGHT -#define _cimg_cap_prop_frame_count cv::VideoCaptureProperties::CAP_PROP_FRAME_COUNT -#else -#define _cimg_fourcc CV_FOURCC -#define _cimg_cap_prop_frame_width CV_CAP_PROP_FRAME_WIDTH -#define _cimg_cap_prop_frame_height CV_CAP_PROP_FRAME_HEIGHT -#define _cimg_cap_prop_frame_count CV_CAP_PROP_FRAME_COUNT -#endif -#endif - -// Configure LibPNG support. -// (http://www.libpng.org) -// -// Define 'cimg_use_png' to enable LibPNG support. -// -// PNG library may be used to get a native support of '.png' files. -// (see methods 'CImg::{load,save}_png()'. -#ifdef cimg_use_png -extern "C" { -#include "png.h" -} -#endif - -// Configure LibJPEG support. -// (http://en.wikipedia.org/wiki/Libjpeg) -// -// Define 'cimg_use_jpeg' to enable LibJPEG support. -// -// JPEG library may be used to get a native support of '.jpg' files. -// (see methods 'CImg::{load,save}_jpeg()'). -#ifdef cimg_use_jpeg -extern "C" { -#include "jpeglib.h" -#include "setjmp.h" -} -#endif - -// Configure LibTIFF support. -// (http://www.libtiff.org) -// -// Define 'cimg_use_tiff' to enable LibTIFF support. -// -// TIFF library may be used to get a native support of '.tif' files. -// (see methods 'CImg[List]::{load,save}_tiff()'). -#ifdef cimg_use_tiff -extern "C" { -#define uint64 uint64_hack_ -#define int64 int64_hack_ -#include "tiffio.h" -#undef uint64 -#undef int64 -} -#endif - -// Configure HEIF support -// (https://github.com/strukturag/libheif) -// -// Define 'cimg_use_heif' to enable HEIF support. -// -// HEIF library may be used to get a native support of '.heic' and '.avif' files. -// (see method 'CImg::load_heif()'). -#ifdef cimg_use_heif -#include -#endif - -// Configure LibMINC2 support. -// (http://en.wikibooks.org/wiki/MINC/Reference/MINC2.0_File_Format_Reference) -// -// Define 'cimg_use_minc2' to enable LibMINC2 support. -// -// MINC2 library may be used to get a native support of '.mnc' files. -// (see methods 'CImg::{load,save}_minc2()'). -#ifdef cimg_use_minc2 -#include "minc_io_simple_volume.h" -#include "minc_1_simple.h" -#include "minc_1_simple_rw.h" -#endif - -// Configure Zlib support. -// (http://www.zlib.net) -// -// Define 'cimg_use_zlib' to enable Zlib support. -// -// Zlib library may be used to allow compressed data in '.cimgz' files -// (see methods 'CImg[List]::{load,save}_cimg()'). -#ifdef cimg_use_zlib -extern "C" { -#include "zlib.h" -} -#endif - -// Configure libcurl support. -// (http://curl.haxx.se/libcurl/) -// -// Define 'cimg_use_curl' to enable libcurl support. -// -// Libcurl may be used to get a native support of file downloading from the network. -// (see method 'cimg::load_network()'.) -#ifdef cimg_use_curl -#include "curl/curl.h" -#endif - -// Configure Magick++ support. -// (http://www.imagemagick.org/Magick++) -// -// Define 'cimg_use_magick' to enable Magick++ support. -// -// Magick++ library may be used to get a native support of various image file formats. -// (see methods 'CImg::{load,save}()'). -#ifdef cimg_use_magick -#include "Magick++.h" -#endif - -// Configure FFTW3 support. -// (http://www.fftw.org) -// -// Define 'cimg_use_fftw3' to enable libFFTW3 support. -// -// FFTW3 library may be used to efficiently compute the Fast Fourier Transform -// of image data, without restriction on the image size. -// (see method 'CImg[List]::FFT()'). -#ifdef cimg_use_fftw3 -extern "C" { -#include "fftw3.h" -} -#endif - -// Configure LibBoard support. -// (http://libboard.sourceforge.net/) -// -// Define 'cimg_use_board' to enable Board support. -// -// Board library may be used to draw 3D objects in vector-graphics canvas -// that can be saved as '.ps' or '.svg' files afterwards. -// (see method 'CImg::draw_object3d()'). -#ifdef cimg_use_board -#include "Board.h" -#endif - -// Configure OpenEXR support. -// (http://www.openexr.com/) -// -// Define 'cimg_use_openexr' to enable OpenEXR support. -// -// OpenEXR library may be used to get a native support of '.exr' files. -// (see methods 'CImg::{load,save}_exr()'). -#ifdef cimg_use_openexr -#if __GNUC__>=5 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated" -#pragma GCC diagnostic ignored "-Wdeprecated-copy" -#pragma GCC diagnostic ignored "-Wshadow" -#endif -#include "ImfRgbaFile.h" -#include "ImfInputFile.h" -#include "ImfChannelList.h" -#include "ImfMatrixAttribute.h" -#include "ImfArray.h" -#if __GNUC__>=5 -#pragma GCC diagnostic pop -#endif -#endif - -// Configure TinyEXR support. -// (https://github.com/syoyo/tinyexr) -// -// Define 'cimg_use_tinyexr' to enable TinyEXR support. -// -// TinyEXR is a small, single header-only library to load and save OpenEXR(.exr) images. -#ifdef cimg_use_tinyexr -#ifndef TINYEXR_IMPLEMENTATION -#define TINYEXR_IMPLEMENTATION -#endif -#include "tinyexr.h" -#endif - -// Lapack configuration. -// (http://www.netlib.org/lapack) -// -// Define 'cimg_use_lapack' to enable LAPACK support. -// -// Lapack library may be used in several CImg methods to speed up -// matrix computations (eigenvalues, inverse, ...). -#ifdef cimg_use_lapack -extern "C" { - extern void sgetrf_(int*, int*, float*, int*, int*, int*); - extern void sgetri_(int*, float*, int*, int*, float*, int*, int*); - extern void sgetrs_(char*, int*, int*, float*, int*, int*, float*, int*, int*); - extern void sgesvd_(char*, char*, int*, int*, float*, int*, float*, float*, int*, float*, int*, float*, int*, int*); - extern void ssyev_(char*, char*, int*, float*, int*, float*, float*, int*, int*); - extern void dgetrf_(int*, int*, double*, int*, int*, int*); - extern void dgetri_(int*, double*, int*, int*, double*, int*, int*); - extern void dgetrs_(char*, int*, int*, double*, int*, int*, double*, int*, int*); - extern void dgesvd_(char*, char*, int*, int*, double*, int*, double*, double*, - int*, double*, int*, double*, int*, int*); - extern void dsyev_(char*, char*, int*, double*, int*, double*, double*, int*, int*); - extern void dgels_(char*, int*,int*,int*,double*,int*,double*,int*,double*,int*,int*); - extern void sgels_(char*, int*,int*,int*,float*,int*,float*,int*,float*,int*,int*); -} -#endif - -// Check if min/max/PI macros are defined. -// -// CImg does not compile if macros 'min', 'max' or 'PI' are defined, -// because it redefines functions min(), max() and const variable PI in the cimg:: namespace. -// so it '#undef' these macros if necessary, and restore them to reasonable -// values at the end of this file. -#ifdef min -#undef min -#define _cimg_redefine_min -#endif -#ifdef max -#undef max -#define _cimg_redefine_max -#endif -#ifdef PI -#undef PI -#define _cimg_redefine_PI -#endif - -// Define 'cimg_library' namespace suffix. -// -// You may want to add a suffix to the 'cimg_library' namespace, for instance if you need to work -// with several versions of the library at the same time. -#ifdef cimg_namespace_suffix -#define __cimg_library_suffixed(s) cimg_library_##s -#define _cimg_library_suffixed(s) __cimg_library_suffixed(s) -#define cimg_library_suffixed _cimg_library_suffixed(cimg_namespace_suffix) -#else -#define cimg_library_suffixed cimg_library -#endif - -/*------------------------------------------------------------------------------ - # - # Define user-friendly macros. - # - # These CImg macros are prefixed by 'cimg_' and can be used safely in your own - # code. They are useful to parse command line options, or to write image loops. - # - ------------------------------------------------------------------------------*/ - -// Macros to define program usage, and retrieve command line arguments. -#define cimg_usage(usage) cimg_library_suffixed::cimg::option((char*)0,argc,argv,(char*)0,usage,false) -#define cimg_help(str) cimg_library_suffixed::cimg::option((char*)0,argc,argv,str,(char*)0) -#define cimg_option(name,_default,usage) cimg_library_suffixed::cimg::option(name,argc,argv,_default,usage) - -// Macros to define and manipulate local neighborhoods. -#define CImg_2x2(I,T) T I[4]; \ - T& I##cc = I[0]; T& I##nc = I[1]; \ - T& I##cn = I[2]; T& I##nn = I[3]; \ - I##cc = I##nc = \ - I##cn = I##nn = 0 - -#define CImg_3x3(I,T) T I[9]; \ - T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; \ - T& I##pc = I[3]; T& I##cc = I[4]; T& I##nc = I[5]; \ - T& I##pn = I[6]; T& I##cn = I[7]; T& I##nn = I[8]; \ - I##pp = I##cp = I##np = \ - I##pc = I##cc = I##nc = \ - I##pn = I##cn = I##nn = 0 - -#define CImg_4x4(I,T) T I[16]; \ - T& I##pp = I[0]; T& I##cp = I[1]; T& I##np = I[2]; T& I##ap = I[3]; \ - T& I##pc = I[4]; T& I##cc = I[5]; T& I##nc = I[6]; T& I##ac = I[7]; \ - T& I##pn = I[8]; T& I##cn = I[9]; T& I##nn = I[10]; T& I##an = I[11]; \ - T& I##pa = I[12]; T& I##ca = I[13]; T& I##na = I[14]; T& I##aa = I[15]; \ - I##pp = I##cp = I##np = I##ap = \ - I##pc = I##cc = I##nc = I##ac = \ - I##pn = I##cn = I##nn = I##an = \ - I##pa = I##ca = I##na = I##aa = 0 - -#define CImg_5x5(I,T) T I[25]; \ - T& I##bb = I[0]; T& I##pb = I[1]; T& I##cb = I[2]; T& I##nb = I[3]; T& I##ab = I[4]; \ - T& I##bp = I[5]; T& I##pp = I[6]; T& I##cp = I[7]; T& I##np = I[8]; T& I##ap = I[9]; \ - T& I##bc = I[10]; T& I##pc = I[11]; T& I##cc = I[12]; T& I##nc = I[13]; T& I##ac = I[14]; \ - T& I##bn = I[15]; T& I##pn = I[16]; T& I##cn = I[17]; T& I##nn = I[18]; T& I##an = I[19]; \ - T& I##ba = I[20]; T& I##pa = I[21]; T& I##ca = I[22]; T& I##na = I[23]; T& I##aa = I[24]; \ - I##bb = I##pb = I##cb = I##nb = I##ab = \ - I##bp = I##pp = I##cp = I##np = I##ap = \ - I##bc = I##pc = I##cc = I##nc = I##ac = \ - I##bn = I##pn = I##cn = I##nn = I##an = \ - I##ba = I##pa = I##ca = I##na = I##aa = 0 - -#define CImg_2x2x2(I,T) T I[8]; \ - T& I##ccc = I[0]; T& I##ncc = I[1]; \ - T& I##cnc = I[2]; T& I##nnc = I[3]; \ - T& I##ccn = I[4]; T& I##ncn = I[5]; \ - T& I##cnn = I[6]; T& I##nnn = I[7]; \ - I##ccc = I##ncc = \ - I##cnc = I##nnc = \ - I##ccn = I##ncn = \ - I##cnn = I##nnn = 0 - -#define CImg_3x3x3(I,T) T I[27]; \ - T& I##ppp = I[0]; T& I##cpp = I[1]; T& I##npp = I[2]; \ - T& I##pcp = I[3]; T& I##ccp = I[4]; T& I##ncp = I[5]; \ - T& I##pnp = I[6]; T& I##cnp = I[7]; T& I##nnp = I[8]; \ - T& I##ppc = I[9]; T& I##cpc = I[10]; T& I##npc = I[11]; \ - T& I##pcc = I[12]; T& I##ccc = I[13]; T& I##ncc = I[14]; \ - T& I##pnc = I[15]; T& I##cnc = I[16]; T& I##nnc = I[17]; \ - T& I##ppn = I[18]; T& I##cpn = I[19]; T& I##npn = I[20]; \ - T& I##pcn = I[21]; T& I##ccn = I[22]; T& I##ncn = I[23]; \ - T& I##pnn = I[24]; T& I##cnn = I[25]; T& I##nnn = I[26]; \ - I##ppp = I##cpp = I##npp = \ - I##pcp = I##ccp = I##ncp = \ - I##pnp = I##cnp = I##nnp = \ - I##ppc = I##cpc = I##npc = \ - I##pcc = I##ccc = I##ncc = \ - I##pnc = I##cnc = I##nnc = \ - I##ppn = I##cpn = I##npn = \ - I##pcn = I##ccn = I##ncn = \ - I##pnn = I##cnn = I##nnn = 0 - -#define cimg_def2x2(img,x,y) \ - int _n1##x = x<(img).width() - 1?x + 1:(img).width() - 1, \ - _n1##y = y<(img).height() - 1?y + 1:(img).height() - 1 - -#define cimg_def3x3(img,x,y) \ - cimg_def2x2(img,x,y); \ - int _p1##x = x>1?x - 1:0, \ - _p1##y = y>1?y - 1:0 - -#define cimg_def4x4(img,x,y) \ - cimg_def3x3(img,x,y); \ - int _n2##x = x<(img).width() - 2?x + 2:(img).width() - 1, \ - _n2##y = y<(img).height() - 2?y + 2:(img).height() - 1 - -#define cimg_def5x5(img,x,y) \ - cimg_def4x4(img,x,y); \ - int _p2##x = x>2?x - 2:0, \ - _p2##y = y>2?y - 2:0 - -#define cimg_def6x6(img,x,y) \ - cimg_def5x5(img,x,y); \ - int _n3##x = x<(img).width() - 3?x + 3:(img).width() - 1, \ - _n3##y = y<(img).height() - 3?y + 3:(img).height() - 1 - -#define cimg_def7x7(img,x,y) \ - cimg_def6x6(img,x,y); \ - int _p3##x = x>3?x - 3:0, \ - _p3##y = y>3?y - 3:0 - -#define cimg_def8x8(img,x,y) \ - cimg_def7x7(img,x,y); \ - int _n4##x = x<(img).width() - 4?x + 4:(img).width() - 1, \ - _n4##y = y<(img).height() - 4?y + 4:(img).height() - 1 - -#define cimg_def9x9(img,x,y) \ - cimg_def8x8(img,x,y); \ - int _p4##x = x>4?x - 4:0, \ - _p4##y = y>4?y - 4:0 - -#define cimg_def2x2x2(img,x,y,z) \ - cimg_def2x2(img,x,y); \ - int _n1##z = z<(img).depth() - 1?z + 1:(img).depth() - 1 - -#define cimg_def3x3x3(img,x,y,z) \ - cimg_def2x2x2(img,x,y,z); \ - int _p1##x = x>1?x - 1:0, \ - _p1##y = y>1?y - 1:0, \ - _p1##z = z>1?z - 1:0 - -#define cimg_get2x2(img,x,y,z,c,I,T) \ - I[0] = (T)(img)(x,y,z,c), I[1] = (T)(img)(_n1##x,y,z,c), I[2] = (T)(img)(x,_n1##y,z,c), \ - I[3] = (T)(img)(_n1##x,_n1##y,z,c) - -#define cimg_get3x3(img,x,y,z,c,I,T) \ - I[0] = (T)(img)(_p1##x,_p1##y,z,c), I[1] = (T)(img)(x,_p1##y,z,c), I[2] = (T)(img)(_n1##x,_p1##y,z,c), \ - I[3] = (T)(img)(_p1##x,y,z,c), I[4] = (T)(img)(x,y,z,c), I[5] = (T)(img)(_n1##x,y,z,c), \ - I[6] = (T)(img)(_p1##x,_n1##y,z,c), I[7] = (T)(img)(x,_n1##y,z,c), I[8] = (T)(img)(_n1##x,_n1##y,z,c) - -#define cimg_get4x4(img,x,y,z,c,I,T) \ - I[0] = (T)(img)(_p1##x,_p1##y,z,c), I[1] = (T)(img)(x,_p1##y,z,c), I[2] = (T)(img)(_n1##x,_p1##y,z,c), \ - I[3] = (T)(img)(_n2##x,_p1##y,z,c), I[4] = (T)(img)(_p1##x,y,z,c), I[5] = (T)(img)(x,y,z,c), \ - I[6] = (T)(img)(_n1##x,y,z,c), I[7] = (T)(img)(_n2##x,y,z,c), I[8] = (T)(img)(_p1##x,_n1##y,z,c), \ - I[9] = (T)(img)(x,_n1##y,z,c), I[10] = (T)(img)(_n1##x,_n1##y,z,c), I[11] = (T)(img)(_n2##x,_n1##y,z,c), \ - I[12] = (T)(img)(_p1##x,_n2##y,z,c), I[13] = (T)(img)(x,_n2##y,z,c), I[14] = (T)(img)(_n1##x,_n2##y,z,c), \ - I[15] = (T)(img)(_n2##x,_n2##y,z,c) - -#define cimg_get5x5(img,x,y,z,c,I,T) \ - I[0] = (T)(img)(_p2##x,_p2##y,z,c), I[1] = (T)(img)(_p1##x,_p2##y,z,c), I[2] = (T)(img)(x,_p2##y,z,c), \ - I[3] = (T)(img)(_n1##x,_p2##y,z,c), I[4] = (T)(img)(_n2##x,_p2##y,z,c), I[5] = (T)(img)(_p2##x,_p1##y,z,c), \ - I[6] = (T)(img)(_p1##x,_p1##y,z,c), I[7] = (T)(img)(x,_p1##y,z,c), I[8] = (T)(img)(_n1##x,_p1##y,z,c), \ - I[9] = (T)(img)(_n2##x,_p1##y,z,c), I[10] = (T)(img)(_p2##x,y,z,c), I[11] = (T)(img)(_p1##x,y,z,c), \ - I[12] = (T)(img)(x,y,z,c), I[13] = (T)(img)(_n1##x,y,z,c), I[14] = (T)(img)(_n2##x,y,z,c), \ - I[15] = (T)(img)(_p2##x,_n1##y,z,c), I[16] = (T)(img)(_p1##x,_n1##y,z,c), I[17] = (T)(img)(x,_n1##y,z,c), \ - I[18] = (T)(img)(_n1##x,_n1##y,z,c), I[19] = (T)(img)(_n2##x,_n1##y,z,c), I[20] = (T)(img)(_p2##x,_n2##y,z,c), \ - I[21] = (T)(img)(_p1##x,_n2##y,z,c), I[22] = (T)(img)(x,_n2##y,z,c), I[23] = (T)(img)(_n1##x,_n2##y,z,c), \ - I[24] = (T)(img)(_n2##x,_n2##y,z,c) - -#define cimg_get6x6(img,x,y,z,c,I,T) \ - I[0] = (T)(img)(_p2##x,_p2##y,z,c), I[1] = (T)(img)(_p1##x,_p2##y,z,c), I[2] = (T)(img)(x,_p2##y,z,c), \ - I[3] = (T)(img)(_n1##x,_p2##y,z,c), I[4] = (T)(img)(_n2##x,_p2##y,z,c), I[5] = (T)(img)(_n3##x,_p2##y,z,c), \ - I[6] = (T)(img)(_p2##x,_p1##y,z,c), I[7] = (T)(img)(_p1##x,_p1##y,z,c), I[8] = (T)(img)(x,_p1##y,z,c), \ - I[9] = (T)(img)(_n1##x,_p1##y,z,c), I[10] = (T)(img)(_n2##x,_p1##y,z,c), I[11] = (T)(img)(_n3##x,_p1##y,z,c), \ - I[12] = (T)(img)(_p2##x,y,z,c), I[13] = (T)(img)(_p1##x,y,z,c), I[14] = (T)(img)(x,y,z,c), \ - I[15] = (T)(img)(_n1##x,y,z,c), I[16] = (T)(img)(_n2##x,y,z,c), I[17] = (T)(img)(_n3##x,y,z,c), \ - I[18] = (T)(img)(_p2##x,_n1##y,z,c), I[19] = (T)(img)(_p1##x,_n1##y,z,c), I[20] = (T)(img)(x,_n1##y,z,c), \ - I[21] = (T)(img)(_n1##x,_n1##y,z,c), I[22] = (T)(img)(_n2##x,_n1##y,z,c), I[23] = (T)(img)(_n3##x,_n1##y,z,c), \ - I[24] = (T)(img)(_p2##x,_n2##y,z,c), I[25] = (T)(img)(_p1##x,_n2##y,z,c), I[26] = (T)(img)(x,_n2##y,z,c), \ - I[27] = (T)(img)(_n1##x,_n2##y,z,c), I[28] = (T)(img)(_n2##x,_n2##y,z,c), I[29] = (T)(img)(_n3##x,_n2##y,z,c), \ - I[30] = (T)(img)(_p2##x,_n3##y,z,c), I[31] = (T)(img)(_p1##x,_n3##y,z,c), I[32] = (T)(img)(x,_n3##y,z,c), \ - I[33] = (T)(img)(_n1##x,_n3##y,z,c), I[34] = (T)(img)(_n2##x,_n3##y,z,c), I[35] = (T)(img)(_n3##x,_n3##y,z,c) - -#define cimg_get7x7(img,x,y,z,c,I,T) \ - I[0] = (T)(img)(_p3##x,_p3##y,z,c), I[1] = (T)(img)(_p2##x,_p3##y,z,c), I[2] = (T)(img)(_p1##x,_p3##y,z,c), \ - I[3] = (T)(img)(x,_p3##y,z,c), I[4] = (T)(img)(_n1##x,_p3##y,z,c), I[5] = (T)(img)(_n2##x,_p3##y,z,c), \ - I[6] = (T)(img)(_n3##x,_p3##y,z,c), I[7] = (T)(img)(_p3##x,_p2##y,z,c), I[8] = (T)(img)(_p2##x,_p2##y,z,c), \ - I[9] = (T)(img)(_p1##x,_p2##y,z,c), I[10] = (T)(img)(x,_p2##y,z,c), I[11] = (T)(img)(_n1##x,_p2##y,z,c), \ - I[12] = (T)(img)(_n2##x,_p2##y,z,c), I[13] = (T)(img)(_n3##x,_p2##y,z,c), I[14] = (T)(img)(_p3##x,_p1##y,z,c), \ - I[15] = (T)(img)(_p2##x,_p1##y,z,c), I[16] = (T)(img)(_p1##x,_p1##y,z,c), I[17] = (T)(img)(x,_p1##y,z,c), \ - I[18] = (T)(img)(_n1##x,_p1##y,z,c), I[19] = (T)(img)(_n2##x,_p1##y,z,c), I[20] = (T)(img)(_n3##x,_p1##y,z,c), \ - I[21] = (T)(img)(_p3##x,y,z,c), I[22] = (T)(img)(_p2##x,y,z,c), I[23] = (T)(img)(_p1##x,y,z,c), \ - I[24] = (T)(img)(x,y,z,c), I[25] = (T)(img)(_n1##x,y,z,c), I[26] = (T)(img)(_n2##x,y,z,c), \ - I[27] = (T)(img)(_n3##x,y,z,c), I[28] = (T)(img)(_p3##x,_n1##y,z,c), I[29] = (T)(img)(_p2##x,_n1##y,z,c), \ - I[30] = (T)(img)(_p1##x,_n1##y,z,c), I[31] = (T)(img)(x,_n1##y,z,c), I[32] = (T)(img)(_n1##x,_n1##y,z,c), \ - I[33] = (T)(img)(_n2##x,_n1##y,z,c), I[34] = (T)(img)(_n3##x,_n1##y,z,c), I[35] = (T)(img)(_p3##x,_n2##y,z,c), \ - I[36] = (T)(img)(_p2##x,_n2##y,z,c), I[37] = (T)(img)(_p1##x,_n2##y,z,c), I[38] = (T)(img)(x,_n2##y,z,c), \ - I[39] = (T)(img)(_n1##x,_n2##y,z,c), I[40] = (T)(img)(_n2##x,_n2##y,z,c), I[41] = (T)(img)(_n3##x,_n2##y,z,c), \ - I[42] = (T)(img)(_p3##x,_n3##y,z,c), I[43] = (T)(img)(_p2##x,_n3##y,z,c), I[44] = (T)(img)(_p1##x,_n3##y,z,c), \ - I[45] = (T)(img)(x,_n3##y,z,c), I[46] = (T)(img)(_n1##x,_n3##y,z,c), I[47] = (T)(img)(_n2##x,_n3##y,z,c), \ - I[48] = (T)(img)(_n3##x,_n3##y,z,c) - -#define cimg_get8x8(img,x,y,z,c,I,T) \ - I[0] = (T)(img)(_p3##x,_p3##y,z,c), I[1] = (T)(img)(_p2##x,_p3##y,z,c), I[2] = (T)(img)(_p1##x,_p3##y,z,c), \ - I[3] = (T)(img)(x,_p3##y,z,c), I[4] = (T)(img)(_n1##x,_p3##y,z,c), I[5] = (T)(img)(_n2##x,_p3##y,z,c), \ - I[6] = (T)(img)(_n3##x,_p3##y,z,c), I[7] = (T)(img)(_n4##x,_p3##y,z,c), I[8] = (T)(img)(_p3##x,_p2##y,z,c), \ - I[9] = (T)(img)(_p2##x,_p2##y,z,c), I[10] = (T)(img)(_p1##x,_p2##y,z,c), I[11] = (T)(img)(x,_p2##y,z,c), \ - I[12] = (T)(img)(_n1##x,_p2##y,z,c), I[13] = (T)(img)(_n2##x,_p2##y,z,c), I[14] = (T)(img)(_n3##x,_p2##y,z,c), \ - I[15] = (T)(img)(_n4##x,_p2##y,z,c), I[16] = (T)(img)(_p3##x,_p1##y,z,c), I[17] = (T)(img)(_p2##x,_p1##y,z,c), \ - I[18] = (T)(img)(_p1##x,_p1##y,z,c), I[19] = (T)(img)(x,_p1##y,z,c), I[20] = (T)(img)(_n1##x,_p1##y,z,c), \ - I[21] = (T)(img)(_n2##x,_p1##y,z,c), I[22] = (T)(img)(_n3##x,_p1##y,z,c), I[23] = (T)(img)(_n4##x,_p1##y,z,c), \ - I[24] = (T)(img)(_p3##x,y,z,c), I[25] = (T)(img)(_p2##x,y,z,c), I[26] = (T)(img)(_p1##x,y,z,c), \ - I[27] = (T)(img)(x,y,z,c), I[28] = (T)(img)(_n1##x,y,z,c), I[29] = (T)(img)(_n2##x,y,z,c), \ - I[30] = (T)(img)(_n3##x,y,z,c), I[31] = (T)(img)(_n4##x,y,z,c), I[32] = (T)(img)(_p3##x,_n1##y,z,c), \ - I[33] = (T)(img)(_p2##x,_n1##y,z,c), I[34] = (T)(img)(_p1##x,_n1##y,z,c), I[35] = (T)(img)(x,_n1##y,z,c), \ - I[36] = (T)(img)(_n1##x,_n1##y,z,c), I[37] = (T)(img)(_n2##x,_n1##y,z,c), I[38] = (T)(img)(_n3##x,_n1##y,z,c), \ - I[39] = (T)(img)(_n4##x,_n1##y,z,c), I[40] = (T)(img)(_p3##x,_n2##y,z,c), I[41] = (T)(img)(_p2##x,_n2##y,z,c), \ - I[42] = (T)(img)(_p1##x,_n2##y,z,c), I[43] = (T)(img)(x,_n2##y,z,c), I[44] = (T)(img)(_n1##x,_n2##y,z,c), \ - I[45] = (T)(img)(_n2##x,_n2##y,z,c), I[46] = (T)(img)(_n3##x,_n2##y,z,c), I[47] = (T)(img)(_n4##x,_n2##y,z,c), \ - I[48] = (T)(img)(_p3##x,_n3##y,z,c), I[49] = (T)(img)(_p2##x,_n3##y,z,c), I[50] = (T)(img)(_p1##x,_n3##y,z,c), \ - I[51] = (T)(img)(x,_n3##y,z,c), I[52] = (T)(img)(_n1##x,_n3##y,z,c), I[53] = (T)(img)(_n2##x,_n3##y,z,c), \ - I[54] = (T)(img)(_n3##x,_n3##y,z,c), I[55] = (T)(img)(_n4##x,_n3##y,z,c), I[56] = (T)(img)(_p3##x,_n4##y,z,c), \ - I[57] = (T)(img)(_p2##x,_n4##y,z,c), I[58] = (T)(img)(_p1##x,_n4##y,z,c), I[59] = (T)(img)(x,_n4##y,z,c), \ - I[60] = (T)(img)(_n1##x,_n4##y,z,c), I[61] = (T)(img)(_n2##x,_n4##y,z,c), I[62] = (T)(img)(_n3##x,_n4##y,z,c), \ - I[63] = (T)(img)(_n4##x,_n4##y,z,c); - -#define cimg_get9x9(img,x,y,z,c,I,T) \ - I[0] = (T)(img)(_p4##x,_p4##y,z,c), I[1] = (T)(img)(_p3##x,_p4##y,z,c), I[2] = (T)(img)(_p2##x,_p4##y,z,c), \ - I[3] = (T)(img)(_p1##x,_p4##y,z,c), I[4] = (T)(img)(x,_p4##y,z,c), I[5] = (T)(img)(_n1##x,_p4##y,z,c), \ - I[6] = (T)(img)(_n2##x,_p4##y,z,c), I[7] = (T)(img)(_n3##x,_p4##y,z,c), I[8] = (T)(img)(_n4##x,_p4##y,z,c), \ - I[9] = (T)(img)(_p4##x,_p3##y,z,c), I[10] = (T)(img)(_p3##x,_p3##y,z,c), I[11] = (T)(img)(_p2##x,_p3##y,z,c), \ - I[12] = (T)(img)(_p1##x,_p3##y,z,c), I[13] = (T)(img)(x,_p3##y,z,c), I[14] = (T)(img)(_n1##x,_p3##y,z,c), \ - I[15] = (T)(img)(_n2##x,_p3##y,z,c), I[16] = (T)(img)(_n3##x,_p3##y,z,c), I[17] = (T)(img)(_n4##x,_p3##y,z,c), \ - I[18] = (T)(img)(_p4##x,_p2##y,z,c), I[19] = (T)(img)(_p3##x,_p2##y,z,c), I[20] = (T)(img)(_p2##x,_p2##y,z,c), \ - I[21] = (T)(img)(_p1##x,_p2##y,z,c), I[22] = (T)(img)(x,_p2##y,z,c), I[23] = (T)(img)(_n1##x,_p2##y,z,c), \ - I[24] = (T)(img)(_n2##x,_p2##y,z,c), I[25] = (T)(img)(_n3##x,_p2##y,z,c), I[26] = (T)(img)(_n4##x,_p2##y,z,c), \ - I[27] = (T)(img)(_p4##x,_p1##y,z,c), I[28] = (T)(img)(_p3##x,_p1##y,z,c), I[29] = (T)(img)(_p2##x,_p1##y,z,c), \ - I[30] = (T)(img)(_p1##x,_p1##y,z,c), I[31] = (T)(img)(x,_p1##y,z,c), I[32] = (T)(img)(_n1##x,_p1##y,z,c), \ - I[33] = (T)(img)(_n2##x,_p1##y,z,c), I[34] = (T)(img)(_n3##x,_p1##y,z,c), I[35] = (T)(img)(_n4##x,_p1##y,z,c), \ - I[36] = (T)(img)(_p4##x,y,z,c), I[37] = (T)(img)(_p3##x,y,z,c), I[38] = (T)(img)(_p2##x,y,z,c), \ - I[39] = (T)(img)(_p1##x,y,z,c), I[40] = (T)(img)(x,y,z,c), I[41] = (T)(img)(_n1##x,y,z,c), \ - I[42] = (T)(img)(_n2##x,y,z,c), I[43] = (T)(img)(_n3##x,y,z,c), I[44] = (T)(img)(_n4##x,y,z,c), \ - I[45] = (T)(img)(_p4##x,_n1##y,z,c), I[46] = (T)(img)(_p3##x,_n1##y,z,c), I[47] = (T)(img)(_p2##x,_n1##y,z,c), \ - I[48] = (T)(img)(_p1##x,_n1##y,z,c), I[49] = (T)(img)(x,_n1##y,z,c), I[50] = (T)(img)(_n1##x,_n1##y,z,c), \ - I[51] = (T)(img)(_n2##x,_n1##y,z,c), I[52] = (T)(img)(_n3##x,_n1##y,z,c), I[53] = (T)(img)(_n4##x,_n1##y,z,c), \ - I[54] = (T)(img)(_p4##x,_n2##y,z,c), I[55] = (T)(img)(_p3##x,_n2##y,z,c), I[56] = (T)(img)(_p2##x,_n2##y,z,c), \ - I[57] = (T)(img)(_p1##x,_n2##y,z,c), I[58] = (T)(img)(x,_n2##y,z,c), I[59] = (T)(img)(_n1##x,_n2##y,z,c), \ - I[60] = (T)(img)(_n2##x,_n2##y,z,c), I[61] = (T)(img)(_n3##x,_n2##y,z,c), I[62] = (T)(img)(_n4##x,_n2##y,z,c), \ - I[63] = (T)(img)(_p4##x,_n3##y,z,c), I[64] = (T)(img)(_p3##x,_n3##y,z,c), I[65] = (T)(img)(_p2##x,_n3##y,z,c), \ - I[66] = (T)(img)(_p1##x,_n3##y,z,c), I[67] = (T)(img)(x,_n3##y,z,c), I[68] = (T)(img)(_n1##x,_n3##y,z,c), \ - I[69] = (T)(img)(_n2##x,_n3##y,z,c), I[70] = (T)(img)(_n3##x,_n3##y,z,c), I[71] = (T)(img)(_n4##x,_n3##y,z,c), \ - I[72] = (T)(img)(_p4##x,_n4##y,z,c), I[73] = (T)(img)(_p3##x,_n4##y,z,c), I[74] = (T)(img)(_p2##x,_n4##y,z,c), \ - I[75] = (T)(img)(_p1##x,_n4##y,z,c), I[76] = (T)(img)(x,_n4##y,z,c), I[77] = (T)(img)(_n1##x,_n4##y,z,c), \ - I[78] = (T)(img)(_n2##x,_n4##y,z,c), I[79] = (T)(img)(_n3##x,_n4##y,z,c), I[80] = (T)(img)(_n4##x,_n4##y,z,c) - -#define cimg_get2x2x2(img,x,y,z,c,I,T) \ - I[0] = (T)(img)(x,y,z,c), I[1] = (T)(img)(_n1##x,y,z,c), I[2] = (T)(img)(x,_n1##y,z,c), \ - I[3] = (T)(img)(_n1##x,_n1##y,z,c), I[4] = (T)(img)(x,y,_n1##z,c), I[5] = (T)(img)(_n1##x,y,_n1##z,c), \ - I[6] = (T)(img)(x,_n1##y,_n1##z,c), I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c) - -#define cimg_get3x3x3(img,x,y,z,c,I,T) \ - I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c), I[1] = (T)(img)(x,_p1##y,_p1##z,c), \ - I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c), I[3] = (T)(img)(_p1##x,y,_p1##z,c), I[4] = (T)(img)(x,y,_p1##z,c), \ - I[5] = (T)(img)(_n1##x,y,_p1##z,c), I[6] = (T)(img)(_p1##x,_n1##y,_p1##z,c), I[7] = (T)(img)(x,_n1##y,_p1##z,c), \ - I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c), I[9] = (T)(img)(_p1##x,_p1##y,z,c), I[10] = (T)(img)(x,_p1##y,z,c), \ - I[11] = (T)(img)(_n1##x,_p1##y,z,c), I[12] = (T)(img)(_p1##x,y,z,c), I[13] = (T)(img)(x,y,z,c), \ - I[14] = (T)(img)(_n1##x,y,z,c), I[15] = (T)(img)(_p1##x,_n1##y,z,c), I[16] = (T)(img)(x,_n1##y,z,c), \ - I[17] = (T)(img)(_n1##x,_n1##y,z,c), I[18] = (T)(img)(_p1##x,_p1##y,_n1##z,c), I[19] = (T)(img)(x,_p1##y,_n1##z,c), \ - I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c), I[21] = (T)(img)(_p1##x,y,_n1##z,c), I[22] = (T)(img)(x,y,_n1##z,c), \ - I[23] = (T)(img)(_n1##x,y,_n1##z,c), I[24] = (T)(img)(_p1##x,_n1##y,_n1##z,c), I[25] = (T)(img)(x,_n1##y,_n1##z,c), \ - I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c) - -// Macros to perform various image loops. -// -// These macros are simpler to use than loops with C++ iterators. -#define cimg_for(img,ptrs,T_ptrs) \ - for (T_ptrs *ptrs = (img)._data, *_max##ptrs = (img)._data + (img).size(); ptrs<_max##ptrs; ++ptrs) -#define cimg_rof(img,ptrs,T_ptrs) for (T_ptrs *ptrs = (img)._data + (img).size() - 1; ptrs>=(img)._data; --ptrs) -#define cimg_foroff(img,off) for (cimg_ulong off = 0, _max##off = (img).size(); off<_max##off; ++off) -#define cimg_rofoff(img,off) for (cimg_long off = (cimg_long)((img).size() - 1); off>=0; --off) - -#define cimg_for1(bound,i) for (int i = 0; i<(int)(bound); ++i) -#define cimg_forX(img,x) cimg_for1((img)._width,x) -#define cimg_forY(img,y) cimg_for1((img)._height,y) -#define cimg_forZ(img,z) cimg_for1((img)._depth,z) -#define cimg_forC(img,c) cimg_for1((img)._spectrum,c) -#define cimg_forXY(img,x,y) cimg_forY(img,y) cimg_forX(img,x) -#define cimg_forXZ(img,x,z) cimg_forZ(img,z) cimg_forX(img,x) -#define cimg_forYZ(img,y,z) cimg_forZ(img,z) cimg_forY(img,y) -#define cimg_forXC(img,x,c) cimg_forC(img,c) cimg_forX(img,x) -#define cimg_forYC(img,y,c) cimg_forC(img,c) cimg_forY(img,y) -#define cimg_forZC(img,z,c) cimg_forC(img,c) cimg_forZ(img,z) -#define cimg_forXYZ(img,x,y,z) cimg_forZ(img,z) cimg_forXY(img,x,y) -#define cimg_forXYC(img,x,y,c) cimg_forC(img,c) cimg_forXY(img,x,y) -#define cimg_forXZC(img,x,z,c) cimg_forC(img,c) cimg_forXZ(img,x,z) -#define cimg_forYZC(img,y,z,c) cimg_forC(img,c) cimg_forYZ(img,y,z) -#define cimg_forXYZC(img,x,y,z,c) cimg_forC(img,c) cimg_forXYZ(img,x,y,z) - -#define cimg_rof1(bound,i) for (int i = (int)(bound) - 1; i>=0; --i) -#define cimg_rofX(img,x) cimg_rof1((img)._width,x) -#define cimg_rofY(img,y) cimg_rof1((img)._height,y) -#define cimg_rofZ(img,z) cimg_rof1((img)._depth,z) -#define cimg_rofC(img,c) cimg_rof1((img)._spectrum,c) -#define cimg_rofXY(img,x,y) cimg_rofY(img,y) cimg_rofX(img,x) -#define cimg_rofXZ(img,x,z) cimg_rofZ(img,z) cimg_rofX(img,x) -#define cimg_rofYZ(img,y,z) cimg_rofZ(img,z) cimg_rofY(img,y) -#define cimg_rofXC(img,x,c) cimg_rofC(img,c) cimg_rofX(img,x) -#define cimg_rofYC(img,y,c) cimg_rofC(img,c) cimg_rofY(img,y) -#define cimg_rofZC(img,z,c) cimg_rofC(img,c) cimg_rofZ(img,z) -#define cimg_rofXYZ(img,x,y,z) cimg_rofZ(img,z) cimg_rofXY(img,x,y) -#define cimg_rofXYC(img,x,y,c) cimg_rofC(img,c) cimg_rofXY(img,x,y) -#define cimg_rofXZC(img,x,z,c) cimg_rofC(img,c) cimg_rofXZ(img,x,z) -#define cimg_rofYZC(img,y,z,c) cimg_rofC(img,c) cimg_rofYZ(img,y,z) -#define cimg_rofXYZC(img,x,y,z,c) cimg_rofC(img,c) cimg_rofXYZ(img,x,y,z) - -#define cimg_for_in1(bound,i0,i1,i) \ - for (int i = (int)(i0)<0?0:(int)(i0), _max##i = (int)(i1)<(int)(bound)?(int)(i1):(int)(bound) - 1; i<=_max##i; ++i) -#define cimg_for_inX(img,x0,x1,x) cimg_for_in1((img)._width,x0,x1,x) -#define cimg_for_inY(img,y0,y1,y) cimg_for_in1((img)._height,y0,y1,y) -#define cimg_for_inZ(img,z0,z1,z) cimg_for_in1((img)._depth,z0,z1,z) -#define cimg_for_inC(img,c0,c1,c) cimg_for_in1((img)._spectrum,c0,c1,c) -#define cimg_for_inXY(img,x0,y0,x1,y1,x,y) cimg_for_inY(img,y0,y1,y) cimg_for_inX(img,x0,x1,x) -#define cimg_for_inXZ(img,x0,z0,x1,z1,x,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inX(img,x0,x1,x) -#define cimg_for_inXC(img,x0,c0,x1,c1,x,c) cimg_for_inC(img,c0,c1,c) cimg_for_inX(img,x0,x1,x) -#define cimg_for_inYZ(img,y0,z0,y1,z1,y,z) cimg_for_inZ(img,x0,z1,z) cimg_for_inY(img,y0,y1,y) -#define cimg_for_inYC(img,y0,c0,y1,c1,y,c) cimg_for_inC(img,c0,c1,c) cimg_for_inY(img,y0,y1,y) -#define cimg_for_inZC(img,z0,c0,z1,c1,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inZ(img,z0,z1,z) -#define cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_inZ(img,z0,z1,z) cimg_for_inXY(img,x0,y0,x1,y1,x,y) -#define cimg_for_inXYC(img,x0,y0,c0,x1,y1,c1,x,y,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXY(img,x0,y0,x1,y1,x,y) -#define cimg_for_inXZC(img,x0,z0,c0,x1,z1,c1,x,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inXZ(img,x0,z0,x1,z1,x,z) -#define cimg_for_inYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_inC(img,c0,c1,c) cimg_for_inYZ(img,y0,z0,y1,z1,y,z) -#define cimg_for_inXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ - cimg_for_inC(img,c0,c1,c) cimg_for_inXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) -#define cimg_for_insideX(img,x,n) cimg_for_inX(img,n,(img)._width - 1 - (n),x) -#define cimg_for_insideY(img,y,n) cimg_for_inY(img,n,(img)._height - 1 - (n),y) -#define cimg_for_insideZ(img,z,n) cimg_for_inZ(img,n,(img)._depth - 1 - (n),z) -#define cimg_for_insideC(img,c,n) cimg_for_inC(img,n,(img)._spectrum - 1 - (n),c) -#define cimg_for_insideXY(img,x,y,n) cimg_for_inXY(img,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),x,y) -#define cimg_for_insideXYZ(img,x,y,z,n) \ - cimg_for_inXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z) -#define cimg_for_insideXYZC(img,x,y,z,c,n) \ - cimg_for_inXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z) - -#define cimg_for_out1(boundi,i0,i1,i) \ - for (int i = (int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); ++i, i = i==(int)(i0)?(int)(i1) + 1:i) -#define cimg_for_out2(boundi,boundj,i0,j0,i1,j1,i,j) \ - for (int j = 0; j<(int)(boundj); ++j) \ - for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j?0:(int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); \ - ++i, i = _n1j?i:(i==(int)(i0)?(int)(i1) + 1:i)) -#define cimg_for_out3(boundi,boundj,boundk,i0,j0,k0,i1,j1,k1,i,j,k) \ - for (int k = 0; k<(int)(boundk); ++k) \ - for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \ - for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k?0:(int)(i0)>0?0:(int)(i1) + 1; i<(int)(boundi); \ - ++i, i = _n1j || _n1k?i:(i==(int)(i0)?(int)(i1) + 1:i)) -#define cimg_for_out4(boundi,boundj,boundk,boundl,i0,j0,k0,l0,i1,j1,k1,l1,i,j,k,l) \ - for (int l = 0; l<(int)(boundl); ++l) \ - for (int _n1l = (int)(l<(int)(l0) || l>(int)(l1)), k = 0; k<(int)(boundk); ++k) \ - for (int _n1k = (int)(k<(int)(k0) || k>(int)(k1)), j = 0; j<(int)(boundj); ++j) \ - for (int _n1j = (int)(j<(int)(j0) || j>(int)(j1)), i = _n1j || _n1k || _n1l?0:(int)(i0)>0?0:(int)(i1) + 1; \ - i<(int)(boundi); ++i, i = _n1j || _n1k || _n1l?i:(i==(int)(i0)?(int)(i1) + 1:i)) -#define cimg_for_outX(img,x0,x1,x) cimg_for_out1((img)._width,x0,x1,x) -#define cimg_for_outY(img,y0,y1,y) cimg_for_out1((img)._height,y0,y1,y) -#define cimg_for_outZ(img,z0,z1,z) cimg_for_out1((img)._depth,z0,z1,z) -#define cimg_for_outC(img,c0,c1,c) cimg_for_out1((img)._spectrum,c0,c1,c) -#define cimg_for_outXY(img,x0,y0,x1,y1,x,y) cimg_for_out2((img)._width,(img)._height,x0,y0,x1,y1,x,y) -#define cimg_for_outXZ(img,x0,z0,x1,z1,x,z) cimg_for_out2((img)._width,(img)._depth,x0,z0,x1,z1,x,z) -#define cimg_for_outXC(img,x0,c0,x1,c1,x,c) cimg_for_out2((img)._width,(img)._spectrum,x0,c0,x1,c1,x,c) -#define cimg_for_outYZ(img,y0,z0,y1,z1,y,z) cimg_for_out2((img)._height,(img)._depth,y0,z0,y1,z1,y,z) -#define cimg_for_outYC(img,y0,c0,y1,c1,y,c) cimg_for_out2((img)._height,(img)._spectrum,y0,c0,y1,c1,y,c) -#define cimg_for_outZC(img,z0,c0,z1,c1,z,c) cimg_for_out2((img)._depth,(img)._spectrum,z0,c0,z1,c1,z,c) -#define cimg_for_outXYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) \ - cimg_for_out3((img)._width,(img)._height,(img)._depth,x0,y0,z0,x1,y1,z1,x,y,z) -#define cimg_for_outXYC(img,x0,y0,c0,x1,y1,c1,x,y,c) \ - cimg_for_out3((img)._width,(img)._height,(img)._spectrum,x0,y0,c0,x1,y1,c1,x,y,c) -#define cimg_for_outXZC(img,x0,z0,c0,x1,z1,c1,x,z,c) \ - cimg_for_out3((img)._width,(img)._depth,(img)._spectrum,x0,z0,c0,x1,z1,c1,x,z,c) -#define cimg_for_outYZC(img,y0,z0,c0,y1,z1,c1,y,z,c) \ - cimg_for_out3((img)._height,(img)._depth,(img)._spectrum,y0,z0,c0,y1,z1,c1,y,z,c) -#define cimg_for_outXYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ - cimg_for_out4((img)._width,(img)._height,(img)._depth,(img)._spectrum,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) -#define cimg_for_borderX(img,x,n) cimg_for_outX(img,n,(img)._width - 1 - (n),x) -#define cimg_for_borderY(img,y,n) cimg_for_outY(img,n,(img)._height - 1 - (n),y) -#define cimg_for_borderZ(img,z,n) cimg_for_outZ(img,n,(img)._depth - 1 - (n),z) -#define cimg_for_borderC(img,c,n) cimg_for_outC(img,n,(img)._spectrum - 1 - (n),c) -#define cimg_for_borderXY(img,x,y,n) cimg_for_outXY(img,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),x,y) -#define cimg_for_borderXYZ(img,x,y,z,n) \ - cimg_for_outXYZ(img,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n),(img)._depth - 1 - (n),x,y,z) -#define cimg_for_borderXYZC(img,x,y,z,c,n) \ - cimg_for_outXYZC(img,n,n,n,n,(img)._width - 1 - (n),(img)._height - 1 - (n), \ - (img)._depth - 1 - (n),(img)._spectrum - 1 - (n),x,y,z,c) - -#define cimg_for_spiralXY(img,x,y) \ - for (int x = 0, y = 0, _n1##x = 1, _n1##y = (img).width()*(img).height(); _n1##y; \ - --_n1##y, _n1##x+=(_n1##x>>2) - ((!(_n1##x&3)?--y:((_n1##x&3)==1?(img)._width - 1 - ++x:\ - ((_n1##x&3)==2?(img)._height - 1 - ++y:--x))))?0:1) - -#define cimg_for_lineXY(x,y,x0,y0,x1,y1) \ - for (int x = (int)(x0), y = (int)(y0), _sx = 1, _sy = 1, _steep = 0, \ - _dx=(x1)>(x0)?(int)(x1) - (int)(x0):(_sx=-1,(int)(x0) - (int)(x1)), \ - _dy=(y1)>(y0)?(int)(y1) - (int)(y0):(_sy=-1,(int)(y0) - (int)(y1)), \ - _counter = _dx, \ - _err = _dx>_dy?(_dy>>1):((_steep=1),(_counter=_dy),(_dx>>1)); \ - _counter>=0; \ - --_counter, x+=_steep? \ - (y+=_sy,(_err-=_dx)<0?_err+=_dy,_sx:0): \ - (y+=(_err-=_dy)<0?_err+=_dx,_sy:0,_sx)) - -#define cimg_for2(bound,i) \ - for (int i = 0, _n1##i = 1>=(bound)?(int)(bound) - 1:1; \ - _n1##i<(int)(bound) || i==--_n1##i; \ - ++i, ++_n1##i) -#define cimg_for2X(img,x) cimg_for2((img)._width,x) -#define cimg_for2Y(img,y) cimg_for2((img)._height,y) -#define cimg_for2Z(img,z) cimg_for2((img)._depth,z) -#define cimg_for2C(img,c) cimg_for2((img)._spectrum,c) -#define cimg_for2XY(img,x,y) cimg_for2Y(img,y) cimg_for2X(img,x) -#define cimg_for2XZ(img,x,z) cimg_for2Z(img,z) cimg_for2X(img,x) -#define cimg_for2XC(img,x,c) cimg_for2C(img,c) cimg_for2X(img,x) -#define cimg_for2YZ(img,y,z) cimg_for2Z(img,z) cimg_for2Y(img,y) -#define cimg_for2YC(img,y,c) cimg_for2C(img,c) cimg_for2Y(img,y) -#define cimg_for2ZC(img,z,c) cimg_for2C(img,c) cimg_for2Z(img,z) -#define cimg_for2XYZ(img,x,y,z) cimg_for2Z(img,z) cimg_for2XY(img,x,y) -#define cimg_for2XZC(img,x,z,c) cimg_for2C(img,c) cimg_for2XZ(img,x,z) -#define cimg_for2YZC(img,y,z,c) cimg_for2C(img,c) cimg_for2YZ(img,y,z) -#define cimg_for2XYZC(img,x,y,z,c) cimg_for2C(img,c) cimg_for2XYZ(img,x,y,z) - -#define cimg_for_in2(bound,i0,i1,i) \ - for (int i = (int)(i0)<0?0:(int)(i0), \ - _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1; \ - i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \ - ++i, ++_n1##i) -#define cimg_for_in2X(img,x0,x1,x) cimg_for_in2((img)._width,x0,x1,x) -#define cimg_for_in2Y(img,y0,y1,y) cimg_for_in2((img)._height,y0,y1,y) -#define cimg_for_in2Z(img,z0,z1,z) cimg_for_in2((img)._depth,z0,z1,z) -#define cimg_for_in2C(img,c0,c1,c) cimg_for_in2((img)._spectrum,c0,c1,c) -#define cimg_for_in2XY(img,x0,y0,x1,y1,x,y) cimg_for_in2Y(img,y0,y1,y) cimg_for_in2X(img,x0,x1,x) -#define cimg_for_in2XZ(img,x0,z0,x1,z1,x,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2X(img,x0,x1,x) -#define cimg_for_in2XC(img,x0,c0,x1,c1,x,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2X(img,x0,x1,x) -#define cimg_for_in2YZ(img,y0,z0,y1,z1,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2Y(img,y0,y1,y) -#define cimg_for_in2YC(img,y0,c0,y1,c1,y,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2Y(img,y0,y1,y) -#define cimg_for_in2ZC(img,z0,c0,z1,c1,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2Z(img,z0,z1,z) -#define cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in2Z(img,z0,z1,z) cimg_for_in2XY(img,x0,y0,x1,y1,x,y) -#define cimg_for_in2XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2XZ(img,x0,y0,x1,y1,x,z) -#define cimg_for_in2YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in2C(img,c0,c1,c) cimg_for_in2YZ(img,y0,z0,y1,z1,y,z) -#define cimg_for_in2XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ - cimg_for_in2C(img,c0,c1,c) cimg_for_in2XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) - -#define cimg_for3(bound,i) \ - for (int i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound) - 1:1; \ - _n1##i<(int)(bound) || i==--_n1##i; \ - _p1##i = i++, ++_n1##i) -#define cimg_for3X(img,x) cimg_for3((img)._width,x) -#define cimg_for3Y(img,y) cimg_for3((img)._height,y) -#define cimg_for3Z(img,z) cimg_for3((img)._depth,z) -#define cimg_for3C(img,c) cimg_for3((img)._spectrum,c) -#define cimg_for3XY(img,x,y) cimg_for3Y(img,y) cimg_for3X(img,x) -#define cimg_for3XZ(img,x,z) cimg_for3Z(img,z) cimg_for3X(img,x) -#define cimg_for3XC(img,x,c) cimg_for3C(img,c) cimg_for3X(img,x) -#define cimg_for3YZ(img,y,z) cimg_for3Z(img,z) cimg_for3Y(img,y) -#define cimg_for3YC(img,y,c) cimg_for3C(img,c) cimg_for3Y(img,y) -#define cimg_for3ZC(img,z,c) cimg_for3C(img,c) cimg_for3Z(img,z) -#define cimg_for3XYZ(img,x,y,z) cimg_for3Z(img,z) cimg_for3XY(img,x,y) -#define cimg_for3XZC(img,x,z,c) cimg_for3C(img,c) cimg_for3XZ(img,x,z) -#define cimg_for3YZC(img,y,z,c) cimg_for3C(img,c) cimg_for3YZ(img,y,z) -#define cimg_for3XYZC(img,x,y,z,c) cimg_for3C(img,c) cimg_for3XYZ(img,x,y,z) - -#define cimg_for_in3(bound,i0,i1,i) \ - for (int i = (int)(i0)<0?0:(int)(i0), \ - _p1##i = i - 1<0?0:i - 1, \ - _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1; \ - i<=(int)(i1) && (_n1##i<(int)(bound) || i==--_n1##i); \ - _p1##i = i++, ++_n1##i) -#define cimg_for_in3X(img,x0,x1,x) cimg_for_in3((img)._width,x0,x1,x) -#define cimg_for_in3Y(img,y0,y1,y) cimg_for_in3((img)._height,y0,y1,y) -#define cimg_for_in3Z(img,z0,z1,z) cimg_for_in3((img)._depth,z0,z1,z) -#define cimg_for_in3C(img,c0,c1,c) cimg_for_in3((img)._spectrum,c0,c1,c) -#define cimg_for_in3XY(img,x0,y0,x1,y1,x,y) cimg_for_in3Y(img,y0,y1,y) cimg_for_in3X(img,x0,x1,x) -#define cimg_for_in3XZ(img,x0,z0,x1,z1,x,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3X(img,x0,x1,x) -#define cimg_for_in3XC(img,x0,c0,x1,c1,x,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3X(img,x0,x1,x) -#define cimg_for_in3YZ(img,y0,z0,y1,z1,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3Y(img,y0,y1,y) -#define cimg_for_in3YC(img,y0,c0,y1,c1,y,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3Y(img,y0,y1,y) -#define cimg_for_in3ZC(img,z0,c0,z1,c1,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3Z(img,z0,z1,z) -#define cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in3Z(img,z0,z1,z) cimg_for_in3XY(img,x0,y0,x1,y1,x,y) -#define cimg_for_in3XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3XZ(img,x0,y0,x1,y1,x,z) -#define cimg_for_in3YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in3C(img,c0,c1,c) cimg_for_in3YZ(img,y0,z0,y1,z1,y,z) -#define cimg_for_in3XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ - cimg_for_in3C(img,c0,c1,c) cimg_for_in3XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) - -#define cimg_for4(bound,i) \ - for (int i = 0, _p1##i = 0, _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ - _n2##i = 2>=(bound)?(int)(bound) - 1:2; \ - _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \ - _p1##i = i++, ++_n1##i, ++_n2##i) -#define cimg_for4X(img,x) cimg_for4((img)._width,x) -#define cimg_for4Y(img,y) cimg_for4((img)._height,y) -#define cimg_for4Z(img,z) cimg_for4((img)._depth,z) -#define cimg_for4C(img,c) cimg_for4((img)._spectrum,c) -#define cimg_for4XY(img,x,y) cimg_for4Y(img,y) cimg_for4X(img,x) -#define cimg_for4XZ(img,x,z) cimg_for4Z(img,z) cimg_for4X(img,x) -#define cimg_for4XC(img,x,c) cimg_for4C(img,c) cimg_for4X(img,x) -#define cimg_for4YZ(img,y,z) cimg_for4Z(img,z) cimg_for4Y(img,y) -#define cimg_for4YC(img,y,c) cimg_for4C(img,c) cimg_for4Y(img,y) -#define cimg_for4ZC(img,z,c) cimg_for4C(img,c) cimg_for4Z(img,z) -#define cimg_for4XYZ(img,x,y,z) cimg_for4Z(img,z) cimg_for4XY(img,x,y) -#define cimg_for4XZC(img,x,z,c) cimg_for4C(img,c) cimg_for4XZ(img,x,z) -#define cimg_for4YZC(img,y,z,c) cimg_for4C(img,c) cimg_for4YZ(img,y,z) -#define cimg_for4XYZC(img,x,y,z,c) cimg_for4C(img,c) cimg_for4XYZ(img,x,y,z) - -#define cimg_for_in4(bound,i0,i1,i) \ - for (int i = (int)(i0)<0?0:(int)(i0), \ - _p1##i = i - 1<0?0:i - 1, \ - _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ - _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2; \ - i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \ - _p1##i = i++, ++_n1##i, ++_n2##i) -#define cimg_for_in4X(img,x0,x1,x) cimg_for_in4((img)._width,x0,x1,x) -#define cimg_for_in4Y(img,y0,y1,y) cimg_for_in4((img)._height,y0,y1,y) -#define cimg_for_in4Z(img,z0,z1,z) cimg_for_in4((img)._depth,z0,z1,z) -#define cimg_for_in4C(img,c0,c1,c) cimg_for_in4((img)._spectrum,c0,c1,c) -#define cimg_for_in4XY(img,x0,y0,x1,y1,x,y) cimg_for_in4Y(img,y0,y1,y) cimg_for_in4X(img,x0,x1,x) -#define cimg_for_in4XZ(img,x0,z0,x1,z1,x,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4X(img,x0,x1,x) -#define cimg_for_in4XC(img,x0,c0,x1,c1,x,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4X(img,x0,x1,x) -#define cimg_for_in4YZ(img,y0,z0,y1,z1,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4Y(img,y0,y1,y) -#define cimg_for_in4YC(img,y0,c0,y1,c1,y,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4Y(img,y0,y1,y) -#define cimg_for_in4ZC(img,z0,c0,z1,c1,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4Z(img,z0,z1,z) -#define cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in4Z(img,z0,z1,z) cimg_for_in4XY(img,x0,y0,x1,y1,x,y) -#define cimg_for_in4XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4XZ(img,x0,y0,x1,y1,x,z) -#define cimg_for_in4YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in4C(img,c0,c1,c) cimg_for_in4YZ(img,y0,z0,y1,z1,y,z) -#define cimg_for_in4XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ - cimg_for_in4C(img,c0,c1,c) cimg_for_in4XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) - -#define cimg_for5(bound,i) \ - for (int i = 0, _p2##i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ - _n2##i = 2>=(bound)?(int)(bound) - 1:2; \ - _n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i); \ - _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i) -#define cimg_for5X(img,x) cimg_for5((img)._width,x) -#define cimg_for5Y(img,y) cimg_for5((img)._height,y) -#define cimg_for5Z(img,z) cimg_for5((img)._depth,z) -#define cimg_for5C(img,c) cimg_for5((img)._spectrum,c) -#define cimg_for5XY(img,x,y) cimg_for5Y(img,y) cimg_for5X(img,x) -#define cimg_for5XZ(img,x,z) cimg_for5Z(img,z) cimg_for5X(img,x) -#define cimg_for5XC(img,x,c) cimg_for5C(img,c) cimg_for5X(img,x) -#define cimg_for5YZ(img,y,z) cimg_for5Z(img,z) cimg_for5Y(img,y) -#define cimg_for5YC(img,y,c) cimg_for5C(img,c) cimg_for5Y(img,y) -#define cimg_for5ZC(img,z,c) cimg_for5C(img,c) cimg_for5Z(img,z) -#define cimg_for5XYZ(img,x,y,z) cimg_for5Z(img,z) cimg_for5XY(img,x,y) -#define cimg_for5XZC(img,x,z,c) cimg_for5C(img,c) cimg_for5XZ(img,x,z) -#define cimg_for5YZC(img,y,z,c) cimg_for5C(img,c) cimg_for5YZ(img,y,z) -#define cimg_for5XYZC(img,x,y,z,c) cimg_for5C(img,c) cimg_for5XYZ(img,x,y,z) - -#define cimg_for_in5(bound,i0,i1,i) \ - for (int i = (int)(i0)<0?0:(int)(i0), \ - _p2##i = i - 2<0?0:i - 2, \ - _p1##i = i - 1<0?0:i - 1, \ - _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ - _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2; \ - i<=(int)(i1) && (_n2##i<(int)(bound) || _n1##i==--_n2##i || i==(_n2##i = --_n1##i)); \ - _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i) -#define cimg_for_in5X(img,x0,x1,x) cimg_for_in5((img)._width,x0,x1,x) -#define cimg_for_in5Y(img,y0,y1,y) cimg_for_in5((img)._height,y0,y1,y) -#define cimg_for_in5Z(img,z0,z1,z) cimg_for_in5((img)._depth,z0,z1,z) -#define cimg_for_in5C(img,c0,c1,c) cimg_for_in5((img)._spectrum,c0,c1,c) -#define cimg_for_in5XY(img,x0,y0,x1,y1,x,y) cimg_for_in5Y(img,y0,y1,y) cimg_for_in5X(img,x0,x1,x) -#define cimg_for_in5XZ(img,x0,z0,x1,z1,x,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5X(img,x0,x1,x) -#define cimg_for_in5XC(img,x0,c0,x1,c1,x,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5X(img,x0,x1,x) -#define cimg_for_in5YZ(img,y0,z0,y1,z1,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5Y(img,y0,y1,y) -#define cimg_for_in5YC(img,y0,c0,y1,c1,y,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5Y(img,y0,y1,y) -#define cimg_for_in5ZC(img,z0,c0,z1,c1,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5Z(img,z0,z1,z) -#define cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in5Z(img,z0,z1,z) cimg_for_in5XY(img,x0,y0,x1,y1,x,y) -#define cimg_for_in5XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5XZ(img,x0,y0,x1,y1,x,z) -#define cimg_for_in5YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in5C(img,c0,c1,c) cimg_for_in5YZ(img,y0,z0,y1,z1,y,z) -#define cimg_for_in5XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ - cimg_for_in5C(img,c0,c1,c) cimg_for_in5XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) - -#define cimg_for6(bound,i) \ - for (int i = 0, _p2##i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ - _n2##i = 2>=(bound)?(int)(bound) - 1:2, \ - _n3##i = 3>=(bound)?(int)(bound) - 1:3; \ - _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \ - _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) -#define cimg_for6X(img,x) cimg_for6((img)._width,x) -#define cimg_for6Y(img,y) cimg_for6((img)._height,y) -#define cimg_for6Z(img,z) cimg_for6((img)._depth,z) -#define cimg_for6C(img,c) cimg_for6((img)._spectrum,c) -#define cimg_for6XY(img,x,y) cimg_for6Y(img,y) cimg_for6X(img,x) -#define cimg_for6XZ(img,x,z) cimg_for6Z(img,z) cimg_for6X(img,x) -#define cimg_for6XC(img,x,c) cimg_for6C(img,c) cimg_for6X(img,x) -#define cimg_for6YZ(img,y,z) cimg_for6Z(img,z) cimg_for6Y(img,y) -#define cimg_for6YC(img,y,c) cimg_for6C(img,c) cimg_for6Y(img,y) -#define cimg_for6ZC(img,z,c) cimg_for6C(img,c) cimg_for6Z(img,z) -#define cimg_for6XYZ(img,x,y,z) cimg_for6Z(img,z) cimg_for6XY(img,x,y) -#define cimg_for6XZC(img,x,z,c) cimg_for6C(img,c) cimg_for6XZ(img,x,z) -#define cimg_for6YZC(img,y,z,c) cimg_for6C(img,c) cimg_for6YZ(img,y,z) -#define cimg_for6XYZC(img,x,y,z,c) cimg_for6C(img,c) cimg_for6XYZ(img,x,y,z) - -#define cimg_for_in6(bound,i0,i1,i) \ - for (int i = (int)(i0)<0?0:(int)(i0), \ - _p2##i = i - 2<0?0:i - 2, \ - _p1##i = i - 1<0?0:i - 1, \ - _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ - _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \ - _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3; \ - i<=(int)(i1) && \ - (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \ - _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) -#define cimg_for_in6X(img,x0,x1,x) cimg_for_in6((img)._width,x0,x1,x) -#define cimg_for_in6Y(img,y0,y1,y) cimg_for_in6((img)._height,y0,y1,y) -#define cimg_for_in6Z(img,z0,z1,z) cimg_for_in6((img)._depth,z0,z1,z) -#define cimg_for_in6C(img,c0,c1,c) cimg_for_in6((img)._spectrum,c0,c1,c) -#define cimg_for_in6XY(img,x0,y0,x1,y1,x,y) cimg_for_in6Y(img,y0,y1,y) cimg_for_in6X(img,x0,x1,x) -#define cimg_for_in6XZ(img,x0,z0,x1,z1,x,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6X(img,x0,x1,x) -#define cimg_for_in6XC(img,x0,c0,x1,c1,x,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6X(img,x0,x1,x) -#define cimg_for_in6YZ(img,y0,z0,y1,z1,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6Y(img,y0,y1,y) -#define cimg_for_in6YC(img,y0,c0,y1,c1,y,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6Y(img,y0,y1,y) -#define cimg_for_in6ZC(img,z0,c0,z1,c1,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6Z(img,z0,z1,z) -#define cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in6Z(img,z0,z1,z) cimg_for_in6XY(img,x0,y0,x1,y1,x,y) -#define cimg_for_in6XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6XZ(img,x0,y0,x1,y1,x,z) -#define cimg_for_in6YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in6C(img,c0,c1,c) cimg_for_in6YZ(img,y0,z0,y1,z1,y,z) -#define cimg_for_in6XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ - cimg_for_in6C(img,c0,c1,c) cimg_for_in6XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) - -#define cimg_for7(bound,i) \ - for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ - _n2##i = 2>=(bound)?(int)(bound) - 1:2, \ - _n3##i = 3>=(bound)?(int)(bound) - 1:3; \ - _n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i); \ - _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) -#define cimg_for7X(img,x) cimg_for7((img)._width,x) -#define cimg_for7Y(img,y) cimg_for7((img)._height,y) -#define cimg_for7Z(img,z) cimg_for7((img)._depth,z) -#define cimg_for7C(img,c) cimg_for7((img)._spectrum,c) -#define cimg_for7XY(img,x,y) cimg_for7Y(img,y) cimg_for7X(img,x) -#define cimg_for7XZ(img,x,z) cimg_for7Z(img,z) cimg_for7X(img,x) -#define cimg_for7XC(img,x,c) cimg_for7C(img,c) cimg_for7X(img,x) -#define cimg_for7YZ(img,y,z) cimg_for7Z(img,z) cimg_for7Y(img,y) -#define cimg_for7YC(img,y,c) cimg_for7C(img,c) cimg_for7Y(img,y) -#define cimg_for7ZC(img,z,c) cimg_for7C(img,c) cimg_for7Z(img,z) -#define cimg_for7XYZ(img,x,y,z) cimg_for7Z(img,z) cimg_for7XY(img,x,y) -#define cimg_for7XZC(img,x,z,c) cimg_for7C(img,c) cimg_for7XZ(img,x,z) -#define cimg_for7YZC(img,y,z,c) cimg_for7C(img,c) cimg_for7YZ(img,y,z) -#define cimg_for7XYZC(img,x,y,z,c) cimg_for7C(img,c) cimg_for7XYZ(img,x,y,z) - -#define cimg_for_in7(bound,i0,i1,i) \ - for (int i = (int)(i0)<0?0:(int)(i0), \ - _p3##i = i - 3<0?0:i - 3, \ - _p2##i = i - 2<0?0:i - 2, \ - _p1##i = i - 1<0?0:i - 1, \ - _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ - _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \ - _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3; \ - i<=(int)(i1) && \ - (_n3##i<(int)(bound) || _n2##i==--_n3##i || _n1##i==--_n2##i || i==(_n3##i = _n2##i = --_n1##i)); \ - _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i) -#define cimg_for_in7X(img,x0,x1,x) cimg_for_in7((img)._width,x0,x1,x) -#define cimg_for_in7Y(img,y0,y1,y) cimg_for_in7((img)._height,y0,y1,y) -#define cimg_for_in7Z(img,z0,z1,z) cimg_for_in7((img)._depth,z0,z1,z) -#define cimg_for_in7C(img,c0,c1,c) cimg_for_in7((img)._spectrum,c0,c1,c) -#define cimg_for_in7XY(img,x0,y0,x1,y1,x,y) cimg_for_in7Y(img,y0,y1,y) cimg_for_in7X(img,x0,x1,x) -#define cimg_for_in7XZ(img,x0,z0,x1,z1,x,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7X(img,x0,x1,x) -#define cimg_for_in7XC(img,x0,c0,x1,c1,x,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7X(img,x0,x1,x) -#define cimg_for_in7YZ(img,y0,z0,y1,z1,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7Y(img,y0,y1,y) -#define cimg_for_in7YC(img,y0,c0,y1,c1,y,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7Y(img,y0,y1,y) -#define cimg_for_in7ZC(img,z0,c0,z1,c1,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7Z(img,z0,z1,z) -#define cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in7Z(img,z0,z1,z) cimg_for_in7XY(img,x0,y0,x1,y1,x,y) -#define cimg_for_in7XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7XZ(img,x0,y0,x1,y1,x,z) -#define cimg_for_in7YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in7C(img,c0,c1,c) cimg_for_in7YZ(img,y0,z0,y1,z1,y,z) -#define cimg_for_in7XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ - cimg_for_in7C(img,c0,c1,c) cimg_for_in7XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) - -#define cimg_for8(bound,i) \ - for (int i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound) - 1:1, \ - _n2##i = 2>=(bound)?(int)(bound) - 1:2, \ - _n3##i = 3>=(bound)?(int)(bound) - 1:3, \ - _n4##i = 4>=(bound)?(int)(bound) - 1:4; \ - _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ - i==(_n4##i = _n3##i = _n2##i = --_n1##i); \ - _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) -#define cimg_for8X(img,x) cimg_for8((img)._width,x) -#define cimg_for8Y(img,y) cimg_for8((img)._height,y) -#define cimg_for8Z(img,z) cimg_for8((img)._depth,z) -#define cimg_for8C(img,c) cimg_for8((img)._spectrum,c) -#define cimg_for8XY(img,x,y) cimg_for8Y(img,y) cimg_for8X(img,x) -#define cimg_for8XZ(img,x,z) cimg_for8Z(img,z) cimg_for8X(img,x) -#define cimg_for8XC(img,x,c) cimg_for8C(img,c) cimg_for8X(img,x) -#define cimg_for8YZ(img,y,z) cimg_for8Z(img,z) cimg_for8Y(img,y) -#define cimg_for8YC(img,y,c) cimg_for8C(img,c) cimg_for8Y(img,y) -#define cimg_for8ZC(img,z,c) cimg_for8C(img,c) cimg_for8Z(img,z) -#define cimg_for8XYZ(img,x,y,z) cimg_for8Z(img,z) cimg_for8XY(img,x,y) -#define cimg_for8XZC(img,x,z,c) cimg_for8C(img,c) cimg_for8XZ(img,x,z) -#define cimg_for8YZC(img,y,z,c) cimg_for8C(img,c) cimg_for8YZ(img,y,z) -#define cimg_for8XYZC(img,x,y,z,c) cimg_for8C(img,c) cimg_for8XYZ(img,x,y,z) - -#define cimg_for_in8(bound,i0,i1,i) \ - for (int i = (int)(i0)<0?0:(int)(i0), \ - _p3##i = i - 3<0?0:i - 3, \ - _p2##i = i - 2<0?0:i - 2, \ - _p1##i = i - 1<0?0:i - 1, \ - _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ - _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \ - _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3, \ - _n4##i = i + 4>=(int)(bound)?(int)(bound) - 1:i + 4; \ - i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ - i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \ - _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) -#define cimg_for_in8X(img,x0,x1,x) cimg_for_in8((img)._width,x0,x1,x) -#define cimg_for_in8Y(img,y0,y1,y) cimg_for_in8((img)._height,y0,y1,y) -#define cimg_for_in8Z(img,z0,z1,z) cimg_for_in8((img)._depth,z0,z1,z) -#define cimg_for_in8C(img,c0,c1,c) cimg_for_in8((img)._spectrum,c0,c1,c) -#define cimg_for_in8XY(img,x0,y0,x1,y1,x,y) cimg_for_in8Y(img,y0,y1,y) cimg_for_in8X(img,x0,x1,x) -#define cimg_for_in8XZ(img,x0,z0,x1,z1,x,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8X(img,x0,x1,x) -#define cimg_for_in8XC(img,x0,c0,x1,c1,x,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8X(img,x0,x1,x) -#define cimg_for_in8YZ(img,y0,z0,y1,z1,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8Y(img,y0,y1,y) -#define cimg_for_in8YC(img,y0,c0,y1,c1,y,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8Y(img,y0,y1,y) -#define cimg_for_in8ZC(img,z0,c0,z1,c1,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8Z(img,z0,z1,z) -#define cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in8Z(img,z0,z1,z) cimg_for_in8XY(img,x0,y0,x1,y1,x,y) -#define cimg_for_in8XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8XZ(img,x0,y0,x1,y1,x,z) -#define cimg_for_in8YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in8C(img,c0,c1,c) cimg_for_in8YZ(img,y0,z0,y1,z1,y,z) -#define cimg_for_in8XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ - cimg_for_in8C(img,c0,c1,c) cimg_for_in8XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) - -#define cimg_for9(bound,i) \ - for (int i = 0, _p4##i = 0, _p3##i = 0, _p2##i = 0, _p1##i = 0, \ - _n1##i = 1>=(int)(bound)?(int)(bound) - 1:1, \ - _n2##i = 2>=(int)(bound)?(int)(bound) - 1:2, \ - _n3##i = 3>=(int)(bound)?(int)(bound) - 1:3, \ - _n4##i = 4>=(int)(bound)?(int)(bound) - 1:4; \ - _n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ - i==(_n4##i = _n3##i = _n2##i = --_n1##i); \ - _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) -#define cimg_for9X(img,x) cimg_for9((img)._width,x) -#define cimg_for9Y(img,y) cimg_for9((img)._height,y) -#define cimg_for9Z(img,z) cimg_for9((img)._depth,z) -#define cimg_for9C(img,c) cimg_for9((img)._spectrum,c) -#define cimg_for9XY(img,x,y) cimg_for9Y(img,y) cimg_for9X(img,x) -#define cimg_for9XZ(img,x,z) cimg_for9Z(img,z) cimg_for9X(img,x) -#define cimg_for9XC(img,x,c) cimg_for9C(img,c) cimg_for9X(img,x) -#define cimg_for9YZ(img,y,z) cimg_for9Z(img,z) cimg_for9Y(img,y) -#define cimg_for9YC(img,y,c) cimg_for9C(img,c) cimg_for9Y(img,y) -#define cimg_for9ZC(img,z,c) cimg_for9C(img,c) cimg_for9Z(img,z) -#define cimg_for9XYZ(img,x,y,z) cimg_for9Z(img,z) cimg_for9XY(img,x,y) -#define cimg_for9XZC(img,x,z,c) cimg_for9C(img,c) cimg_for9XZ(img,x,z) -#define cimg_for9YZC(img,y,z,c) cimg_for9C(img,c) cimg_for9YZ(img,y,z) -#define cimg_for9XYZC(img,x,y,z,c) cimg_for9C(img,c) cimg_for9XYZ(img,x,y,z) - -#define cimg_for_in9(bound,i0,i1,i) \ - for (int i = (int)(i0)<0?0:(int)(i0), \ - _p4##i = i - 4<0?0:i - 4, \ - _p3##i = i - 3<0?0:i - 3, \ - _p2##i = i - 2<0?0:i - 2, \ - _p1##i = i - 1<0?0:i - 1, \ - _n1##i = i + 1>=(int)(bound)?(int)(bound) - 1:i + 1, \ - _n2##i = i + 2>=(int)(bound)?(int)(bound) - 1:i + 2, \ - _n3##i = i + 3>=(int)(bound)?(int)(bound) - 1:i + 3, \ - _n4##i = i + 4>=(int)(bound)?(int)(bound) - 1:i + 4; \ - i<=(int)(i1) && (_n4##i<(int)(bound) || _n3##i==--_n4##i || _n2##i==--_n3##i || _n1##i==--_n2##i || \ - i==(_n4##i = _n3##i = _n2##i = --_n1##i)); \ - _p4##i = _p3##i, _p3##i = _p2##i, _p2##i = _p1##i, _p1##i = i++, ++_n1##i, ++_n2##i, ++_n3##i, ++_n4##i) -#define cimg_for_in9X(img,x0,x1,x) cimg_for_in9((img)._width,x0,x1,x) -#define cimg_for_in9Y(img,y0,y1,y) cimg_for_in9((img)._height,y0,y1,y) -#define cimg_for_in9Z(img,z0,z1,z) cimg_for_in9((img)._depth,z0,z1,z) -#define cimg_for_in9C(img,c0,c1,c) cimg_for_in9((img)._spectrum,c0,c1,c) -#define cimg_for_in9XY(img,x0,y0,x1,y1,x,y) cimg_for_in9Y(img,y0,y1,y) cimg_for_in9X(img,x0,x1,x) -#define cimg_for_in9XZ(img,x0,z0,x1,z1,x,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9X(img,x0,x1,x) -#define cimg_for_in9XC(img,x0,c0,x1,c1,x,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9X(img,x0,x1,x) -#define cimg_for_in9YZ(img,y0,z0,y1,z1,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9Y(img,y0,y1,y) -#define cimg_for_in9YC(img,y0,c0,y1,c1,y,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9Y(img,y0,y1,y) -#define cimg_for_in9ZC(img,z0,c0,z1,c1,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9Z(img,z0,z1,z) -#define cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) cimg_for_in9Z(img,z0,z1,z) cimg_for_in9XY(img,x0,y0,x1,y1,x,y) -#define cimg_for_in9XZC(img,x0,z0,c0,x1,y1,c1,x,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9XZ(img,x0,y0,x1,y1,x,z) -#define cimg_for_in9YZC(img,y0,z0,c0,y1,z1,c1,y,z,c) cimg_for_in9C(img,c0,c1,c) cimg_for_in9YZ(img,y0,z0,y1,z1,y,z) -#define cimg_for_in9XYZC(img,x0,y0,z0,c0,x1,y1,z1,c1,x,y,z,c) \ - cimg_for_in9C(img,c0,c1,c) cimg_for_in9XYZ(img,x0,y0,z0,x1,y1,z1,x,y,z) - -#define cimg_for2x2(img,x,y,z,c,I,T) \ - cimg_for2((img)._height,y) for (int x = 0, \ - _n1##x = (int)( \ - (I[0] = (T)(img)(0,y,z,c)), \ - (I[2] = (T)(img)(0,_n1##y,z,c)), \ - 1>=(img)._width?(img).width() - 1:1); \ - (_n1##x<(img).width() && ( \ - (I[1] = (T)(img)(_n1##x,y,z,c)), \ - (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ - x==--_n1##x; \ - I[0] = I[1], \ - I[2] = I[3], \ - ++x, ++_n1##x) - -#define cimg_for_in2x2(img,x0,y0,x1,y1,x,y,z,c,I,T) \ - cimg_for_in2((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _n1##x = (int)( \ - (I[0] = (T)(img)(x,y,z,c)), \ - (I[2] = (T)(img)(x,_n1##y,z,c)), \ - x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \ - x<=(int)(x1) && ((_n1##x<(img).width() && ( \ - (I[1] = (T)(img)(_n1##x,y,z,c)), \ - (I[3] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ - x==--_n1##x); \ - I[0] = I[1], \ - I[2] = I[3], \ - ++x, ++_n1##x) - -#define cimg_for3x3(img,x,y,z,c,I,T) \ - cimg_for3((img)._height,y) for (int x = 0, \ - _p1##x = 0, \ - _n1##x = (int)( \ - (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \ - (I[3] = I[4] = (T)(img)(0,y,z,c)), \ - (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)), \ - 1>=(img)._width?(img).width() - 1:1); \ - (_n1##x<(img).width() && ( \ - (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[5] = (T)(img)(_n1##x,y,z,c)), \ - (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ - x==--_n1##x; \ - I[0] = I[1], I[1] = I[2], \ - I[3] = I[4], I[4] = I[5], \ - I[6] = I[7], I[7] = I[8], \ - _p1##x = x++, ++_n1##x) - -#define cimg_for_in3x3(img,x0,y0,x1,y1,x,y,z,c,I,T) \ - cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p1##x = x - 1<0?0:x - 1, \ - _n1##x = (int)( \ - (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \ - (I[3] = (T)(img)(_p1##x,y,z,c)), \ - (I[6] = (T)(img)(_p1##x,_n1##y,z,c)), \ - (I[1] = (T)(img)(x,_p1##y,z,c)), \ - (I[4] = (T)(img)(x,y,z,c)), \ - (I[7] = (T)(img)(x,_n1##y,z,c)), \ - x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \ - x<=(int)(x1) && ((_n1##x<(img).width() && ( \ - (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[5] = (T)(img)(_n1##x,y,z,c)), \ - (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ - x==--_n1##x); \ - I[0] = I[1], I[1] = I[2], \ - I[3] = I[4], I[4] = I[5], \ - I[6] = I[7], I[7] = I[8], \ - _p1##x = x++, ++_n1##x) - -#define cimg_for4x4(img,x,y,z,c,I,T) \ - cimg_for4((img)._height,y) for (int x = 0, \ - _p1##x = 0, \ - _n1##x = 1>=(img)._width?(img).width() - 1:1, \ - _n2##x = (int)( \ - (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \ - (I[4] = I[5] = (T)(img)(0,y,z,c)), \ - (I[8] = I[9] = (T)(img)(0,_n1##y,z,c)), \ - (I[12] = I[13] = (T)(img)(0,_n2##y,z,c)), \ - (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[6] = (T)(img)(_n1##x,y,z,c)), \ - (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \ - 2>=(img)._width?(img).width() - 1:2); \ - (_n2##x<(img).width() && ( \ - (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \ - (I[7] = (T)(img)(_n2##x,y,z,c)), \ - (I[11] = (T)(img)(_n2##x,_n1##y,z,c)), \ - (I[15] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \ - _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \ - I[0] = I[1], I[1] = I[2], I[2] = I[3], \ - I[4] = I[5], I[5] = I[6], I[6] = I[7], \ - I[8] = I[9], I[9] = I[10], I[10] = I[11], \ - I[12] = I[13], I[13] = I[14], I[14] = I[15], \ - _p1##x = x++, ++_n1##x, ++_n2##x) - -#define cimg_for_in4x4(img,x0,y0,x1,y1,x,y,z,c,I,T) \ - cimg_for_in4((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p1##x = x - 1<0?0:x - 1, \ - _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \ - _n2##x = (int)( \ - (I[0] = (T)(img)(_p1##x,_p1##y,z,c)), \ - (I[4] = (T)(img)(_p1##x,y,z,c)), \ - (I[8] = (T)(img)(_p1##x,_n1##y,z,c)), \ - (I[12] = (T)(img)(_p1##x,_n2##y,z,c)), \ - (I[1] = (T)(img)(x,_p1##y,z,c)), \ - (I[5] = (T)(img)(x,y,z,c)), \ - (I[9] = (T)(img)(x,_n1##y,z,c)), \ - (I[13] = (T)(img)(x,_n2##y,z,c)), \ - (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[6] = (T)(img)(_n1##x,y,z,c)), \ - (I[10] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[14] = (T)(img)(_n1##x,_n2##y,z,c)), \ - x + 2>=(int)(img)._width?(img).width() - 1:x + 2); \ - x<=(int)(x1) && ((_n2##x<(img).width() && ( \ - (I[3] = (T)(img)(_n2##x,_p1##y,z,c)), \ - (I[7] = (T)(img)(_n2##x,y,z,c)), \ - (I[11] = (T)(img)(_n2##x,_n1##y,z,c)), \ - (I[15] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \ - _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \ - I[0] = I[1], I[1] = I[2], I[2] = I[3], \ - I[4] = I[5], I[5] = I[6], I[6] = I[7], \ - I[8] = I[9], I[9] = I[10], I[10] = I[11], \ - I[12] = I[13], I[13] = I[14], I[14] = I[15], \ - _p1##x = x++, ++_n1##x, ++_n2##x) - -#define cimg_for5x5(img,x,y,z,c,I,T) \ - cimg_for5((img)._height,y) for (int x = 0, \ - _p2##x = 0, _p1##x = 0, \ - _n1##x = 1>=(img)._width?(img).width() - 1:1, \ - _n2##x = (int)( \ - (I[0] = I[1] = I[2] = (T)(img)(_p2##x,_p2##y,z,c)), \ - (I[5] = I[6] = I[7] = (T)(img)(0,_p1##y,z,c)), \ - (I[10] = I[11] = I[12] = (T)(img)(0,y,z,c)), \ - (I[15] = I[16] = I[17] = (T)(img)(0,_n1##y,z,c)), \ - (I[20] = I[21] = I[22] = (T)(img)(0,_n2##y,z,c)), \ - (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \ - (I[8] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[13] = (T)(img)(_n1##x,y,z,c)), \ - (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[23] = (T)(img)(_n1##x,_n2##y,z,c)), \ - 2>=(img)._width?(img).width() - 1:2); \ - (_n2##x<(img).width() && ( \ - (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ - (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \ - (I[14] = (T)(img)(_n2##x,y,z,c)), \ - (I[19] = (T)(img)(_n2##x,_n1##y,z,c)), \ - (I[24] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \ - _n1##x==--_n2##x || x==(_n2##x = --_n1##x); \ - I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \ - I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \ - I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \ - I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \ - I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \ - _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x) - -#define cimg_for_in5x5(img,x0,y0,x1,y1,x,y,z,c,I,T) \ - cimg_for_in5((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p2##x = x - 2<0?0:x - 2, \ - _p1##x = x - 1<0?0:x - 1, \ - _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \ - _n2##x = (int)( \ - (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \ - (I[5] = (T)(img)(_p2##x,_p1##y,z,c)), \ - (I[10] = (T)(img)(_p2##x,y,z,c)), \ - (I[15] = (T)(img)(_p2##x,_n1##y,z,c)), \ - (I[20] = (T)(img)(_p2##x,_n2##y,z,c)), \ - (I[1] = (T)(img)(_p1##x,_p2##y,z,c)), \ - (I[6] = (T)(img)(_p1##x,_p1##y,z,c)), \ - (I[11] = (T)(img)(_p1##x,y,z,c)), \ - (I[16] = (T)(img)(_p1##x,_n1##y,z,c)), \ - (I[21] = (T)(img)(_p1##x,_n2##y,z,c)), \ - (I[2] = (T)(img)(x,_p2##y,z,c)), \ - (I[7] = (T)(img)(x,_p1##y,z,c)), \ - (I[12] = (T)(img)(x,y,z,c)), \ - (I[17] = (T)(img)(x,_n1##y,z,c)), \ - (I[22] = (T)(img)(x,_n2##y,z,c)), \ - (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \ - (I[8] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[13] = (T)(img)(_n1##x,y,z,c)), \ - (I[18] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[23] = (T)(img)(_n1##x,_n2##y,z,c)), \ - x + 2>=(int)(img)._width?(img).width() - 1:x + 2); \ - x<=(int)(x1) && ((_n2##x<(img).width() && ( \ - (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ - (I[9] = (T)(img)(_n2##x,_p1##y,z,c)), \ - (I[14] = (T)(img)(_n2##x,y,z,c)), \ - (I[19] = (T)(img)(_n2##x,_n1##y,z,c)), \ - (I[24] = (T)(img)(_n2##x,_n2##y,z,c)),1)) || \ - _n1##x==--_n2##x || x==(_n2##x = --_n1##x)); \ - I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], \ - I[5] = I[6], I[6] = I[7], I[7] = I[8], I[8] = I[9], \ - I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], \ - I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], \ - I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \ - _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x) - -#define cimg_for6x6(img,x,y,z,c,I,T) \ - cimg_for6((img)._height,y) for (int x = 0, \ - _p2##x = 0, _p1##x = 0, \ - _n1##x = 1>=(img)._width?(img).width() - 1:1, \ - _n2##x = 2>=(img)._width?(img).width() - 1:2, \ - _n3##x = (int)( \ - (I[0] = I[1] = I[2] = (T)(img)(_p2##x,_p2##y,z,c)), \ - (I[6] = I[7] = I[8] = (T)(img)(0,_p1##y,z,c)), \ - (I[12] = I[13] = I[14] = (T)(img)(0,y,z,c)), \ - (I[18] = I[19] = I[20] = (T)(img)(0,_n1##y,z,c)), \ - (I[24] = I[25] = I[26] = (T)(img)(0,_n2##y,z,c)), \ - (I[30] = I[31] = I[32] = (T)(img)(0,_n3##y,z,c)), \ - (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \ - (I[9] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[15] = (T)(img)(_n1##x,y,z,c)), \ - (I[21] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[27] = (T)(img)(_n1##x,_n2##y,z,c)), \ - (I[33] = (T)(img)(_n1##x,_n3##y,z,c)), \ - (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ - (I[10] = (T)(img)(_n2##x,_p1##y,z,c)), \ - (I[16] = (T)(img)(_n2##x,y,z,c)), \ - (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \ - (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \ - (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \ - 3>=(img)._width?(img).width() - 1:3); \ - (_n3##x<(img).width() && ( \ - (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \ - (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \ - (I[17] = (T)(img)(_n3##x,y,z,c)), \ - (I[23] = (T)(img)(_n3##x,_n1##y,z,c)), \ - (I[29] = (T)(img)(_n3##x,_n2##y,z,c)), \ - (I[35] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \ - _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x); \ - I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \ - I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \ - I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \ - I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \ - I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \ - I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \ - _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x) - -#define cimg_for_in6x6(img,x0,y0,x1,y1,x,y,z,c,I,T) \ - cimg_for_in6((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)x0, \ - _p2##x = x - 2<0?0:x - 2, \ - _p1##x = x - 1<0?0:x - 1, \ - _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \ - _n2##x = x + 2>=(int)(img)._width?(img).width() - 1:x + 2, \ - _n3##x = (int)( \ - (I[0] = (T)(img)(_p2##x,_p2##y,z,c)), \ - (I[6] = (T)(img)(_p2##x,_p1##y,z,c)), \ - (I[12] = (T)(img)(_p2##x,y,z,c)), \ - (I[18] = (T)(img)(_p2##x,_n1##y,z,c)), \ - (I[24] = (T)(img)(_p2##x,_n2##y,z,c)), \ - (I[30] = (T)(img)(_p2##x,_n3##y,z,c)), \ - (I[1] = (T)(img)(_p1##x,_p2##y,z,c)), \ - (I[7] = (T)(img)(_p1##x,_p1##y,z,c)), \ - (I[13] = (T)(img)(_p1##x,y,z,c)), \ - (I[19] = (T)(img)(_p1##x,_n1##y,z,c)), \ - (I[25] = (T)(img)(_p1##x,_n2##y,z,c)), \ - (I[31] = (T)(img)(_p1##x,_n3##y,z,c)), \ - (I[2] = (T)(img)(x,_p2##y,z,c)), \ - (I[8] = (T)(img)(x,_p1##y,z,c)), \ - (I[14] = (T)(img)(x,y,z,c)), \ - (I[20] = (T)(img)(x,_n1##y,z,c)), \ - (I[26] = (T)(img)(x,_n2##y,z,c)), \ - (I[32] = (T)(img)(x,_n3##y,z,c)), \ - (I[3] = (T)(img)(_n1##x,_p2##y,z,c)), \ - (I[9] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[15] = (T)(img)(_n1##x,y,z,c)), \ - (I[21] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[27] = (T)(img)(_n1##x,_n2##y,z,c)), \ - (I[33] = (T)(img)(_n1##x,_n3##y,z,c)), \ - (I[4] = (T)(img)(_n2##x,_p2##y,z,c)), \ - (I[10] = (T)(img)(_n2##x,_p1##y,z,c)), \ - (I[16] = (T)(img)(_n2##x,y,z,c)), \ - (I[22] = (T)(img)(_n2##x,_n1##y,z,c)), \ - (I[28] = (T)(img)(_n2##x,_n2##y,z,c)), \ - (I[34] = (T)(img)(_n2##x,_n3##y,z,c)), \ - x + 3>=(int)(img)._width?(img).width() - 1:x + 3); \ - x<=(int)(x1) && ((_n3##x<(img).width() && ( \ - (I[5] = (T)(img)(_n3##x,_p2##y,z,c)), \ - (I[11] = (T)(img)(_n3##x,_p1##y,z,c)), \ - (I[17] = (T)(img)(_n3##x,y,z,c)), \ - (I[23] = (T)(img)(_n3##x,_n1##y,z,c)), \ - (I[29] = (T)(img)(_n3##x,_n2##y,z,c)), \ - (I[35] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \ - _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3## x = _n2##x = --_n1##x)); \ - I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], \ - I[6] = I[7], I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], \ - I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], I[16] = I[17], \ - I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \ - I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], \ - I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], I[34] = I[35], \ - _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x) - -#define cimg_for7x7(img,x,y,z,c,I,T) \ - cimg_for7((img)._height,y) for (int x = 0, \ - _p3##x = 0, _p2##x = 0, _p1##x = 0, \ - _n1##x = 1>=(img)._width?(img).width() - 1:1, \ - _n2##x = 2>=(img)._width?(img).width() - 1:2, \ - _n3##x = (int)( \ - (I[0] = I[1] = I[2] = I[3] = (T)(img)(_p3##x,_p3##y,z,c)), \ - (I[7] = I[8] = I[9] = I[10] = (T)(img)(0,_p2##y,z,c)), \ - (I[14] = I[15] = I[16] = I[17] = (T)(img)(0,_p1##y,z,c)), \ - (I[21] = I[22] = I[23] = I[24] = (T)(img)(0,y,z,c)), \ - (I[28] = I[29] = I[30] = I[31] = (T)(img)(0,_n1##y,z,c)), \ - (I[35] = I[36] = I[37] = I[38] = (T)(img)(0,_n2##y,z,c)), \ - (I[42] = I[43] = I[44] = I[45] = (T)(img)(0,_n3##y,z,c)), \ - (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \ - (I[11] = (T)(img)(_n1##x,_p2##y,z,c)), \ - (I[18] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[25] = (T)(img)(_n1##x,y,z,c)), \ - (I[32] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[39] = (T)(img)(_n1##x,_n2##y,z,c)), \ - (I[46] = (T)(img)(_n1##x,_n3##y,z,c)), \ - (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \ - (I[12] = (T)(img)(_n2##x,_p2##y,z,c)), \ - (I[19] = (T)(img)(_n2##x,_p1##y,z,c)), \ - (I[26] = (T)(img)(_n2##x,y,z,c)), \ - (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \ - (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \ - (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \ - 3>=(img)._width?(img).width() - 1:3); \ - (_n3##x<(img).width() && ( \ - (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ - (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \ - (I[20] = (T)(img)(_n3##x,_p1##y,z,c)), \ - (I[27] = (T)(img)(_n3##x,y,z,c)), \ - (I[34] = (T)(img)(_n3##x,_n1##y,z,c)), \ - (I[41] = (T)(img)(_n3##x,_n2##y,z,c)), \ - (I[48] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \ - _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x); \ - I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \ - I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \ - I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \ - I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \ - I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \ - I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \ - I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \ - _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x) - -#define cimg_for_in7x7(img,x0,y0,x1,y1,x,y,z,c,I,T) \ - cimg_for_in7((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p3##x = x - 3<0?0:x - 3, \ - _p2##x = x - 2<0?0:x - 2, \ - _p1##x = x - 1<0?0:x - 1, \ - _n1##x = x + 1>=(int)(img)._width?(img).width() - 1:x + 1, \ - _n2##x = x + 2>=(int)(img)._width?(img).width() - 1:x + 2, \ - _n3##x = (int)( \ - (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \ - (I[7] = (T)(img)(_p3##x,_p2##y,z,c)), \ - (I[14] = (T)(img)(_p3##x,_p1##y,z,c)), \ - (I[21] = (T)(img)(_p3##x,y,z,c)), \ - (I[28] = (T)(img)(_p3##x,_n1##y,z,c)), \ - (I[35] = (T)(img)(_p3##x,_n2##y,z,c)), \ - (I[42] = (T)(img)(_p3##x,_n3##y,z,c)), \ - (I[1] = (T)(img)(_p2##x,_p3##y,z,c)), \ - (I[8] = (T)(img)(_p2##x,_p2##y,z,c)), \ - (I[15] = (T)(img)(_p2##x,_p1##y,z,c)), \ - (I[22] = (T)(img)(_p2##x,y,z,c)), \ - (I[29] = (T)(img)(_p2##x,_n1##y,z,c)), \ - (I[36] = (T)(img)(_p2##x,_n2##y,z,c)), \ - (I[43] = (T)(img)(_p2##x,_n3##y,z,c)), \ - (I[2] = (T)(img)(_p1##x,_p3##y,z,c)), \ - (I[9] = (T)(img)(_p1##x,_p2##y,z,c)), \ - (I[16] = (T)(img)(_p1##x,_p1##y,z,c)), \ - (I[23] = (T)(img)(_p1##x,y,z,c)), \ - (I[30] = (T)(img)(_p1##x,_n1##y,z,c)), \ - (I[37] = (T)(img)(_p1##x,_n2##y,z,c)), \ - (I[44] = (T)(img)(_p1##x,_n3##y,z,c)), \ - (I[3] = (T)(img)(x,_p3##y,z,c)), \ - (I[10] = (T)(img)(x,_p2##y,z,c)), \ - (I[17] = (T)(img)(x,_p1##y,z,c)), \ - (I[24] = (T)(img)(x,y,z,c)), \ - (I[31] = (T)(img)(x,_n1##y,z,c)), \ - (I[38] = (T)(img)(x,_n2##y,z,c)), \ - (I[45] = (T)(img)(x,_n3##y,z,c)), \ - (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \ - (I[11] = (T)(img)(_n1##x,_p2##y,z,c)), \ - (I[18] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[25] = (T)(img)(_n1##x,y,z,c)), \ - (I[32] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[39] = (T)(img)(_n1##x,_n2##y,z,c)), \ - (I[46] = (T)(img)(_n1##x,_n3##y,z,c)), \ - (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \ - (I[12] = (T)(img)(_n2##x,_p2##y,z,c)), \ - (I[19] = (T)(img)(_n2##x,_p1##y,z,c)), \ - (I[26] = (T)(img)(_n2##x,y,z,c)), \ - (I[33] = (T)(img)(_n2##x,_n1##y,z,c)), \ - (I[40] = (T)(img)(_n2##x,_n2##y,z,c)), \ - (I[47] = (T)(img)(_n2##x,_n3##y,z,c)), \ - x + 3>=(int)(img)._width?(img).width() - 1:x + 3); \ - x<=(int)(x1) && ((_n3##x<(img).width() && ( \ - (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ - (I[13] = (T)(img)(_n3##x,_p2##y,z,c)), \ - (I[20] = (T)(img)(_n3##x,_p1##y,z,c)), \ - (I[27] = (T)(img)(_n3##x,y,z,c)), \ - (I[34] = (T)(img)(_n3##x,_n1##y,z,c)), \ - (I[41] = (T)(img)(_n3##x,_n2##y,z,c)), \ - (I[48] = (T)(img)(_n3##x,_n3##y,z,c)),1)) || \ - _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n3##x = _n2##x = --_n1##x)); \ - I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], \ - I[7] = I[8], I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], \ - I[14] = I[15], I[15] = I[16], I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], \ - I[21] = I[22], I[22] = I[23], I[23] = I[24], I[24] = I[25], I[25] = I[26], I[26] = I[27], \ - I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], I[32] = I[33], I[33] = I[34], \ - I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], I[40] = I[41], \ - I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], I[47] = I[48], \ - _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x) - -#define cimg_for8x8(img,x,y,z,c,I,T) \ - cimg_for8((img)._height,y) for (int x = 0, \ - _p3##x = 0, _p2##x = 0, _p1##x = 0, \ - _n1##x = 1>=((img)._width)?(img).width() - 1:1, \ - _n2##x = 2>=((img)._width)?(img).width() - 1:2, \ - _n3##x = 3>=((img)._width)?(img).width() - 1:3, \ - _n4##x = (int)( \ - (I[0] = I[1] = I[2] = I[3] = (T)(img)(_p3##x,_p3##y,z,c)), \ - (I[8] = I[9] = I[10] = I[11] = (T)(img)(0,_p2##y,z,c)), \ - (I[16] = I[17] = I[18] = I[19] = (T)(img)(0,_p1##y,z,c)), \ - (I[24] = I[25] = I[26] = I[27] = (T)(img)(0,y,z,c)), \ - (I[32] = I[33] = I[34] = I[35] = (T)(img)(0,_n1##y,z,c)), \ - (I[40] = I[41] = I[42] = I[43] = (T)(img)(0,_n2##y,z,c)), \ - (I[48] = I[49] = I[50] = I[51] = (T)(img)(0,_n3##y,z,c)), \ - (I[56] = I[57] = I[58] = I[59] = (T)(img)(0,_n4##y,z,c)), \ - (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \ - (I[12] = (T)(img)(_n1##x,_p2##y,z,c)), \ - (I[20] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[28] = (T)(img)(_n1##x,y,z,c)), \ - (I[36] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[44] = (T)(img)(_n1##x,_n2##y,z,c)), \ - (I[52] = (T)(img)(_n1##x,_n3##y,z,c)), \ - (I[60] = (T)(img)(_n1##x,_n4##y,z,c)), \ - (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \ - (I[13] = (T)(img)(_n2##x,_p2##y,z,c)), \ - (I[21] = (T)(img)(_n2##x,_p1##y,z,c)), \ - (I[29] = (T)(img)(_n2##x,y,z,c)), \ - (I[37] = (T)(img)(_n2##x,_n1##y,z,c)), \ - (I[45] = (T)(img)(_n2##x,_n2##y,z,c)), \ - (I[53] = (T)(img)(_n2##x,_n3##y,z,c)), \ - (I[61] = (T)(img)(_n2##x,_n4##y,z,c)), \ - (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ - (I[14] = (T)(img)(_n3##x,_p2##y,z,c)), \ - (I[22] = (T)(img)(_n3##x,_p1##y,z,c)), \ - (I[30] = (T)(img)(_n3##x,y,z,c)), \ - (I[38] = (T)(img)(_n3##x,_n1##y,z,c)), \ - (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \ - (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \ - (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \ - 4>=((img)._width)?(img).width() - 1:4); \ - (_n4##x<(img).width() && ( \ - (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \ - (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \ - (I[23] = (T)(img)(_n4##x,_p1##y,z,c)), \ - (I[31] = (T)(img)(_n4##x,y,z,c)), \ - (I[39] = (T)(img)(_n4##x,_n1##y,z,c)), \ - (I[47] = (T)(img)(_n4##x,_n2##y,z,c)), \ - (I[55] = (T)(img)(_n4##x,_n3##y,z,c)), \ - (I[63] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \ - _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \ - I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \ - I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \ - I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \ - I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \ - I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \ - I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \ - I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \ - I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \ - _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x) - -#define cimg_for_in8x8(img,x0,y0,x1,y1,x,y,z,c,I,T) \ - cimg_for_in8((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p3##x = x - 3<0?0:x - 3, \ - _p2##x = x - 2<0?0:x - 2, \ - _p1##x = x - 1<0?0:x - 1, \ - _n1##x = x + 1>=(img).width()?(img).width() - 1:x + 1, \ - _n2##x = x + 2>=(img).width()?(img).width() - 1:x + 2, \ - _n3##x = x + 3>=(img).width()?(img).width() - 1:x + 3, \ - _n4##x = (int)( \ - (I[0] = (T)(img)(_p3##x,_p3##y,z,c)), \ - (I[8] = (T)(img)(_p3##x,_p2##y,z,c)), \ - (I[16] = (T)(img)(_p3##x,_p1##y,z,c)), \ - (I[24] = (T)(img)(_p3##x,y,z,c)), \ - (I[32] = (T)(img)(_p3##x,_n1##y,z,c)), \ - (I[40] = (T)(img)(_p3##x,_n2##y,z,c)), \ - (I[48] = (T)(img)(_p3##x,_n3##y,z,c)), \ - (I[56] = (T)(img)(_p3##x,_n4##y,z,c)), \ - (I[1] = (T)(img)(_p2##x,_p3##y,z,c)), \ - (I[9] = (T)(img)(_p2##x,_p2##y,z,c)), \ - (I[17] = (T)(img)(_p2##x,_p1##y,z,c)), \ - (I[25] = (T)(img)(_p2##x,y,z,c)), \ - (I[33] = (T)(img)(_p2##x,_n1##y,z,c)), \ - (I[41] = (T)(img)(_p2##x,_n2##y,z,c)), \ - (I[49] = (T)(img)(_p2##x,_n3##y,z,c)), \ - (I[57] = (T)(img)(_p2##x,_n4##y,z,c)), \ - (I[2] = (T)(img)(_p1##x,_p3##y,z,c)), \ - (I[10] = (T)(img)(_p1##x,_p2##y,z,c)), \ - (I[18] = (T)(img)(_p1##x,_p1##y,z,c)), \ - (I[26] = (T)(img)(_p1##x,y,z,c)), \ - (I[34] = (T)(img)(_p1##x,_n1##y,z,c)), \ - (I[42] = (T)(img)(_p1##x,_n2##y,z,c)), \ - (I[50] = (T)(img)(_p1##x,_n3##y,z,c)), \ - (I[58] = (T)(img)(_p1##x,_n4##y,z,c)), \ - (I[3] = (T)(img)(x,_p3##y,z,c)), \ - (I[11] = (T)(img)(x,_p2##y,z,c)), \ - (I[19] = (T)(img)(x,_p1##y,z,c)), \ - (I[27] = (T)(img)(x,y,z,c)), \ - (I[35] = (T)(img)(x,_n1##y,z,c)), \ - (I[43] = (T)(img)(x,_n2##y,z,c)), \ - (I[51] = (T)(img)(x,_n3##y,z,c)), \ - (I[59] = (T)(img)(x,_n4##y,z,c)), \ - (I[4] = (T)(img)(_n1##x,_p3##y,z,c)), \ - (I[12] = (T)(img)(_n1##x,_p2##y,z,c)), \ - (I[20] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[28] = (T)(img)(_n1##x,y,z,c)), \ - (I[36] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[44] = (T)(img)(_n1##x,_n2##y,z,c)), \ - (I[52] = (T)(img)(_n1##x,_n3##y,z,c)), \ - (I[60] = (T)(img)(_n1##x,_n4##y,z,c)), \ - (I[5] = (T)(img)(_n2##x,_p3##y,z,c)), \ - (I[13] = (T)(img)(_n2##x,_p2##y,z,c)), \ - (I[21] = (T)(img)(_n2##x,_p1##y,z,c)), \ - (I[29] = (T)(img)(_n2##x,y,z,c)), \ - (I[37] = (T)(img)(_n2##x,_n1##y,z,c)), \ - (I[45] = (T)(img)(_n2##x,_n2##y,z,c)), \ - (I[53] = (T)(img)(_n2##x,_n3##y,z,c)), \ - (I[61] = (T)(img)(_n2##x,_n4##y,z,c)), \ - (I[6] = (T)(img)(_n3##x,_p3##y,z,c)), \ - (I[14] = (T)(img)(_n3##x,_p2##y,z,c)), \ - (I[22] = (T)(img)(_n3##x,_p1##y,z,c)), \ - (I[30] = (T)(img)(_n3##x,y,z,c)), \ - (I[38] = (T)(img)(_n3##x,_n1##y,z,c)), \ - (I[46] = (T)(img)(_n3##x,_n2##y,z,c)), \ - (I[54] = (T)(img)(_n3##x,_n3##y,z,c)), \ - (I[62] = (T)(img)(_n3##x,_n4##y,z,c)), \ - x + 4>=(img).width()?(img).width() - 1:x + 4); \ - x<=(int)(x1) && ((_n4##x<(img).width() && ( \ - (I[7] = (T)(img)(_n4##x,_p3##y,z,c)), \ - (I[15] = (T)(img)(_n4##x,_p2##y,z,c)), \ - (I[23] = (T)(img)(_n4##x,_p1##y,z,c)), \ - (I[31] = (T)(img)(_n4##x,y,z,c)), \ - (I[39] = (T)(img)(_n4##x,_n1##y,z,c)), \ - (I[47] = (T)(img)(_n4##x,_n2##y,z,c)), \ - (I[55] = (T)(img)(_n4##x,_n3##y,z,c)), \ - (I[63] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \ - _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \ - I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], \ - I[8] = I[9], I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], \ - I[16] = I[17], I[17] = I[18], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], \ - I[24] = I[25], I[25] = I[26], I[26] = I[27], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], \ - I[32] = I[33], I[33] = I[34], I[34] = I[35], I[35] = I[36], I[36] = I[37], I[37] = I[38], I[38] = I[39], \ - I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[44] = I[45], I[45] = I[46], I[46] = I[47], \ - I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[53] = I[54], I[54] = I[55], \ - I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[62] = I[63], \ - _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x) - -#define cimg_for9x9(img,x,y,z,c,I,T) \ - cimg_for9((img)._height,y) for (int x = 0, \ - _p4##x = 0, _p3##x = 0, _p2##x = 0, _p1##x = 0, \ - _n1##x = 1>=((img)._width)?(img).width() - 1:1, \ - _n2##x = 2>=((img)._width)?(img).width() - 1:2, \ - _n3##x = 3>=((img)._width)?(img).width() - 1:3, \ - _n4##x = (int)( \ - (I[0] = I[1] = I[2] = I[3] = I[4] = (T)(img)(_p4##x,_p4##y,z,c)), \ - (I[9] = I[10] = I[11] = I[12] = I[13] = (T)(img)(0,_p3##y,z,c)), \ - (I[18] = I[19] = I[20] = I[21] = I[22] = (T)(img)(0,_p2##y,z,c)), \ - (I[27] = I[28] = I[29] = I[30] = I[31] = (T)(img)(0,_p1##y,z,c)), \ - (I[36] = I[37] = I[38] = I[39] = I[40] = (T)(img)(0,y,z,c)), \ - (I[45] = I[46] = I[47] = I[48] = I[49] = (T)(img)(0,_n1##y,z,c)), \ - (I[54] = I[55] = I[56] = I[57] = I[58] = (T)(img)(0,_n2##y,z,c)), \ - (I[63] = I[64] = I[65] = I[66] = I[67] = (T)(img)(0,_n3##y,z,c)), \ - (I[72] = I[73] = I[74] = I[75] = I[76] = (T)(img)(0,_n4##y,z,c)), \ - (I[5] = (T)(img)(_n1##x,_p4##y,z,c)), \ - (I[14] = (T)(img)(_n1##x,_p3##y,z,c)), \ - (I[23] = (T)(img)(_n1##x,_p2##y,z,c)), \ - (I[32] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[41] = (T)(img)(_n1##x,y,z,c)), \ - (I[50] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[59] = (T)(img)(_n1##x,_n2##y,z,c)), \ - (I[68] = (T)(img)(_n1##x,_n3##y,z,c)), \ - (I[77] = (T)(img)(_n1##x,_n4##y,z,c)), \ - (I[6] = (T)(img)(_n2##x,_p4##y,z,c)), \ - (I[15] = (T)(img)(_n2##x,_p3##y,z,c)), \ - (I[24] = (T)(img)(_n2##x,_p2##y,z,c)), \ - (I[33] = (T)(img)(_n2##x,_p1##y,z,c)), \ - (I[42] = (T)(img)(_n2##x,y,z,c)), \ - (I[51] = (T)(img)(_n2##x,_n1##y,z,c)), \ - (I[60] = (T)(img)(_n2##x,_n2##y,z,c)), \ - (I[69] = (T)(img)(_n2##x,_n3##y,z,c)), \ - (I[78] = (T)(img)(_n2##x,_n4##y,z,c)), \ - (I[7] = (T)(img)(_n3##x,_p4##y,z,c)), \ - (I[16] = (T)(img)(_n3##x,_p3##y,z,c)), \ - (I[25] = (T)(img)(_n3##x,_p2##y,z,c)), \ - (I[34] = (T)(img)(_n3##x,_p1##y,z,c)), \ - (I[43] = (T)(img)(_n3##x,y,z,c)), \ - (I[52] = (T)(img)(_n3##x,_n1##y,z,c)), \ - (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \ - (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \ - (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \ - 4>=((img)._width)?(img).width() - 1:4); \ - (_n4##x<(img).width() && ( \ - (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \ - (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \ - (I[26] = (T)(img)(_n4##x,_p2##y,z,c)), \ - (I[35] = (T)(img)(_n4##x,_p1##y,z,c)), \ - (I[44] = (T)(img)(_n4##x,y,z,c)), \ - (I[53] = (T)(img)(_n4##x,_n1##y,z,c)), \ - (I[62] = (T)(img)(_n4##x,_n2##y,z,c)), \ - (I[71] = (T)(img)(_n4##x,_n3##y,z,c)), \ - (I[80] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \ - _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x); \ - I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \ - I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], \ - I[16] = I[17], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \ - I[24] = I[25], I[25] = I[26], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], \ - I[32] = I[33], I[33] = I[34], I[34] = I[35], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], \ - I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[45] = I[46], I[46] = I[47], I[47] = I[48], \ - I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[54] = I[55], I[55] = I[56], \ - I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[63] = I[64], \ - I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \ - I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], \ - I[79] = I[80], \ - _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x) - -#define cimg_for_in9x9(img,x0,y0,x1,y1,x,y,z,c,I,T) \ - cimg_for_in9((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p4##x = x - 4<0?0:x - 4, \ - _p3##x = x - 3<0?0:x - 3, \ - _p2##x = x - 2<0?0:x - 2, \ - _p1##x = x - 1<0?0:x - 1, \ - _n1##x = x + 1>=(img).width()?(img).width() - 1:x + 1, \ - _n2##x = x + 2>=(img).width()?(img).width() - 1:x + 2, \ - _n3##x = x + 3>=(img).width()?(img).width() - 1:x + 3, \ - _n4##x = (int)( \ - (I[0] = (T)(img)(_p4##x,_p4##y,z,c)), \ - (I[9] = (T)(img)(_p4##x,_p3##y,z,c)), \ - (I[18] = (T)(img)(_p4##x,_p2##y,z,c)), \ - (I[27] = (T)(img)(_p4##x,_p1##y,z,c)), \ - (I[36] = (T)(img)(_p4##x,y,z,c)), \ - (I[45] = (T)(img)(_p4##x,_n1##y,z,c)), \ - (I[54] = (T)(img)(_p4##x,_n2##y,z,c)), \ - (I[63] = (T)(img)(_p4##x,_n3##y,z,c)), \ - (I[72] = (T)(img)(_p4##x,_n4##y,z,c)), \ - (I[1] = (T)(img)(_p3##x,_p4##y,z,c)), \ - (I[10] = (T)(img)(_p3##x,_p3##y,z,c)), \ - (I[19] = (T)(img)(_p3##x,_p2##y,z,c)), \ - (I[28] = (T)(img)(_p3##x,_p1##y,z,c)), \ - (I[37] = (T)(img)(_p3##x,y,z,c)), \ - (I[46] = (T)(img)(_p3##x,_n1##y,z,c)), \ - (I[55] = (T)(img)(_p3##x,_n2##y,z,c)), \ - (I[64] = (T)(img)(_p3##x,_n3##y,z,c)), \ - (I[73] = (T)(img)(_p3##x,_n4##y,z,c)), \ - (I[2] = (T)(img)(_p2##x,_p4##y,z,c)), \ - (I[11] = (T)(img)(_p2##x,_p3##y,z,c)), \ - (I[20] = (T)(img)(_p2##x,_p2##y,z,c)), \ - (I[29] = (T)(img)(_p2##x,_p1##y,z,c)), \ - (I[38] = (T)(img)(_p2##x,y,z,c)), \ - (I[47] = (T)(img)(_p2##x,_n1##y,z,c)), \ - (I[56] = (T)(img)(_p2##x,_n2##y,z,c)), \ - (I[65] = (T)(img)(_p2##x,_n3##y,z,c)), \ - (I[74] = (T)(img)(_p2##x,_n4##y,z,c)), \ - (I[3] = (T)(img)(_p1##x,_p4##y,z,c)), \ - (I[12] = (T)(img)(_p1##x,_p3##y,z,c)), \ - (I[21] = (T)(img)(_p1##x,_p2##y,z,c)), \ - (I[30] = (T)(img)(_p1##x,_p1##y,z,c)), \ - (I[39] = (T)(img)(_p1##x,y,z,c)), \ - (I[48] = (T)(img)(_p1##x,_n1##y,z,c)), \ - (I[57] = (T)(img)(_p1##x,_n2##y,z,c)), \ - (I[66] = (T)(img)(_p1##x,_n3##y,z,c)), \ - (I[75] = (T)(img)(_p1##x,_n4##y,z,c)), \ - (I[4] = (T)(img)(x,_p4##y,z,c)), \ - (I[13] = (T)(img)(x,_p3##y,z,c)), \ - (I[22] = (T)(img)(x,_p2##y,z,c)), \ - (I[31] = (T)(img)(x,_p1##y,z,c)), \ - (I[40] = (T)(img)(x,y,z,c)), \ - (I[49] = (T)(img)(x,_n1##y,z,c)), \ - (I[58] = (T)(img)(x,_n2##y,z,c)), \ - (I[67] = (T)(img)(x,_n3##y,z,c)), \ - (I[76] = (T)(img)(x,_n4##y,z,c)), \ - (I[5] = (T)(img)(_n1##x,_p4##y,z,c)), \ - (I[14] = (T)(img)(_n1##x,_p3##y,z,c)), \ - (I[23] = (T)(img)(_n1##x,_p2##y,z,c)), \ - (I[32] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[41] = (T)(img)(_n1##x,y,z,c)), \ - (I[50] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[59] = (T)(img)(_n1##x,_n2##y,z,c)), \ - (I[68] = (T)(img)(_n1##x,_n3##y,z,c)), \ - (I[77] = (T)(img)(_n1##x,_n4##y,z,c)), \ - (I[6] = (T)(img)(_n2##x,_p4##y,z,c)), \ - (I[15] = (T)(img)(_n2##x,_p3##y,z,c)), \ - (I[24] = (T)(img)(_n2##x,_p2##y,z,c)), \ - (I[33] = (T)(img)(_n2##x,_p1##y,z,c)), \ - (I[42] = (T)(img)(_n2##x,y,z,c)), \ - (I[51] = (T)(img)(_n2##x,_n1##y,z,c)), \ - (I[60] = (T)(img)(_n2##x,_n2##y,z,c)), \ - (I[69] = (T)(img)(_n2##x,_n3##y,z,c)), \ - (I[78] = (T)(img)(_n2##x,_n4##y,z,c)), \ - (I[7] = (T)(img)(_n3##x,_p4##y,z,c)), \ - (I[16] = (T)(img)(_n3##x,_p3##y,z,c)), \ - (I[25] = (T)(img)(_n3##x,_p2##y,z,c)), \ - (I[34] = (T)(img)(_n3##x,_p1##y,z,c)), \ - (I[43] = (T)(img)(_n3##x,y,z,c)), \ - (I[52] = (T)(img)(_n3##x,_n1##y,z,c)), \ - (I[61] = (T)(img)(_n3##x,_n2##y,z,c)), \ - (I[70] = (T)(img)(_n3##x,_n3##y,z,c)), \ - (I[79] = (T)(img)(_n3##x,_n4##y,z,c)), \ - x + 4>=(img).width()?(img).width() - 1:x + 4); \ - x<=(int)(x1) && ((_n4##x<(img).width() && ( \ - (I[8] = (T)(img)(_n4##x,_p4##y,z,c)), \ - (I[17] = (T)(img)(_n4##x,_p3##y,z,c)), \ - (I[26] = (T)(img)(_n4##x,_p2##y,z,c)), \ - (I[35] = (T)(img)(_n4##x,_p1##y,z,c)), \ - (I[44] = (T)(img)(_n4##x,y,z,c)), \ - (I[53] = (T)(img)(_n4##x,_n1##y,z,c)), \ - (I[62] = (T)(img)(_n4##x,_n2##y,z,c)), \ - (I[71] = (T)(img)(_n4##x,_n3##y,z,c)), \ - (I[80] = (T)(img)(_n4##x,_n4##y,z,c)),1)) || \ - _n3##x==--_n4##x || _n2##x==--_n3##x || _n1##x==--_n2##x || x==(_n4##x = _n3##x = _n2##x = --_n1##x)); \ - I[0] = I[1], I[1] = I[2], I[2] = I[3], I[3] = I[4], I[4] = I[5], I[5] = I[6], I[6] = I[7], I[7] = I[8], \ - I[9] = I[10], I[10] = I[11], I[11] = I[12], I[12] = I[13], I[13] = I[14], I[14] = I[15], I[15] = I[16], \ - I[16] = I[17], I[18] = I[19], I[19] = I[20], I[20] = I[21], I[21] = I[22], I[22] = I[23], I[23] = I[24], \ - I[24] = I[25], I[25] = I[26], I[27] = I[28], I[28] = I[29], I[29] = I[30], I[30] = I[31], I[31] = I[32], \ - I[32] = I[33], I[33] = I[34], I[34] = I[35], I[36] = I[37], I[37] = I[38], I[38] = I[39], I[39] = I[40], \ - I[40] = I[41], I[41] = I[42], I[42] = I[43], I[43] = I[44], I[45] = I[46], I[46] = I[47], I[47] = I[48], \ - I[48] = I[49], I[49] = I[50], I[50] = I[51], I[51] = I[52], I[52] = I[53], I[54] = I[55], I[55] = I[56], \ - I[56] = I[57], I[57] = I[58], I[58] = I[59], I[59] = I[60], I[60] = I[61], I[61] = I[62], I[63] = I[64], \ - I[64] = I[65], I[65] = I[66], I[66] = I[67], I[67] = I[68], I[68] = I[69], I[69] = I[70], I[70] = I[71], \ - I[72] = I[73], I[73] = I[74], I[74] = I[75], I[75] = I[76], I[76] = I[77], I[77] = I[78], I[78] = I[79], \ - I[79] = I[80], \ - _p4##x = _p3##x, _p3##x = _p2##x, _p2##x = _p1##x, _p1##x = x++, ++_n1##x, ++_n2##x, ++_n3##x, ++_n4##x) - -#define cimg_for2x2x2(img,x,y,z,c,I,T) \ - cimg_for2((img)._depth,z) cimg_for2((img)._height,y) for (int x = 0, \ - _n1##x = (int)( \ - (I[0] = (T)(img)(0,y,z,c)), \ - (I[2] = (T)(img)(0,_n1##y,z,c)), \ - (I[4] = (T)(img)(0,y,_n1##z,c)), \ - (I[6] = (T)(img)(0,_n1##y,_n1##z,c)), \ - 1>=(img)._width?(img).width() - 1:1); \ - (_n1##x<(img).width() && ( \ - (I[1] = (T)(img)(_n1##x,y,z,c)), \ - (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[5] = (T)(img)(_n1##x,y,_n1##z,c)), \ - (I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \ - x==--_n1##x; \ - I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \ - ++x, ++_n1##x) - -#define cimg_for_in2x2x2(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \ - cimg_for_in2((img)._depth,z0,z1,z) cimg_for_in2((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _n1##x = (int)( \ - (I[0] = (T)(img)(x,y,z,c)), \ - (I[2] = (T)(img)(x,_n1##y,z,c)), \ - (I[4] = (T)(img)(x,y,_n1##z,c)), \ - (I[6] = (T)(img)(x,_n1##y,_n1##z,c)), \ - x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \ - x<=(int)(x1) && ((_n1##x<(img).width() && ( \ - (I[1] = (T)(img)(_n1##x,y,z,c)), \ - (I[3] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[5] = (T)(img)(_n1##x,y,_n1##z,c)), \ - (I[7] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \ - x==--_n1##x); \ - I[0] = I[1], I[2] = I[3], I[4] = I[5], I[6] = I[7], \ - ++x, ++_n1##x) - -#define cimg_for3x3x3(img,x,y,z,c,I,T) \ - cimg_for3((img)._depth,z) cimg_for3((img)._height,y) for (int x = 0, \ - _p1##x = 0, \ - _n1##x = (int)( \ - (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,_p1##z,c)), \ - (I[3] = I[4] = (T)(img)(0,y,_p1##z,c)), \ - (I[6] = I[7] = (T)(img)(0,_n1##y,_p1##z,c)), \ - (I[9] = I[10] = (T)(img)(0,_p1##y,z,c)), \ - (I[12] = I[13] = (T)(img)(0,y,z,c)), \ - (I[15] = I[16] = (T)(img)(0,_n1##y,z,c)), \ - (I[18] = I[19] = (T)(img)(0,_p1##y,_n1##z,c)), \ - (I[21] = I[22] = (T)(img)(0,y,_n1##z,c)), \ - (I[24] = I[25] = (T)(img)(0,_n1##y,_n1##z,c)), \ - 1>=(img)._width?(img).width() - 1:1); \ - (_n1##x<(img).width() && ( \ - (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \ - (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \ - (I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c)), \ - (I[11] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[14] = (T)(img)(_n1##x,y,z,c)), \ - (I[17] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c)), \ - (I[23] = (T)(img)(_n1##x,y,_n1##z,c)), \ - (I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \ - x==--_n1##x; \ - I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \ - I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \ - I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \ - _p1##x = x++, ++_n1##x) - -#define cimg_for_in3x3x3(img,x0,y0,z0,x1,y1,z1,x,y,z,c,I,T) \ - cimg_for_in3((img)._depth,z0,z1,z) cimg_for_in3((img)._height,y0,y1,y) for (int x = (int)(x0)<0?0:(int)(x0), \ - _p1##x = x - 1<0?0:x - 1, \ - _n1##x = (int)( \ - (I[0] = (T)(img)(_p1##x,_p1##y,_p1##z,c)), \ - (I[3] = (T)(img)(_p1##x,y,_p1##z,c)), \ - (I[6] = (T)(img)(_p1##x,_n1##y,_p1##z,c)), \ - (I[9] = (T)(img)(_p1##x,_p1##y,z,c)), \ - (I[12] = (T)(img)(_p1##x,y,z,c)), \ - (I[15] = (T)(img)(_p1##x,_n1##y,z,c)), \ - (I[18] = (T)(img)(_p1##x,_p1##y,_n1##z,c)), \ - (I[21] = (T)(img)(_p1##x,y,_n1##z,c)), \ - (I[24] = (T)(img)(_p1##x,_n1##y,_n1##z,c)), \ - (I[1] = (T)(img)(x,_p1##y,_p1##z,c)), \ - (I[4] = (T)(img)(x,y,_p1##z,c)), \ - (I[7] = (T)(img)(x,_n1##y,_p1##z,c)), \ - (I[10] = (T)(img)(x,_p1##y,z,c)), \ - (I[13] = (T)(img)(x,y,z,c)), \ - (I[16] = (T)(img)(x,_n1##y,z,c)), \ - (I[19] = (T)(img)(x,_p1##y,_n1##z,c)), \ - (I[22] = (T)(img)(x,y,_n1##z,c)), \ - (I[25] = (T)(img)(x,_n1##y,_n1##z,c)), \ - x + 1>=(int)(img)._width?(img).width() - 1:x + 1); \ - x<=(int)(x1) && ((_n1##x<(img).width() && ( \ - (I[2] = (T)(img)(_n1##x,_p1##y,_p1##z,c)), \ - (I[5] = (T)(img)(_n1##x,y,_p1##z,c)), \ - (I[8] = (T)(img)(_n1##x,_n1##y,_p1##z,c)), \ - (I[11] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[14] = (T)(img)(_n1##x,y,z,c)), \ - (I[17] = (T)(img)(_n1##x,_n1##y,z,c)), \ - (I[20] = (T)(img)(_n1##x,_p1##y,_n1##z,c)), \ - (I[23] = (T)(img)(_n1##x,y,_n1##z,c)), \ - (I[26] = (T)(img)(_n1##x,_n1##y,_n1##z,c)),1)) || \ - x==--_n1##x); \ - I[0] = I[1], I[1] = I[2], I[3] = I[4], I[4] = I[5], I[6] = I[7], I[7] = I[8], \ - I[9] = I[10], I[10] = I[11], I[12] = I[13], I[13] = I[14], I[15] = I[16], I[16] = I[17], \ - I[18] = I[19], I[19] = I[20], I[21] = I[22], I[22] = I[23], I[24] = I[25], I[25] = I[26], \ - _p1##x = x++, ++_n1##x) - -#define cimglist_for(list,l) for (int l = 0; l<(int)(list)._width; ++l) -#define cimglist_rof(list,l) for (int l = (int)(list)._width - 1; l>=0; --l) -#define cimglist_for_in(list,l0,l1,l) \ - for (int l = (int)(l0)<0?0:(int)(l0), _max##l = (unsigned int)l1<(list)._width?(int)(l1):(int)(list)._width - 1; \ - l<=_max##l; ++l) - -#define cimglist_apply(list,fn) cimglist_for(list,__##fn) (list)[__##fn].fn - -// Macros used to display error messages when exceptions are thrown. -// You should not use these macros is your own code. -#define _cimgdisplay_instance "[instance(%u,%u,%u,%c%s%c)] CImgDisplay::" -#define cimgdisplay_instance _width,_height,_normalization,_title?'\"':'[',_title?_title:"untitled",_title?'\"':']' -#define _cimg_instance "[instance(%u,%u,%u,%u,%p,%sshared)] CImg<%s>::" -#define cimg_instance _width,_height,_depth,_spectrum,_data,_is_shared?"":"non-",pixel_type() -#define _cimglist_instance "[instance(%u,%u,%p)] CImgList<%s>::" -#define cimglist_instance _width,_allocated_width,_data,pixel_type() - -/*------------------------------------------------ - # - # - # Define cimg_library:: namespace - # - # - -------------------------------------------------*/ -//! Contains all classes and functions of the \CImg library. -/** - This namespace is defined to avoid functions and class names collisions - that could happen with the inclusion of other C++ header files. - Anyway, it should not happen often and you should reasonably start most of your - \CImg-based programs with - \code - #include "CImg.h" - using namespace cimg_library; - \endcode - to simplify the declaration of \CImg Library objects afterwards. -**/ -namespace cimg_library_suffixed { - - // Declare the four classes of the CImg Library. - template struct CImg; - template struct CImgList; - struct CImgDisplay; - struct CImgException; - - // Declare cimg:: namespace. - // This is an incomplete namespace definition here. It only contains some - // necessary stuff to ensure a correct declaration order of the classes and functions - // defined afterwards. - namespace cimg { - - // Define character sequences for colored terminal output. -#ifdef cimg_use_vt100 - static const char t_normal[] = { 0x1b, '[', '0', ';', '0', ';', '0', 'm', 0 }; - static const char t_black[] = { 0x1b, '[', '0', ';', '3', '0', ';', '5', '9', 'm', 0 }; - static const char t_red[] = { 0x1b, '[', '0', ';', '3', '1', ';', '5', '9', 'm', 0 }; - static const char t_green[] = { 0x1b, '[', '0', ';', '3', '2', ';', '5', '9', 'm', 0 }; - static const char t_yellow[] = { 0x1b, '[', '0', ';', '3', '3', ';', '5', '9', 'm', 0 }; - static const char t_blue[] = { 0x1b, '[', '0', ';', '3', '4', ';', '5', '9', 'm', 0 }; - static const char t_magenta[] = { 0x1b, '[', '0', ';', '3', '5', ';', '5', '9', 'm', 0 }; - static const char t_cyan[] = { 0x1b, '[', '0', ';', '3', '6', ';', '5', '9', 'm', 0 }; - static const char t_white[] = { 0x1b, '[', '0', ';', '3', '7', ';', '5', '9', 'm', 0 }; - static const char t_bold[] = { 0x1b, '[', '1', 'm', 0 }; - static const char t_underscore[] = { 0x1b, '[', '4', 'm', 0 }; -#else - static const char t_normal[] = { 0 }; - static const char *const t_black = cimg::t_normal, - *const t_red = cimg::t_normal, - *const t_green = cimg::t_normal, - *const t_yellow = cimg::t_normal, - *const t_blue = cimg::t_normal, - *const t_magenta = cimg::t_normal, - *const t_cyan = cimg::t_normal, - *const t_white = cimg::t_normal, - *const t_bold = cimg::t_normal, - *const t_underscore = cimg::t_normal; -#endif - - inline std::FILE* output(std::FILE *file=0); - inline void info(); - - //! Avoid warning messages due to unused parameters. Do nothing actually. - template - inline void unused(const T&, ...) {} - - // [internal] Lock/unlock a mutex for managing concurrent threads. - // 'lock_mode' can be { 0=unlock | 1=lock | 2=trylock }. - // 'n' can be in [0,31] but mutex range [0,15] is reserved by CImg. - inline int mutex(const unsigned int n, const int lock_mode=1); - - inline unsigned int& exception_mode(const unsigned int value, const bool is_set) { - static unsigned int mode = cimg_verbosity; - if (is_set) { cimg::mutex(0); mode = value<4?value:4; cimg::mutex(0,0); } - return mode; - } - - // Functions to return standard streams 'stdin', 'stdout' and 'stderr'. - inline FILE* _stdin(const bool throw_exception=true); - inline FILE* _stdout(const bool throw_exception=true); - inline FILE* _stderr(const bool throw_exception=true); - - // Mandatory because Microsoft's _snprintf() and _vsnprintf() do not add the '\0' character - // at the end of the string. -#if cimg_OS==2 && defined(_MSC_VER) - inline int _snprintf(char *const s, const size_t size, const char *const format, ...) { - va_list ap; - va_start(ap,format); - const int result = _vsnprintf(s,size,format,ap); - va_end(ap); - return result; - } - - inline int _vsnprintf(char *const s, const size_t size, const char *const format, va_list ap) { - int result = -1; - cimg::mutex(6); - if (size) result = _vsnprintf_s(s,size,_TRUNCATE,format,ap); - if (result==-1) result = _vscprintf(format,ap); - cimg::mutex(6,0); - return result; - } - - // Mutex-protected version of sscanf, sprintf and snprintf. - // Used only MacOSX, as it seems those functions are not re-entrant on MacOSX. -#elif defined(__MACOSX__) || defined(__APPLE__) - inline int _sscanf(const char *const s, const char *const format, ...) { - cimg::mutex(6); - va_list args; - va_start(args,format); - const int result = std::vsscanf(s,format,args); - va_end(args); - cimg::mutex(6,0); - return result; - } - - inline int _sprintf(char *const s, const char *const format, ...) { - cimg::mutex(6); - va_list args; - va_start(args,format); - const int result = std::vsprintf(s,format,args); - va_end(args); - cimg::mutex(6,0); - return result; - } - - inline int _snprintf(char *const s, const size_t n, const char *const format, ...) { - cimg::mutex(6); - va_list args; - va_start(args,format); - const int result = std::vsnprintf(s,n,format,args); - va_end(args); - cimg::mutex(6,0); - return result; - } - - inline int _vsnprintf(char *const s, const size_t size, const char* format, va_list ap) { - cimg::mutex(6); - const int result = std::vsnprintf(s,size,format,ap); - cimg::mutex(6,0); - return result; - } -#endif - - //! Set current \CImg exception mode. - /** - The way error messages are handled by \CImg can be changed dynamically, using this function. - \param mode Desired exception mode. Possible values are: - - \c 0: Hide library messages (quiet mode). - - \c 1: Print library messages on the console. - - \c 2: Display library messages on a dialog window. - - \c 3: Do as \c 1 + add extra debug warnings (slow down the code!). - - \c 4: Do as \c 2 + add extra debug warnings (slow down the code!). - **/ - inline unsigned int& exception_mode(const unsigned int mode) { - return exception_mode(mode,true); - } - - //! Return current \CImg exception mode. - /** - \note By default, return the value of configuration macro \c cimg_verbosity - **/ - inline unsigned int& exception_mode() { - return exception_mode(0,false); - } - - inline unsigned int openmp_mode(const unsigned int value, const bool is_set) { - static unsigned int mode = 2; - if (is_set) { cimg::mutex(0); mode = value<2?value:2; cimg::mutex(0,0); } - return mode; - } - - //! Set current \CImg openmp mode. - /** - The way openmp-based methods are handled by \CImg can be changed dynamically, using this function. - \param mode Desired openmp mode. Possible values are: - - \c 0: Never parallelize. - - \c 1: Always parallelize. - - \c 2: Adaptive parallelization mode (default behavior). - **/ - inline unsigned int openmp_mode(const unsigned int mode) { - return openmp_mode(mode,true); - } - - //! Return current \CImg openmp mode. - inline unsigned int openmp_mode() { - return openmp_mode(0,false); - } - -#ifndef cimg_openmp_sizefactor -#define cimg_openmp_sizefactor 1 -#endif -#define cimg_openmp_if(cond) if ((cimg::openmp_mode()==1 || (cimg::openmp_mode()>1 && (cond)))) -#define cimg_openmp_if_size(size,min_size) cimg_openmp_if((size)>=(cimg_openmp_sizefactor)*(min_size)) -#ifdef _MSC_VER -// Disable 'collapse()' directive for MSVC (supports only OpenMP 2.0). -#define cimg_openmp_collapse(k) -#else -#define cimg_openmp_collapse(k) collapse(k) -#endif - -#if cimg_OS==2 -// Disable parallelization of simple loops on Windows, due to noticed performance drop. -#define cimg_openmp_for(instance,expr,min_size) cimg_rof((instance),ptr,T) *ptr = (T)(expr); -#else -#define cimg_openmp_for(instance,expr,min_size) \ - cimg_pragma_openmp(parallel for cimg_openmp_if_size((instance).size(),min_size)) \ - cimg_rof((instance),ptr,T) *ptr = (T)(expr); -#endif - - // Display a simple dialog box, and wait for the user's response. - inline int dialog(const char *const title, const char *const msg, - const char *const button1_label="OK", const char *const button2_label=0, - const char *const button3_label=0, const char *const button4_label=0, - const char *const button5_label=0, const char *const button6_label=0, - const bool centering=false); - - // Evaluate math expression. - inline double eval(const char *const expression, - const double x=0, const double y=0, const double z=0, const double c=0); - - } // namespace cimg { ... - - /*--------------------------------------- - # - # Define the CImgException structures - # - --------------------------------------*/ - //! Instances of \c CImgException are thrown when errors are encountered in a \CImg function call. - /** - \par Overview - - CImgException is the base class of all exceptions thrown by \CImg (except \b CImgAbortException). - CImgException is never thrown itself. Derived classes that specify the type of errord are thrown instead. - These classes can be: - - - \b CImgAbortException: Thrown when a computationally-intensive function is aborted by an external signal. - This is the only \c non-derived exception class. - - - \b CImgArgumentException: Thrown when one argument of a called \CImg function is invalid. - This is probably one of the most thrown exception by \CImg. - For instance, the following example throws a \c CImgArgumentException: - \code - CImg img(100,100,1,3); // Define a 100x100 color image with float-valued pixels - img.mirror('e'); // Try to mirror image along the (non-existing) 'e'-axis - \endcode - - - \b CImgDisplayException: Thrown when something went wrong during the display of images in CImgDisplay instances. - - - \b CImgInstanceException: Thrown when an instance associated to a called \CImg method does not fit - the function requirements. For instance, the following example throws a \c CImgInstanceException: - \code - const CImg img; // Define an empty image - const float value = img.at(0); // Try to read first pixel value (does not exist) - \endcode - - - \b CImgIOException: Thrown when an error occurred when trying to load or save image files. - This happens when trying to read files that do not exist or with invalid formats. - For instance, the following example throws a \c CImgIOException: - \code - const CImg img("missing_file.jpg"); // Try to load a file that does not exist - \endcode - - - \b CImgWarningException: Thrown only if configuration macro \c cimg_strict_warnings is set, and - when a \CImg function has to display a warning message (see cimg::warn()). - - It is not recommended to throw CImgException instances by yourself, - since they are expected to be thrown only by \CImg. - When an error occurs in a library function call, \CImg may display error messages on the screen or on the - standard output, depending on the current \CImg exception mode. - The \CImg exception mode can be get and set by functions cimg::exception_mode() and - cimg::exception_mode(unsigned int). - - \par Exceptions handling - - In all cases, when an error occurs in \CImg, an instance of the corresponding exception class is thrown. - This may lead the program to break (this is the default behavior), but you can bypass this behavior by - handling the exceptions by yourself, - using a usual try { ... } catch () { ... } block, as in the following example: - \code - #define "CImg.h" - using namespace cimg_library; - int main() { - cimg::exception_mode(0); // Enable quiet exception mode - try { - ... // Here, do what you want to stress CImg - } catch (CImgException& e) { // You succeeded: something went wrong! - std::fprintf(stderr,"CImg Library Error: %s",e.what()); // Display your custom error message - ... // Do what you want now to save the ship! - } - } - \endcode - **/ - struct CImgException : public std::exception { -#define _cimg_exception_err(etype,disp_flag) \ - std::va_list ap, ap2; \ - va_start(ap,format); va_start(ap2,format); \ - int size = cimg_vsnprintf(0,0,format,ap2); \ - if (size++>=0) { \ - delete[] _message; \ - _message = new char[(size_t)size]; \ - cimg_vsnprintf(_message,(size_t)size,format,ap); \ - if (cimg::exception_mode()) { \ - std::fprintf(cimg::output(),"\n%s[CImg] *** %s ***%s %s\n",cimg::t_red,etype,cimg::t_normal,_message); \ - if (cimg_display && disp_flag && !(cimg::exception_mode()%2)) try { cimg::dialog(etype,_message,"Abort"); } \ - catch (CImgException&) {} \ - if (cimg::exception_mode()>=3) cimg_library_suffixed::cimg::info(); \ - } \ - } \ - va_end(ap); va_end(ap2); - - char *_message; - CImgException() { _message = new char[1]; *_message = 0; } - CImgException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgException",true); } - CImgException(const CImgException& e):std::exception(e) { - const size_t size = std::strlen(e._message); - _message = new char[size + 1]; - std::strncpy(_message,e._message,size); - _message[size] = 0; - } - ~CImgException() throw() { delete[] _message; } - CImgException& operator=(const CImgException& e) { - const size_t size = std::strlen(e._message); - _message = new char[size + 1]; - std::strncpy(_message,e._message,size); - _message[size] = 0; - return *this; - } - //! Return a C-string containing the error message associated to the thrown exception. - const char *what() const throw() { return _message; } - }; // struct CImgException { ... - - // The CImgAbortException class is used to throw an exception when - // a computationally-intensive function has been aborted by an external signal. - struct CImgAbortException : public std::exception { - char *_message; - CImgAbortException() { _message = new char[1]; *_message = 0; } - CImgAbortException(const char *const format, ...):_message(0) { _cimg_exception_err("CImgAbortException",true); } - CImgAbortException(const CImgAbortException& e):std::exception(e) { - const size_t size = std::strlen(e._message); - _message = new char[size + 1]; - std::strncpy(_message,e._message,size); - _message[size] = 0; - } - ~CImgAbortException() throw() { delete[] _message; } - CImgAbortException& operator=(const CImgAbortException& e) { - const size_t size = std::strlen(e._message); - _message = new char[size + 1]; - std::strncpy(_message,e._message,size); - _message[size] = 0; - return *this; - } - //! Return a C-string containing the error message associated to the thrown exception. - const char *what() const throw() { return _message; } - }; // struct CImgAbortException { ... - - // The CImgArgumentException class is used to throw an exception related - // to invalid arguments encountered in a library function call. - struct CImgArgumentException : public CImgException { - CImgArgumentException(const char *const format, ...) { _cimg_exception_err("CImgArgumentException",true); } - }; // struct CImgArgumentException { ... - - // The CImgDisplayException class is used to throw an exception related - // to display problems encountered in a library function call. - struct CImgDisplayException : public CImgException { - CImgDisplayException(const char *const format, ...) { _cimg_exception_err("CImgDisplayException",false); } - }; // struct CImgDisplayException { ... - - // The CImgInstanceException class is used to throw an exception related - // to an invalid instance encountered in a library function call. - struct CImgInstanceException : public CImgException { - CImgInstanceException(const char *const format, ...) { _cimg_exception_err("CImgInstanceException",true); } - }; // struct CImgInstanceException { ... - - // The CImgIOException class is used to throw an exception related - // to input/output file problems encountered in a library function call. - struct CImgIOException : public CImgException { - CImgIOException(const char *const format, ...) { _cimg_exception_err("CImgIOException",true); } - }; // struct CImgIOException { ... - - // The CImgWarningException class is used to throw an exception for warnings - // encountered in a library function call. - struct CImgWarningException : public CImgException { - CImgWarningException(const char *const format, ...) { _cimg_exception_err("CImgWarningException",false); } - }; // struct CImgWarningException { ... - - /*------------------------------------- - # - # Define cimg:: namespace - # - -----------------------------------*/ - //! Contains \a low-level functions and variables of the \CImg Library. - /** - Most of the functions and variables within this namespace are used by the \CImg library for low-level operations. - You may use them to access specific const values or environment variables internally used by \CImg. - \warning Never write using namespace cimg_library::cimg; in your source code. Lot of functions in the - cimg:: namespace have the same names as standard C functions that may be defined in the global - namespace ::. - **/ - namespace cimg { - - // Define traits that will be used to determine the best data type to work in CImg functions. - // - template struct type { - static const char* string() { - static const char* s[] = { "unknown", "unknown8", "unknown16", "unknown24", - "unknown32", "unknown40", "unknown48", "unknown56", - "unknown64", "unknown72", "unknown80", "unknown88", - "unknown96", "unknown104", "unknown112", "unknown120", - "unknown128" }; - return s[(sizeof(T)<17)?sizeof(T):0]; - } - static bool is_float() { return false; } - static bool is_inf(const T) { return false; } - static bool is_nan(const T) { return false; } - static bool is_finite(const T) { return true; } - static T min() { return ~max(); } - static T max() { return (T)1<<(8*sizeof(T) - 1); } - static T inf() { return max(); } - static T cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(T)val; } - static const char* format() { return "%s"; } - static const char* format_s() { return "%s"; } - static const char* format(const T& val) { static const char *const s = "unknown"; cimg::unused(val); return s; } - }; - - template<> struct type { - static const char* string() { - static const char *const s = "bool"; - return s; - } - static bool is_float() { return false; } - static bool is_inf(const bool) { return false; } - static bool is_nan(const bool) { return false; } - static bool is_finite(const bool) { return true; } - static bool min() { return false; } - static bool max() { return true; } - static bool inf() { return max(); } - static bool is_inf() { return false; } - static bool cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(bool)val; } - static const char* format() { return "%s"; } - static const char* format_s() { return "%s"; } - static const char* format(const bool val) { static const char* s[] = { "false", "true" }; return s[val?1:0]; } - }; - - template<> struct type { - static const char* string() { static const char *const s = "uint8"; return s; } - static bool is_float() { return false; } - static bool is_inf(const unsigned char) { return false; } - static bool is_nan(const unsigned char) { return false; } - static bool is_finite(const unsigned char) { return true; } - static unsigned char min() { return 0; } - static unsigned char max() { return (unsigned char)-1; } - static unsigned char inf() { return max(); } - static unsigned char cut(const double val) { - return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; } - static const char* format() { return "%u"; } - static const char* format_s() { return "%u"; } - static unsigned int format(const unsigned char val) { return (unsigned int)val; } - }; - -#if defined(CHAR_MAX) && CHAR_MAX==255 - template<> struct type { - static const char* string() { static const char *const s = "uint8"; return s; } - static bool is_float() { return false; } - static bool is_inf(const char) { return false; } - static bool is_nan(const char) { return false; } - static bool is_finite(const char) { return true; } - static char min() { return 0; } - static char max() { return (char)-1; } - static char inf() { return max(); } - static char cut(const double val) { - return val<(double)min()?min():val>(double)max()?max():(unsigned char)val; } - static const char* format() { return "%u"; } - static const char* format_s() { return "%u"; } - static unsigned int format(const char val) { return (unsigned int)val; } - }; -#else - template<> struct type { - static const char* string() { static const char *const s = "int8"; return s; } - static bool is_float() { return false; } - static bool is_inf(const char) { return false; } - static bool is_nan(const char) { return false; } - static bool is_finite(const char) { return true; } - static char min() { return ~max(); } - static char max() { return (char)((unsigned char)-1>>1); } - static char inf() { return max(); } - static char cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(char)val; } - static const char* format() { return "%d"; } - static const char* format_s() { return "%d"; } - static int format(const char val) { return (int)val; } - }; -#endif - - template<> struct type { - static const char* string() { static const char *const s = "int8"; return s; } - static bool is_float() { return false; } - static bool is_inf(const signed char) { return false; } - static bool is_nan(const signed char) { return false; } - static bool is_finite(const signed char) { return true; } - static signed char min() { return ~max(); } - static signed char max() { return (signed char)((unsigned char)-1>>1); } - static signed char inf() { return max(); } - static signed char cut(const double val) { - return val<(double)min()?min():val>(double)max()?max():(signed char)val; } - static const char* format() { return "%d"; } - static const char* format_s() { return "%d"; } - static int format(const signed char val) { return (int)val; } - }; - - template<> struct type { - static const char* string() { static const char *const s = "uint16"; return s; } - static bool is_float() { return false; } - static bool is_inf(const unsigned short) { return false; } - static bool is_nan(const unsigned short) { return false; } - static bool is_finite(const unsigned short) { return true; } - static unsigned short min() { return 0; } - static unsigned short max() { return (unsigned short)-1; } - static unsigned short inf() { return max(); } - static unsigned short cut(const double val) { - return val<(double)min()?min():val>(double)max()?max():(unsigned short)val; } - static const char* format() { return "%u"; } - static const char* format_s() { return "%u"; } - static unsigned int format(const unsigned short val) { return (unsigned int)val; } - }; - - template<> struct type { - static const char* string() { static const char *const s = "int16"; return s; } - static bool is_float() { return false; } - static bool is_inf(const short) { return false; } - static bool is_nan(const short) { return false; } - static bool is_finite(const short) { return true; } - static short min() { return ~max(); } - static short max() { return (short)((unsigned short)-1>>1); } - static short inf() { return max(); } - static short cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(short)val; } - static const char* format() { return "%d"; } - static const char* format_s() { return "%d"; } - static int format(const short val) { return (int)val; } - }; - - template<> struct type { - static const char* string() { static const char *const s = "uint32"; return s; } - static bool is_float() { return false; } - static bool is_inf(const unsigned int) { return false; } - static bool is_nan(const unsigned int) { return false; } - static bool is_finite(const unsigned int) { return true; } - static unsigned int min() { return 0; } - static unsigned int max() { return (unsigned int)-1; } - static unsigned int inf() { return max(); } - static unsigned int cut(const double val) { - return val<(double)min()?min():val>(double)max()?max():(unsigned int)val; } - static const char* format() { return "%u"; } - static const char* format_s() { return "%u"; } - static unsigned int format(const unsigned int val) { return val; } - }; - - template<> struct type { - static const char* string() { static const char *const s = "int32"; return s; } - static bool is_float() { return false; } - static bool is_inf(const int) { return false; } - static bool is_nan(const int) { return false; } - static bool is_finite(const int) { return true; } - static int min() { return ~max(); } - static int max() { return (int)(~0U>>1); } - static int inf() { return max(); } - static int cut(const double val) { return val<(double)min()?min():val>(double)max()?max():(int)val; } - static const char* format() { return "%d"; } - static const char* format_s() { return "%d"; } - static int format(const int val) { return val; } - }; - - template<> struct type { - static const char* string() { static const char *const s = "uint64"; return s; } - static bool is_float() { return false; } - static bool is_inf(const cimg_uint64) { return false; } - static bool is_nan(const cimg_uint64) { return false; } - static bool is_finite(const cimg_uint64) { return true; } - static cimg_uint64 min() { return 0; } - static cimg_uint64 max() { return (cimg_uint64)-1; } - static cimg_uint64 inf() { return max(); } - static cimg_uint64 cut(const double val) { - return val<(double)min()?min():val>(double)max()?max():(cimg_uint64)val; } - static const char* format() { return cimg_fuint64; } - static const char* format_s() { return cimg_fuint64; } - static cimg_uint64 format(const cimg_uint64 val) { return val; } - }; - - template<> struct type { - static const char* string() { static const char *const s = "int64"; return s; } - static bool is_float() { return false; } - static bool is_inf(const cimg_int64) { return false; } - static bool is_nan(const cimg_int64) { return false; } - static bool is_finite(const cimg_int64) { return true; } - static cimg_int64 min() { return ~max(); } - static cimg_int64 max() { return (cimg_int64)((cimg_uint64)-1>>1); } - static cimg_int64 inf() { return max(); } - static cimg_int64 cut(const double val) { - return val<(double)min()?min():val>(double)max()?max():(cimg_int64)val; - } - static const char* format() { return cimg_fint64; } - static const char* format_s() { return cimg_fint64; } - static long format(const long val) { return (long)val; } - }; - - template<> struct type { - static const char* string() { static const char *const s = "float64"; return s; } - static bool is_float() { return true; } - static bool is_inf(const double val) { -#ifdef isinf - return (bool)isinf(val); -#else - return !is_nan(val) && (val::min() || val>cimg::type::max()); -#endif - } - static bool is_nan(const double val) { // Custom version that works with '-ffast-math' - if (sizeof(double)==8) { - cimg_uint64 u; - std::memcpy(&u,&val,sizeof(double)); - return ((unsigned int)(u>>32)&0x7fffffff) + ((unsigned int)u!=0)>0x7ff00000; - } -#ifdef isnan - return (bool)isnan(val); -#else - return !(val==val); -#endif - } - static bool is_finite(const double val) { -#ifdef isfinite - return (bool)isfinite(val); -#else - return !is_nan(val) && !is_inf(val); -#endif - } - static double min() { return -DBL_MAX; } - static double max() { return DBL_MAX; } - static double inf() { -#ifdef INFINITY - return (double)INFINITY; -#else - return max()*max(); -#endif - } - static double nan() { -#ifdef NAN - return (double)NAN; -#else - const double val_nan = -std::sqrt(-1.); return val_nan; -#endif - } - static double cut(const double val) { return val; } - static const char* format() { return "%.17g"; } - static const char* format_s() { return "%g"; } - static double format(const double val) { return val; } - }; - - template<> struct type { - static const char* string() { static const char *const s = "float32"; return s; } - static bool is_float() { return true; } - static bool is_inf(const float val) { -#ifdef isinf - return (bool)isinf(val); -#else - return !is_nan(val) && (val::min() || val>cimg::type::max()); -#endif - } - static bool is_nan(const float val) { // Custom version that works with '-ffast-math' - if (sizeof(float)==4) { - unsigned int u; - std::memcpy(&u,&val,sizeof(float)); - return (u&0x7fffffff)>0x7f800000; - } -#ifdef isnan - return (bool)isnan(val); -#else - return !(val==val); -#endif - } - static bool is_finite(const float val) { -#ifdef isfinite - return (bool)isfinite(val); -#else - return !is_nan(val) && !is_inf(val); -#endif - } - static float min() { return -FLT_MAX; } - static float max() { return FLT_MAX; } - static float inf() { return (float)cimg::type::inf(); } - static float nan() { return (float)cimg::type::nan(); } - static float cut(const double val) { return (float)val; } - static float cut(const float val) { return (float)val; } - static const char* format() { return "%.9g"; } - static const char* format_s() { return "%g"; } - static double format(const float val) { return (double)val; } - }; - - template<> struct type { - static const char* string() { static const char *const s = "float128"; return s; } - static bool is_float() { return true; } - static bool is_inf(const long double val) { -#ifdef isinf - return (bool)isinf(val); -#else - return !is_nan(val) && (val::min() || val>cimg::type::max()); -#endif - } - static bool is_nan(const long double val) { -#ifdef isnan - return (bool)isnan(val); -#else - return !(val==val); -#endif - } - static bool is_finite(const long double val) { -#ifdef isfinite - return (bool)isfinite(val); -#else - return !is_nan(val) && !is_inf(val); -#endif - } - static long double min() { return -LDBL_MAX; } - static long double max() { return LDBL_MAX; } - static long double inf() { return max()*max(); } - static long double nan() { const long double val_nan = -std::sqrt(-1.L); return val_nan; } - static long double cut(const long double val) { return val; } - static const char* format() { return "%.17g"; } - static const char* format_s() { return "%g"; } - static double format(const long double val) { return (double)val; } - }; - -#ifdef cimg_use_half - template<> struct type { - static const char* string() { static const char *const s = "float16"; return s; } - static bool is_float() { return true; } - static bool is_inf(const long double val) { -#ifdef isinf - return (bool)isinf(val); -#else - return !is_nan(val) && (val::min() || val>cimg::type::max()); -#endif - } - static bool is_nan(const half val) { // Custom version that works with '-ffast-math' - if (sizeof(half)==2) { - short u; - std::memcpy(&u,&val,sizeof(short)); - return (bool)((u&0x7fff)>0x7c00); - } - return cimg::type::is_nan((float)val); - } - static bool is_finite(const half val) { -#ifdef isfinite - return (bool)isfinite(val); -#else - return !is_nan(val) && !is_inf(val); -#endif - } - static half min() { return (half)-65504; } - static half max() { return (half)65504; } - static half inf() { return max()*max(); } - static half nan() { const half val_nan = (half)-std::sqrt(-1.); return val_nan; } - static half cut(const double val) { return (half)val; } - static const char* format() { return "%.9g"; } - static const char* format_s() { return "%g"; } - static double format(const half val) { return (double)val; } - }; -#endif - - template struct superset { typedef T type; }; - template<> struct superset { typedef unsigned char type; }; - template<> struct superset { typedef char type; }; - template<> struct superset { typedef signed char type; }; - template<> struct superset { typedef unsigned short type; }; - template<> struct superset { typedef short type; }; - template<> struct superset { typedef unsigned int type; }; - template<> struct superset { typedef int type; }; - template<> struct superset { typedef cimg_uint64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef short type; }; - template<> struct superset { typedef short type; }; - template<> struct superset { typedef unsigned short type; }; - template<> struct superset { typedef short type; }; - template<> struct superset { typedef unsigned int type; }; - template<> struct superset { typedef int type; }; - template<> struct superset { typedef cimg_uint64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef short type; }; - template<> struct superset { typedef short type; }; - template<> struct superset { typedef int type; }; - template<> struct superset { typedef short type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef int type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef short type; }; - template<> struct superset { typedef short type; }; - template<> struct superset { typedef int type; }; - template<> struct superset { typedef short type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef int type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef int type; }; - template<> struct superset { typedef int type; }; - template<> struct superset { typedef int type; }; - template<> struct superset { typedef unsigned int type; }; - template<> struct superset { typedef int type; }; - template<> struct superset { typedef cimg_uint64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef int type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef int type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_uint64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef cimg_int64 type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef double type; }; - template<> struct superset { typedef double type; }; - -#ifdef cimg_use_half - template<> struct superset { typedef float type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef float type; }; - template<> struct superset { typedef double type; }; -#endif - - template struct superset2 { - typedef typename superset::type>::type type; - }; - - template struct superset3 { - typedef typename superset::type>::type type; - }; - - template struct last { typedef t2 type; }; - -#define _cimg_Tt typename cimg::superset::type -#define _cimg_Tfloat typename cimg::superset::type -#define _cimg_tfloat typename cimg::superset::type -#define _cimg_Ttfloat typename cimg::superset2::type -#define _cimg_Ttdouble typename cimg::superset2::type - - // Define variables used internally by CImg. -#if cimg_display==1 - struct X11_static { - unsigned int nb_wins; - pthread_t *events_thread; - pthread_cond_t wait_event; - pthread_mutex_t wait_event_mutex; - CImgDisplay **wins; - Display *display; - unsigned int nb_bits; - bool is_blue_first; - bool is_shm_enabled; - bool byte_order; - -#ifdef cimg_use_xrandr - XRRScreenSize *resolutions; - Rotation curr_rotation; - unsigned int curr_resolution; - unsigned int nb_resolutions; -#endif - X11_static():nb_wins(0),events_thread(0),display(0), - nb_bits(0),is_blue_first(false),is_shm_enabled(false),byte_order(false) { -#ifdef __FreeBSD__ - XInitThreads(); -#endif - wins = new CImgDisplay*[1024]; - pthread_mutex_init(&wait_event_mutex,0); - pthread_cond_init(&wait_event,0); - -#ifdef cimg_use_xrandr - resolutions = 0; - curr_rotation = 0; - curr_resolution = nb_resolutions = 0; -#endif - } - - ~X11_static() { - delete[] wins; - /* - if (events_thread) { - pthread_cancel(*events_thread); - delete events_thread; - } - if (display) { } // XCloseDisplay(display); } - pthread_cond_destroy(&wait_event); - pthread_mutex_unlock(&wait_event_mutex); - pthread_mutex_destroy(&wait_event_mutex); - */ - } - }; // struct X11_static { ... -#if defined(cimg_module) - X11_static& X11_attr(); -#elif defined(cimg_main) - X11_static& X11_attr() { static X11_static val; return val; } -#else - inline X11_static& X11_attr() { static X11_static val; return val; } -#endif - -#elif cimg_display==2 - struct Win32_static { - HANDLE wait_event; - Win32_static() { wait_event = CreateEvent(0,FALSE_WIN,FALSE_WIN,0); } - }; // struct Win32_static { ... -#if defined(cimg_module) - Win32_static& Win32_attr(); -#elif defined(cimg_main) - Win32_static& Win32_attr() { static Win32_static val; return val; } -#else - inline Win32_static& Win32_attr() { static Win32_static val; return val; } -#endif -#endif -#define cimg_lock_display() cimg::mutex(15) -#define cimg_unlock_display() cimg::mutex(15,0) - - struct Mutex_static { -#if cimg_OS==1 && (defined(cimg_use_pthread) || cimg_display==1) - pthread_mutex_t mutex[32]; - Mutex_static() { for (unsigned int i = 0; i<32; ++i) pthread_mutex_init(&mutex[i],0); } - void lock(const unsigned int n) { pthread_mutex_lock(&mutex[n]); } - void unlock(const unsigned int n) { pthread_mutex_unlock(&mutex[n]); } - int trylock(const unsigned int n) { return pthread_mutex_trylock(&mutex[n]); } -#elif cimg_OS==2 - HANDLE mutex[32]; - Mutex_static() { for (unsigned int i = 0; i<32; ++i) mutex[i] = CreateMutex(0,FALSE_WIN,0); } - void lock(const unsigned int n) { WaitForSingleObject(mutex[n],INFINITE); } - void unlock(const unsigned int n) { ReleaseMutex(mutex[n]); } - int trylock(const unsigned int) { return 0; } -#else - Mutex_static() {} - void lock(const unsigned int) {} - void unlock(const unsigned int) {} - int trylock(const unsigned int) { return 0; } -#endif - }; // struct Mutex_static { ... -#if defined(cimg_module) - Mutex_static& Mutex_attr(); -#elif defined(cimg_main) - Mutex_static& Mutex_attr() { static Mutex_static val; return val; } -#else - inline Mutex_static& Mutex_attr() { static Mutex_static val; return val; } -#endif - -#if defined(cimg_use_magick) - struct Magick_static { - Magick_static() { - Magick::InitializeMagick(""); - } - }; // struct Magick_static { ... - static Magick_static _Magick_static; -#endif - -#if defined(cimg_use_fftw3) && !defined(cimg_use_fftw3_singlethread) - struct FFTW3_static { - FFTW3_static() { - fftw_init_threads(); - } - }; // struct FFTW3_static { ... - static FFTW3_static _FFTW3_static; -#endif - -#if cimg_display==1 - // Define keycodes for X11-based graphical systems. - const unsigned int keyESC = XK_Escape; - const unsigned int keyF1 = XK_F1; - const unsigned int keyF2 = XK_F2; - const unsigned int keyF3 = XK_F3; - const unsigned int keyF4 = XK_F4; - const unsigned int keyF5 = XK_F5; - const unsigned int keyF6 = XK_F6; - const unsigned int keyF7 = XK_F7; - const unsigned int keyF8 = XK_F8; - const unsigned int keyF9 = XK_F9; - const unsigned int keyF10 = XK_F10; - const unsigned int keyF11 = XK_F11; - const unsigned int keyF12 = XK_F12; - const unsigned int keyPAUSE = XK_Pause; - const unsigned int key1 = XK_1; - const unsigned int key2 = XK_2; - const unsigned int key3 = XK_3; - const unsigned int key4 = XK_4; - const unsigned int key5 = XK_5; - const unsigned int key6 = XK_6; - const unsigned int key7 = XK_7; - const unsigned int key8 = XK_8; - const unsigned int key9 = XK_9; - const unsigned int key0 = XK_0; - const unsigned int keyBACKSPACE = XK_BackSpace; - const unsigned int keyINSERT = XK_Insert; - const unsigned int keyHOME = XK_Home; - const unsigned int keyPAGEUP = XK_Page_Up; - const unsigned int keyTAB = XK_Tab; - const unsigned int keyQ = XK_q; - const unsigned int keyW = XK_w; - const unsigned int keyE = XK_e; - const unsigned int keyR = XK_r; - const unsigned int keyT = XK_t; - const unsigned int keyY = XK_y; - const unsigned int keyU = XK_u; - const unsigned int keyI = XK_i; - const unsigned int keyO = XK_o; - const unsigned int keyP = XK_p; - const unsigned int keyDELETE = XK_Delete; - const unsigned int keyEND = XK_End; - const unsigned int keyPAGEDOWN = XK_Page_Down; - const unsigned int keyCAPSLOCK = XK_Caps_Lock; - const unsigned int keyA = XK_a; - const unsigned int keyS = XK_s; - const unsigned int keyD = XK_d; - const unsigned int keyF = XK_f; - const unsigned int keyG = XK_g; - const unsigned int keyH = XK_h; - const unsigned int keyJ = XK_j; - const unsigned int keyK = XK_k; - const unsigned int keyL = XK_l; - const unsigned int keyENTER = XK_Return; - const unsigned int keySHIFTLEFT = XK_Shift_L; - const unsigned int keyZ = XK_z; - const unsigned int keyX = XK_x; - const unsigned int keyC = XK_c; - const unsigned int keyV = XK_v; - const unsigned int keyB = XK_b; - const unsigned int keyN = XK_n; - const unsigned int keyM = XK_m; - const unsigned int keySHIFTRIGHT = XK_Shift_R; - const unsigned int keyARROWUP = XK_Up; - const unsigned int keyCTRLLEFT = XK_Control_L; - const unsigned int keyAPPLEFT = XK_Super_L; - const unsigned int keyALT = XK_Alt_L; - const unsigned int keySPACE = XK_space; - const unsigned int keyALTGR = XK_Alt_R; - const unsigned int keyAPPRIGHT = XK_Super_R; - const unsigned int keyMENU = XK_Menu; - const unsigned int keyCTRLRIGHT = XK_Control_R; - const unsigned int keyARROWLEFT = XK_Left; - const unsigned int keyARROWDOWN = XK_Down; - const unsigned int keyARROWRIGHT = XK_Right; - const unsigned int keyPAD0 = XK_KP_0; - const unsigned int keyPAD1 = XK_KP_1; - const unsigned int keyPAD2 = XK_KP_2; - const unsigned int keyPAD3 = XK_KP_3; - const unsigned int keyPAD4 = XK_KP_4; - const unsigned int keyPAD5 = XK_KP_5; - const unsigned int keyPAD6 = XK_KP_6; - const unsigned int keyPAD7 = XK_KP_7; - const unsigned int keyPAD8 = XK_KP_8; - const unsigned int keyPAD9 = XK_KP_9; - const unsigned int keyPADADD = XK_KP_Add; - const unsigned int keyPADSUB = XK_KP_Subtract; - const unsigned int keyPADMUL = XK_KP_Multiply; - const unsigned int keyPADDIV = XK_KP_Divide; - -#elif cimg_display==2 - // Define keycodes for Windows. - const unsigned int keyESC = VK_ESCAPE; - const unsigned int keyF1 = VK_F1; - const unsigned int keyF2 = VK_F2; - const unsigned int keyF3 = VK_F3; - const unsigned int keyF4 = VK_F4; - const unsigned int keyF5 = VK_F5; - const unsigned int keyF6 = VK_F6; - const unsigned int keyF7 = VK_F7; - const unsigned int keyF8 = VK_F8; - const unsigned int keyF9 = VK_F9; - const unsigned int keyF10 = VK_F10; - const unsigned int keyF11 = VK_F11; - const unsigned int keyF12 = VK_F12; - const unsigned int keyPAUSE = VK_PAUSE; - const unsigned int key1 = '1'; - const unsigned int key2 = '2'; - const unsigned int key3 = '3'; - const unsigned int key4 = '4'; - const unsigned int key5 = '5'; - const unsigned int key6 = '6'; - const unsigned int key7 = '7'; - const unsigned int key8 = '8'; - const unsigned int key9 = '9'; - const unsigned int key0 = '0'; - const unsigned int keyBACKSPACE = VK_BACK; - const unsigned int keyINSERT = VK_INSERT; - const unsigned int keyHOME = VK_HOME; - const unsigned int keyPAGEUP = VK_PRIOR; - const unsigned int keyTAB = VK_TAB; - const unsigned int keyQ = 'Q'; - const unsigned int keyW = 'W'; - const unsigned int keyE = 'E'; - const unsigned int keyR = 'R'; - const unsigned int keyT = 'T'; - const unsigned int keyY = 'Y'; - const unsigned int keyU = 'U'; - const unsigned int keyI = 'I'; - const unsigned int keyO = 'O'; - const unsigned int keyP = 'P'; - const unsigned int keyDELETE = VK_DELETE; - const unsigned int keyEND = VK_END; - const unsigned int keyPAGEDOWN = VK_NEXT; - const unsigned int keyCAPSLOCK = VK_CAPITAL; - const unsigned int keyA = 'A'; - const unsigned int keyS = 'S'; - const unsigned int keyD = 'D'; - const unsigned int keyF = 'F'; - const unsigned int keyG = 'G'; - const unsigned int keyH = 'H'; - const unsigned int keyJ = 'J'; - const unsigned int keyK = 'K'; - const unsigned int keyL = 'L'; - const unsigned int keyENTER = VK_RETURN; - const unsigned int keySHIFTLEFT = VK_SHIFT; - const unsigned int keyZ = 'Z'; - const unsigned int keyX = 'X'; - const unsigned int keyC = 'C'; - const unsigned int keyV = 'V'; - const unsigned int keyB = 'B'; - const unsigned int keyN = 'N'; - const unsigned int keyM = 'M'; - const unsigned int keySHIFTRIGHT = VK_SHIFT; - const unsigned int keyARROWUP = VK_UP; - const unsigned int keyCTRLLEFT = VK_CONTROL; - const unsigned int keyAPPLEFT = VK_LWIN; - const unsigned int keyALT = VK_LMENU; - const unsigned int keySPACE = VK_SPACE; - const unsigned int keyALTGR = VK_CONTROL; - const unsigned int keyAPPRIGHT = VK_RWIN; - const unsigned int keyMENU = VK_APPS; - const unsigned int keyCTRLRIGHT = VK_CONTROL; - const unsigned int keyARROWLEFT = VK_LEFT; - const unsigned int keyARROWDOWN = VK_DOWN; - const unsigned int keyARROWRIGHT = VK_RIGHT; - const unsigned int keyPAD0 = 0x60; - const unsigned int keyPAD1 = 0x61; - const unsigned int keyPAD2 = 0x62; - const unsigned int keyPAD3 = 0x63; - const unsigned int keyPAD4 = 0x64; - const unsigned int keyPAD5 = 0x65; - const unsigned int keyPAD6 = 0x66; - const unsigned int keyPAD7 = 0x67; - const unsigned int keyPAD8 = 0x68; - const unsigned int keyPAD9 = 0x69; - const unsigned int keyPADADD = VK_ADD; - const unsigned int keyPADSUB = VK_SUBTRACT; - const unsigned int keyPADMUL = VK_MULTIPLY; - const unsigned int keyPADDIV = VK_DIVIDE; - -#else - // Define random keycodes when no display is available. - // (should rarely be used then!). - const unsigned int keyESC = 1U; //!< Keycode for the \c ESC key (architecture-dependent) - const unsigned int keyF1 = 2U; //!< Keycode for the \c F1 key (architecture-dependent) - const unsigned int keyF2 = 3U; //!< Keycode for the \c F2 key (architecture-dependent) - const unsigned int keyF3 = 4U; //!< Keycode for the \c F3 key (architecture-dependent) - const unsigned int keyF4 = 5U; //!< Keycode for the \c F4 key (architecture-dependent) - const unsigned int keyF5 = 6U; //!< Keycode for the \c F5 key (architecture-dependent) - const unsigned int keyF6 = 7U; //!< Keycode for the \c F6 key (architecture-dependent) - const unsigned int keyF7 = 8U; //!< Keycode for the \c F7 key (architecture-dependent) - const unsigned int keyF8 = 9U; //!< Keycode for the \c F8 key (architecture-dependent) - const unsigned int keyF9 = 10U; //!< Keycode for the \c F9 key (architecture-dependent) - const unsigned int keyF10 = 11U; //!< Keycode for the \c F10 key (architecture-dependent) - const unsigned int keyF11 = 12U; //!< Keycode for the \c F11 key (architecture-dependent) - const unsigned int keyF12 = 13U; //!< Keycode for the \c F12 key (architecture-dependent) - const unsigned int keyPAUSE = 14U; //!< Keycode for the \c PAUSE key (architecture-dependent) - const unsigned int key1 = 15U; //!< Keycode for the \c 1 key (architecture-dependent) - const unsigned int key2 = 16U; //!< Keycode for the \c 2 key (architecture-dependent) - const unsigned int key3 = 17U; //!< Keycode for the \c 3 key (architecture-dependent) - const unsigned int key4 = 18U; //!< Keycode for the \c 4 key (architecture-dependent) - const unsigned int key5 = 19U; //!< Keycode for the \c 5 key (architecture-dependent) - const unsigned int key6 = 20U; //!< Keycode for the \c 6 key (architecture-dependent) - const unsigned int key7 = 21U; //!< Keycode for the \c 7 key (architecture-dependent) - const unsigned int key8 = 22U; //!< Keycode for the \c 8 key (architecture-dependent) - const unsigned int key9 = 23U; //!< Keycode for the \c 9 key (architecture-dependent) - const unsigned int key0 = 24U; //!< Keycode for the \c 0 key (architecture-dependent) - const unsigned int keyBACKSPACE = 25U; //!< Keycode for the \c BACKSPACE key (architecture-dependent) - const unsigned int keyINSERT = 26U; //!< Keycode for the \c INSERT key (architecture-dependent) - const unsigned int keyHOME = 27U; //!< Keycode for the \c HOME key (architecture-dependent) - const unsigned int keyPAGEUP = 28U; //!< Keycode for the \c PAGEUP key (architecture-dependent) - const unsigned int keyTAB = 29U; //!< Keycode for the \c TAB key (architecture-dependent) - const unsigned int keyQ = 30U; //!< Keycode for the \c Q key (architecture-dependent) - const unsigned int keyW = 31U; //!< Keycode for the \c W key (architecture-dependent) - const unsigned int keyE = 32U; //!< Keycode for the \c E key (architecture-dependent) - const unsigned int keyR = 33U; //!< Keycode for the \c R key (architecture-dependent) - const unsigned int keyT = 34U; //!< Keycode for the \c T key (architecture-dependent) - const unsigned int keyY = 35U; //!< Keycode for the \c Y key (architecture-dependent) - const unsigned int keyU = 36U; //!< Keycode for the \c U key (architecture-dependent) - const unsigned int keyI = 37U; //!< Keycode for the \c I key (architecture-dependent) - const unsigned int keyO = 38U; //!< Keycode for the \c O key (architecture-dependent) - const unsigned int keyP = 39U; //!< Keycode for the \c P key (architecture-dependent) - const unsigned int keyDELETE = 40U; //!< Keycode for the \c DELETE key (architecture-dependent) - const unsigned int keyEND = 41U; //!< Keycode for the \c END key (architecture-dependent) - const unsigned int keyPAGEDOWN = 42U; //!< Keycode for the \c PAGEDOWN key (architecture-dependent) - const unsigned int keyCAPSLOCK = 43U; //!< Keycode for the \c CAPSLOCK key (architecture-dependent) - const unsigned int keyA = 44U; //!< Keycode for the \c A key (architecture-dependent) - const unsigned int keyS = 45U; //!< Keycode for the \c S key (architecture-dependent) - const unsigned int keyD = 46U; //!< Keycode for the \c D key (architecture-dependent) - const unsigned int keyF = 47U; //!< Keycode for the \c F key (architecture-dependent) - const unsigned int keyG = 48U; //!< Keycode for the \c G key (architecture-dependent) - const unsigned int keyH = 49U; //!< Keycode for the \c H key (architecture-dependent) - const unsigned int keyJ = 50U; //!< Keycode for the \c J key (architecture-dependent) - const unsigned int keyK = 51U; //!< Keycode for the \c K key (architecture-dependent) - const unsigned int keyL = 52U; //!< Keycode for the \c L key (architecture-dependent) - const unsigned int keyENTER = 53U; //!< Keycode for the \c ENTER key (architecture-dependent) - const unsigned int keySHIFTLEFT = 54U; //!< Keycode for the \c SHIFTLEFT key (architecture-dependent) - const unsigned int keyZ = 55U; //!< Keycode for the \c Z key (architecture-dependent) - const unsigned int keyX = 56U; //!< Keycode for the \c X key (architecture-dependent) - const unsigned int keyC = 57U; //!< Keycode for the \c C key (architecture-dependent) - const unsigned int keyV = 58U; //!< Keycode for the \c V key (architecture-dependent) - const unsigned int keyB = 59U; //!< Keycode for the \c B key (architecture-dependent) - const unsigned int keyN = 60U; //!< Keycode for the \c N key (architecture-dependent) - const unsigned int keyM = 61U; //!< Keycode for the \c M key (architecture-dependent) - const unsigned int keySHIFTRIGHT = 62U; //!< Keycode for the \c SHIFTRIGHT key (architecture-dependent) - const unsigned int keyARROWUP = 63U; //!< Keycode for the \c ARROWUP key (architecture-dependent) - const unsigned int keyCTRLLEFT = 64U; //!< Keycode for the \c CTRLLEFT key (architecture-dependent) - const unsigned int keyAPPLEFT = 65U; //!< Keycode for the \c APPLEFT key (architecture-dependent) - const unsigned int keyALT = 66U; //!< Keycode for the \c ALT key (architecture-dependent) - const unsigned int keySPACE = 67U; //!< Keycode for the \c SPACE key (architecture-dependent) - const unsigned int keyALTGR = 68U; //!< Keycode for the \c ALTGR key (architecture-dependent) - const unsigned int keyAPPRIGHT = 69U; //!< Keycode for the \c APPRIGHT key (architecture-dependent) - const unsigned int keyMENU = 70U; //!< Keycode for the \c MENU key (architecture-dependent) - const unsigned int keyCTRLRIGHT = 71U; //!< Keycode for the \c CTRLRIGHT key (architecture-dependent) - const unsigned int keyARROWLEFT = 72U; //!< Keycode for the \c ARROWLEFT key (architecture-dependent) - const unsigned int keyARROWDOWN = 73U; //!< Keycode for the \c ARROWDOWN key (architecture-dependent) - const unsigned int keyARROWRIGHT = 74U; //!< Keycode for the \c ARROWRIGHT key (architecture-dependent) - const unsigned int keyPAD0 = 75U; //!< Keycode for the \c PAD0 key (architecture-dependent) - const unsigned int keyPAD1 = 76U; //!< Keycode for the \c PAD1 key (architecture-dependent) - const unsigned int keyPAD2 = 77U; //!< Keycode for the \c PAD2 key (architecture-dependent) - const unsigned int keyPAD3 = 78U; //!< Keycode for the \c PAD3 key (architecture-dependent) - const unsigned int keyPAD4 = 79U; //!< Keycode for the \c PAD4 key (architecture-dependent) - const unsigned int keyPAD5 = 80U; //!< Keycode for the \c PAD5 key (architecture-dependent) - const unsigned int keyPAD6 = 81U; //!< Keycode for the \c PAD6 key (architecture-dependent) - const unsigned int keyPAD7 = 82U; //!< Keycode for the \c PAD7 key (architecture-dependent) - const unsigned int keyPAD8 = 83U; //!< Keycode for the \c PAD8 key (architecture-dependent) - const unsigned int keyPAD9 = 84U; //!< Keycode for the \c PAD9 key (architecture-dependent) - const unsigned int keyPADADD = 85U; //!< Keycode for the \c PADADD key (architecture-dependent) - const unsigned int keyPADSUB = 86U; //!< Keycode for the \c PADSUB key (architecture-dependent) - const unsigned int keyPADMUL = 87U; //!< Keycode for the \c PADMUL key (architecture-dependent) - const unsigned int keyPADDIV = 88U; //!< Keycode for the \c PADDDIV key (architecture-dependent) -#endif - - const double PI = 3.14159265358979323846; //!< Value of the mathematical constant PI - - // Define a 10x13 binary font (small sans). - static const char *const data_font_small[] = { - " UwlwnwoyuwHwlwmwcwlwnw[xuwowlwmwoyuwRwlwnxcw Mw (wnwnwuwpwuypwuwoy" - "ZwnwmwuwowuwmwnwnwuwowuwfwuxnwnwmwuwpwuypwuwZwnwnwtwpwtwow'y Hw cwnw >{ jw %xdxZwdw_wexfwYwkw 7yowoyFx=w " - "ry qw %wuw !xnwkwnwoyuwfwuw[wkwnwcwowrwpwdwuwoxuwpwkwnwoyuwRwkwnwbwpwNyoyoyoyoy;wdwnxpxtxowG|!ydwnwuwowtwow" - "pxswqxlwnxnxmwDwoyoxnyoymwp{oyq{pyoy>ypwqwpwp{oyqzo{q{pzrwrwowlwqwswpwnwqwsxswpypzoyqzozq}swrwrwqwtwswswtxsxswq" - "ws}qwnwkwnydwew_wfwdwkwmwowkw(w0wmwmwGwtwdxQw swuwnwo{q{pynwp|rwtwtwqydwcwcwcwmwmxgwqwpwnzpwuwpzoyRzoyoyexnynwd" - "z\\xnxgxrwsxrwsyswowmwmwmwmwmwmwo}ryp{q{q{q{nwmwnwmwozqxswpyoyoyoyoyeyuwswrwrwrwrwrwrwrwrwqwrwmwtwnwmwnwuwpwuyp" - "wuwoyZwmwnwuwowuwmwqwkwuwowuwoxnwuxowmwnwuwpwuypwuwZwmwnwuwowuwnwowmwtw\\wuwuwqwswqwswqwswqwswEwqwtweypzr~qyIw " - "rwswewnwuwowuwozswtwuwqwtwmwnwlwowuwuwowOxpxuxqwuwowswqwswoxpwlwjwqwswqwswy~}P{|k~-{|w~}k{|w~}Ww~|S{|k~X{|v~vv~|Y{|}k~}|Z{|y~" - "}y|xy|}w~| s{|}k~}|Z{|l~|V{}p~}\"{|y~}|w{|}w~|V{|}|u{|v~P{}x~} {{}h~} N{|~y}y|}x~|S{|v~}|y{|}w~}2{|w~y}x~|g{}x" - "~|k{|w~y}x~|g{}x~|kx}|w{|}w~}k{}x~}%{}t~|P{}t~|P{}t~|P{}t~|P{}t~|P{}t~}W{|[~}e{}f~}b{}c~|a{}c~|a{}c~|a{}c~|X{}w" - "~}M{}w~}M{}w~}M{}w~}Z{|d~}|`{}t~}kv~b{|g~}]{|g~}]{|g~}]{|g~}]{|g~}){|g~|{|w~|h{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f" - "{|v~h{}w~}f{|v~|j{|v~|b{}w~}L{|u~}|w{|}v~|W{|w~|Iw~}Qw~x{}x~|V{}y~}x{}s~|X{|v~|wv~}Vx~}v{|x~| D{}x~}I{}w~Q{}x~|" - "xw~U{}w~}w{|v~T{|w~|J{|w~Q{|x~}x{|x~|V{|v~vv~|T{}q~}|Wx~|x{}s~T{|w~I{|w~|R{|x~}x{}x~|Vx~}x{}s~|X{|v~vv~| Fw~}J{" - "|w~|R{|x~}x{|x~}Uv~|w{}w~}Q{|w~|Ww~}Hv~}w{}w~} Pw~}y{|x~}cY~ i{}y~|#{|w~}Qm~|`m~}w{|m~|\\{}v~| ;{}`~} -" - "{|r~x}t~}$v~}R{}x~}vw~}S{|w~t{|x~}U{|y~|_{|w~}w{}w~|n{}x~}_{|t~w}u~|Q{}x~}K{}w~N{}x~}Jx~ +{|w~Xs~y}s~|\\m~}X{}" - "f~\\{}g~}R{|s~}\\{|g~}Y{|i~|`{}c~|_{|s~w}s~}]{|s~x}s~ hr~}r~|[{|f~}Xs~}Y{}d~|\\{|c~}g{}b~|^{}c~|`{}e~_{|a~|g{" - "}w~}hv~|Y{}w~}M{}w~}W{}w~}n{|u~|_{}w~}V{}s~}jr~|h{}s~|lv~c{|p~}q~}^{}f~}_{|p~}q~}`{}e~[{}q~}p~dZ~g{|v~h{}w~}h{|" - "v~|f{|v~p{|v~m{|t~}m{}w~}m{|v~|m{}v~c{}v~jv~}e\\~]{|w~}Nw~}D{|w~|Sp~| ww~|!w~} `{|w~|${}w~}!w~}Cv~Lv~Tw~}Dv~ " - " Ov~ !{}w~}Mw~|N{|v~ :{}v~|s{|v~V{|t}|V{|t~s}w~| p{|v~ {{|v~|t{|v~|Vs~}W{}c~|_{}d~}c{|d~|W{|v~Y{}^~|iv~" - "}r{|v~qv~}f{|p~}q~}${}r~} v{}w~ v{}q~| ?y~}Ps~x}u~,v~k{}w~|Ww~|Su~}v|}w~X{|v~vv~|Z{}v~}y|wy|}v~}[{|}q{}x~} t{}" - "v~}y|wy|}v~}&{}w~|x{|w~}#y|r{}x~}Kw~|R{|w~ {{}p~}v|x~} H{}x~|S{}w~t{}w~|3x|x{}x~|h{|x~}j{|}|x{}x~|h{|x~}`{|w~l{" - "|w~$s~}Ps~}Ps~}Ps~}Ps~}Pr~W{}[~}g{|c~}c{}c~|a{}c~|a{}c~|a{}c~|X{}w~}M{}w~}M{}w~}M{}w~}Z{|b~}a{}s~|lv~c{|p~}q~}_" - "{|p~}q~}_{|p~}q~}_{|p~}q~}_{|p~}q~}+{|p~}q~}w~|g{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}e{}v~jv~}a{}w~}Lu~r{" - "|v~V{|w~J{}x~}Q{}x~|w{}x~Vx~|w{}u~}Vv|vv|U{}x~}x|}w~ Bw~|K{|w~|R{|x~}w{|x~}Vu|vv|S{|w~K{|w~|Qx~}v{}x~Uv|vv|T{|}" - "t~}|Tx~|w{|u~|S{}x~}Jw~}Qw~vw~Vx~|w{}u~}Vv|vv| Dw~|Kw~|Qw~v{}x~|Vv|vv|Pw~|Vw~}Hv|uv| G{|t}|P{|t}|P{|t}|P{|t}|P{" - "|t}|Lw~|xw~c{|[~} iy~}\"u~|S{|l~a{}l~|x{}l~]{}t~ ={|^~} .{|u~}|u{|}w~}$v~}R{}x~}vw~}S{}x~}t{}x~}Xy|y}y~y}x" - "|cw~}u{}w~o{|w~^u~}t{|}y~|Q{}x~}Kw~|N{|w~|T{}sx~s{} 4{}x~}Y{}v~}|v{}u~\\m~}X{}v~y}|wy|s~]{}x~}x|v{|}t~}Sr~}\\{" - "|v~k|Z{|t~}|v{|y}y~|`h|u~^t~|u{|}u~|^u~}|v{|}v~} iv~y|v{|t~]{|o~y}p~|[{|r~|Z{}w~}q|}s~]{|s~}|t{|}u~}g{}w~}r|y" - "}q~}_{}w~}h|_{}w~}j|`{|s~}|s{|}t~|g{}w~}hv~|Y{}w~}M{}w~}W{}w~}o{}u~|^{}w~}V{}r~k{|r~|h{}r~lv~d{|t~}|uy|s~_{}w~}" - "s|y}t~}a{|t~}|uy|s~a{}w~}s|y}s~]{}u~}|ty|}v~dn|}v~}n|g{|v~h{}w~}gv~}f{}w~}ov~|n{|t~}mv~|l{}v~|o{|v~|bv~}l{}v~dc" - "|u~}]{|w~}N{}w~D{|w~|T{}o~| x{|w~!w~} `{|w~|${}w~ w~} >w~}Dv~ Ov~ !{}w~|Mw~|M{}w~ :v~|q{}w~|Xp~}X{}v~|p{|" - "}| o{}w~| v~|r{|v~W{|r~|X{}v~}i|^{}w~}h|d{|s~}y|xy|}s~}[{|y}u~y}y|]{}w~}h|v~|iv~}r{|v~qv~}g{|t~}|uy|s~&{}p" - "~} w{}w~ w{}o~| @y~}Q{}v~}|u{|}y~,{|w~}m{|w~}Vw~|T{|v~|s{|}~({|w~}|o{|}w~|P{}x~| w{|w~}|o{|}w~|(x~}tw~ rw~K{}x" - "~|Rw~ {{}o~}w{|x~} H{}x~|T{|w~r{}x~}-{}x~|hw~|d{}x~|hw~|_{}x~|mw~|%{|r~|R{|r~|R{|r~|R{|r~|R{|r~|R{}r~|Y{|v~|y{|" - "v~}h|h{|s~}|t{|}u~}c{}w~}h|`{}w~}h|`{}w~}h|`{}w~}h|W{}w~}M{}w~}M{}w~}M{}w~}Z{|v~r|x}q~b{}r~lv~d{|t~}|uy|s~a{|t~" - "}|uy|s~a{|t~}|uy|s~a{|t~}|uy|s~a{|t~}|uy|s~-{|t~}|u{|}q~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}dv~}l{}v~`" - "{}w~}M{|v~p{}w~|V{}x~}L{}x~}Q{|x~|ux~}Wx~|v{|w~} {{}q~| Aw~|Lw~|Qw~u{}x~| y{|x~}Lw~|Q{}x~tx~}#{|}r~}Rx~u{|}y~}|" - "Q{}x~}L{}x~}Q{}x~|v{|x~}Wx~|v{}w~} j{|w~L{}x~}Q{}x~|u{}x~ x{}x~}Uw~} b{|}p~}|V{|}p~}|V{|}p~}|V{|}p~}|V{|}p~}|" - "P{|w~|xx|av~|fv~| j{|y~|#{}t~Sk~|c{|k~}y{|k~}_{|s~} ?{}t~}y| u{|u~|p{}y~}$v~}R{}x~}vw~}Sw~|tw~|[{|}m~}|h{" - "|w~sw~|p{}x~|_{}v~|q{|}|Q{}x~}L{}w~Lw~}U{}y~|ux~u{|y~}U{|x}| `w~|Z{|v~}s{|v~}]w~y}y|{}w~}X{}x~|p{|u~|^y}|n{|u~" - "|U{}x~y}w~}\\{|w~}K{|u~}o{}|Mv~|_{}v~}q{|u~_{}v~}r{|v~| jy~}|qu~|_{}t~}y|s{|}t~}\\{}w~}w~}Z{}w~}o{|u~}_{|t~|n" - "{|}x~}g{}w~}n{|}t~}`{}w~}L{}w~}P{|t~}m{|}w~|g{}w~}hv~|Y{}w~}M{}w~}W{}w~}p{}u~|]{}w~}V{}w~}w~|l{}r~|h{}r~|mv~e{|" - "u~}|p{|t~`{}w~}q{|}u~|c{|u~}|p{|t~b{}w~}p{}u~|_{|u~|n{|}y~W{|v~|Z{|v~h{}w~}g{|v~fv~|o{}w~}n{}x~}w~mv~|kv~}ov~}a" - "{|v~|n{|v~|M{}v~}\\{|w~}N{|w~|E{|w~|U{}v~}{|u~| x{|x~}\"w~} `{|w~|$v~ w~} >w~}Dv~ Ov~ !v~Lw~|M{}w~| <{|w~" - "}p{|w~}Xn~|Zv~ _{|v~ !{|w~}p{}w~}X{}w~}w~}W{}v~|M{}w~}R{|t~|p{|t~|_{|}l~}|`{}w~}hv~|iv~}r{|v~qv~}h{|u~}|p{|" - "t~({}n~} x{}w~ x{}m~| Ay~}R{|v~}p{}+{}w~|nv~Uw~|T{}w~| x{|w~|k{|w~|Q{|x~| x{|w~|k{|w~|*{|x~rx~|R{|w}Fw~Kw~|S{}" - "x~| {|n~}w{|x~} H{}x~|T{}x~}qw~|.{}x~|i{}x~}c{}x~|i{}x~}^{}x~|n{}x~}${}w~}w~}R{}w~}w~}R{}w~}w~}R{}w~}w~}R{}w~}w" - "~}Rv~|w~}Y{}w~}x{|v~U{|t~|n{|}x~}c{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~n{|}s~c{}r~|mv~e{|u~}|p{|" - "t~c{|u~}|p{|t~c{|u~}|p{|t~c{|u~}|p{|t~c{|u~}|p{|t~/{|u~}|p{}t~}e{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}d{|v" - "~|n{|v~|`{}w~}M{}w~}ow~}U{}x~|N{|w~Px~}t{|x~|Xx|sy| w{}s~| @{|w~M{}x~|Q{}x~|tw~ x{}x~}N{}x~|Q{|x~|t{|x~|&{}t~}v" - "~} t{}x~|N{|x~}Q{|x~}t{}x~|Xx|sy| g{|x~}N{|x~}Q{|x~}sx~} {{|x~}Tw~} d{|j~|Z{|j~|Z{|j~|Z{|j~|Z{|j~|R{|w~Z{}w~}" - "g{}w~} Ay|J{}y~#{|s~}Tk~}c{}j~|{}j~_q~| A{}u~} q{}v~|n{}~}$v~}R{}x~}vw~}Sw~t{|w~\\{|h~|i{}x~}s{}x~}q{|x~}^" - "v~|C{}x~}Lw~}L{}w~V{|v~|wx~w{|v~|V{}w~ a{|w~Yv~}q{|v~|^{}y|u{}w~}Xy}|m{|u~M{|v~}V{|w~|}w~}\\{|w~}Ku~|?{|v~^u~o" - "{}v~|a{|v~}p{}v~ j{~|nv~}`u~}|l{|}u~]v~{v~Z{}w~}mu~_u~}j{|y~}g{}w~}l{|}u~}a{}w~}L{}w~}Q{|u~}i{|}y~|g{}w~}hv~|" - "Y{}w~}M{}w~}W{}w~}q{}u~|\\{}w~}V{}w~|w~}lw~|v~|h{}q~mv~f{|u~}m{|u~}a{}w~}o{}v~}d{|u~}m{|u~}c{}w~}o{|u~_{}v~|j{|" - "W{|v~|Z{|v~h{}w~}fv~|h{}v~n{}w~}nw~|w~|o{|v~j{|v~}q{}v~_{}v~nv~}M{|u~[{|w~}Mw~}E{|w~|V{}v~}x{|u~| vw~} `{|w~|$" - "w~} w~} >w~}Dv~ Ov~ !v~Lw~|M{}w~| <{}w~|ow~}Xm~|[v~ ^v~| \"v~|p{|v~Xv~{v~V{}v~|N{}w~}Ru~}l{}u~|b{|g~}" - "|b{}w~}hv~|iv~}r{|v~qv~}i{|u~}m{|u~}*{}l~} y{}w~ y{}k~| By~}R{}v~ y{|w~}o{|w~}Uw~|T{}w~ x{|x~}g{}x~|R{|x~} y{|" - "x~}g{}x~|+{}y~}r{}y~}R{}w~Fx~}M{|}w~ Mm~}w{|x~} H{}x~|Tw~p{}x~|.{}x~|j{|w~b{}x~|j{|w~]w~n{|w~#v~{v~Rv~{v~Rv~{v~" - "Rv~{v~Rv~{v~S{|w~}{}w~|Zv~|x{|v~Uu~}j{|y~}c{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~k{}t~d{}q~mv~f{|" - "u~}m{|u~}e{|u~}m{|u~}e{|u~}m{|u~}e{|u~}m{|u~}e{|u~}m{|u~}1{|u~}m{|u~}e{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w" - "~}c{}v~nv~}_{}w~}Mv~n{}w~Tw}N{|x}P{|x}r{|x} F{|}x~}| ={|x}|O{|x}|Px}|s{|x}| xw|Nw|Pw|rw|'{|v~}|y{|v~} tw}Nw}P{|" - "x}rx}| 6w|Nw|Ox|rw| Nw~} e{}h~}\\{}h~}\\{}h~}\\{}h~}\\{}h~}S{|w~Z{|v~gv~| Ay~}L{|y~}${|q~}V{|j~ci~}|i~|a{}p~|" - "Oy|Uw|jw|Vu|Wv|kw|b{}v~} p{|v~|l{|}$v~}R{}x~}vw~}T{|x~}t{|x~}]{|g~|i{}x~|s{|w~qw~|^v~B{}x~}M{|w~|L{|w~}V{|}" - "w~}xx~x{}w~}|U{}w~ a{}w~Z{|v~o{}w~}U{}w~}X{|j{}v~|M{}v~Vw~}{}w~}\\{|w~}L{|v~|>v~}_{|v~|nv~}a{}v~nv~| \\{}w~}" - "b{|u~|h{|}v~|`{|w~}{}w~|[{}w~}m{|v~|a{}v~}gy}g{}w~}j{}u~|b{}w~}L{}w~}Q{}v~}f{|~|g{}w~}hv~|Y{}w~}M{}w~}W{}w~}r{}" - "u~|[{}w~}V{}w~y|w~m{|w~{v~|h{}w~}v~|nv~f{}v~}ju~|b{}w~}nu~d{}v~}ju~|d{}w~}n{}v~|`v~}D{|v~|Z{|v~h{}w~}f{}w~}hv~}" - "n{|v~o{|w~{}x~}o{}w~}i{}v~|s{|v~|^v~}p{}v~M{|u~|[{|w~}M{}x~}E{|w~|W{}v~|v{|u~| ww~} `{|w~|$w~} w~} >w~}Dv~ " - "Ov~ !v~Lw~|M{|w~| <{}w~|ow~}Xy~}w|}t~[v~| _{}w~} #{|w~}n{}w~|Z{|w~}{}w~|Vu~|O{}w~}S{}v~}j{}u~c{}d~|c{}w~" - "}hv~|iv~}r{|v~qv~}i{}v~}ju~|,{}v~y}w~|v~} {{}w~ {{}v~y}w~|u~| Cy~}R{}w~}R{|ey|_{}w~|pv~Tw~|T{}w~ y{|x~}e{}x~|\\" - "{|}p~} {{|x~}e{}x~|,{}y~}r{}y~}R{}w~G{}x~|Rq~| N{|m~}w{|x~} H{}x~|U{|w~p{|x~}.{}x~|j{}x~|b{}x~|j{}x~|_{|w~|n{}" - "x~|${|w~}{}w~|T{|w~}{}w~|T{|w~}{}w~|T{|w~}{}w~|T{|w~}{}w~|T{}w~|{|w~}[{|v~w{|v~V{}v~}gy}c{}w~}M{}w~}M{}w~}M{}w~" - "}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~j{|u~}e{}w~}v~|nv~f{}v~}ju~|f{}v~}ju~|f{}v~}ju~|f{}v~}ju~|f{}v~}ju~|c{}d{}|d{}v~}" - "k{}u~|f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}bv~}p{}v~^{}m~y}|Yv~o{|}w~ Py~}|u{|v~} 2w~} f{" - "}u~}x|{x|}t~^{}u~}x|{x|}t~^{}u~}x|{x|}t~^{}u~}x|{x|}t~^{}u~}x|{x|}t~T{|w~Yv~|i{|v~ A{}x~}M{}y~|$o~|W{|j~ch~}i~}" - "b{}n~T{|}t~y}|Zw~}kw~}X{}u~|X{}w~|m{}w~|d{|v~| ov~}j{|$v~}R{}x~}vw~}T{}x~}t{}x~}]u~}|{|y~|y{|y}x~|iw~|rw~r{" - "}x~}]v~B{}x~}Mv~Jv~T{|}w~|{x~{|w~}|S{}w~ aw~}Z{}w~}o{|v~U{}w~}Ev~}M{|v~W{}w~y{}w~}\\{|w~}Lv~}>{|v~|_{|v~m{}w~}" - "av~|n{|v~ 8{|y}6{|~|4{}v~c{|v~}d{|v~`{}w~|{|w~}[{}w~}lv~|b{|v~}e{|g{}w~}i{}u~b{}w~}L{}w~}R{|v~}dy|g{}w~}hv~|Y{}" - "w~}M{}w~}W{}w~}s{}u~Y{}w~}V{}w~|{w~|nw~}{v~|h{}w~y|v~nv~g{|v~}i{|u~b{}w~}n{|v~|f{|v~}i{|u~d{}w~}n{|v~|a{|v~C{|v" - "~|Z{|v~h{}w~}f{|v~|j{|v~|mv~|p{|w~{|x~}ov~|hv~}sv~}]{|v~|r{|v~|Mu~|Z{|w~}M{|w~E{|w~|X{}v~|t{|u~| xw~} `{|w~|$w" - "~} w~} >w~}Dv~ Ov~ !w~}Lw~|M{|w~| {|v~]{|v~m{}w~}b{|w~}l{}w~}W{|v}M{}v~D{}r~}6{|r~}|>{|v~|e{}w~|^{|w~|dv~w{|v~\\{}w~}lv~|c{}v~N{}w~}g{}v~|d{" - "}w~}L{}w~}S{}v~L{}w~}hv~|Y{}w~}M{}w~}W{}w~}vu~}V{}w~}V{}w~|yw~}pw~}yv~|h{}w~|y{}w~}pv~h{}v~e{}v~|d{}w~}mv~}g{}v" - "~e{}v~|f{}w~}mv~}a{|v~C{|v~|Z{|v~h{}w~}dv~|l{|v~k{|v~q{|w~x{}x~}q{}w~}e{}v~wv~}Y{|v~|v{|v~|N{|v~}W{|w~}L{|w~F{|" - "w~|[{}v~l{}v~ S{|}k~|Zw~}y{|o~}V{|k~|\\{|o~}y{|w~|\\{|m~}X{}k~}Y{|o~}y{|w~|`w~}y{|o~}Sv~Lv~Tw~}o{|v~}Wv~_w~}y{|" - "o~|v{|o~|ew~}y{|o~}Y{|}n~}|[w~}y{|o~}Y{|o~}y{|w~|Zw~}y{|r~|[{}j~[{}i~]{|w~|m{}w~|b{}w~|k{|w~}i{|w~}q{|u~|q{|w~|" - "h{|v~|o{|v~}b{}w~|k{|w~}`d~Uw~}Lw~|M{|w~| n{|o~}vw~|av~o{}w~|M{|v~[{|o~}|U{}k~}]w~}y{|o~}_u~|k{|w~}Wu~X{|w~|m{" - "}w~|dv~|h{|v~_{}x~}x{}s~}__~|dv~t{}w~t{|w~}\\{}n~}Y{|}e~}f{|`~b{|w~}l{}w~|\\v~w{|v~T{|u~R{}w~}U{}v~dv~}i{}u~u{|" - "v~u{|u~|g{}w~}hv~|iv~}r{|v~qv~|k{}v~e{}v~|c{~}I{|y~}w{}w~w{|y~}I{}~|U{}w~T{}~|k{}~|\\y~}w{}w~w{|y~| v~}P{}k~Z{|" - "v~S{|v~}x{|}v~}|y{|v~}^{|w~}u{|w~}Rw~|S{|u~}${}y~|v{}v~}|wy|}y~u{|y~}c{|x~}r{|x~}Q{|q{| W{}y~|uw~vy|v~u{|y~}-w~" - "|v{|w~Q{}w~K{|w~|I{|w~'{|w~|m{}w~|a{}m~}w{|x~} H{}x~|U{|x~}p{|x~}]{|q{|X{}x~|m{|w~_{}x~|m{|w~]{|}w~}q{|w~Pv~|Sv" - "~w{|v~Vv~w{|v~Vv~w{|v~Vv~w{|v~Vv~w{|v~W{|v~vv~^{|v~|v{|v~X{}v~J{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z" - "{|v~g{|v~}g{}w~|y{}w~}pv~h{}v~e{}v~|j{}v~e{}v~|j{}v~e{}v~|j{}v~e{}v~|j{}v~e{}v~|g{|u~l{}v~}g{}v~kw~}{}v~g{|v~h{" - "}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}`{|v~|v{|v~|\\{}w~}s|y}t~}_w~}u{|v~|Y{|}k~|Z{|}k~|Z{|}k~|Z{|}k~|Z{|}k~|Z{|" - "}k~|d{|}k~|v{|m~}_{|k~|[{|m~}W{|m~}W{|m~}W{|m~}Rv~Lv~Lv~Lv~Q{|}l~\\w~}y{|o~}Y{|}n~}|X{|}n~}|X{|}n~}|X{|}n~}|X{|" - "}n~}|S{}u~S{|}n~}{|x~}a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|b{}w~|k{|w~}aw~}y{|o~}^{}w~|k{|w~} X{|w~}" - "t{}w~t{|w~}f{|w~}h{|w~}f{|w~}yy|p{|}y{|w~}f{|w~}ly|y{|w~}f{|w~}h{|w~}X{}x~}X{|v~kv~| Cv~|Lx~&{|i~|Y{|m~}bU~|e{}" - "h~\\{|u~}|xy|}u~^w~}kw~}Yr~}X{}w~}ov~d{}w~ lv~| lv~}R{}x~}vw~}^{}Z~f{|w~|v{|y~|`w~|s{|w~tw~|[{|v~|D{}x~}Nw~" - "}H{}w~|Q{|t~|N{}w~ c{|w~|Zv~|lv~|W{}w~}E{}w~}M{}w~}Z{|w~|w{}w~}\\{|w~}N{|v~={}w~}\\v~|nv~|b{}w~}l{}v~W{}v~M{}v" - "~G{|}p~|6{|o~}@u~e{|w~|\\{}w~e{|w~}v{}w~|]{}w~}m{|v~|cv~}N{}w~}g{|v~}d{}w~}L{}w~}Sv~}L{}w~}hv~|Y{}w~}M{}w~}W{}w" - "~}x{|u~}U{}w~}V{}w~|y{}w~q{|w~|yv~|h{}w~|y{|v~pv~hv~}e{|v~}d{}w~}mv~}gv~}e{|v~}f{}w~}mv~}a{|v~|D{|v~|Z{|v~h{}w~" - "}d{}w~}l{}w~}jv~|r{|w~x{|x~}qv~|e{|v~}y{}v~W{}v~vv~}N{|u~V{|w~}Kw~|G{|w~|\\{}w~}j{}v~ T{}i~}[w~}{}m~}X{}j~|]{}m" - "~}{|w~|]{}j~Y{}k~}Z{}m~}{|w~|`w~}{|l~Tv~Lv~Tw~}p{}v~}Vv~_w~}{|m~|x{|m~|fw~}{|m~}[{|j~|\\w~}{}m~}[{}m~}{|w~|Zw~}" - "{|q~|\\{}i~[{}i~]{|w~|m{}w~|b{|w~}k{}w~|hw~}q{|u~}q{}w~|g{}v~ov~}a{|w~}k{}w~|`d~Uw~}Lw~|M{|w~| Gy|l{|Z{}m~}x{|w" - "~`v~p{|v~Kv~Z{|m~|X{}j~}]w~}{|l~`t~|l{}w~|X{|u~}Y{|w~|m{}w~|e{}v~f{}w~}b{|v~}y{|q~}`_~|dv~t{}w~t{|w~}^{|k~}[{|c" - "~}f{|`~b{}w~}l{}w~}]{|w~}vv~|T{|v~}S{}w~}Uv~}d{}v~j{|u~t{|v~t{|u~g{}w~}hv~|iv~}r{|v~r{|v~|kv~}e{|v~}dx~}I{|}v{}" - "w~v{|}I{}x~|V{}w~U{}x~|m{}x~|\\{|v{}w~vy| {{v~}R{|i~Z{|v~R{|v~}|q~}|v~}\\v~u{}w~Qw~|R{|t~|'{|y~}v{}w~}p{|t{}y~|" - "d{}x~|r{|x~}Ry}r{|~ X{|y~}tw~sw~|u{}y~|.{|w~}x|}w~|Q{}w~L{|w~|G{|x~}({|w~|m{}w~|a{}m~}w{|x~} H{}x~|U{|w~p{|x~}]" - "{~|r{|}Y{}x~|mw~|_{}x~|m{}x~|[{|w~|r{}x~|Pv~|T{|w~}v{}w~|X{|w~}v{}w~|X{|w~}v{}w~|X{|w~}v{}w~|X{|w~}v{}w~|X{}w~}" - "v{}w~}_{}w~}u{|v~Xv~}J{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~fu~g{}w~|y{|v~pv~hv~}e{|v~}jv~}e{|v~}" - "jv~}e{|v~}jv~}e{|v~}jv~}e{|v~}f{|u~n{}v~}fv~}l{}x~}y{|v~|h{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}_{}v~vv~}[" - "{}w~}q{|}u~|`w~}uv~W{}i~}[{}i~}[{}i~}[{}i~}[{}i~}[{}i~}e{}i~}x{}k~}a{}j~|\\{}j~Y{}j~Y{}j~Y{}j~Sv~Lv~Lv~Lv~R{}j~" - "}]w~}{|m~}[{|j~|Z{|j~|Z{|j~|Z{|j~|Z{|j~|T{}u~T{|f~`{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|b{|w~}k{}w~|a" - "w~}{}m~}_{|w~}k{}w~| Xw~}s{}w~s{}w~fw~}f{}w~fw~}y{|y~|r{|y~}y{}w~fw~}l{|y~}y{}w~fw~}f{}w~X{}x~}Wv~|m{|v~ C{}w~}" - "[{|}|o{|y~|&g~|Y{}n~|b{}V~e{|g~}]v~}r{|v~}_w~}kw~}Z{|r~}X{|v~p{|w~}dw~} pw|v~l| {{v~}R{}x~}vw~}^{}Z~f{|w~|v" - "{|y~|`{}x~}s{|x~}u{}x~}Y{}v~|E{}x~}O{|w~}H{}w~|S{|}r~}|P{}w~ c{|w~Yv~|lv~|W{}w~}Ev~|N{|v~|Zw~}v{}w~}\\{|w~}|}v" - "~y}|X{}w~}>{|v~|\\{}w~}o{|v~a{}w~}l{}v~W{}v~M{}v~J{|}p~}|2{|}p~}|D{}v~|e{}x~}p{|}w~}|vx|uw~|f{}w~|v{|w~}]{}w~}m" - "{}v~c{|v~|N{}w~}fv~}d{}w~}L{}w~}T{|v~|L{}w~}hv~|Y{}w~}M{}w~}W{}w~}y{|u~}T{}w~}V{}w~|y{|w~|r{}x~}xv~|h{}w~|x{}w~" - "}qv~i{|v~|dv~}d{}w~}mv~}h{|v~|dv~}f{}w~}n{|v~|`u~D{|v~|Z{|v~h{}w~}d{|v~m{|v~|j{}w~}r{}x~}x{|w~qv~|d{}v~y|v~|Vv~" - "}x{}v~Mu~|V{|w~}K{}x~}G{|w~|]{}w~}h{|v~ U{}u~v}s~}\\w~}|v~w}t~}Zr~v}v~|^{}t~w}v~}|w~|^{}t~v}t~Zv}v~s}[{}t~w}v~}" - "|w~|`w~}|u~x}t~}Uv~Lv~Tw~}q{}v~|Uv~_w~}|v~x}s~y{|v~x}s~fw~}|u~x}t~}]{|s~x}s~|]w~}|v~w}t~}]{|t~w}v~}|w~|Zw~}|t~}" - "x~|]{}t~u}u~[{|x}v~q}]{|w~|m{}w~|av~kv~g{}w~q{}t~qv~e{}v~q{}v~_v~|m{|v~_d~Uw~}Lw~|M{|w~| J{|}v~}r{}v~}|_{}u~w}u" - "~|y{}x~}`v~q{|v~}K{}w~|\\{}w~}p~}Z{}s~w}u~}]w~}|u~x}t~}as~m{|v~W{}t~Y{|w~|m{}w~|ev~|f{|v~c{|u~}yn~a_~|dv~t{}w~t" - "{|w~}_{|t~w}t~}]{|b~}f{|`~b{}w~|l{}w~}]{}w~|v{|w~}S{|v~}T{}w~}Uv~|d{|v~|k{}v~|t{|v~s{}v~|h{}w~}hv~|i{}w~}r{|v~r" - "{|v~|l{|v~|dv~}ev~}C{}w~C{}v~|W{}w~V{}v~n{|v~|W{}w~ sv~}S{|s~}y~x}v~Z{|v~Q{|e~}[{|w~}w{|w~}Qw~|R{}r~|){}y~|w{|w" - "~}g{|y~}dw~q{}x~}S{}~}s{}y~ X{}y~|tw~s{}x~}u{|y~}-{}p~}P{}w~M{|w~|F{|x~}({|w~|m{}w~|a{}m~}w{|x~} H{}x~|Tw~p{}x~" - "|]y~}s{|y~Z{}x~|n{|x~}^{}x~|n{|w~Y{|x~}s{|x~}Ov~|T{}w~|v{|w~}X{}w~|v{|w~}X{}w~|v{|w~}X{}w~|v{|w~}X{}w~|v{|w~}Xv" - "~u{|v~_v~|u{|v~Y{|v~|J{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~f{}v~g{}w~|x{}w~}qv~i{|v~|dv~}k{|v~|d" - "v~}k{|v~|dv~}k{|v~|dv~}k{|v~|dv~}e{|u~p{}v~}f{|v~|m{}w~wv~}h{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}^v~}x{}v" - "~Z{}w~}o{}v~}`w~}v{|w~|W{}u~v}s~}\\{}u~v}s~}\\{}u~v}s~}\\{}u~v}s~}\\{}u~v}s~}\\{}u~v}s~}f{}u~v}s~}{s~w}t~}cr~v}" - "v~|]{}t~v}t~[{}t~v}t~[{}t~v}t~[{}t~v}t~Tv~Lv~Lv~Lv~S{}h~|^w~}|u~x}t~}]{|s~x}s~|\\{|s~x}s~|\\{|s~x}s~|\\{|s~x}s~" - "|\\{|s~x}s~|U{}u~U{|s~x}q~|`{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|av~|m{|v~`w~}|v~w}t~}_v~|m{|v~ X{|w~" - "r{}w~rw~}h{|w~dw~}h{|w~y{|w~|t{|w~}yw~}h{|w~l{|w~}yw~}h{|w~dw~}Y{}x~}W{}w~}m{}w~} Xg|}v~s|e{|}x~}o{}y~&{}f~Y{|o" - "~}a{|V~f{|e~}_{|w~}p{|v~_w~}kw~}Z{}w~}v~Wv~|q{}w~}e{|w~ pc~} {{v~}R{|x}|v{|x}|^{}Z~f{|w~|v{|y~|`{|w~s{}x~}v" - "{|w~Wu~|F{|x}|O{}w~|H{|w~}U{|}w~|x~|w~}|R{}w~ c{}x~}Yv~|lv~|W{}w~}F{|v~N{|v~}Z{}w~u{}w~}\\{|k~}Z{}w~}x{|}u~y}|" - "L{}v~Zv~|pv~}a{|v~l{}v~|X{}v~M{}v~M{|}p~}|,{|}p~}|H{}v~|e{|w~q{|q~}y{}x~|v{|x~}fv~tv~]{}w~}n{}v~|c{|v~|N{}w~}f{" - "}v~d{}w~}L{}w~}T{}v~|L{}w~}hv~|Y{}w~}M{}w~}W{}w~}{|u~}S{}w~}V{}w~|xw~}rw~|xv~|h{}w~|x{|v~|rv~i{|v~|d{}v~d{}w~}n" - "{|v~|h{|v~|d{}v~f{}w~}n{}v~|`{}v~}|F{|v~|Z{|v~h{}w~}cv~|n{}v~i{}w~}rw~|ww~|s{|v~b{}q~}U{|v~|{|v~|N{}v~|U{|w~}K{" - "|w~G{|w~|^{}w~}f{|v~ V{}y~}|r{|u~|]r~|u{|u~}\\{}u~}s{|}y~|_{|u~|u{|}s~|_{}v~}|t{}v~}Vw~}T{|u~|u{|}s~|`r~|u{|u~|" - "Vv~Lv~Tw~}ru~|Tv~_r~|v{|}v~}{w~|u{}v~}gr~|u{|u~|^u~}|v{|}u~]r~|u{|u~|_{|u~|u{|}s~|Zr~}|v{|\\v~}|r{|}y~Wv~S{|w~|" - "m{}w~|a{}w~|m{|w~}g{}w~|rs~qw~}dv~}s{|v~|_{}w~}m{}w~|Nu~Uw~}Lw~|M{|w~| K{}r~u{|r~}a{|v~}|v{}v~yw~|`v~r{|u~|K{|w" - "~|]{}w~|xy|}t~}[u~}|s{|}~}]r~|u{|u~|ay|v~|n{}w~|X{|s~|Z{|w~|m{}w~|f{|v~dv~|e{|u~}|{|v~y|}v~}bx}u~q}u~x}|dv~t{}w" - "~t{|w~}_u~|u{|u~|_{|u~}|v{|}t~v}f{|q}u~p}b{}w~|l{|v~]v~tv~R{}v~}U{}w~}V{|v~|cv~}l{|v~}s{|v~s{|v~}h{}w~}hv~|i{}v" - "~r{|v~r{|v~|l{|v~|d{}v~fu~|C{}w~C{|u~|X{}w~W{}v~}m{}v~|X{}w~ sv~}T{|u~}|yy~}x{|}y~Z{|v~P{|g~}Y{}w~|xv~Pw~|T{|v~" - "}u~}*x~v{}w~ex~dw~qw~}U{|x~}t{}x~ Xx~sw~s{}x~}tx~,{|r~|O{}w~N{|w~|Dw~({|w~|m{}w~|a{|m~}w{|x~} H{}x~|T{}x~}qw~|]" - "x~}t{|x~|\\{}x~|nw~]{}x~|nw~|Xw~sw~|Ov~|Tv~tv~Xv~tv~Xv~tv~Xv~tv~Xv~tv~Y{|w~}tv~|a{|v~t{|v~Y{|v~|J{}w~}M{}w~}M{}" - "w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~f{|v~|h{}w~|x{|v~|rv~i{|v~|d{}v~k{|v~|d{}v~k{|v~|d{}v~k{|v~|d{}v~k{|v~|d{" - "}v~d{|u~r{}v~}e{|v~|n{}w~v{}v~h{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}^{|v~|{|v~|Z{}w~}nu~`w~}v{}w~V{}y~}|r" - "{|u~|]{}y~}|r{|u~|]{}y~}|r{|u~|]{}y~}|r{|u~|]{}y~}|r{|u~|]{}y~}|r{|u~|g{}y~}|r{|o~}|u{|}v~}e{}u~}s{|}y~|^{}v~}|" - "t{}v~}]{}v~}|t{}v~}]{}v~}|t{}v~}]{}v~}|t{}v~}Uv~Lv~Lv~Lv~T{}u~}|v{|}v~}^r~|u{|u~|^u~}|v{|}u~\\u~}|v{|}u~\\u~}|v" - "{|}u~\\u~}|v{|}u~\\u~}|v{|}u~U{}u~Uu~}|u{}u~|_{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{}w~}m{}w~|`r~|u{" - "|u~|`{}w~}m{}w~| Xw~|r{}w~r{|w~hw~|d{|w~hw~|yu~|v{|u~y{|w~hw~|m{|u~y{|w~hw~|d{|w~Y{}x~}Vv~mv~| XZ~}g{}t~oy~}'{}" - "e~}Y{}p~_W~|fc~|`v~n{}w~|`w~}kw~}Zv~|}w~|X{}w~}qv~|e{}x~} q{|c~| {{v~} y{|x~}t{}x~}]{|w~}v{|y~|_w~|u{|w~|vw" - "~|Wt~ p{}w~|H{|v~V{}w~}yx~y{}w~}S{}w~ cw~|Z{|v~k{}w~}W{}w~}Fv~}Qy|u~}Z{|w~|u{}w~}\\{|i~|\\v~|y{}p~}|Nv~}Z{|v~|" - "s{|v~}`{|v~lu~|X{}v~M{}v~P{|}p~}|b{|Z~}b{|}p~}|L{}v~}d{}x~|r{|n~{}x~|uw~|h{}w~}t{}w~|^{}w~}q{|}u~}b{}v~M{}w~}f{" - "}v~d{}w~}L{}w~}T{}v~K{}w~}hv~|Y{}w~}M{}w~}W{}w~}|u~}R{}w~}V{}w~|x{|w~s{}w~wv~|h{}w~|w{}w~}rv~i{}v~c{}v~d{}w~}n{" - "}v~|h{}v~c{}v~f{}w~}o{|u~_{|t~}|H{|v~|Z{|v~h{}w~}c{}v~nv~}i{|v~s{|w~|w{}x~}s{}w~}b{|q~S{}v~|v~}N{}v~}T{|w~}K{|w" - "~|H{|w~| s{}|m{}w~}]t~}q{}v~|^{}v~}ny|_u~q{}t~|`{|v~|q{|v~|Ww~}Tu~q{|t~|`t~}r{|v~}Vv~Lv~Tw~}t{|u~Rv~_t~}r{}v~}" - "y~}r{}v~gt~}r{|v~}_{}v~|r{|v~}^s~q{}v~_{}v~|r{}t~|Zs~T{|w~}m{|Wv~S{|w~|m{}w~|a{|w~}mv~|g{|w~}s{|s~|s{|w~|d{|v~|" - "u{|v~}]v~mv~N{}v~Tw~}Lw~|M{|w~| L{}p~w{|p~}bv~}s{}w~y|w~_v~wx|}t~}J{|w~}^{}w~r{}u~|]{|v~|Ot~}r{|v~}_{|v~nv~W{}s" - "~}Z{|w~|m{}w~|f{}w~}d{}w~}eu~}x{|w~|x{}v~|`{|w~}q{|w~}`v~t{}w~t{|w~}`{}v~q{}v~_u~}r{|v~}V{|w~}Wv~|l{|v~^{}w~}t{" - "}w~|R{}v~}V{}w~}V{|v~bv~}l{|v~|s{|v~r{}v~h{}w~}hv~|i{}v~r{|v~r{}v~k{}v~c{}v~gu~|B{}w~B{|u~|Y{}w~X{}v~}k{}v~|Y{}" - "w~ sv~}Tu~|wy~}u{|Z{|v~O{|u~}|x{|}v~}_{|p~}y{|p~}Ww~|Tw~}y{|t~|,y~}vw~|e{}y~dw~|s{}w~}V{|w~}u{}w~ Xy~}sw~s{}x~}" - "t{}y~*y}x~}|[m|}w~l|^{}w~C{|x~}({|w~|m{}w~|`m~}w{|x~} H{}x~|T{|w~|s{}x~}\\w~}u{|w~|]{}x~|o{}x~}]{}x~|o{}x~}Ww~t" - "{}x~}Nv~|U{}w~}t{}w~|Z{}w~}t{}w~|Z{}w~}t{}w~|Z{}w~}t{}w~|Z{}w~}t{}w~|Z{}w~|t{|w~}av~}t{|v~Y{}v~I{}w~}M{}w~}M{}w" - "~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~f{|v~|h{}w~|w{}w~}rv~i{}v~c{}v~k{}v~c{}v~k{}v~c{}v~k{}v~c{}v~k{}v~c{}v~c{|" - "u~t{}v~}d{}v~n{|w~|v{|v~h{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}]{}v~|v~}Y{}w~}n{|v~|aw~}vv~V{}|m{}w~}]{}|m" - "{}w~}]{}|m{}w~}]{}|m{}w~}]{}|m{}w~}]{}|m{}w~}g{}|m{}r~|q{|v~|g{}v~}ny|_{|v~|q{|v~|_{|v~|q{|v~|_{|v~|q{|v~|_{|v~" - "|q{|v~|Vv~Lv~Lv~Lv~U{|v~}q{|v~|_t~}r{|v~}_{}v~|r{|v~}^{}v~|r{|v~}^{}v~|r{|v~}^{}v~|r{|v~}^{}v~|r{|v~}V{}u~V{}v~" - "|r{|v~}_{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|`v~mv~_s~q{}v~_v~mv~ X{|w~q{}w~q{}x~|j{|w~b{}x~|j{|w~wu~" - "|x{|u~|x{}x~|j{|w~m{|u~|x{}x~|j{|w~b{}x~|Z{}x~}V{}w~|o{|v~ WZ~}gx~}w~|q{}y~|({|c~}_v|{}r~u|d{}X~f{}b~|b{|w~}mw~" - "}`w~}kw~}[{|v~{}w~}X{|w~}r{|v~d{}x~| q{}c~ yv~} y{}x~}t{}x~}\\v~}w{|y~|_{}w~|vw~}v{|x~}X{|r~ qv~Fv~X{}w~}|x" - "x~x{|}w~}U{}w~ d{|w~Y{|v~k{}w~}W{}w~}G{}v~|Xm~}Y{}x~}t{}w~}\\{|h~}]v~y|l~}P{|v~|Y{|u~u|}v~}_{|v~|n{|u~|X{}v~M{" - "}v~R{|o~}|`{|Z~}_{|}p~}|P{}v~}cw~r{|l~}x~|u{|x~|hv~|t{|v~^{}e~}a{}v~M{}w~}f{|v~|e{}d~|_{}g~|d{}v~K{}^~|Y{}w~}M{" - "}w~}W{}p~|Q{}w~}V{}w~|ww~|tw~}wv~|h{}w~|vv~|sv~i{}v~c{|v~|e{}w~}o{|u~g{}v~c{|v~|g{}w~}p{|u~|^{}q~y}|M{|v~|Z{|v~" - "h{}w~}c{|v~|p{|v~gv~|t{|w~v{|x~}sv~|a{|s~|Rq~}N{}v~}S{|w~}Jw~}H{|w~| bv~|^t~ov~}^v~}P{|v~|p{}u~|`v~|o{|v~Ww~}U" - "{|v~o{}u~|`u~}p{|v~Vv~Lv~Tw~}u{|v~}Qv~_u~}pt~}pv~|hu~}p{|v~`{|v~|p{|v~|_t~ov~}a{|v~|p{}u~|Zt~S{}w~Gv~S{|w~|m{}w" - "~|`v~|o{|v~ev~s{|x~y}x~}s{}w~|c{}v~uv~}\\{}w~|o{|w~}O{}v~|U{|w~}Lw~|M{|w~} M{|x~}x|}w~}xv~}x|}x~|d{}v~qw~y}x~}_" - "v~x{}q~}I{|w~}_{|w~|q{|u~]{}w~|Nu~}p{|v~^{}w~|p{|w~}X{|q~Z{|w~|m{}w~|fv~|d{|v~f{|v~}w{}w~|wu~`{|w~}q{|w~}`v~t{}" - "w~t{|w~}a{|v~ov~}a{|v~}p{}v~|W{|w~}Wv~}l|}v~^v~|t{|v~Q{}v~}W{}w~}V{|v~b{}w~}l{}v~r{|v~r{}v~|i{}w~}hv~|i{|v~|s{|" - "v~r{}v~k{}v~xi~}y{|v~|iu~|A{}w~A{|u~|Z{}w~Y{}v~}i{}v~|Z{}w~ sv}|U{}v~|vy~}S{|v~O{|w~}s{|v~_{|o~|{o~}Ww~|U{}x~}v" - "{}u~}.{|y~|w{|w~d{|y~|e{}w~t{}v~}W{|v~|v{}w~}cY|8{|y~|sw~sw~|t{|y~| `{|Z~}_{}x~}C{|w~}({|w~|m{}w~|`{|n~}w{|x~} " - "H{}x~|Sv~|u{}w~|\\{}v~v{|v~|^{}x~|p{|w~\\{}x~|p{|w~W{|x~}u{|w~Mv}|Uv~|t{|v~Zv~|t{|v~Zv~|t{|v~Zv~|t{|v~Zv~|t{|v~" - "Zv~rv~b{|v~s{|c~l{}v~I{}d~|`{}d~|`{}d~|`{}d~|W{}w~}M{}w~}M{}w~}M{}w~}Z{|v~ev~}h{}w~|vv~|sv~i{}v~c{|v~|l{}v~c{|v" - "~|l{}v~c{|v~|l{}v~c{|v~|l{}v~c{|v~|c{|u~v{}v~}c{}v~o{|w~|u{|v~|i{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}\\q~" - "}X{}w~}mv~}aw~}vv~Ev~|Mv~|Mv~|Mv~|Mv~|Mv~|Ws~|o{}w~}gv~}Ov~|o{|v~_v~|o{|v~_v~|o{|v~_v~|o{|v~Vv~Lv~Lv~Lv~Uv~}o{}" - "w~}_u~}p{|v~`{|v~|p{|v~|`{|v~|p{|v~|`{|v~|p{|v~|`{|v~|p{|v~|`{|v~|p{|v~|Wt|W{|v~|q{}u~|`{|w~|m{}w~|a{|w~|m{}w~|" - "a{|w~|m{}w~|a{|w~|m{}w~|`{}w~|o{|w~}_t~ov~}`{}w~|o{|w~} X{}x~}q{}w~q{|x~}j{}x~}b{|x~}j{}x~}vu~|yu~|w{|x~}j{}x~}" - "mu~|w{|x~}j{}x~}b{|x~}Z{}x~}V{|v~o{}w~} WZ~}g{}|yw~}qx~'a~|c{|}t~}k~}|fY~}g{}`~b{|w~|m{}w~`w~}kw~}[{|w~}{|v~Wv~" - "r{}w~}dw~| lv~| kv~| yw~|tw~|\\{}v~}|y{|y~|^v~}y|}v~uw~X{|p~ rv~Fv~Xw~|vx~v{|w~U{}w~ d{}x~}Y{|v~k{}w~}W{}w" - "~}H{|v~}Wo~}|Y{|w~|t{}w~}\\{|v~x}|x}s~}^v~|j~}Q{}w~}V{}l~}]v~}n{}u~}X{}v~M{|v}U{|}p~}|]{|Z~}\\{}o~|S{}v~}c{|x~}" - "rv~}|w{|}t~|tx~}i{|v~rv~|_{}h~}|_v~}M{}w~}f{|v~|e{}d~|_{}g~|dv~}K{}^~|Y{}w~}M{}w~}W{}q~|P{}w~}V{}w~|w{}w~u{|w~|" - "wv~|h{}w~|v{}w~}sv~iv~}c{|v~|e{}w~}p{|u~|gv~}c{|v~|g{}w~}sy|}u~}\\{}m~}|Q{|v~|Z{|v~h{}w~}bv~}p{}w~}g{}w~}t{}x~}" - "v{|w~sv~|`{}u~}Q{|r~|O{|u~R{|w~}J{}w~H{|w~| b{|w~}^u~|o{|v~_{}v~Ov~}nu~|a{}w~}m{}w~|Xw~}Uv~|nu~|`u~nv~|Wv~Lv~T" - "w~}v{}v~}Pv~_u~o{}u~|p{}w~}hu~nv~|a{}w~}n{}w~}_u~|o{|v~a{}w~}nu~|Zu~|S{}w~Gv~S{|w~|m{}w~|`{}w~}o{}w~}e{}w~s{}x~" - "}|w~sv~a{}v~w{}v~[{|w~}ov~|P{}v~|T{|w~}Lw~|M{|w~}:{|4x~|v{|w~}{}x~}u{}x~dv~}q{}s~|_v~x{}r~}S{|y}~y}|w{|w~}_w~}o" - "{|v~}^{}w~Mu~nv~|_{|w~}pv~|X{}w~}v~|[{|w~|m{}w~|g{|v~bv~|g{}v~v{}w~v{|v~|a{|w~}q{|w~}`v~t{}w~t{|w~}a{}w~|o{|v~a" - "{}v~nv~}W{|w~}W`~_{|v~rv~|Q{}v~|X{}w~}V{|v~b{}w~}lu~r{|v~r{|v~|i{}w~}hv~|hv~}s{|v~rv~}kv~}xi~}y{|v~|ju~|@{}w~@{" - "|u~|[{}w~Z{}v~}g{}v~|[{}w~ Gv~}uy~}S{|v~Ow~}q{|w~|`{|n~}o~}Ww~|Uw~|t{}u~|0{|y~|w{|x~}d{|y~|e{|v~}w|t~}X{|v~|vv~" - "}c{|Z~}8{|y~|sw~t{}w~s{|y~| `{|Z~}`{}x~}M{|~}|v{|}v~'{|w~|m{}w~|_{}o~}w{|x~}Vv}| s{}x~|S{|v~}|{y|}w~}Z{}v~|w{|v" - "~}_{}x~|pw~|o{}w~m{}x~|p{}x~|vy|}w~y}|g{|w~|u{}x~|o{}w~3{|v~rv~|\\{|v~rv~|\\{|v~rv~|\\{|v~rv~|\\{|v~rv~|\\{}w~}" - "r{}w~|c{}w~}s{|c~lv~}I{}d~|`{}d~|`{}d~|`{}d~|W{}w~}M{}w~}M{}w~}M{}w~}_{}i~}nv~}h{}w~|v{}w~}sv~iv~}c{|v~|lv~}c{|" - "v~|lv~}c{|v~|lv~}c{|v~|lv~}c{|v~|b{|u~x{}v~}bv~}p{|w~}t{|v~|i{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}\\{|r~|" - "X{}w~}mv~}aw~}v{}w~}F{|w~}M{|w~}M{|w~}M{|w~}M{|w~}M{|w~}W{|u~}m{}w~h{}v~O{}w~}m{}w~|a{}w~}m{}w~|a{}w~}m{}w~|a{}" - "w~}m{}w~|Wv~Lv~Lv~Lv~V{}v~n{|v~_u~nv~|a{}w~}n{}w~}`{}w~}n{}w~}`{}w~}n{}w~}`{}w~}n{}w~}`{}w~}n{}w~},{}w~}q{}t~}`" - "{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|`{|w~}ov~|_u~|o{|v~`{|w~}ov~| X{}x~|q{}w~q{|w~j{}x~|b{|w~j{}x~|u" - "u~|u~|v{|w~j{}x~|nu~|v{|w~j{}x~|b{|w~Zw~}Uv~|q{|v~ VZ~}c{}w~r{|y~}({}`~d{}^~|h{|Z~g{|_~}c{}w~l{|w~`w~}kw~}[{}w~" - "|yv~|X{}w~|sv~|dV~} 2v~| k{}w~| {{|w~t{|w~Zs~y}y~|^{|o~|v{}x~}rx|e{|v~y}u~n{|w~},{|v~Fv~|Y{|~}tx~t{}~|U{}w~ " - " dw~|Y{|v~k{}w~}W{}w~}Hu~Vp~}|Y{|w~}s{}w~}\\{|~}|q{}t~|`{|q~}|xy|t~|Rv~|U{|}p~|[{}v~|ot~} V{|}p~}|Z{|Z~}Z{|}p~}" - "|W{}v~|b{}x~|s{}w~|s{|u~|tw~i{}w~}r{}w~}_{}g~}|`v~}M{}w~}f{|v~|e{}d~|_{}g~|dv~}K{}^~|Y{}w~}M{}w~}W{}q~O{}w~}V{}" - "w~|w{|w~|v{}w~vv~|h{}w~|uv~|tv~iv~}c{|v~|e{}w~}sy|s~fv~}c{|v~|g{}f~}Z{}k~}S{|v~|Z{|v~h{}w~}b{|v~pv~|g{}w~}tw~|u" - "w~|u{|v~_{}u~O{}t~|O{|u~|R{|w~}J{|w~|I{|w~| aw~}^v~}m{}w~}`v~|P{|v~m{}v~|av~l{|w~}Xw~}V{|v~m{|v~|`v~}n{}w~|Wv~" - "Lv~Tw~}w{}v~}Ov~_v~}o{|v~}o{|w~}hv~}n{}w~|av~|n{|v~|`u~mv~|bv~m{}v~|Zv~}R{}w~Gv~S{|w~|m{}w~|`{|v~ov~d{}w~|tw~|{" - "w~|u{|w~}`v~}y{|v~|Z{}w~|q{|v~P{}v~|Sv~|Lw~|Lv~|W{|y}w~}|iy}5{|y~}sw~|x~}s{}y~|f{|v~|ps~^v~x{}q~}|W{|r~|y{|w~}`" - "{}w~m{}v~^{}w~Mv~}n{}w~|^{}w~q{|v~Wv~y|w~}[{|w~|m{}w~|g{}v~b{}w~}h{|v~|v{}w~u{}w~}a{|w~}q{|w~}`v~t{}w~t{|w~}av~" - "mv~|c{|v~|n{|v~W{|w~}W`~_{}w~}r{}w~}Q{|v~}X{}w~}V{|v~b{}w~}lv~}r{|v~r{|v~|i{}w~}hv~|h{}v~s{|v~s{|v~|kv~}xi~}y{|" - "v~|ku~|?{}w~?{|u~|\\{}w~[{}v~}e{}v~|\\{}w~ H{}v~ty~}S{|v~P{|w~o{}w~_s|}r~s|Vw~|V{|w~r{|u~0{|y~v{}x~}d{|y~|d{}o~" - "|x~}Y{}v~v{|v~|b{|Z~}8{|y~rw~u}v~|s{|y~| `{|Z~}a{}l~|X{|m~|'{|w~|m{}w~|^o~}w{|x~}W{|v~| xm~}W{|n~}X{|v~|vv~}e{}" - "n~}v{}x~}o{|v~m{}x~|q{|w~w{|o~|t{|~}y|w{|}v~u{|x~}o{|v~3{}w~}r{}w~}\\{}w~}r{}w~}\\{}w~}r{}w~}\\{}w~}r{}w~}\\{}w" - "~}r{}w~}\\v~|r{|w~}cv~|s{|c~lv~}I{}d~|`{}d~|`{}d~|`{}d~|W{}w~}M{}w~}M{}w~}M{}w~}_{}i~}nv~}h{}w~|uv~|tv~iv~}c{|v" - "~|lv~}c{|v~|lv~}c{|v~|lv~}c{|v~|lv~}c{|v~|a{|u~|}v~}av~}pw~}s{|v~|i{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}[" - "{}t~|W{}w~}mv~}aw~}v{}v~|Fw~}Lw~}Lw~}Lw~}Lw~}Lw~}Vu~l{|w~|iv~|Ov~l{|w~}av~l{|w~}av~l{|w~}av~l{|w~}Wv~Lv~Lv~Lv~V" - "v~|mv~|`v~}n{}w~|av~|n{|v~|av~|n{|v~|av~|n{|v~|av~|n{|v~|av~|n{|v~|-v~|r{|x~}v~`{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{" - "}w~|a{|w~|m{}w~|_{}w~|q{|v~^u~mv~|`{}w~|q{|v~ Ww~p{}w~pw~jw~yd|yw~jw~t{|p~|tw~jw~nu~|tw~jw~pv~}qw~Zw~|U{}w~}q{}" - "w~} F{}w~}W{|w~|s{}y~|){|_~}f{}\\~|h{}\\~|g{}^~c{}w~l{|w~|aw~}kw~}[v~x{}w~}X{|w~}t{|v~cV~} 2v~| k{}w~| {{|x~" - "}t{|x~}Z{|o~}y|`{|}r~|v{|w~t{}u~}|hv~}y{}u~o{|w~|,{|v~F{}w~|X{|sx~s{|T{}w~ e{|w~X{|v~k{}w~}W{}w~}Iu~|Vm~|[{}w~" - "r{}w~}L{}u~`{|r~|s{|u~S{}v~V{|}m~}|\\u~p{}t~} Y{|}p~}|VY|W{|}p~}|[{|v~|aw~rw~}q{|v~|t{}x~iv~q{|v~_{}e~}av~}M{}w" - "~}f{|v~|e{}d~|_{}g~|dv~}m{}n~|h{}^~|Y{}w~}M{}w~}W{}q~}P{}w~}V{}w~|vw~}vw~}vv~|h{}w~|u{}v~tv~iv~}bv~|e{}e~|fv~}b" - "v~|g{}g~}X{|}k~}U{|v~|Z{|v~h{}w~}av~|r{|v~f{|v~u{|w~|u{}x~}u{}w~}`{|t~|O{}v~}Nu~|Q{|w~}Iw~}I{|w~| a{}w~^v~|m{|" - "w~}a{|v~O{|w~}lv~|b{|w~}kv~Xw~}V{|w~}lv~|`v~|n{|w~}Wv~Lv~Tw~}x{}v~|Nv~_v~|nv~|nv~hv~|n{|w~}b{|v~lv~|`v~}m{|w~}c" - "{|w~}m{|v~|Zv~|R{}w~|Hv~S{|w~|m{}w~|_{}w~|q{|w~}d{|w~}u{|w~y{}x~|u{|w~|`{|v~y|v~}Y{|w~}q{}w~|Q{|v~}S{}v~Kw~|L{}" - "w~}Y{|p~}|n{|y~}5{}y~r{|t~qy~}f{}v~ot~}^v~x{}o~}Y{}p~|{|w~|`w~}lv~|_{|w~}Nv~|n{|w~}^{|w~|r{}w~|X{}w~}yv~[{|w~|m" - "{}w~|gv~}b{}v~h{|v~u{}w~u{|v~a{|w~}q{|w~}`v~t{}w~t{|w~}b{|w~}m{|w~}c{|v~lv~|X{|w~}W`~_v~|r{|v~Qu~W{}w~}V{|v~b{}" - "w~}lv~}r{|v~qv~|i{}w~}hv~|h{|v~|t{|v~s{}v~jv~}xi~}xv~|lu~[|]{}w~\\\\|u~|]{}w~\\{}v~}c|u~|]{}w~ H{}w~}ty~}X{}g~|" - "[{}x~}nw~Vs~|Nw~|V{}x~}pv~}1{}y~v{}x~}d{|y~}c{}r~}{|x~}Z{}w~}v{|v~|a{|Z~}8{}y~rn~}q{|y~} `{|Z~}a{}l~|X{|o~}|&{|" - "w~|m{}w~|]{}q~}w{|x~}W{|v~| xm~}V{|}q~|V{|v~|v{}w~}fm~}vw~o{|u~rm~}vw~|w{}n~|u{|m~|uw~|p{|u~3v~q{|v~\\v~q{|v~\\" - "v~q{|v~\\v~q{|v~\\v~q{|v~]{|v~pv~|e{}w~}r{|c~lv~}I{}d~|`{}d~|`{}d~|`{}d~|W{}w~}M{}w~}M{}w~}M{}w~}_{}i~}nv~}h{}w" - "~|u{}v~tv~iv~}bv~|lv~}bv~|lv~}bv~|lv~}bv~|lv~}bv~|`{|p~}`v~}q{}x~}qv~|i{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}" - "w~}Z{}v~}V{}w~}mv~}aw~}uu~}G{}w~L{}w~L{}w~L{}w~L{}w~L{}w~V{}w~}kw~}j{|v~O{|w~}kv~b{|w~}kv~b{|w~}kv~b{|w~}kv~Wv~" - "Lv~Lv~Lv~W{|v~l{}w~}`v~|n{|w~}b{|v~lv~|b{|v~lv~|b{|v~lv~|b{|v~lv~|b{|v~lv~|.{|v~r{|w~{}w~|a{|w~|m{}w~|a{|w~|m{}" - "w~|a{|w~|m{}w~|a{|w~|m{}w~|_{|w~}q{}w~|^v~}m{|w~}`{|w~}q{}w~| Ww~yd~|{w~jw~yd~|{w~jw~s{|r~|sw~jw~ou~|sw~jw~pv~}" - "qw~Zw~|U{|v~qv~| G{}w~}Uw~}sx~({}^~g{}Z~g]~}f{|_~|cw~}l{|w~|aw~}kw~}\\{|v~x{|v~Wv~t{}w~}cV~} 2v~| k{}w~| {{}" - "x~}t{}x~}Y{|}m~}`{|}w~}|tw~|v{|q~}j{}v~w{}u~p{}w~|,{|w~}F{}w~|Ox~Z{|Z~} t{}x~}X{|v~k{}w~}W{}w~}J{}v~|Ut|}t~}]{" - "|w~|r{}w~}K{}v~|a{|s~p{|v~}Tv~}W{}i~}]{}u~|t{|}s~} Z{|q~}| e{|}q~}\\v~}`x~}s{}w~ov~|t{}x~|k{|w~}p{}w~|`{}w~}p|}" - "t~|cv~}M{}w~}f{|v~|e{}w~}i|^{}w~}l|cv~}m{}n~|h{}w~}h|v~|Y{}w~}M{}w~}W{}w~}u~}Q{}w~}V{}w~|v{}w~w{|w~uv~|h{}w~|tv" - "~|uv~iv~}c{|v~|e{}f~|ev~}c{|v~|g{}i~}S{|}m~}V{|v~|Z{|v~h{}w~}a{}w~}rv~}ev~|v{|w~t{|w~uv~|`r~O{|v~|O{}v~}P{|w~}I" - "{}w~I{|w~| a{}w~^v~|lv~a{}w~}O{}w~|lv~|b{|w~|k{}w~Xw~}V{}w~|lv~|`v~m{|w~}Wv~Lv~Tw~}yu~|Mv~_v~mv~mv~hv~m{|w~}b{" - "}w~}l{}w~}`v~|m{|v~c{}w~|lv~|Zv~Q{}v~|Iv~S{|w~|m{}w~|_{|w~}q{}w~|cv~u{}x~}y{}x~}u{}w~^{}q~}Wv~qv~Q{|v~}Uy|}v~|K" - "w~|L{|u~}|^{|k~}|s{|}x~}5y~}q{}v~|q{}y~f{}w~}o{}u~|^v~ty|}s~[{|u~y}v~y|w~|a{|w~}l{}w~}^{}w~|Ov~m{|w~}]w~}rv~Wv~" - "|y{}w~}\\{|w~|m{}w~|gv~|b{|v~h{}w~}u{}w~tv~a{|w~}q{|w~}`v~t{}w~t{|w~}b{}w~|m{|v~c{}w~}l{}w~}X{|w~}W`~`{|w~}pv~|" - "S{}v~|W{}w~}V{|v~bv~}lv~}r{|v~r{|v~|i{}w~}hv~|gu~t{|v~t{|v~}jv~}xh|y{|v~|mT~]{}w~]T~|^{}w~]{}U~|^{}w~ Hv~|ty~}X" - "{}g~|[w~|nw~|W{}u~}Mw~|V{}w~ov~1{|y~v{}x~}d{|y~|ay}x~y}ww|[{}w~}v{|v~|`{|Z~}8{|y~ro~o{|y~| Q{}w~R{}l~|V{|y}v~y}" - "|${|w~|m{}w~|\\{|}s~}w{|x~}W{|v~| xm~}T{|y}w~}|S{|v~|v{}w~}gm~}w{}x~}oy~y}x~rm~}w{}x~}v{}~}y|w{|v~u{|o~}t{}x~}o", - "t~^v|V{|w~}p{}w~|^{|w~}p{}w~|^{|w~}p{}w~|^{|w~}p{}w~|^{|w~}p{}w~|^{}w~}p{}w~}ev~|r{|v~h|lv~}I{}w~}i|_{}w~}i|_{}" - "w~}i|_{}w~}i|V{}w~}M{}w~}M{}w~}M{}w~}_v}u~r}nv~}h{}w~|tv~|uv~iv~}c{|v~|lv~}c{|v~|lv~}c{|v~|lv~}c{|v~|lv~}c{|v~|" - "_{|r~}_v~}r{}w~q{|v~|i{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}Z{|v~|V{}w~}mv~}aw~}u{|t~|I{}w~L{}w~L{}w~L{}w~" - "L{}w~L{}w~V{}w~|kv~j{}w~}O{|w~|k{}w~b{|w~|k{}w~b{|w~|k{}w~b{|w~|k{}w~Wv~Lv~Lv~Lv~W{}w~}l{|w~}`v~m{|w~}b{}w~}l{}" - "w~}b{}w~}l{}w~}b{}w~}l{}w~}b{}w~}l{}w~}b{}w~}l{}w~}eY|f{}w~}rw~y{|w~}a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|" - "m{}w~|^v~qv~]v~|m{|v~_v~qv~ Vw~yd~|{}x~|kw~yd~|{}x~|kw~r{|t~|r{}x~|kw~pu~|r{}x~|kw~pv~}q{}x~|[w~|T{}w~|s{|v~ G{" - "}v~T{}w~t{|y~}(]~|i{|Y~}h{|_~}d{|a~}bw~}kw~|aw~}kw~}\\{}w~}wv~|Xv~|u{}w~|cV~} 2v~| k{}w~| {{w~|tw~|W{|}m~}T{" - "}x~}v{|o~}l{|v~|v{}u~q{}w~+{|w~}F{}w~|Ox~Z{|Z~}+m| ww~|X{|v~k{}w~}W{}w~}K{}v~}K{|}v~}^w~}q{}w~}Ju~a{|t~|o{}v~U{" - "|v~|X{}u~}|wy|u~}]t~}y|{y|}q~} Z{|t~}| _{|}t~}\\v~`{|x~}s{}x~}o{|w~|t{}x~|kv~|p{|w~}`{}w~}n{|u~cv~}M{}w~}f{|v~|" - "e{}w~}L{}w~}Tv~}m{}n~|h{}w~}hv~|Y{}w~}M{}w~}W{}w~}|u~}R{}w~}V{}w~|v{|w~|x{}x~}uv~|h{}w~|t{|v~uv~iv~}c{|v~|e{}h~" - "}cv~}c{|v~|g{}h~}Qy|y}p~W{|v~|Z{|v~h{}w~}a{|v~s{|v~|e{}w~}v{}x~}t{|w~uv~|a{}r~}P{|v~|P{}v~}O{|w~}I{|w~|J{|w~| " - "n{|y}l~^v~kv~a{}w~|Ov~|l{}w~|b{}w~|k{}w~|Yw~}Vv~|l{}w~|`v~m{|w~}Wv~Lv~Tw~}|u~Kv~_v~mv~mv~hv~m{|w~}b{}w~|l{|v~`v" - "~kv~c{}w~|l{}w~|Zv~Pu~}|Kv~S{|w~|m{}w~|^v~qv~b{}w~u{}x~|y{|w~uv~]{}r~V{}w~|s{|w~}R{|v~}X{|q~}Jw~|K{|q~}c{}g~}w|" - "}u~}5y~}pw~}p{}y~fv~|o{}u~]v~p{|t~\\v~}w{|w~}w~|a{}w~|l{|w~}]{}w~}y|Rv~m{|w~}]{}w~s{}w~}X{}w~}x{|v~\\{|w~|m{}w~" - "|h{|v~|b{|v~|i{}w~|u{}w~tv~|b{|w~}q{|w~}`v~t{}w~t{|w~}bv~kv~c{}w~|l{|w~}X{|w~}Wv~jv~`v~|p{}w~}T{}v~|V{}w~}V{|v~" - "|cv~|lv~}r{|v~r{|v~|i{}w~}hv~|g{}v~}u{|v~tu~|jv~}c{|v~|n{|T~]{}w~]T~}^{}w~]T~}^{}w~ I{|v~sy~}X{}g~|[w~m{}x~|Vu~" - "|#{|w~|p{|w~|2{|y~|w{|x~}d{|y~|3v~}v{}v~|Aw~}8{|y~|sw~x{|w~}p{|y~| Q{}w~ p{|w~|m{}w~|Y{|}v~}w{|x~}W{|v~| jv~}" - "v{}v~|W{|w~o{}y~{}x~r{}n~}x{|w~uy|rw~|ty|t}|s{|w~o{}y~|}x~^{}w~|Wv~|p{|w~}^v~|p{|w~}^v~|p{|w~}^v~|p{|w~}^v~|p{|" - "w~}^v~|p{|v~f{|v~q{|v~Yv~}I{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~ev~}h{}w~|t{|v~uv~iv~}c{|v~|lv~}" - "c{|v~|lv~}c{|v~|lv~}c{|v~|lv~}c{|v~|^{|t~}^v~}s{}w~p{|v~|i{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}Z{|v~|V{}w" - "~}n{|v~|aw~}t{}t~}W{|y}l~Y{|y}l~Y{|y}l~Y{|y}l~Y{|y}l~Y{|y}l~c{|y}l~j{}w~j{}w~|O{}w~|k{}w~|c{}w~|k{}w~|c{}w~|k{}" - "w~|c{}w~|k{}w~|Xv~Lv~Lv~Lv~W{}w~|l{|v~`v~m{|w~}b{}w~|l{|v~b{}w~|l{|v~b{}w~|l{|v~b{}w~|l{|v~b{}w~|l{|v~f{|Z~}f{}" - "w~|s{}x~|y{|w~}a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|^{}w~|s{|w~}]v~kv~_{}w~|s{|w~} Vw~yd~|{}x~|kw~yd" - "~|{}x~|kw~qt~|r{}x~|kw~qu~|q{}x~|kw~pv~}q{}x~|[w~|T{|w~}s{}w~} H{|v~|T{|w~|u{}y~({|]~}i{}X~g{|`~b{}b~aw~}kw~}aw" - "~}kw~}\\v~|w{}w~}X{}w~}uv~bw~}Z| 5x|v~}p| v{}w~| {|w~t{|w~S{|}n~|Vw~uv~|y{|}w~}m{}w~}t{}u~rw~}+{|w~}F{}w~|Ox" - "~Z{|Z~},{|m~ x{|w~|X{|v~k{}w~}W{}w~}L{}v~}H{}v~}`{}w~p{}w~}J{}v~`t~n{|v~|V{}v~X{}v~}q{}v~}^{|j~|v~| Z{|t~| ]{|}" - "u~}]{|w~}`{|x~|sw~|o{|w~|t{}x~|l{|v~nv~`{}w~}lv~}dv~}M{}w~}f{|v~|e{}w~}L{}w~}Tv~}m{}n~|h{}w~}hv~|Y{}w~}M{}w~}W{" - "}w~}{|t~S{}w~}V{}w~|u{}x~}y{|w~|uv~|h{}w~|sv~|vv~iv~}c{|v~|e{}k~}|av~}c{|v~|g{}w~}t|y}u~}M{|}s~}X{|v~|Z{|v~h{}w" - "~}`v~}t{}v~d{}w~}vw~|sw~|w{|v~a{|v~}v~|Q{|v~|Q{|u~N{|w~}Hw~|J{|w~| p{}h~|_v~k{}w~|bv~|Ov~k{}w~|bv~j}v~|Yw~}Vv~" - "k{}w~|`w~}m{|w~}Wv~Lv~Tq~}Jv~_w~}mv~mv~hw~}m{|w~}bv~|l{|v~`v~kv~|dv~k{}w~|Zv~P{}r~}y|Pv~S{|w~|m{}w~|^{}w~|s{|w~" - "}b{|w~|vw~|xw~|w{|w~}\\s~|Uv~sv~|Ru~W{|s~}|Iw~|I{|}t~}d{|u~}w|}g~}5{|y~|p{|x~|p{}y~fv~|o{|v~}]v~n{}v~|^{}w~|ts~" - "`v~|l{|v~\\{}p~}Xw~}m{|w~}]{|w~|tv~|Xv~|wv~|]{|w~|m{}w~|h{|v~|q{}x~}q{|v~|iv~|u{}w~t{}w~|b{|w~}q{|w~}`v~t{}w~t{" - "|w~}bv~kv~|dv~|l{|v~X{|w~}Wv~|l{|v~a{|v~nv~U{|v~}U{}w~}Uv~}d{|v~|l{}v~r{|v~r{|v~|i{}w~}hv~|fu~|v{|v~u{}v~}iv~}c" - "{|v~|n{|T~]{}w~]T~}^{}w~]T~}^{}w~ rw|V{|w~}sy~}X{|w}u~q}Zw~m{}x~|V{}v~\"{|v~ow~|2{|y~|w{|w~d{|y~|4{}w~}v{|v~?w~" - "}8{|y~|sw~vw~}q{|y~| Q{}w~ p{|w~|m{}w~|Ux~}w{|x~}W{|v~| i{}w~|v{|v~Ww~|p{|y~|{}x~`{}x~|j{|x~}bw~|p{|y~}{}x~^{" - "}w~|X{|v~nv~_{|v~nv~_{|v~nv~_{|v~nv~_{|v~nv~_{|w~}nv~|g{}w~}q{|v~Yv~}I{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}" - "M{}w~}Z{|v~ev~}h{}w~|sv~|vv~iv~}c{|v~|lv~}c{|v~|lv~}c{|v~|lv~}c{|v~|lv~}c{|v~|]{}u~|^v~}t{|w~|p{|v~|i{|v~h{}w~}" - "f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}Z{|v~|V{}w~}n{}v~|aw~}s{|s~|[{}h~|\\{}h~|\\{}h~|\\{}h~|\\{}h~|\\{}h~|f{}h~j}v~" - "jv~|Ov~j}v~|cv~j}v~|cv~j}v~|cv~j}v~|Xv~Lv~Lv~Lv~Wv~|l{|v~`w~}m{|w~}bv~|l{|v~bv~|l{|v~bv~|l{|v~bv~|l{|v~bv~|l{|v" - "~f{|Z~}fv~|t{}x~|wv~a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|]v~sv~|]v~kv~|_v~sv~| Vw~yd~|{w~jw~yd~|{w~j" - "w~rr~|sw~jw~ru~|pw~jw~pv~}qw~Zw~|Sv~sv~ H{|v~|Rw~}uy~}({|]~}i{}X~|g{}b~|a{}d~|aw~}kw~}aw~}kw~}]{|v~v{|v~X{|v~v{" - "|w~}b{}x~} pf~ v{|w~ {{|w~t{|x~}P{|y~}r~W{}x~|v{}w~u{}w~mv~r{}u~t{|w~|+{|v~F{}w~|Ox~Z{|Z~},{|m~ x{}w~W{|v~k" - "{}w~}W{}w~}M{}v~}F{}v~a{|w~|p{}w~}Iv~|au~}mv~}Vv~|Y{|v~}o{|v~|]{}m~|{v~| Z{|r~}| c{|}r~}]{|w~}`{|x~|sw~|nw~|t{}" - "x~k{}w~}n{}w~}a{}w~}l{|v~|e{}v~M{}w~}f{}v~d{}w~}L{}w~}T{}v~mr|v~|h{}w~}hv~|Y{}w~}M{}w~}W{}w~}y{|t~T{}w~}V{}w~|u" - "{|w~y{}w~tv~|h{}w~|s{|v~vv~i{}v~c{|v~|e{}w~}r|]{}v~c{|v~|g{}w~}q{}v~}K{|t~|Y{|v~|Z{|v~h{}w~}`{}v~tv~|d{|v~w{|w~" - "|s{}x~}w{}w~}av~}{}v~Q{|v~|R{|u~M{|w~}H{}x~}J{|w~| r{|f~|_w~}k{}w~|bv~|Ov~k{}w~|b`~|Yw~}Vv~k{}w~|`w~}m{|w~}Wv~" - "Lv~Tq~Iv~_w~}mv~mv~hw~}m{|w~}bv~jv~`v~k{}w~|dv~k{}w~|Zw~}O{}o~}|Sv~S{|w~|m{}w~|^{|w~}s{}w~|b{|w~}w{|w~w{}x~}w{|" - "w~|\\{|u~}T{}w~|u{|w~}Ru~V{|s~}|Iw~|J{|}s~}d{|w~|s{|}k~|3y~}p{|x~}p{}y~fv~mv~|]v~m{}v~_{|w~}rt~`v~jv~Z{}r~}Xw~}" - "m{|w~}\\w~}u{|w~}X{|w~}v{}w~}]{|w~|m{}w~|h{|v~|q{}x~}pv~|iv~t{}w~t{}w~|b{|w~}q{|w~}`v~t{}w~t{|w~}bv~k{}w~|dv~jv" - "~X{|w~}W{}w~|l{|v~a{}w~}n{}w~}W{|u~T{}w~}U{}w~}d{}v~k{}v~|s{|v~r{}v~h{}w~}hv~|f{|u~|w{|v~v{}u~h{}v~c{|v~|n{|T~]" - "{}w~]T~|^{}w~]{}U~}^{}w~ s{|w~V{|w~}sy~}S{|v~Pw~|nw~|V{|w~}!{}v~|q{}x~|1y~}vw~|e{}y~ci|]{}w~u{|w~|?w~}7y~}sw~v{" - "|w~|r{}y~ P{}w~ p{|w~|m{}w~|Ux~}w{|x~}W{|v~| Fi|U{|w~|u{}w~X{}x~}p{|y~}y{}x~a{|w~i{|x~}c{}x~}p{|y~}y{}x~^{}w~|" - "X{}w~}n{}w~}`{}w~}n{}w~}`{}w~}n{}w~}`{}w~}n{}w~}`{}w~}n{}w~}`{}w~|n{}w~}h{|v~p{|v~Y{}v~I{}w~}M{}w~}M{}w~}M{}w~}" - "D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~f{|v~|h{}w~|s{|v~vv~i{}v~c{|v~|l{}v~c{|v~|l{}v~c{|v~|l{}v~c{|v~|l{}v~c{|v~|^{}s~|_" - "{}v~u{|w~|o{|v~|i{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}Z{|v~|V{}w~}o{|u~`w~}q{}t~|^{|f~|^{|f~|^{|f~|^{|f~|" - "^{|f~|^{|f~|h{|P~jv~|O`~|c`~|c`~|c`~|Xv~Lv~Lv~Lv~Wv~jv~`w~}m{|w~}bv~jv~bv~jv~bv~jv~bv~jv~bv~jv~f{|Z~}fv~|u{}x~}" - "vv~a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|]{}w~|u{|w~}\\v~k{}w~|_{}w~|u{|w~} Uw~yq}w~r}yw~jw~yd|yw~jw~" - "sp~|tw~jw~su~|ow~jw~pv~}qw~Zw~|S{}w~}u{|w~} Hv~|Q{}w~|w{|y~|({|\\~iW~|f{}d~|_e~|`w~}kw~}aw~}kw~|]{}w~}uv~Wv~|w{" - "}w~|b{}x~} q{|g~| v{|w~({}Z~X{|y~|{|}u~}Y{|w~uw~|tw~}o{|w~}q{}u~u{}w~*{|v~F{}w~|*m|}w~l|,{|m~ xw~}W{|v~k{}w" - "~}W{}w~}N{}v~}Dv~|bw~}o{}w~}Iv~|au~|m{}w~}W{|v~X{}v~m{}v~\\{|p~}xv~| Y{}p~}| i{|}p~}|]{}w~}`{|x~|sw~mw~|t{}x~kv" - "~}n|}v~a{}w~}kv~}e{}v~M{}w~}f{}v~d{}w~}L{}w~}T{}v~dv~|h{}w~}hv~|Y{}w~}M{}w~}W{}w~}x{|t~U{}w~}V{}w~|tw~|{w~}tv~|" - "h{}w~|rv~}wv~i{}v~c{}v~d{}w~}T{}v~c{}v~f{}w~}p{}v~|Ju~}Y{|v~|Z{|v~h{}w~}_v~|v{|v~bv~|x{|w~r{}w~wv~|b{}v~xv~}R{|" - "v~|Ru~|M{|w~}H{|w~J{|w~| s{|q~t}v~|_w~}k{}w~|bv~Nv~k{}w~|b`~|Yw~}Vv~k{}w~|`w~}m{|w~}Wv~Lv~Tp~Jv~_w~}mv~mv~hw~}" - "m{|w~}bv~jv~`w~}k{}w~|dv~k{}w~|Zw~}N{|m~|Uv~S{|w~|m{}w~|]v~t{|v~`v~w{}x~}w{|x~}w{}w~[{|u~|T{|w~}u{}w~|S{}v~|V{|" - "x}t~}Jw~|K{|s~y}|d{|y~}n{|}p~}1y~}p{}w~p{}y~fv~mv~\\v~lv~|`{}w~|r{|v~}`v~jv~\\{|p~}Xw~}m{|w~}\\{}w~u{}w~|Xv~|v{" - "|v~]{|w~|m{}w~|h{|v~p{}w~pv~}iv~t{}w~t{}w~|b{|w~}q{|w~}`v~t{}w~t{|w~}bw~}k{}w~|dv~jv~X{|w~}W{}w~|l{|w~}av~|n{|v" - "~Wu~|T{}w~}U{}v~dv~}k{|v~}s{|v~s{|v~}h{}w~}hv~|e{}u~|x{|v~w{}u~|h{}v~c{}v~l{|u~}\\|]{}w~][|u~|]{}w~\\{}v~}c|u~}" - "]{}w~ s{|w~V{|w~}sy~}S{|v~P{}x~}o{|w~`{|a~}+u~|rw~|1y~}v{}w~ex~d{|j~}]{}w~}v{|v~|@w~}7y~}sw~u{}w~rx~ P{}w~ p{|" - "w~|m{}w~|Ux~}w{|x~} w{|j~}V{|v~|v{}w~}Xw~oy~}x{}x~aw~|i{|x~|cw~ox~x{}x~^{}w~|Xv~}n|}v~`v~}n|}v~`v~}n|}v~`v~}n|" - "}v~`v~}n|}v~a{|b~h{}v~p|}v~Y{}v~I{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~f{|v~|h{}w~|rv~}wv~i{}v~c{" - "}v~k{}v~c{}v~k{}v~c{}v~k{}v~c{}v~k{}v~c{}v~^{}q~|`{}v~v{|w~}n{}v~h{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}Z{" - "|v~|V{}w~}p{|u~|`w~}p{|t~}`{|q~t}v~|_{|q~t}v~|_{|q~t}v~|_{|q~t}v~|_{|q~t}v~|_{|q~t}v~|i{|q~t}`~|kv~N`~|c`~|c`~|" - "c`~|Xv~Lv~Lv~Lv~Wv~jv~`w~}m{|w~}bv~jv~bv~jv~bv~jv~bv~jv~bv~jv~f{|Z~}fv~u{|x~}uv~a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m" - "{}w~|a{|w~|m{}w~|]{|w~}u{}w~|\\w~}k{}w~|_{|w~}u{}w~| U{}x~|q{}w~q{|w~j{}x~|b{|w~j{}x~|uu~|u~|v{|w~j{}x~|uu~|o{|" - "w~j{}x~|qv}|r{|w~[{|w~|S{|v~uv~| TZ~}a{|w~}wx~'{|\\~iW~|ee~|^{|g~}_w~}kw~}aw~}kw~|]v~|u{}w~|X{}w~}wv~|b{|w~| " - " r{}g~ u{|w~({}Z~X{|y~|w{}v~|Zw~|v{|w~s{|w~o{|w~}p{}u~vw~})v~Fv~| w{}w~ x{|m~ y{|w~|Vv~|lv~|W{}w~}O{}v~}C{}w~}" - "c{|w~n|}w~}v|N{}w~}au~l{|v~Wv~}Xv~}m{|v~|[{|y}w~y}|x{|v~ V{|}p~}|XY|X{|}q~}|Z{}w~}`{|x~|sw~mw~|tw~l{|b~|b{}w~}k" - "{}v~e{|v~|N{}w~}fv~}d{}w~}L{}w~}T{|v~|ev~|h{}w~}hv~|Y{}w~}M{}w~}W{}w~}w{|t~V{}w~}V{}w~|t{}w~|w~|tv~|h{}w~|r{|v~" - "wv~i{|v~|d{}v~d{}w~}T{|v~|d{}v~f{}w~}o{}v~J{|u~Y{|v~|Z{|v~h{}w~}_{}w~}v{}w~}b{}w~}x{}x~}r{|w~wv~b{|v~|x{|v~|S{|" - "v~|S{}v~|L{|w~}Gw~|K{|w~| t{|u~}|q{}w~|_v~k{}w~|bv~Nv~k{}w~|b`~|Yw~}Vv~k{}w~|`w~}m{|w~}Wv~Lv~Tw~}|u~Kv~_w~}mv~" - "mv~hw~}m{|w~}bv~jv~`w~}k{}w~|dv~k{}w~|Zw~}L{|}o~}Vv~S{|w~|m{}w~|]{}w~}u{}w~}`{}w~|xw~|w{|w~wv~\\{|s~Sv~uv~S{}v~" - "|O{}v~}Kw~|L{|v~}|_{|~|j{|y}x~y}|/x~q{|v~}qx~fv~m{}x~}\\v~l{}w~|`v~pv~}`v~jv~]n~}Xw~}m{|w~}\\{|w~|vv~X{|v~t{}w~" - "|^{|w~|m{}w~|h{|v~p{}w~pv~|iv~t{}w~t{}w~|b{|w~}q{|w~}`v~t{}w~t{|w~}bw~}k{}w~|dv~jv~X{|w~}W{}w~}l{}w~}b{|v~lv~|Y" - "{}v~|S{}w~}U{|v~}f{|v~|ju~|t{|v~s{}v~|h{}w~}hv~|dt~}y{|v~y{|t~|g{|v~|d{}v~k{|u~|?{}w~>u~|b{|v{}w~[{}v~|e{}v~}\\" - "{}w~ s{|w~V{|w~}sy~}S{|v~P{|w~o{}x~}`{|a~}+{|u~}|u{|w~0{}y~v{|w~}g{|y~}d{|j~}\\{}v~|w{|v~}Aw~}7{}y~sw~tw~}t{|y~" - "} P{}w~ p{|w~|m{}w~|Ux~}w{|x~} w{|j~}W{|v~|vv~}X{}x~|p{}y~|x{}x~b{}x~}hw~c{}x~}p{}y~|x{}x~^v~X{|b~|b{|b~|b{|b" - "~|b{|b~|b{|b~|b{}b~}id~Y{|v~|J{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~f{}v~g{}w~|r{|v~wv~i{|v~|d{}v" - "~k{|v~|d{}v~k{|v~|d{}v~k{|v~|d{}v~k{|v~|d{}v~_{}v~}u~|a{|v~|ww~}m{}v~h{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w~}f{|v~h{}w" - "~}Z{|v~|V{}w~}sy|s~_w~}n{}u~|b{|u~}|q{}w~|`{|u~}|q{}w~|`{|u~}|q{}w~|`{|u~}|q{}w~|`{|u~}|q{}w~|`{|u~}|q{}w~|j{|u" - "~}|q{}a~|kv~N`~|c`~|c`~|c`~|Xv~Lv~Lv~Lv~Wv~jv~`w~}m{|w~}bv~jv~bv~jv~bv~jv~bv~jv~bv~jv~.v~v{|w~tv~a{|w~|m{}w~|a{" - "|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|\\v~uv~[w~}k{}w~|^v~uv~ T{}x~}q{}w~q{|x~}j{}x~}b{|x~}j{}x~}vu~|{|u~|w{|x~}j{}" - "x~}vu~|n{|x~}j{}x~}b{|x~}[{|w~Qv~|w{|v~ SZ~}`v~x{|y~}'{|]~}iW~|e{|g~}\\{}i~}^w~}kw~}aw~}l{|w~|^{|v~t{|w~}X{|v~x" - "{|v~`w~} m{|v~ jw|({}Z~X{|y~|v{}w~}[{}x~}u{}x~}s{|w~o{}w~}o{}u~x{|w~|)v~Fv~ v{}w~ g{}w~Uv~|lv~|W{}w~}P{}v~" - "}B{|v~c{|_~|O{}w~}a{}v~l{|v~X{|v~|Y{|v~|lv~|N{|v~ S{|}p~|[{|Z~}[{|}p~}|X{}w~}`{|x~|sw~|nw~|u{|x~}l{}b~}b{}w~}k{" - "|v~e{|v~}N{}w~}g{|v~}d{}w~}L{}w~}T{|v~}ev~|h{}w~}hv~|Y{}w~}M{}w~}W{}w~}v{|t~W{}w~}V{}w~|t{|r~sv~|h{}w~|q{}w~}xv" - "~i{|v~}dv~}d{}w~}T{|v~}dv~}f{}w~}nv~}J{}v~Y{|v~|Z{|v~|i{}w~}_{|v~vv~|b{}w~}xw~|qw~|y{|v~bv~}v{}v~S{|v~|T{}v~}K{" - "|w~}G{}x~}K{|w~| tv~}n{}w~|_v~kv~|bv~|Ov~k{}w~|bv~Bw~}Vv~k{}w~|`w~}m{|w~}Wv~Lv~Tw~}{|u~|Mv~_w~}mv~mv~hw~}m{|w~" - "}bv~|kv~`v~k{}w~|dv~k{}w~|Zw~}Iy|}q~Wv~S{|w~|m{}w~|]{|v~uv~_{|w~|xw~uw~|y{|w~}\\r~}T{|w~|w{}w~}T{}v~|M{|v~Kw~|L" - "{}w~} O{}y~|rt~|s{|y~}fv~|nw~}\\v~l{|w~}`w~}p{}w~|`v~|kv~^u~}|Qw~}m{|w~}[w~}w{}w~}X{}w~|t{|w~}^{|w~|m{}w~|h{|v~" - "pv~pv~|iv~t{}w~t{}w~|b{|w~}q{|w~}`v~t{}w~t{|w~}bv~k{}w~|dv~|l{|v~X{|w~}W{|w~}l{}w~|b{}w~}l{}w~}Z{|v~}R{}w~}T{}v" - "~f{}v~i{|u~t{|v~t{|u~g{}w~}hv~|cr~}v~}s~}f{|v~}dv~}j{|u~|@{}w~?u~|b{}~|w{}w~vy~a{}v~|g{}v~}b{}~|w{}w~vy} {{}w~|" - "W{|w~}sy~}S{|v~Ow~}q{|w~|`{|a~}){}u~}vw~}0{|y~}v{}w~}p{|t{}y~|d{|j~}[{|v~|vv~}Bw~}7{|y~}tw~t{|w~|u{}y~| P{}w~ " - "p{|w~|m{}w~|Ux~}w{|x~} w{|j~}X{}v~v{|v~}X{|w~p{|y~|w{}x~bw~h{}x~|d{|w~p{|y~}w{}x~^v~X{}b~}b{}b~}b{}b~}b{}b~}b{" - "}b~}b`~j{}d~Y{|v~}J{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~fv~}g{}w~|q{}w~}xv~i{|v~}dv~}k{|v~}dv~}k" - "{|v~}dv~}k{|v~}dv~}k{|v~}dv~}`{}v~|{|u~|b{|v~}x{}x~}lv~}h{|v~|i{}w~}f{|v~|i{}w~}f{|v~|i{}w~}f{|v~|i{}w~}Z{|v~|V" - "{}e~|_w~}m{|u~bv~}n{}w~|`v~}n{}w~|`v~}n{}w~|`v~}n{}w~|`v~}n{}w~|`v~}n{}w~|jv~}n{}w~Tv~|Ov~Lv~Lv~Lv~Av~Lv~Lv~Lv~" - "Wv~|l{|v~`w~}m{|w~}bv~|kv~bv~|kv~bv~|kv~bv~|kv~bv~|kv~.v~vw~|u{|v~a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}" - "w~|\\{|w~|w{}w~}[v~k{}w~|^{|w~|w{}w~} T{|w~q{}w~q{}x~|j{|w~b{}x~|j{|w~wu~|x{|u~|x{}x~|j{|w~wu~|m{}x~|j{|w~b{}x~" - "|[{|w~Q{|w~}w{}w~} SZ~}`{}w~|y{}y~|'{|n~y}~|n~}i{}k~x}k~c{|i~}Z{}j~]w~}kw~}a{}w~l{|w~|^{}w~}sv~Wv~|y{}w~}`{}w~|" - " mv~| o{}Z~X{|y~|v{|w~}\\{|w~t{}x~|rw~|p{}w~}n{}u~yw~}(v~|Gv~ v{}w~ gw~}U{}w~}m{|v~V{}w~}Q{}v~}A{|v~c{|_~" - "|O{}w~}a{}v~l{|v~X{}v~X{|v~k{}w~}N{}w~} Q{|}p~}|^{|Z~}^{|}p~}|U{}w~}`{|x~}sw~|o{|w~|u{}x~|l`~b{}w~}k{|v~|eu~N{}" - "w~}g{}v~|d{}w~}L{}w~}Su~ev~|h{}w~}hv~|Y{}w~}M{}w~}W{}w~}u{|t~X{}w~}V{}w~|ss~}sv~|h{}w~|q{|v~|yv~hu~e{|v~|d{}w~}" - "Su~e{|v~|f{}w~}n{}v~|K{|v~|Z{|v~|Yv~|i{}w~}^v~|x{}v~a{|v~y{|w~|q{}x~}y{}w~}c{}v~tv~}T{|v~|U{|v~}J{|w~}G{|w~K{|w" - "~| u{|v~m{}w~|_v~kv~a{}w~|O{}w~|l{}w~|bv~|Cw~}V{}w~|l{}w~|`w~}m{|w~}Wv~Lv~Tw~}y{|u~|Nv~_w~}mv~mv~hw~}m{|w~}bv~" - "|l{|v~`v~kv~cv~|l{}w~|Zw~}D{|}u~}Xv~S{|w~|m{}w~|\\{}w~|w{|w~}^w~}y{|w~u{}x~}y{}w~|]{}q~|Tv~wv~|U{|v~}K{}w~|Lw~|" - "Lv~ N{|x~s{}x~{w~|tx~|fv~|o{|v~\\v~l{|w~}a{|w~|p{}w~_{}w~|l{|v~_{}v~|Ow~}m{|w~}[{}w~|xv~X{|v~rv~|_{|w~|m{}w~|h{" - "|v~|qv~pv~|iv~|u{}w~t{}w~|b{|w~}q{|w~}`v~t{}w~t{|w~|bv~kv~c{}w~|l{|v~X{|w~}Vv~l{}w~|bv~|l{|v~[{|v~}Q{}w~}T{|v~}" - "h{|v~|hu~}u{|v~u{|u~|g{}w~}hv~|b{}f~|du~e{|v~|i{|u~|A{}w~@u~|b{}x~|x{}w~ww~a{}v~|i{}v~}b{}x~|x{}w~w{}y~} {}w~|W" - "{|v~sy~}S{|v~O{|w~}s{}w~}^q|}v~q|'{}t~|{|w~}.x~u{}v~}|wy|}y~tx~/{|v~|v{}w~}Cw~}6x~tw~s{}w~ux~ O{}w~ p{|w~|m{}w" - "~|Ux~}w{|x~} B{}w~}v{|v~|Ww~|q{|y~}v{}x~c{}x~|i{}x~}cw~|q{|y~}v{}x~_{|v~X`~b`~b`~b`~b`~c{|`~|kc~Xu~J{}w~}M{}w~" - "}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~g{|v~}g{}w~|q{|v~|yv~hu~e{|v~|ju~e{|v~|ju~e{|v~|ju~e{|v~|ju~e{|v~|a{}" - "v~|x{|u~|bu~y{}w~l{|v~|gv~|i{}w~}ev~|i{}w~}ev~|i{}w~}ev~|i{}w~}Z{|v~|V{}f~|^w~}l{|v~|d{|v~m{}w~|a{|v~m{}w~|a{|v" - "~m{}w~|a{|v~m{}w~|a{|v~m{}w~|a{|v~m{}w~|k{|v~m{}w~T{}w~|Ov~|Mv~|Mv~|Mv~|Bv~Lv~Lv~Lv~W{}w~|l{|v~`w~}m{|w~}bv~|l{" - "|v~bv~|l{|v~bv~|l{|v~bv~|l{|v~bv~|l{|v~.v~|x{}x~|t{|v~a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|a{|w~|m{}w~|[v~wv~|[v" - "~kv~\\v~wv~| Sw~|r{}w~r{|w~hw~|d{|w~hw~|yu~|v{|u~y{|w~hw~|yu~|m{|w~hw~|d{|w~Z{|w~Pv~wv~| SZ~}_w~}yx~%n~{|~{|o~|" - "i{|l~}|}|l~}b{}j~Xk~|]w~}kw~}a{}w~l{}w~]v~|s{}w~|X{}w~}yv~|_w~} mv~} g{}x~}t{}x~}O{|y~|uw~}\\{}x~|t{}x~|rw" - "~|p{|w~}m{}u~}w~|({}w~|H{|w~} v{}w~ h{|w~|U{}w~}m{|v~V{}w~}R{}v~}@{|v~c{|_~|Ov~|a{|v~l{}w~}Xv~}X{|v~k{}w~}Nv~|" - " N{|}p~}|a{|Z~}a{|}p~}|R{|w}|_x~}s{}x~}o{}w~|v{|w~l{}`~|c{}w~}k{|v~|e{}v~|O{}w~}gu~c{}w~}L{}w~}S{}v~|fv~|h{}w~}" - "hv~|Y{}w~}M{}w~}W{}w~}t{|t~Y{}w~}V{}w~|s{}t~rv~|h{}w~|p{}w~}yv~h{}v~|f{}v~c{}w~}S{}v~|f{}v~e{}w~}mv~}K{|v~|Z{|v" - "~|Yv~|iv~|^{}w~}xv~}`v~|{|w~p{}w~yv~|d{|v~|t{|v~|U{|v~|V{|u~I{|w~}Fw~|L{|w~| u{}w~|mv~|_v~|m{|v~a{}w~}O{}w~|lv" - "~|b{}w~|Cw~}V{}w~|lv~|`w~}m{|w~}Wv~Lv~Tw~}x{|u~|Ov~_w~}mv~mv~hw~}m{|w~}b{}w~|l{|w~}`v~kv~c{}w~|lv~|Zw~}B{|u~Xv~" - "S{|w~|m{}w~|\\{|w~}w{}w~|^v~y{}x~}u{|x~}y{}w~]{|v~|}v~T{}w~|y{|w~}U{|v~}J{|w~}Lw~|M{|w~} Mx~}v{|w~|{|w~|v{}x~e{" - "}w~|o{}v~\\v~l{|w~}a{|w~|pw~}_{}w~|l{|w~}_v~Mw~}m{|w~}[{|w~}y{|w~}X{}w~|r{}w~}_{|w~|m{}w~|h{|v~|qv~|r{|v~|i{}w~" - "|u{}w~tv~|b{|w~}q{|w~}`v~t{}w~t{}w~|bv~kv~c{}w~|l{|w~}X{|w~}Vv~lv~b{}v~jv~|\\u~P{}w~}S{}v~|iu~g{|t~|w{|v~v{}u~}" - "f{}w~}hv~|a{}h~|c{}v~|f{}v~g{|u~|B{}w~Au~|b{}v~|y{}w~xu~a{}v~|k{}v~}b{}v~|y{}w~x{}w~}!{}w~|Vv~sy~}S{|v~O{|u~}y|" - "{y|u~}T{|w~}Lw}|P{|}p~}-{|y~}u{}l~u{}y~|.{|v~|v{}w~}Dw~}6{|y~}uw~rw~}w{}y~| O{}w~ p{|w~|m{}w~|Ux~}w{|x~} C{}w" - "~}v{|v~|W{}x~}px~u{}x~d{|w~i{}x~}c{}x~}px~u{}x~_{}w~}Y{}`~|d{}`~|d{}`~|d{}`~|d{}`~|d{}w~}j|}w~}l{|c~X{}v~|K{}w~" - "}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~gu~|g{}w~|p{}w~}yv~h{}v~|f{}v~i{}v~|f{}v~i{}v~|f{}v~i{}v~|f{}v~" - "i{}v~|f{}v~a{}v~|v{|u~|c{}v~|}w~|l{}v~fv~|iv~|ev~|iv~|ev~|iv~|ev~|iv~|Z{|v~|V{}h~}\\w~}k{}w~|d{}w~|mv~|a{}w~|mv" - "~|a{}w~|mv~|a{}w~|mv~|a{}w~|mv~|a{}w~|mv~|k{}w~|mv~|U{}w~}O{}w~|M{}w~|M{}w~|M{}w~|Bv~Lv~Lv~Lv~W{}w~}l{}w~}`w~}m" - "{|w~}b{}w~|l{|w~}b{}w~|l{|w~}b{}w~|l{|w~}b{}w~|l{|w~}b{}w~|l{|w~}.{}w~|y{}x~|s{|w~}a{|w~|m{}w~|a{|w~|m{}w~|a{|w" - "~|m{}w~|a{|w~|m{}w~|[{}w~|y{|w~}Zv~kv~\\{}w~|y{|w~} R{|w~r{}w~rw~}h{|w~dw~}h{|w~y{|w~|t{|w~}yw~}h{|w~y{|w~|lw~}" - "h{|w~dw~}Z{|w~P{}w~|y{|w~} Rs}v~g}|_{}w~{|y~}%{|p~|{|~yp~}g{}m~{}~{}m~|a{}l~|X{|m~}\\w~}kw~}a{|w~|mv~]v~r{}w~}X" - "{|v~{|v~^{}w~} n{}v~ gw~|tw~|O{|y~|uw~}]{|x~}sw~|rw~|p{|v~l{}r~}'{|w~}H{|w~} v{}w~ h{|w~T{|v~m{}w~}V{}w~}" - "S{}v~}?{|v~c{|_~|Ov~|`v~|m{}w~}Y{|v~W{|v~k{}w~}O{|v~ J{|}p~}|d{|Z~}d{|}p~}|-w~s{|w~ov~|v{}x~|lv~|j{|v~c{}w~}k{}" - "v~cv~}O{}w~}h{}v~|c{}w~}L{}w~}Rv~}fv~|h{}w~}hv~|Y{}w~}M{}w~}W{}w~}rt~Z{}w~}V{}w~|ru~}rv~|h{}w~|p{|v~|{v~h{|v~}g" - "{|v~}c{}w~}Rv~}g{|v~}e{}w~}m{|v~|L{|v~|Z{|v~|Y{}w~}j{|v~|^{|v~|{|v~_{}w~}{}x~}p{|w~yv~cv~}r{}v~U{|v~|W{|u~|I{|w" - "~}F{}x~}L{|w~| u{}w~|n{|v~|_v~}m{}w~}a{|w~}O{|w~}m{|v~|b{}w~}Cw~}V{|w~}m{|v~|`w~}m{|w~}Wv~Lv~Tw~}vu~|Pv~_w~}mv" - "~mv~hw~}m{|w~}b{|w~}l{}w~}`v~|m{|w~}c{|w~}lv~|Zw~}@v~|Yv~S{|w~}mv~|[v~wv~]{}w~|{w~|u{|w~yw~}]v~}y{}v~U{|w~}y{}w" - "~|V{|v~}I{|w~}Lw~|M{|w~} M{|w~x}v~}x{}v~x}w~|e{}w~}ou~|]v~l{|w~|a{|w~p{}w~|_{|w~}l{}w~}`{|w~}Mw~}m{|w~}Zv~y{}w~" - "|Y{|v~q{|v~_{|w~}m{}w~|gv~|r{|v~|r{|v~h{}w~}u{}w~tv~a{|w~}q{|w~}`v~t{}w~t{}w~|bv~|m{|w~}c{|w~}l{}w~}X{|w~}V{}w~" - "|n{|w~}bv~}j{}v~]{}v~|P{}w~}Ru~j{}v~|f{|t~}|y{|v~x{|t~}e{}w~}hv~|`{|}l~}`v~}g{|v~}f{|u~|C{}w~Bu~|`u~|{}w~yu~|`{" - "}v~|m{}v~}a{|u~|{}w~y{}v~}!{}w~|Vv~|ty~}S{|v~P{|g~}U{|w~}Lw~|N{|r~}+{}y~|u{|}o~}v{|y~}+v~}v{}v~Ew~}5{}y~|vw~r{|" - "w~|y{|y~} N{}w~ p{|w~}m{}w~|Ux~}w{|x~} Dv~}v{}v~|W{|w~p{}y~|u{}x~dw~|j{}w~c{|w~p{}y~|u{}x~`{}v~|Yv~|j{|v~dv~|" - "j{|v~dv~|j{|v~dv~|j{|v~dv~|j{|v~dv~|j{|v~l{}w~}n{|v~Wv~}K{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~h{" - "|v~}f{}w~|p{|v~|{v~h{|v~}g{|v~}i{|v~}g{|v~}i{|v~}g{|v~}i{|v~}g{|v~}i{|v~}g{|v~}b{}v~|t{|u~|cq~|l{|v~}f{}w~}j{|v" - "~|e{}w~}j{|v~|e{}w~}j{|v~|e{}w~}j{|v~|Z{|v~|V{}k~}|Zw~}k{}w~}d{}w~|n{|v~|a{}w~|n{|v~|a{}w~|n{|v~|a{}w~|n{|v~|a{" - "}w~|n{|v~|a{}w~|n{|v~|k{}w~|n{|v~}U{|w~}O{}w~}M{}w~}M{}w~}M{}w~}Bv~Lv~Lv~Lv~W{|v~lv~|`w~}m{|w~}b{|w~}l{}w~}b{|w" - "~}l{}w~}b{|w~}l{}w~}b{|w~}l{}w~}b{|w~}l{}w~}Xt|X{}w~}{}x~}r{}w~}a{|w~}mv~|a{|w~}mv~|a{|w~}mv~|a{|w~}mv~|[{|w~}y" - "{}w~|Zv~|m{|w~}\\{|w~}y{}w~| Qw~}s{}w~s{}w~fw~}f{}w~fw~}y{|y~|r{|y~}y{}w~fw~}y{|y~|l{}w~fw~}f{}w~Y{|w~P{|v~y{}w" - "~| Kv~}J{|w~|}y~|${}r~}y{}~y{|q~f{|n~|{}~yn~}_m~|V{|o~}[w~}kw~}`w~}n{|w~}^{|w~}r{|v~Wv~{}w~}]v~| o{|v~| hw" - "~t{|w~N{|y~|uw~}]w~|s{}x~|rw~|ov~|l{}s~&{|w~}H{}w~| v{}w~ h{}x~}Sv~|nv~|V{}w~}T{}v~}>{}w~}Q{}w~}J{}v~_{}w~}mv~" - "}Y{}w~}Vv~|lv~|Ov~} G{|}p~}|0{|}o~}*{}x~rw~}q{}v~|w{}w~l{|v~hv~|d{}w~}ku~c{}v~}P{}w~}i{}u~b{}w~}L{}w~}R{}v~|gv~" - "|h{}w~}hv~|Y{}w~}M{}w~}W{}w~}qt~[{}w~}V{}w~|r{}v~|rv~|h{}w~|o{}w~}{v~g{}v~|hu~|c{}w~}R{}v~|hu~|e{}w~}lv~}L{}v~Y" - "{|v~|Y{}v~j{}v~\\{}w~}{}w~}_{|v~{w~|ow~y|v~d{}v~pv~}V{|v~|Wu~|H{|w~}F{|w~L{|w~| u{}w~m{}v~|_u~mv~|a{|v~Nv~|n{}" - "v~|b{|v~Cw~}Uv~|n{}v~|`w~}m{|w~}Wv~Lv~Tw~}uu~|Qv~_w~}mv~mv~hw~}m{|w~}b{|v~lv~|`v~}m{}w~}c{|v~m{|v~|Zw~}@{}w~|Yv" - "~S{|w~}mv~|[{}w~|y{|w~}]{|w~}{w~sw~y|w~}^{}w~}wv~}U{}w~yv~Uv~}Gw~}Lw~|M{|w~| L{|q~}v{}q~|d{|w~}p{|u~|]v~l{}w~|a" - "{|w~pv~^{|v~lv~|`{|w~|Mw~}m{|w~}Z{}w~y|v~X{}w~}pv~|`{|w~}mv~|gv~}r{|v~}r{}v~h{|v~u{}w~u{|w~}a{|w~}q{|w~}`{}w~|u" - "{}w~tv~av~}m{}w~}c{|v~lv~|X{|w~}V{|w~}n{}w~|c{|v~i{|v~|_{}v~}O{}w~}R{|v~}l{}v~|d{|r~y}v~y}s~}d{}w~}hv~|]{|}s~y}" - "|^{}v~|hu~|e{|v~}C{}w~C{}v~|^u~|}w~{}v~|^{}v~n{|v~}_{|u~|}w~{}v~} {}w~|V{}w~}ty~}S{|v~Q{}e~}V{|w~}Lw~|L{|t~*{|x" - "~|t{|y}u~}|u{|x~|*{}w~|v{|v~Fw~}5{|x~|ww|qw|y{|x~| >{|w~}mv~|Ux~}w{|x~} Ev~}v{|v~U{}x~|q{|y~}t{}x~e{}x~}j{}w" - "~b{}x~|q{|y~}t{}x~a{}v~}Y{|v~hv~|f{|v~hv~|f{|v~hv~|f{|v~hv~|f{|v~hv~|f{}v~hv~|n{|v~|n{|v~W{}v~}L{}w~}M{}w~}M{}w" - "~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~i{|u~|f{}w~|o{}w~}{v~g{}v~|hu~|h{}v~|hu~|h{}v~|hu~|h{}v~|hu~|h{}v~|hu~|c{}" - "v~|r{|u~|d{}s~|ku~|f{}v~j{}v~d{}v~j{}v~d{}v~j{}v~d{}v~j{}v~Y{|v~|V{}w~}r|Vw~}k{|w~|d{}w~m{}v~|a{}w~m{}v~|a{}w~m" - "{}v~|a{}w~m{}v~|a{}w~m{}v~|a{}w~m{}v~|k{}w~m{}u~U{|v~O{|v~M{|v~M{|v~M{|v~Bv~Lv~Lv~Lv~Vv~|n{|v~_w~}m{|w~}b{|v~lv" - "~|b{|v~lv~|b{|v~lv~|b{|v~lv~|b{|v~lv~|X{}u~X{|v~|x~}qv~|a{|w~}mv~|a{|w~}mv~|a{|w~}mv~|a{|w~}mv~|Z{}w~yv~Yv~}m{}" - "w~}[{}w~yv~ P{|w~}t{}w~t{|w~}f{|w~}h{|w~}f{|w~}yy|p{|}y{|w~}f{|w~}yy|l{|w~}f{|w~}h{|w~}Y{|w~Ov~y|v~ K{}w~}Hw~}y" - "~}\"{}t~}x{}~x{|s~d{|p~}y{}~y{|p~}]o~|T{}p~Zw~}kw~}`{}w~|o{}w~|^{}w~|qv~|X{}w~|v~|]{|v~| o{}v~j{} {|x~}t{|" - "x~}N{|y~|v{}w~}^{}x~}r{}x~}rw~|o{}v~k{}u~|%v~Hv~ u{}w~ hw~|S{}v~o{}v~U{}w~}U{}v~}>{|v~}Q{}w~}Ju~_{|v~n{|v~|Z{|" - "v~|Vv~}m{|v~|P{}v~ C{}o~}4{|o~}|({|x~}s{}w~}s{}u~|x{}w~|l{}w~}h{}w~}d{}w~}l{|v~}bu~|g{|}g{}w~}j{}u~|b{}w~}L{}w~" - "}R{|u~|hv~|h{}w~}hv~|Y{}w~}M{}w~}W{}w~}pt~\\{}w~}V{}w~|r{|v}qv~|h{}w~|nv~|v~g{|u~|j{}v~}b{}w~}R{|u~i{}v~}d{}w~}" - "l{|v~|M{}v~Y{|v~|Y{|v~|kv~}\\{|v~{v~|_{|v~|w~|o{}x~y}w~}e{|v~|p{|v~|W{|v~|X{}v~}G{|w~}F{|w~|M{|w~| u{}w~|nu~|_" - "u~}o{}v~_v~}O{}w~}o{|u~|av~}Dw~}U{}w~}o{|u~|`w~}m{|w~}Wv~Lv~Tw~}t{}v~|Rv~_w~}mv~mv~hw~}m{|w~}av~|n{|v~_u~mv~|bv" - "~|n{}v~|Zw~}@{}w~|Yv~Rv~n{}v~|[{|w~}y{}w~|\\w~}|x~}s{}x~y}w~|_{}v~v{|v~|V{|w~y}w~}Vu~Fw~}Lw~|M{|w~| K{|s~}t{}s~" - "|bv~p{}u~}]v~|mv~`{|w~q{}w~}]v~}n{}v~_{|w~|Mw~}m{|w~}Yw~y}w~|Xv~o{|w~}`{|v~n{|v~|g{}v~r{}u~rv~}gv~|v{}w~uv~|a{|" - "w~}q{|w~}`{|w~}u{}w~u{|v~au~mv~|bv~}n{}v~Vv~Uv~nv~b{}w~}hv~}`{|v~}N{}w~}Q{|v~}n{}v~}b{|c~}c{}w~}hv~|Z{|v~Z{|u~|" - "j{}v~}c{|w~B{}w~B{}x~|\\u~}w~}v~|\\{}x~|m{}x~}]{|u~}w~}v~} {{v~|V{|v~|uy~}S{|v~R{}v~y|q~}|u~W{|w~}Lw~|J{}u~*{|x" - "~|e{|x~|({}x~}u{|w~F{|x}|4{|x~|e{|x~| ={|v~n{|v~|Ux~}w{|x~} Ew~|u{|x~}U{|x~}p{}j~}iw~j{}w~b{|x~}p{}j~}f{}v~}" - "X{}w~}h{}w~}f{}w~}h{}w~}f{}w~}h{}w~}f{}w~}h{}w~}f{}w~}h{}w~}fv~}h{}w~}n{}w~}m{|v~Vu~|g{|}c{}w~}M{}w~}M{}w~}M{}w" - "~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~j{|u~}e{}w~|nv~|v~g{|u~|j{}v~}g{|u~|j{}v~}g{|u~|j{}v~}g{|u~|j{}v~}g{|u~|j{}v~}c{" - "}v~|p{|u~|e{|t~}k{}v~}e{|v~|kv~}d{|v~|kv~}d{|v~|kv~}d{|v~|kv~}Y{|v~|V{}w~}Mw~}k{}w~|d{}w~|nu~|a{}w~|nu~|a{}w~|n" - "u~|a{}w~|nu~|a{}w~|nu~|a{}w~|nu~|k{}w~|nt~|Uv~}Ov~}Mv~}Mv~}Mv~}Cv~Lv~Lv~Lv~V{}v~nv~}_w~}m{|w~}av~|n{|v~`v~|n{|v" - "~`v~|n{|v~`v~|n{|v~`v~|n{|v~W{}u~Wr~q{|v~_v~n{}v~|`v~n{}v~|`v~n{}v~|`v~n{}v~|Z{|w~y}w~}Yu~mv~|[{|w~y}w~} O{}w~}" - "u{}w~u{}w~}d{}w~}j{}w~}d{}w~}j{}w~}d{}w~}j{}w~}d{}w~}j{}w~}X{}w~O{|w~y}w~} L{}w~}G{}u~|!{|}x~}|w{}~v{}w~}b{|r~|" - "x{}~w{}s~|\\{|q~}Rq~|Zw~}kw~}`{|v~p{|v~]v~p{}w~}X{|q~[{}v~} p{|v~}ly}$v}|\"{}x~}t{}x~}Yy}|s{|y~|w{|v~|_{|w~" - "q{}x~}s{|w~n{|v~}l{|u~}%{}w~|Iw~} u{}w~L{}w~} tv}|P{|w~R{|v~|pv~}U{}w~}V{}v~}={}v~|Q{}w~}K{}v~|^v~|o{}v~Y{}v~U{" - "}v~m{}v~P{|v~}U{|v}M{}w~}F{|}q~}6{|q~}|G{|w}|^w~ru~y|x{|}t~y|}v~|kv~|h{|v~d{}w~}m{|u~|b{|u~|i{|~}g{}w~}l{|}u~}a" - "{}w~}L{}w~}Q{}u~|iv~|h{}w~}hv~|Y{}w~}M{}w~}W{}w~}ot~]{}w~}V{}w~|bv~|h{}w~|n{}q~f{}u~k{}u~a{}w~}Q{}u~k{|u~c{}w~}" - "kv~}c{|}h{|v~}Y{|v~|X{}v~l{}v~|[v~}v~]v~}w~n{}r~|ev~}n{}v~W{|v~|Y{}v~}F{|w~}Ew~}M{|w~| u{}w~|o{}u~|_t~|q{|v~}_" - "{|v~|P{|v~}pt~|a{|v~|Ew~}U{|v~|pt~|`w~}m{|w~}Wv~Lv~Tw~}s{}v~|Sv~_w~}mv~mv~hw~}m{|w~}a{}v~nv~}_u~}o{}v~a{}v~o{|u" - "~|Zw~}@{}w~|Y{}w~|Sv~|p{|u~|Zv~{|v~[v~}x~}s{|r~_{|v~|u{}v~Uq~V{}v~|Fw~}Lw~|M{|w~| I{|y}~y}|r{|}x~}|`{}w~}qs~]u~" - "n{|v~`{|w~r{|v~\\{|v~nv~}_{|w~}Mw~}m{|w~}Y{}r~X{}w~}nv~`{|v~|o{}v~|g{|v~|st~|t{|v~|g{}v~v{}w~v{|v~`{|w~}q{|w~}_" - "v~|v{}w~uv~}au~}o{}v~a{|v~nv~}Vv~U{|w~}p{}w~}bv~|h{|v~`u~M{}w~}P{|u~|q{}v~}_{}g~}|b{}w~}hv~|Z{|v~Y{}u~k{}u~a{|y" - "~A{}w~A{}~|Zl~|Z{}~|k{}~}[{|l~} yv~}Uv~}uy~}S{|v~S{}v~|x{|y}x~}|wu~X{|w~}Lw~|I{|v~}*{}x~|g{|x~}&{}y~}t{|x~ T{}x" - "~|g{|x~} <{|v~|o{}v~|Ux~}w{|x~} Ex~|t{|y~}Tw~|p{}j~}j{}x~|k{}x~}aw~|p{}j~}g{}v~}Wv~|h{|v~fv~|h{|v~fv~|h{|v~f" - "v~|h{|v~fv~|h{|v~g{|v~g{|v~|ov~|m{|v~V{|u~|i{|~}c{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~k{}t~d{}w~" - "|n{}q~f{}u~k{}u~e{}u~k{}u~e{}u~k{}u~e{}u~k{}u~e{}u~k{}u~c{}v~|n{|u~|e{}u~|l{}u~c{}v~l{}v~|c{}v~l{}v~|c{}v~l{}v~" - "|c{}v~l{}v~|Y{|v~|V{}w~}Mw~}kv~c{}w~|o{}u~|a{}w~|o{}u~|a{}w~|o{}u~|a{}w~|o{}u~|a{}w~|o{}u~|a{}w~|o{}u~|k{}w~|o{" - "}s~U{|v~|P{|v~|N{|v~|N{|v~|N{|v~|Dv~Lv~Lv~Lv~Uv~}p{}v~^w~}m{|w~}a{}v~nv~}`{}v~nv~}`{}v~nv~}`{}v~nv~}`{}v~nv~}W{" - "}u~W{}t~|qv~}_v~|p{|u~|`v~|p{|u~|`v~|p{|u~|`v~|p{|u~|Yq~Xu~}o{}v~Yq~ M{}w~}|w{}x~}v{}v~b{}w~}|m{}v~b{}w~}|m{}v~" - "b{}w~}|m{}v~b{}w~}|m{}v~W{}x~}Nq~| M{|v~F{|u~ py~|V{|}y~y}|vy~|w{|y}y~y}Y{|s~}Q{|s~|Yw~}kw~}_{}v~|s{}v~|^{|w~}p" - "{|v~X{|r~}Z{}u~} q{}v~}o{|y~}$v~}\"w~|tw~|Y{}y~}|u{|y~|x{|u~^{}x~|q{|w~s{}x~}mu~}n{|s~}&{|w~|J{|w~| u{}w~L{" - "}v~ u{|v~|P{}x~}Q{}v~|r{}v~T{}w~}W{}v~}O{}|k{}v~}P{}w~}]{}|l{}u~]{|v~|q{}v~|Yv~}U{|v~}o{}v~}Q{|v~}T{}v~M{}v~C{|" - "}t~}6{|t~}|D{}w~}^{}x~|s{|m~y}q~|k{|v~fv~|e{}w~}n{|u~}`{}u~|l{|}y~}g{}w~}n{|}t~}`{}w~}L{}w~}P{}u~}jv~|h{}w~}hv~" - "|Y{}w~}M{}w~}W{}w~}nt~^{}w~}V{}w~|bv~|h{}w~|mq~e{}u~|n{}u~|a{}w~}P{}u~|n{}u~|c{}w~}k{|v~|d{|y~}k{|u~|Y{|v~|X{|u" - "~n{|u~Z{}r~}]{}s~}n{|r~e{}v~lv~}X{|v~|Z{|u~E{|w~}E{}w~M{|w~| u{|v~p{|t~|_s~|s{|u~]u~|P{}v~}s{|s~|`u~|k{|Ww~}T{" - "}v~}s{|s~|`w~}m{|w~}Wv~Lv~Tw~}r{}v~}Tv~_w~}mv~mv~hw~}m{|w~}`v~}p{}v~|_t~|q{|v~|`v~}q{|t~|Zw~}Q{|kv~|Y{}w~}S{}v~" - "pt~|Z{}w~y}w~}[{}s~|rs~}_v~}s{}w~}V{}s~}W{}v~|Ew~}Lw~|M{|w~| r{|v~|s{}s~}^u~}ov~|_w~|s{}w~|[v~}pu~]v~|Nw~}m{|w" - "~}Y{|s~}Xv~m{}w~|a{|u~p{|u~|fv~}t{}x~}x~}t{}v~ev~}w{}w~w{|v~}`{|w~}q{|w~}_{}v~|w{}w~v{}v~`t~|q{|v~|`v~}p{}v~U{}" - "w~|Uv~|r{|v~b{|v~fv~|bu~|M{}w~}O{|u~}t{|u~}\\{|k~}|`{}w~}hv~|Z{|v~X{}u~|n{}u~|`{|@{}w~@{|Xn~|X{|i{|Y{|n~} xv~}U" - "{|v~}vy~}S{|v~T{|v~|jv~}Y{|w~}Lw~|H{|v~|*{}x~}i{}x~}${}~}s{|y~ S{}x~}i{}x~} ;{|u~p{|u~|Ux~}w{|x~} Ey~|s{|~}T" - "{}x~}o{}j~}k{|w~k{}x~}a{}x~}o{}j~}h{}v~}W{|v~fv~|h{|v~fv~|h{|v~fv~|h{|v~fv~|h{|v~fv~|h{}w~}f{}w~}p{|v~l{|v~U{}u" - "~|l{|}y~}c{}w~}M{}w~}M{}w~}M{}w~}D{}w~}M{}w~}M{}w~}M{}w~}Z{|v~n{|}s~c{}w~|mq~e{}u~|n{}u~|d{}u~|n{}u~|d{}u~|n{}u" - "~|d{}u~|n{}u~|d{}u~|n{}u~|d{}v~|l{|u~|et~|n{}u~|c{|u~n{|u~b{|u~n{|u~b{|u~n{|u~b{|u~n{|u~X{|v~|V{}w~}Mw~}x{|p{}v" - "~c{|v~p{|t~|a{|v~p{|t~|a{|v~p{|t~|a{|v~p{|t~|a{|v~p{|t~|a{|v~p{|t~|k{|v~p{|q~j{|gu~|Pu~|k{|_u~|k{|_u~|k{|_u~|k{" - "|Vv~Lv~Lv~Lv~U{|v~}r{}v~}^w~}m{|w~}`v~}p{}v~|_v~}p{}v~|_v~}p{}v~|_v~}p{}v~|_v~}p{}v~|W{}u~Vu~|q{}v~|_{}v~pt~|`{" - "}v~pt~|`{}v~pt~|`{}v~pt~|Y{}s~}Xt~|q{|v~|Y{}s~} Lu~}p{}u~|au~}p{}u~|au~}p{}u~|au~}p{}u~|au~}p{}u~|W{}x~}N{}s~} " - "M{|v~|Ev~} py~|Jy~|M{}t~O{|u~}Xw~}kw~}_{|t~}w|}u~}]{}w~}ov~|Xr~|Y{}t~}y| tt~|r{}x~}$v~}\"w~t{|w~X{}v~}y|y{|" - "y~y|}t~|_{|x~}ow~}tw~|m{|t~|r{|}q~}&w~}J{}w~ t{}w~L{}v~ u{|v~|Pw~|Pu~|t{}v~|\\s|}w~}r|a{}v~}Nx~}|p{}t~O{}w~}]{}" - "y~}|q{}t~|\\{}v~|s{}u~Y{|v~|T{}u~|r{}u~|_{~}|r{|}u~|T{}v~M{}v~@{|}w~}6{|w~}|A{}w~}^{|w~r{|o~}{}s~}iv~}f{}w~}e{}" - "w~}q|y}s~|_{}t~|p{|}w~}g{}w~}r|y}q~}_{}w~}g|`{}w~}O{}t~}o{|}u~|h{}w~}hv~|Y{}w~}M{}w~}W{}w~}mt~_{}w~}h|i{}w~|bv~" - "|h{}w~|m{}r~dt~}|r{|t~|`{}w~}Ot~}q{|t~}b{}w~}jv~}d{|w~}|p{|}u~}X{|v~|W{}u~|q{}u~|Z{|r~|]{|s~|mr~f{|v~|l{|v~|Y{|" - "v~|[{|u~}b|^{|w~}E{|w~|N{|w~| tv~}r{}s~|_w~y}x~}|w{|}u~|]{|u~|p{|}|^t~y|x{|}w~}w~|`{|u~|n{|y~|Xw~}St~y|x{|}w~}" - "w~|`w~}m{|w~}Wv~Lv~Tw~}q{}v~}Uv~_w~}mv~mv~hw~}m{|w~}`{}v~}r{}v~}^s~}s{|v~}_{}v~}s{|s~|Zw~}Qy~}|o{}w~}X{|v~}|U{|" - "v~}s{|s~|Z{|q~Z{|s~qs~|`{}w~}qv~}Vs~|X{}v~|Dw~}Lw~|M{|w~| qu~|u{}w~|v~}_s~|s{|u~^{}w~t{}w~}Z{|v~}|t{|}v~|]{}v~" - "|ny|^w~}m{|w~}Xs~|Y{}w~}m{|w~}a{|t~|s{}t~}f{}v~}v{|w~{w~|v{}v~}e{}v~}x{}w~x{}u~_{|w~}q{|w~}^u~}|y{}w~x{}u~}`s~}" - "s{|v~}_{|v~}|t{|}v~|U{|v~}|W{|v~|t{|v~|bu~f|v~}c{}v~}h|_{}w~}Vs}t~}v{}t~s}`{|y}t~y}|]{}w~}hv~|Z{|v~Wt~}|r{|t~|#" - "{}w~ vp~| {|p~} wv~}T{}v~}wy~}v{}~Z{|v~S{}x~|hx~}X{|w~}Lw~|G{}w~}){|w~|m{|w~|\"{|}q{} R{|w~|m{|w~| XY| ${|u~}r{" - "|t~}Ux~}w{|x~} E{}qy|T{|w~c{}x~gw~|lw~}a{|w~c{}x~e{}v~}Vv~}f{}w~}hv~}f{}w~}hv~}f{}w~}hv~}f{}w~}hv~}f{}w~}hv~|f" - "{|v~pv~}l{|v~}h|h{}t~|p{|}w~}c{}w~}g|a{}w~}g|a{}w~}g|a{}w~}g|X{}w~}M{}w~}M{}w~}M{}w~}Z{|v~r|x}q~b{}w~|m{}r~dt~}" - "|r{|t~|bt~}|r{|t~|bt~}|r{|t~|bt~}|r{|t~|bt~}|r{|t~|d{|v~|j{|v~}f{}s~}|r{|t~|a{}u~|q{}u~|a{}u~|q{}u~|a{}u~|q{}u~" - "|a{}u~|q{}u~|X{|v~|V{}w~}Mw~}xy~}y|wy|u~|bv~}r{}s~|`v~}r{}s~|`v~}r{}s~|`v~}r{}s~|`v~}r{}s~|`v~}r{}s~|jv~}r{}w~}" - "|u~|o{|}y~g{|u~|p{|}|_{|u~|n{|y~|`{|u~|n{|y~|`{|u~|n{|y~|`{|u~|n{|y~|Wv~Lv~Lv~Lv~T{}u~}|x{|}u~}]w~}m{|w~}`{}v~}" - "r{}v~}^{}v~}r{}v~}^{}v~}r{}v~}^{}v~}r{}v~}^{}v~}r{}v~}V{}u~V{|v~}r{}v~}^{|v~}s{|s~|`{|v~}s{|s~|`{|v~}s{|s~|`{|v" - "~}s{|s~|Xs~|Xs~}s{|v~}Ws~| K{}u~}x|{x|}t~^{}u~}x|{x|}t~^{}u~}x|{x|}t~^{}u~}x|{x|}t~^{}u~}x|{x|}t~U{}x~}N{|s~| M" - "{|w~|D{}w~| q{|y~}K{|y~}L{}v~|N{}v~Ww~}kw~}^{|j~}\\v~|o{}w~}X{}s~W{|^~} -s~}v|}v~}$v~}#{|w~t{|x~}X{}e~|^w~|o" - "{|w~|v{}w~k{|s~}v|}t~y}v~}'{}w~Jw~} t{}w~L{}v~ u{|v~|Q{|w~O{|u~}w|}u~}\\{|e~|ab~`u~w}|x}r~|O{}w~}]{}v~w}|x}s~}Z" - "t~}w|}t~X{}w~}S{|t~y}v|}t~}^v~y}y|y}s~|S{}v~M{}v~={|}~}6{|y~}|?{}w~}]w~}q{}r~|y{}u~}h{|v~|f{|v~e{}c~|]{}s~y}v|y" - "}t~}g{}b~|^{}c~}`{}w~}N{}r~y}v|y}r~|h{}w~}hv~|Y{}w~}M{}w~}W{}w~}lt~`{}d~}i{}w~|bv~|h{}w~|lr~cr~}v|}s~}_{}w~}Ns~" - "y}v|}s~}a{}w~}j{|v~|e{|s~}u|}r~W{|v~|Vs~}v|y}t~|Xs~}\\{|s~|m{}t~}fv~}j{}v~Y{|v~|[{}\\~}^{|w~}Dw~}N{|w~| t{}u~y" - "|x{|}w~y}w~|_w~}{k~|[{|t~}|wy|}x~|^{|k~y|w~|_{|t~}|vy|y}w~|Xw~}S{|k~y|w~|`w~}m{|w~}Wv~Lv~Tw~}p{}v~}Vv~_w~}mv~mv" - "~hw~}m{|w~}_{}u~}|x{|}u~}]w~y}w~y|yy|}u~|^{}u~}|x{|}w~}w~|Zw~}Qv~}y|v{|}u~|Wm~[{}u~}w|}v~}w~|Y{}s~}Yt~}q{}t~|a{" - "}v~p{|v~|W{}t~W{}d~Uw~}Lw~|M{|w~| q{|u~}|y{|}v~{|s~br~}y|yy|}u~|^{|w~}v{}v~X{}u~}y|{y|}u~}\\{|t~}|vy|y}y~}^w~}" - "m{|w~}X{}t~Xv~|lv~|b{|s~}v|}q~x}hu~}|{y|w~}{}w~}|{|}u~c{}u~}|}w~|}t~|_{|w~}q{|v~}_{|s~}v~}s~}_w~y}w~y|yy|}u~|^{" - "}u~}y|{y|}u~}S{}r~}Z{}v~}|x{|}v~}b{|Z~c{}c~}_{}w~}Vk~v{}l~|^{|v~Y{}w~}hv~|Z{|v~Vr~}v|}s~|\"{}w~ ur~| y{|r~} vv~" - "}St~}y|y~}{y|}x~`{}b~}a{}~|f{~}W{|w~}Lw~|G{|w~}({|v~}|s{|}v~| E{|v~}|s{|}v~| X{|Z~} ${|s~}y|{y|}q~}|}Xx~}w{|x~" - "} l{}x~|c{}x~h{}x~}m{|w~|`{}x~|c{}x~f{|v~}V{|v~|f{|v~i{|v~|f{|v~i{|v~|f{|v~i{|v~|f{|v~i{|v~|f{|v~i{|v~dv~|r{|" - "v~k{|b~g{}s~y}v|y}t~}c{}c~}a{}c~}a{}c~}a{}c~}X{}w~}M{}w~}M{}w~}M{}w~}Z{|b~}a{}w~|lr~cr~}v|}s~}`r~}v|}s~}`r~}v|}" - "s~}`r~}v|}s~}`r~}v|}s~}b{|x~|h{|x~}f{}o~}v|}s~}_s~}v|y}t~|_s~}v|y}t~|_s~}v|y}t~|_s~}v|y}t~|W{|v~|V{}w~}Mw~}xk~}" - "a{}u~y|x{|}w~y}w~|`{}u~y|x{|}w~y}w~|`{}u~y|x{|}w~y}w~|`{}u~y|x{|}w~y}w~|`{}u~y|x{|}w~y}w~|`{}u~y|x{|}w~y}w~|j{}" - "u~y|x{|}u~y{|t~}|vy|}v~f{|t~}|wy|}x~|^{|t~}|vy|y}w~|_{|t~}|vy|y}w~|_{|t~}|vy|y}w~|_{|t~}|vy|y}w~|Wv~Lv~Lv~Lv~S{" - "}j~}\\w~}m{|w~}_{}u~}|x{|}u~}\\{}u~}|x{|}u~}\\{}u~}|x{|}u~}\\{}u~}|x{|}u~}\\{}u~}|x{|}u~}U{}u~V{}t~}|x{|}u~}\\{" - "}u~}w|}v~}w~|_{}u~}w|}v~}w~|_{}u~}w|}v~}w~|_{}u~}w|}v~}w~|X{}t~Ww~y}w~y|yy|}u~|W{}t~ I{}h~}\\{}h~}\\{}h~}\\{}h~" - "}\\{}h~}T{}x~}Ms~ K{|y~}C{|w~ p{}x~K{}x~Kw~|L{}x~|Ww~}kw~}]{|l~}\\{|v~n{|w~}X{|s~U{}`~} -{|h~|$v~}#{}x~}t{}x" - "~}X{|}g~|^{}x~}m{}w~}y|}v~|j{|g~}y{}v~}({|w~|L{|w~| t{}w~L{}v~ u{|v~|Q{}x~}N{}k~}[{|e~|ab~`e~|N{}w~}]{}g~}Y{|i~" - "|Xv~|R{|g~}]i~|R{}v~M{}v~;y|5{|<{}w~}]{|w~|p{|v}|w{|x}|e{}v~dv~}f{}e~}|[{}d~|g{}d~}\\{}c~}`{}w~}M{}c~}|g{}w~}hv" - "~|Y{}w~}M{}w~}W{}w~}kt~a{}d~}i{}w~|bv~|h{}w~|l{|s~b{}f~|^{}w~}M{}f~|`{}w~}iv~}e{|c~V{|v~|Uf~}W{}t~|[s~l{}t~|g{}" - "v~hv~}Z{|v~|[{}\\~}^{|w~}D{}w~N{|w~| sj~{}w~|_w~}{|m~|Y{}i~|]{|m~|{|w~|^{|f~|Xw~}R{|m~|{}w~|`w~}m{|w~}Wv~Lv~Tw" - "~}o{}v~}Wv~_w~}mv~mv~hw~}m{|w~}^h~\\w~}{k~|\\k~y|w~|Zw~}Qg~}V{|n~Zk~{}w~|Y{|s~|Y{}u~}q{|t~a{|v~|o{}v~W{|u~|W{}d" - "~Uw~}Lw~|M{|w~| p{|l~|ys~be~}\\{}v~x}u~V{}j~}Z{|h~}^w~}m{|w~}X{|u~|Y{|w~}k{}w~}b{|w~}m~|s~h{|m~xm~|b{}g~|^{|w~" - "}pr~a{|f~}^w~}{k~|\\{}j~}R{|r~}Y{}l~}a{}Z~}d{}c~}_{}w~}Vk~v{}l~|^{|v~Y{}w~}hv~|Z{|v~U{}f~|!{}w~ tt~| w{|t~} uv~" - "}R{}i~`{}b~}`{|?{|w~}Lw~|Fw~}&{}t~w}t~} A{}t~w}t~} V{|Z~} ${|w~}m~|s~Xx~}w{|x~} m{|x~}b{}x~hw~lk~k{|x~}b{}x~" - "fv~}U{}v~dv~}j{}v~dv~}j{}v~dv~}j{}v~dv~}j{}v~dv~}j{}w~}d{}w~}r{}w~}k{|b~f{}d~|c{}c~}a{}c~}a{}c~}a{}c~}X{}w~}M{}" - "w~}M{}w~}M{}w~}Z{|d~}|`{}w~|l{|s~b{}f~|^{}f~|^{}f~|^{}f~|^{}f~|`{|~|f{|~}f{|w~|}f~|]f~}]f~}]f~}]f~}V{|v~|V{}w~}" - "Mw~}xl~}_j~{}w~|_j~{}w~|_j~{}w~|_j~{}w~|_j~{}w~|_j~{}w~|ii~w{|f~e{}i~|]{|f~|^{|f~|^{|f~|^{|f~|Wv~Lv~Lv~Lv~R{}l~" - "}[w~}m{|w~}^h~Zh~Zh~Zh~Zh~){|f~Zk~{}w~|^k~{}w~|^k~{}w~|^k~{}w~|X{|u~|Ww~}{k~|V{|u~| H{|j~|Z{|j~|Z{|j~|Z{|j~|Z{|" - "j~|S{}x~}M{}u~} I{}Ax~} pw~|Lw~|L{|y~|Jy~|Vw~}kw~}[{}o~|[{}w~}mv~Wt~}T{|}b~} +{}l~}\"v~}#w~|tw~|U{|}l~}]{|w~" - "ko~|h{|j~}|w{}u~({}w~L{}w~ s{}w~Lv~| u{|v~|Qw~}M{|m~}Z{|e~|ab~`g~}|M{}w~}]{}h~|W{|k~W{}v~P{|i~|\\k~}P{}v~Mv~| " - "i{}w~}\\{}w~Jv~}d{}v~f{}g~}|X{|}h~}e{}g~}|Z{}c~}`{}w~}L{|}g~}|e{}w~}hv~|Y{}w~}M{}w~}W{}w~}jt~b{}d~}i{}w~|bv~|h{" - "}w~|ks~a{|i~}\\{}w~}L{|i~}^{}w~}i{|v~|e{}f~}U{|v~|T{}i~|Ut~Z{}u~}l{|t~g{|v~|h{|v~|[{|v~|[{}\\~}^{|w~}D{|w~N{|w~" - "| s{|l~|{}w~|_w~}x{}q~}|W{|j~|[{}p~|y{|w~|]{|g~|Xw~}P{}q~}|y{}w~|`w~}m{|w~}Wv~Lv~Tw~}n{|v~}Xv~_w~}mv~mv~hw~}m{" - "|w~}]{}l~}[w~}{|m~|Zm~|{|w~|Zw~}Qh~|T{|o~Z{|m~|{}w~|Xs~X{}u~|pu~}av~}m{}w~}Wu~V{}d~Uw~}Lw~|M{|w~| o{|n~|w{}u~b" - "f~}Z{}p~}T{}l~}X{|i~}^w~}m{|w~}Wu~Xv~|k{|v~b{|w~y|o~|{}t~g{|o~|x{|o~}`{}i~|]{|w~}p{}s~_{}j~}|]w~}{|m~|Z{}l~}P{|" - "s~}X{}n~}`X~d{}c~}_{}w~}Vk~v{}l~|^{|v~Y{}w~}hv~|Z{|v~T{|i~} {{}w~ sv~| u{|v~} tv~}Q{}j~`{}b~}#{|w~}Lw~|G{|w~}${" - "}m~} ={}m~} T{|Z~} ${|w~y|o~|{}t~Xx~}w{|x~} mw~|b{}x~i{}x~|lk~kw~|b{}x~g{|v~Tv~}d{}v~jv~}d{}v~jv~}d{}v~jv~}d" - "{}v~jv~}d{}v~k{|v~|d{|v~rv~|k{|b~e{|}h~}a{}c~}a{}c~}a{}c~}a{}c~}X{}w~}M{}w~}M{}w~}M{}w~}Z{|g~}|]{}w~|ks~a{|i~}[" - "{|i~}[{|i~}[{|i~}[{|i~}/{|w~|y{|i~}Z{}i~|[{}i~|[{}i~|[{}i~|U{|v~|V{}w~}Mw~}xm~|^{|l~|{}w~|_{|l~|{}w~|_{|l~|{}w~" - "|_{|l~|{}w~|_{|l~|{}w~|_{|l~|{}w~|i{|l~}u{|g~d{|j~|\\{|g~|]{|g~|]{|g~|]{|g~|Wv~Lv~Lv~Lv~Q{|}p~}|Zw~}m{|w~}]{}l~" - "}X{}l~}X{}l~}X{}l~}X{}l~}){|w~}l~}Y{|m~|{}w~|^{|m~|{}w~|^{|m~|{}w~|^{|m~|{}w~|Wu~Vw~}{|m~|Tu~ E{|}p~}|V{|}p~}|V" - "{|}p~}|V{|}p~}|V{|}p~}|Qw~}Lu~| i{}y~| q{|w~}M{|w~}K{|}I{|}Uw~}kw~}Y{|y}w~y}|Yv~|m{}w~|X{}u~|Q{|}e~} *{|}p~" - "}|!v~}#w~t{|w~Py|x}y~x}y|[w~|j{}r~|e{|n~}|t{}u~){|w~|N{|w~| s{}w~Lv~ t{|v~|R{|w~|L{|}p~|Y{|e~|ab~`y|}l~}|K{}w~}" - "]{|}k~|S{}o~|Vv~}N{|m~}Z{}n~}|O{}v~Mv~ h{}w~}[v~L{|v~|d{|v~|g{}k~y}y|T{|}m~}|c{}m~x}y|W{}c~}`{}w~}J{|}k~}|c{}w" - "~}hv~|Y{}w~}M{}w~}W{}w~}it~c{}d~}i{}w~|bv~|h{}w~|k{|t~_{|m~}|[{}w~}J{|l~|]{}w~}h{}w~}c{|}k~}|T{|v~R{|}m~|S{}v~}" - "Z{|u~|kt~gv~}f{}v~[{|v~|[{}\\~}^{|w~}Cw~|O{|w~| q{}p~}x{}w~|_v}vy}w~y}|S{}m~}Xy}w~y}|w{|w}|[{|l~}|Vw~}N{|}w~y}" - "|w{}w~|`v}lw}|Wv~Lv~Tv}m{|u}Yv}_w~}mv~mv~hw~}m{|w~}\\{|n~|Zw~}x{}q~}W{}q~}|y{|w~|Zw~}Q{|}l~}P{|y}s~X{}q~}x{}w~|" - "X{}u~}X{|u~o{}v~|b{}w~}kv~}X{}w~}V{}d~Uv~Lw~|M{|w~| n{|}q~}u{|}w~bv~{}o~}|X{|r~|R{|}p~}|U{}l~}|^w~}m{|w~}W{}w~" - "}Xw}|i{|w}b{|w~|{|q~|y{|t~f{|q~|v{|q~|^{|l~}[{|w~}os~]{|}o~}|[w~}x{}q~}W{|}p~}|M{|}v~}W{|p~|`{|X~|e{}c~}_{}w~}V" - "k~v{}l~|^{|v~Y{}w~}hv~|Z{|v~R{|m~}| y{}w~ rx~| s{|x~} sv~}P{|}n~}|`{}b~}#{|w~}Lw~|Ty|pv~|\"y|}u~}y| 9y|}u~}y| " - "R{|Z~} ${|w~|{|q~|y{|t~Xx~}w{|x~} y}| q{}x~}aw}j{|w~kk~l{}x~}aw}gv~}U{|v~|d{|v~|l{|v~|d{|v~|l{|v~|d{|v~|l{|v~|" - "d{|v~|l{|v~|d{|v~|l{|v}bv}|t{}w~}j{|b~c{|}m~}|_{}c~}a{}c~}a{}c~}a{}c~}X{}w~}M{}w~}M{}w~}M{}w~}Z{|m~x}y|Z{}w~|k{" - "|t~_{|m~}|X{|m~}|X{|m~}|X{|m~}|X{|m~}|.w~}v{|}n~}|X{|}m~|X{|}m~|X{|}m~|X{|}m~|S{|v~|V{}w~}Mv|wy|}u~y}|Z{}p~}x{}" - "w~|]{}p~}x{}w~|]{}p~}x{}w~|]{}p~}x{}w~|]{}p~}x{}w~|]{}p~}x{}w~|g{}o~|r{|l~}|a{}m~}Y{|l~}|Y{|l~}|Y{|l~}|Y{|l~}|U" - "v~Lv~Lv~Lv~O{|y}v~y}|Xw~}m{|w~}\\{|n~|V{|n~|V{|n~|V{|n~|V{|n~|(w~|{|n~|V{}q~}x{}w~|\\{}q~}x{}w~|\\{}q~}x{}w~|\\" - "{}q~}x{}w~|W{}w~}Vw~}x{}q~}R{}w~} B{|t}|P{|t}|P{|t}|P{|t}|P{|t}|Nw~} 3{|~} ;f| '{|y}w~}y| 8{|y~|X{|x~}" - "h{|}w~}|ay|y}w~y}| rw~}N{}w~ ?{|w~| D{}w~I{|y}w~y}|%b|\\{|x}u~y}|!y|y}u~y}y|O{|y}w~y}| {{y|}u~y}|Vy|y}v~}y| u{|" - "w~| B{|v~| 1{|y}u~y}| o{|x}u~y}y| Fv~| 7y|y}v~y}| {{y|y}q~|#y|y}u~y}y| {{|y}v~y}y| a{|w~}C{}x~}O{|w~| oy}" - "v~}|vv|!{|}t~y}|!{|y}t~y}|Sv|Av~\"v|Lv~ Rv|mv|mv|hv|lv|Z{|y}u~}|Xw~}v{|}w~y}|T{|}w~y}|w{|w~|Zv|Ny|y}u~y}| {{|y}" - "w~}|uw|W{|u}|Wv}|o{|v}av|ju|Xv~| sv~Lw~|M{}w~| ly|}v~}|Uv~yy|}v~y}|S{|y}~y}|N{|y}v~y}|Qy|y}v~x}|[v|m{|w~}W{|w~" - "|#{|w~|x{|}w~}|v{|}y~y}c{|y}x~y}ry}x~y}|Z{|y}s~}y|G{}w~}|Zy|v~}|Ww~}v{|}w~y}|T{|y}v~y}| x{|y}w~}| Ry|y}v~y}|" - " Zy| rv~}M{|y}u~}|]`| Iw~|T{|y~}|u{|u~ 5{|w~|x{|}w~}|v{|}x~}Wx~}w{|x~} {}y~} r{|y}|Kw~|L{|y}|Hv~| E" - "{|y}u~y}| qy|y}v~y}|Sy|y}v~y}|Sy|y}v~y}|Sy|y}v~y}|Sy|y}v~y}|+{|y~}r{|y}v~y}|R{|y}v~y}y|S{|y}v~y}y|S{|y}v~y" - "}y|S{|y}v~y}y| oy}v~}|vv|Zy}v~}|vv|Zy}v~}|vv|Zy}v~}|vv|Zy}v~}|vv|Zy}v~}|vv|d{|}v~y}|n{|y}u~y}y|\\{|}t~y}|U{|y}" - "t~y}|T{|y}t~y}|T{|y}t~y}|T{|y}t~y}|Rv|Lv|Lv|Lv|!v|lv|Z{|y}u~}|R{|y}u~}|R{|y}u~}|R{|y}u~}|R{|y}u~}|'{}x~|w{|y}u~" - "}|S{|y}w~}|uw|Z{|y}w~}|uw|Z{|y}w~}|uw|Z{|y}w~}|uw|Vv~|Vw~}v{|}w~y}|Qv~| Mw~| K{|y~| e{|w~Nw~" - "| ?{}w~ Cw~} .{}w~ @{|v~|d{}| Kv~| !u~| J{|w~}C{|w~O{|w~| 9w~} Iv~ bw~}9{|w~| X{|v~ rv" - "~Lw~|M{}w~| w~| D{|w~| .w~| ?{|v~}g{|x~| M{|v~ {|u~| K{|w~}Bw~|P{|w~| :{}w~} Iw~} bw~}9{" - "|w~| X{}w~| r{}w~|Mw~|Mv~ ;v~ S{|w~}W{|w~|#{|w~| j{}w~ s{}w~Uw~} )v~}Iy~} gw~|T{|l~| 4{|w~" - "|Ax~}w{|x~} {{}y~} /v~| ?x~| f{|x~ M{} %{}w~|Uw~}D{}w~| Lw~| K" - "{|y~| d{|w~Pw~| ?{|w~ C{}w~ .{|w~ ={|u~}|l{|u~| N{}v~ {{|u~| L{|q~}H{}x~}V{}q~| :v~| Iw~}" - " bw~}9{|w~| Xv~ q{}w~}Mw~|N{|v~ ;v~ S{|w~}W{|w~|#{|w~| j{}w~ s{}w~Uw~} )v~}Iy~} gw~|T{|}o~}| " - " 3{|w~|Ax~}w{|x~} {{|x~| 0v~}m{} N{|x~ e{}y~} Rv~Tw~}Dv~ S{}x~x{|w~| " - " K{|y~| c{}x~}R{}x~} >{|x~| Cw~} .{|x~| ;{}t~}|sy|}t~| N{|v~} y{|u~| M{|q~}H{|w~V" - "{}q~| ;{}v~ I{|w~} bw~}9{|w~| Y{}w~} q{|v~}|Ow~|P{|}v~} ;v~ S{|w~}W{|w~|#{|w~| j{}w~ s{}w~Uw~} " - " )v~}Iy~} gw~|Q{|y}v~y}| 1{|w~|Ax~}w{|x~} yx~| 0{}v~|p{|~} N{|x~| f{|x~ " - " S{}w~}Tw~}E{}w~} S{}x~|y{|w~ J{|y~| bw~|Sw~| >{}y~} K{}y~} 9{|p~x}q~}| N{|u~" - "| x{|u~ M{|q~} y{}q~| K{|}|p{|u~| I{}w~| bw~}9{|w~| Z{|v~ o{}q~}Tw~|U{|p~ :v~ S{|w~}W{|w~|#{|" - "w~| j{}w~ s{}w~Uw~} )v~}Iy~} gw~| W{|w~|Aw|vx| y{|x~} 0{|u~|s{}x~} N{|x~| " - " f{|x~| U{|v~Sw~}F{|v~ R{|x~}y{}w~ J{|y~| b{|x}|T{|x}| w{}g~}| Q" - "x|y}u~} v{|u~ N{|p} yp}| K{|x~}y|wy|}u~} J{|}v~ aw~}9{|w~| \\{|}v~} nq~}Tw~|U{|q~| :v~ S{|w~}" - "W{|w~|#{|w~| j{}w~ s{}w~Uw~} )v~}Iy~} gw~| W{|w~| :{|}w|}w~| /t~y}x|y}v~} U{|}|x{|w~| " - " f{}x~| W{|}v~}Sw~}H{|}v~} Qq~| J{|y} *{|}l~}| O{}q" - "~ tt| `{|i~} Lr~| aw~}9{|w~| `{}q~ l{}s~}Tw~|U{|s~}| 9v~ S{|w~}W{|w~|#{|w~| j{}w~ s{}w~Uw~" - "} )v~}Iy~} gw~| W{|w~| :{|q~ .{|i~} U{|q~ ly}w|}w~| [{}q~Rw~}" - "L{}q~ P{}r~ M{|y}u~y}y| L{}r~| R{|j~} Ks~} `w~}9{|w~| " - " `{}r~| jy|v}|Tw~|U{|u}| 6v~ S{|w~}W{|w~|#{|w~| j{}w~ s{}w~Uw~} )v~}Iy}| gw~| W{|w~| :{|r~| " - " -{|k~}| U{|r~} l{}r~} Z{}r~|Rw~}L{}r~| O{}t~ " - " k{}t~} -{|`}| `{|}m~}| Jt~} _w~}9{|w~| `{}s~| :w~| cv~ S{|w~}W{|w~|#{|w~| j{}w~ s{}" - "w~Uw~} )v~} d{|w~| 9y}w~y} ){}o~}| S{|}u~}| k{}r~ Y{}s~|Qw~" - "}L{}s~| M{}w~} j{}w~}| +{}`~} ]{|x}v~y}| Gw~y} ]w~}9{|w~" - "| `{}v~}| 8w~| cv~ S{|w~}W{|w~|#{|w~| j{}w~ s{}w~Uw~} g{|w~| 8{|}v~y}| Ly| " - " g{|y}w~}| X{}v~}|Ow~}L{}v~}| Iy| " - "l{}`~} Ww~| " - " L{}`~} Ww}| " - " r{" }; - - // Define a 104x128 binary font (huge sans). - static const char *const data_font_huge[] = { - " " - " " - " " - " " - " " - " " - " " - " " - " FY AY " - "'Z ;W @Y @Y 'Z Y @Y (Z :Y ?Y (Z 0Y ?Y (Z >X " - " " - " " - " " - " " - " )X AX '\\ )XAV 7YDY -] BY BY '[ +YEY 2X AY (\\ -YDY 'XAU 3Y AY (\\ )XAV 8YD" - "Y LY AY (\\ ,YEY #Y " - " " - " " - " " - " (X CX '^ +[CU 6ZEY .` C" - "X CY '] -ZEZ 2X CY (^ .ZEZ )[CU 2Y CY (] *[CU 7ZEZ LY CY (] -ZEZ %Y " - " " - " " - " " - " " - " 'Y EY '^ ,^FV 6ZEY /b CX DX '_ .ZEZ 2Y DX '_ /ZEZ +_FV 1X CX (_ ,^FV 7ZEZ " - " KX CX (_ .ZEZ &Y " - " " - " " - " " - " %Y GY '` .aHV 6ZEY 1e DY FX" - " 'a /ZEZ 1Y FX '` /ZEZ +aHV 0X EX '` .aHV 7ZEZ JX EX (a /ZEZ &X " - " " - " " - " " - " " - " #X GX 'XNX 0dKW 6ZEY 1f DY HX &WMX 0ZEZ 0X GX 'XMW 0ZEZ ,dLX /X GX 'WMX 0dLX 7ZEZ" - " IX GX 'WMX 0ZEZ 'X :T " - " " - " " - " " - " ;X IX 'XLX 1o 5ZEY 2ZLY " - " CX IX &WKW 0ZEZ /X HX (XLX 1ZEZ ,o .Y HX (WKX 1o 6ZEZ IY IY (WKW 0ZEZ (X X MX &WH" - "W 3VHa 4ZEY 3WDW CX LX 'WGW 2ZEZ -X LX 'WHW 2ZEZ -VHa +X KX (XHW 3VHa 5ZEZ GX KX (WGW 2ZEZ )X " - " ?b " - " " - " " - " " - " ?W MW &WFW 4VF^ 3ZEY 4WBV BW MX 'WEW 3ZEZ ,W M" - "X 'WFW 3ZEZ -VF^ )X MX 'WFW 4VF^ 4ZEZ FX MX 'WFW 3ZEZ *X ?d " - " " - " " - " " - " " - " ?W X 'WDW 5UC[ 2ZEY 4VAV AW X &WDW 4ZEZ +W NW 'WDW 4ZEZ -UC[ 'W MW 'WDW 5UC[ 3ZEZ " - "EW MW 'WDW 4ZEZ +X ?f " - " " - " " - " " - " @X \"X 'WBW 6UAW 0ZEY 4V@V B" - "X !W &WBV 4ZEZ +X !W 'WBW 5ZEZ .VAW $W W 'WBW 6UAW 1ZEZ DW W 'WBV 4ZEZ +W >f " - " " - " " - " " - " " - " ?X #W 'W@W U?V AX #W &W@V NX #W &V@W 9W \"W 'W@V .W " - "\"W 'W@V !W >XHX " - " 3Y " - " " - " " - " 6W $W &V>V U?V @W $W &W>V " - " NW $X 'V>V 8W $X (W>V /X $W 'W>V #W >XFX " - " 5Z " - " " - " ,Z " - " GZ " - " #U?V NY 7Z ,X CVCW MY " - " 7Z ,X $Z 7Z ,X >Z 6Y ,X 4Z 7Y +W 7Y @Z " - " " - " +Z " - " " - " HY \"U?V " - " MY 8Y ,Y CVBV LY 9Z ,Y #Z 9Z ,Z >Z 8Y ,Y 3Y 8Z ,Y 9Y " - " ?Z " - " *Y " - " " - " IY !U?V " - " LY :Y ,[ $R>U ,V@V MZ :Y +Z #Y 9Y +Z ?R" - ">U 8Y 9Y +Z %S?U HY :Z ,[ ;Y ?[ " - " " - " )Y " - " 8U " - " 9Y V@U JY Y @Y /X 0Y K` .X " - " ^ =ZEY @Y " - " NVAV

Y E^ /X 0_ %f 1] 'c " - " @ZEZ AY MV" - "CW X *^ +]DU 7ZEZ 5U>U JY ?Y *^ -YEZ 4Y " - " ?Y *^ .ZEZ 5[ ]DU 5Y >Y +^ ,]DU 6ZEZ Y ?Y +_ .ZEZ \"Y Z G[ G\\ @e !f JX !Y " - "LY %d :Y Y Ha /X 0b *j L] D_ " - " +g A[ LY 8Z -ZEZ \"Y 1o )V FX NZ FY " - "%Y ,X NX*Z NW 3WEW H\\ #[ !Z \"[ \"[ \"[ G[7T 8g 0Y " - "@Y +_ ,_FV 7ZEZ 5U>U IY @Y +` .YEZ 3X ?X *` /ZEZ 4[:P 8_FV 4X ?Y +` ._EU 6ZEZ NX @Y *_ .ZEZ #Y ;Y" - " FYEZ ;] GU W ,X " - " FV a \"d -g >d (d +b %b 4f Bg Ie \"e \"h " - " Ge !f IX \"Y LY &e :Y Y Jc /X 0c " - " -n $g I` .j >a ;e HU .U +b Ac 2ZEZ 'b " - " 5o -] Na (c KY .Y #_ 8Y!W'Y\"X.c$X 3XGX Mf -e +d " - ",e ,e ,e \"e=V ;k 1Y BY +XNW .aGV 7ZEZ 5V@V HX AY +XNW .YEZ 3Y AY *WNW /ZEZ 4\\>T 9`GV 3" - "X AY +XNW .`GV 6ZEZ NY AX *XNW /ZEZ $Y :Y FYEZ <_ IU (Q LZ 4Z2Z 1Q " - " &g %Z +XCX MT Y Kd /X 0e 0p " - " (m Lb 1m ,\\ 5~S E~R Ah 'Z :~]+[;Z;Z Ik LW DX DW /i ?Y(Y 4h 5ZEZ" - " ,\\ ,h 7\\ -o .` $f -h NY No %_ %c @_\"X-_\"W0h&W .\\ $\\ \"\\ #\\ #\\ )g 5~a Lm D~S I~S " - "H~R H~R 6Z !Z !Z \"Z :r 8^,Y Bk 2k 2k 2k 2k (kAX+Z(Z#Z(Z$Z(Z$Y'Y&[%[ MZ Im 1X CY *WMX /bHV 7ZEZ 5V@V G" - "X CY *WLW /YEZ 2Y CY *WLW 0ZEZ 3[AW :bHV 3Y BX *WLW 0bHV 6ZEZ MY CX *XMX 0ZEZ $X 9Y FYEZ " - " =a M~i 7U (Q N_ 9_8_ 3R )k 'Z +XCX +X@X 4T >e,X Cl &X IX *X GV " - " GX 5i 0d 2p ;u !^ ?y 2o F~S @n 4j /l N\\ 8x .r Nx 7~R E} >t KZ(Z :Z \"Z 4Z-] KZ 2_'_(^-Z" - " Ep =t 5o Au 1u N~d'Z(Z)Z MZY " - " Le /X 0e 1r +r c 3o -\\ 5~S E~R Dn *Z :~]+[;Z;Z Ko " - " Y EX EY 2m @Y)Y 6l 7ZEZ 0e 2k >e 1o 0c 'j /i X !r (b 'g Eb\"W0c#X0i(W -" - "\\ $] #\\ $] #\\ (f 6~b r F~S I~S H~R H~R 6Z !Z !Z \"Z :w =^,Y Ep 6p 7p 7o 7p ,oDY+Z(Z#Z(Z$Z(Z$Y'Y%Z%Z LZ Kp" - " 1X DX *WKW /WMYJV 6ZEZ 5V@V GY EY *WKX 0YEZ 1Y EY *XKW 1ZEZ 2[EZ :WMZKV 1Y DX *WKX 1WLYKW 6ZEZ L" - "Y EY *WKW 0ZEZ %X 8Y FYEZ >c M~h 7T (S !a Y >X 8f /X 0f 3t -s c " - " 4q /^ 6~S E~R Fr ,Z :~]+[;Z;Z Ms #[ FX F[ 4n @Y*Y 6m 7ZEZ 3k 5l Bk 4o 1f )k 0k #" - "X #u (b (i Fb#X0c#W/k+X .^ %] $^ %] $^ (d 5~b\"v H~S I~S H~R H~R 6Z !Z !Z \"Z :{ A_-Y Gt :t ;t ;s ;t " - " 0sGY*Z(Z#Z(Z$Z(Z$Y'Y$Z'[ LZ Ls 2X FX *WIW 1WJc 6ZEZ 4VBV EY FX *XJW 0YEZ 0X EX )WJW 1ZEZ 1[I^ x %_ ?y 5r F~S Ct :p" - " 6s /e *^ 9| 6z#~ =~R E} B}!Z(Z :Z \"Z 4Z/\\ HZ 2`)`(_.Z Iw @y >w Ez 9z!~d'Z(Z)[ Z;Z0]/Z4Z,Z$[(Z%~^ " - "@e 2X Gf +a MX %Y LY *i :Y Y >Y 9f /X 0g 5v " - " 0u d 6_K_ 0^ 6~S E~R Gu .Z :~]+[;Z;Z w &] GX G] 6U &o ?Y+Y 7X )n 7ZEZ " - "6p 7m Eo 6o 2h *l 1l %X #v (b )k Gb$X/c$X/l,W -^ &_ %^ &_ %^ 'b 4~b$z J~S I~S H~R H~R 6Z !Z " - "!Z \"Z :~ D_-Y Hw =v >w >w >w 4wIX)Z(Z#Z(Z$Z(Z$Y'Y$[)[ KZ Mt 1X HX )WHW 2VHb 6ZEZ 4WDW DX GX )WHW 1YE" - "Z /X GX )WHW 2ZEZ 0[M` ;VHb /X GY *WHW 3VHb 5ZEZ JX GX )WHW 2ZEZ 'Y 7Y FYEZ ?e M~f " - " 7U )U %g Bh@g :W .~T 't +Z +XCX ,X@X 3T Ak1X Er (X JX 'X IV HX 8q" - " =m 7y ?y '` ?y 6s F~S Dv Y >Y " - " :] %X &] 5]C\\ 1v Nc 7\\D\\ 1_ 6~S E~R Iy 0Z :~]+[;Z;Z!y (_ H" - "X H_ 7U 'p ?Y,Y 6X *o 7ZEZ 8t 9YH] Ht 9o 3i *XG[ 1VE[ &Y %x (b *[I[ Hb$W.c%X.VE[-X " - " ._ &_ %_ '_ %_ '` 4~c%} L~S I~S H~R H~R 6Z !Z !Z \"Z :~Q F`.Y Jz @z Az Ay Az 7zKX(Z(Z#Z(Z$Z(Z$Y'Y#[*Z JZ Na" - "J_ 2X IX )WGW 2VG` 5ZEZ 4XFX CX IX )WFW 2YEZ .X IX )WFW 3ZEZ /j 8VG` -X HX *WFW 4VG` 4ZEZ IX IX " - ")WGW 2ZEZ 'X 6Y FYEZ ?XKX M~f 7T )W 'i DiAi ;X 1~V (w -Z " - "+XCX ,X@X 3T AZI[2W Es (X KX &X IV HX 9s >m 7z @z )a ?y 7t F~R Dx >t 9v 8s 2` :~P <~Q&~S" - " A~R E} E~T$Z(Z :Z \"Z 4Z2] FZ 2a+a(`/Z K| C{ C} H| =|!~d'Z(Z(Z!Z9Z1^1Z2[0[!Z+[$~^ @X $X ;Y -e MX 'Y " - "LY +[ +Y Y >Y :[ #X #Z 6\\?[ 2v F\\ " - " 8Z@[ 2` 7~S E~R J{ 1Z :~]+[;Z;Z#} +` HX Ia 8U (q >Y-Y 6X +p 7ZEZ 9bMb ;U@Y JbMb :" - "n 3ZIZ +T@Y 2R>Y 'X %y (XLV +ZEZ IXMW%X.YMW%W-R>Y.W -` '_ &` '_ &` '` 4~c'~R N~S I~S H~R H~R 6Z !Z " - "!Z \"Z :~S Ha/Y K| B| C| D} D| 9|MX'Z(Z#Z(Z$Z(Z$Y'Y\"Z+[ JZ N]B\\ 2X JX *WEW 3UE_ 5ZEZ 3YJY AX JW )WE" - "W 2YEZ -X KX (WFW 3ZEZ .f 5UE_ ,X JX )WFW 4VF_ 4ZEZ HX KX )WEW 3ZEZ (X 5Y FYEZ @YJW M~" - "e 7U *X (j EkCk =Y 3~X )x -Z +XCX ,W?X 3T BYEY3X Ft (X KX %X JV " - " IX 9u ?m 7{ A{ *a ?y 8u F~R Ez @v :v :w 4` :~Q >~S'~U C~R E} G~V$Z(Z :Z \"Z 4Z3] EZ 2a+a(a0Z M~P D" - "| E~P I} ?}!~d'Z(Z'Z\"Z9Z1^1Z1Z0Z [,Z#~^ @X $X ;Y .g MW 'Y LY +Y )Y Y " - " >Y :Z \"X \"Z 7[=Z 3aE[ E[ 9Z>[ 3` 7~S E~R L~ 2Z :~]+[;Z;Z$" - "~P -b IX Jc 9U )r >Y.Y 5X ,]DX 7ZEZ ;\\>\\ \\ 0XDX ,R=Y MX (X %hEW (SG" - "V ,YAY JSHW%W-SGW&X GX/W ,` (a '` (a '` (a 5~d(~S N~S I~S H~R H~R 6Z !Z !Z \"Z :~T Ia/Y L~P F~P F~P F~P F~P" - " <~X&Z(Z#Z(Z$Z(Z$Y'Y\"[-[ IZ \\>Z 1X LX )VCW 4UD] 4ZEZ 2f ?X LX )WDW 3YEZ ,W KX )WDW 4ZEZ -b 2UD] *W" - " KX )WDW 5UD] 3ZEZ GW LX (VCW 4ZEZ )X 4Y FYEZ @XIX M~d 7U *Y *l GmDl ?[ " - " 6~Z *`C\\ -Z +XCX ,W?W 2T CYCY5X E]CZ (X LX $X JV IX 9]E^ @m 7aGb B^Ec ,b ?y " - "9aF[ F~R E_C_ B_E^ ;]E_ ={ 7b ;~R @cBb'~V D~R E} HeBc$Z(Z :Z \"Z 4Z4] DZ 2b-b(a0Z NbCb E} GbCb J~ Aa" - "B_!~d'Z(Z'Z#[9Z2_1Z0Z2[ N[.Z\"~^ @X $X ;Y /i MW (Y LY ,Y (Y Y >Y " - " :Y !X !Y 8[;Z 1\\ 0\\:U D[ ;ZbCh%Z(Z" - "#Z(Z$Z(Z$Y'Y![.Z HZ Z;Z 1X NX )WBV 5VBZ $e >W MX )WBW !X MX )WBW #` /UBZ (W MX )WBW 6UBZ " - " 9X MW (WCW MX 3Y GXHW M~d 8U *[ +m HnFn A] 9~\\ +^=Y" - " -Z +XCX -X@X 2U DXAX5W E\\=V (X LX #X .R@V?Q ,X :\\A\\ @m 7\\>_ CY<_ -c ?y :^=V F~Q E]>^ D]@] " - " j E~R E| Ha8^$Z(Z :Z \"Z 4Z5] CZ 2b-b(b1Z `<_ FZ@d I`=` K[@d C_:Z ~b&Z(Z'Z#Z8Z2`" - "2Z0[4[ LZ/[\"~^ @X #X Y >Y ;Z " - "!X !Y 8Z9Y 6d 4[5R CZ ;Y:Z 5b 8~R D~Q MbAb 8` =~]+[;Z;Z&`=` 1f KX Lg " - " ;U *\\=T =Y0Y 4X ,Z;R 5Z3Y &W !Y3Y 3W@W EW LX *W %jEW KV -X=X @W'X W'X EX1W ,b " - "*b (b )b )b )b 7ZH~R)a:] N~R H~R G~R H~R 6Z !Z !Z \"Z :Z>j Lb0Y N_<` J`<_ J`=` J`=` J`=` @`=e%Z(Z#Z(Z$Z(Z$Y'Y" - " Z/[ HZ !Z9Y 0W X )WAW 6VAW \"d Y >Y ;Y X !Y " - " 8Y8Y 6f 6Z2P BY j BZ(Z+[;Z;Z'_9_ 3h LX Mi <" - "U *[:R V EW KW +W %kEW KV .X;W @W'W NW(X CW2X -c *c )b " - "*c )c +c 7ZHZ 2_5[ NZ !Z Z !Z >Z !Z !Z \"Z :Z7d Mc1Y ^8_ K^8^ L_8^ L_9_ L^8_ B_9b$Z(Z#Z(Z$Z(Z$Y'Y [1[ GZ !Z" - "8Y 0W !W (V?W I` :X !W (V?W X \"X (W@W *d EX !W (W@W 0X \"X (V?W !W 1Y #d ," - "e +d +d ,e #XHW LZ#Z 7U +] -o KqHp C_ X #X " - " Y >Y ;Y X X 9Z7X 6g 7Y" - " #Z =Y8Z 7d 7[ Z )_7_ Bp EZ(Z+[;Z;Z(^5^ 5j MX Nk =U +[7P Z !Z !Z \"Z :Z3a Nc1Y!^5] L]4] N^5^ N^5^ N^5] C^5_#Z(Z#Z(Z$Z(Z$Y'Y N[2Z FZ \"Z7Y /W #W (W>V H^" - " 8X #W (W>V NW \"W (W>W .h EW \"X )W>W 0W #X (V=V \"W 0Y &j 1i 0j 1j 1i &X ` .\\5U -Z +XCX -W?W =r'X>W8X EZ ;X NY !X 1XDVDX 2X " - " &X ;[;[ BWDZ 7T2\\ \"\\ 1XMZ ?Y L\\ 2Z E[7[ G\\9[ >S5[ F`7` ?YNY Y >Y ;Y X Y :Y6Y 7i 9Y \"Y " - " >Y6Y 7YNY 6[ !Z *^3] Dt GZ(Z+[;Z;Z)]2] 6l NX m >U +Z !Y4Z 3X -Y NW(W (W " - " &X)X 8VZ !Z !Z \"Z :Z1` d2Y\"]2] N]2] ]2]!^2]!]2] E]2]\"Z(Z#Z(Z$Z(Z$Y'Y MZ3[ FZ \"Z6X .V $W 'VR4[ G^1^ AZNY Y >Y ;Y X Y :Y6Y 7j :Y \"Y " - " >Y6Z 9YMY 5[ \"Z *]1] Hy IZ(Z+[;Z;Z)\\/\\ 8n X !o ?U ,[ Y5Y 2X -Y W&W )W 'W%W 9V" - "Z " - "!Z !Z \"Z :Z/_!d2Y#]0]!]0]\"]0\\!\\/\\\"]0] F\\0]#Z(Z#Z(Z$Z(Z$Y'Y M[5[ EZ \"Y5X +P " - " %_K[ CY *r 9q 8r 9r 9q *X ;Z%Z >Q JT ,b 0q MsKs Ge " - "C^ *[0R -Z +XCX .X@X @v)X=X:W CY :X Y NX 1[HVH[ 1X 'X ;Z7Z 0Z 7P,[ ![ 3XLZ ?Y M[" - " 1Z EZ4[ I[5Z ?P1Z I^-] BYLY =Z1[ H\\(T'Z-^ JZ MZ *\\$S$Z(Z :Z \"Z 4Z:] >Z 2YMX1XMY(YNZ4Z$].\\ JZ5" - "\\!\\-\\ Z4[ GZ ;Y 9Z(Z%Z'Z4Z5XNX5Z*Z:[ F[6Z [ ;X \"X =Y 5\\C[ #Y LY -Y 'Y 8X >Y " - " >Y ;Y X Y :Y6Y 7k ;Y \"Z @Z5Y 9YLY 5[ #Z +\\.] J| KZ" - "(Z+[;Z;Z*\\-\\ :p !X \"q @U ,Z NY6Y 1X -X W#V *W (W#W :U;V +X DW LW )mEW KV" - " /X9X BW*X LW*X BW3W +YLY -YMY ,YLY -YMY ,YLY -YMZ ;ZFZ 5\\'S NZ !Z Z !Z >Z !Z !Z \"Z :Z-^\"e3Y#\\.]#].\\" - "#\\-\\#\\-\\#\\-\\ H\\.]$Z(Z#Z(Z$Z(Z$Y'Y L[6Z DZ \"Y5Y /[G[ " - " DY +u =u S LU ,c 1q MtLt Hf E] )[.Q " - " -Z +XCX .W?X Bx)X=X;X DZ :X X MY 0ZIVIZ /X 'X ;Z7[ 1Z AZ ![ 4XKZ ?Y MZ 0Z EZ3Z I[5Z " - "Z J])\\ CYLY =Z1[ I\\%R'Z+] KZ MZ +\\\"R$Z(Z :Z \"Z 4Z;] =Z 2YMX1XMY(YNZ4Z$\\,\\ KZ4[\"\\+[ Z4\\ I[ ;Y 9Z(Z$Z" - "(Z4Z5WLW5Z*[<[ DZ7[ !\\ ;X \"X =Y 6\\A[ $Y LY -Y 'Y 8X >Y >Y " - " ;Y X Y :Y6Y 7l Z !Z !Z \"Z :Z,^#YNZ3Y$\\,\\#\\,\\$\\,\\%\\+\\%\\,\\ MP" - " NP N\\-]$Z(Z#Z(Z$Z(Z$Y'Y KZ7[ Dq :Z4X /XC[ EY " - " -x @x >x ?x @x -X :Z'Z ?U MU -e 2q MtLt Ig E[ 'Z,P -Z +XCX .W?W By)" - "XZ0Z" - " J\\#Q'Z*\\ KZ MZ +[ Q$Z(Z :Z \"Z 4Z<] Y 7[>[ %Y LY -Y 'Y 8X >Y >Y ;Y X Y ;Y" - "5Y 7UH_ Z !Z !Z \"Z :Z+]#YMZ4Y%\\*\\%\\*\\&\\*[%[)[%[*\\ R!R [-_%Z(Z#Z" - "(Z$Z(Z$Y'Y K[9[ Ct =Y3X /U@[ \"Q EY .z B{ " - "B{ Az B{ /X :Z'Y >V U -g 4r NvNu Ji *\\ 5X.X 6\\ 7Z1Z M[ '[ 8Z +XCX /X@X C`MTL_)W;" - "WZ0Z " - "J[ 'Z)\\ LZ MZ ,\\ \"Z(Z :Z \"Z 4Z=] ;Z 2YLX3XLY(YMZ5Z%[([ LZ3[$\\)\\\"Z3[ IZ :Y 9Z(Z$Z)Z3Z6XLX6Z(Z>[ B[:Z !" - "\\ 9X !X >Y 8[<[ &Y LY -Y 'Y 8X >Y >Y ;Y X Y ;Y5Y " - "7RB] =\\ $Z BY2Y ;YJY 3[ &Z -[(\\!~U Z(Z+[;Z;Z,\\)\\ ?\\MXL[ $X %\\LXM\\ CU" - " ,Y *Q\"R DY9Y 0X -Y #V=_?V Cm *V LV Z !Z !Z \"Z :Z*]$YMZ4Y%[([%[(['\\)\\'\\)\\'\\)[!T#T\"\\-`&Z(Z#Z(" - "Z$Z(Z$Y'Y J[:Z Bw @Y6[ .Q<[ #S GY /`Da E`C" - "` DaD` C`Da E`C` 0X 9Y(Z ?X !U .h 4r NvNu Kk .c 9X.X 7^ 7Y1Y M[ &Z 7Z +XCX /X@X C\\" - "ITFY)W;W=X BY 9X !X KY +YNVNZ *X (X ;Z4Z 2Z @Z !Z 6YJZ ?Y Z /Z DY2Z JZ1Y ,T T MZ N[ NZ HZJ" - "Y >Z0Z K[ &Z(\\ MZ MZ ,[ !Z(Z :Z \"Z 4Z>] :Z 2YLX3XLY(YLZ6Z&['\\ MZ3[$['[\"Z2Z IZ :Y 9Z(Z#Z*Z2Z7XLX7Z'[@[ @Z;" - "[ ![ 8X !X >Y 9[:[ 'Y LY -Y 'Y 8X >Y >Y ;Y X Y ;Y" - "5Y %\\ =] %Y BY2Z =ZJY 3\\ 'Z .\\'[#cLZLb!Z(Z+[;Z;Z,['[ @\\LXK[ %X &\\KXL\\ " - " DU -Z +S$T EY:Y /X -Z %V?fBU Eo +VEg=V =VZ !Z !Z \"Z :Z)\\$YLZ5Y&\\'['['\\(['['['['['[#V%V#[-a&Z(Z#Z(Z$" - "Z(Z$Y'Y IZ;Z Ay BY9^ G[ %U HY 0]<^ G^=^ F" - "^<] E]<^ G^=^ 1X 9Z)Z @Z \"U .i 5r NvNu Lm 2h ;X.X 7^ 7Y1Y N[ &[ 7Z +XCX /W?X D[GTC" - "V)W;W=W AZ :X \"Y KY *j (X (X ZY .Y3Y 3Z '\\ MZ )Z ;Z 2^ +Y ;Y " - "X Y 6Y /Y5Y $[ =` G^ !Z IZ M\\ #Y2Z =YIZ 3\\ (Z .[%[%aIZI`\"Z(Z+[;Z;Z-[%[ B\\KXJ[" - " &X '\\JXK\\ H\\ 1Z ,U&V EY;Y /X ,Z 'V@jDV Gp +UDj?V >VZ !Z !Z \"Z :Z(\\%YLZ5Y&[&['[&[)\\&[)[%[)" - "[&[$X'X%[-b&Z(Z#Z(Z$Z(Z$Y'Y I[=[ Az CY;` 5\\ $] $\\ \"\\ #\\ $] 8\\/[ 3\\ '\\ #\\ \"[ \"[ \"[ &Z &[ ![" - " #\\ #[ ![ G[@W IYBZ J]8] I\\7\\ H]8] I]8] I\\7\\ 2X 8Y*Z @Z \"U .k 5q N~o Mm 4l =X" - ".X 7^ 7Z3Z NZ %Z 6Z +XCX /W?W D[FT@S)W;W>X AZ :X \"Y JX (f &X )X ;Z3Z 2Z @Z !Z 7" - "XHZ ?Y !Z /Z CY1Y JZ1Z 2Y Y $Z Z HY JYHY ?Z/Y L[ %Z'\\ NZ MZ -[ Z(Z :Z \"Z 4Z@\\ 7Z 2YKX5XKY(YKZ7Z'[" - "$[ NZ2Z%[%[#Z2[ JZ :Y 9Z(Z#[,Z1Z8XJW7Z%ZB[ >[>Z !\\ 7X X ?Y ;[6[ (e 7YE` (e 3aEY 8c 2r 5`DX GYEa (X NX " - "0X1Z 8Y FXD`9` YD` -c 9XD` /aEX :XD] 6g 7t BX0Y LY)Y+X6Z6X)Z/Z NX)Y I} 2Y X Y 9_>W KY5Y #[ =c h >XD` " - "AT#X 5Y 6X0X LY'Y ?RCW ?~Y!X?X?X ;d 'r!~W KZ1Y =YHY 2\\ )Z /[$[%_GZG_#Z(Z+[;Z;Z-[%[ C\\JXI[ 'X (\\IXJ\\ " - " (Y d 5Z -W(X FYV=W +X HX )^ ,Y1Y HnEW KV 0X7W BW-W HW.X M^/X )" - "Y +YHY 2YHZ 1YHY 2ZHY 1YHY 2ZHY ?ZDZ 9[ LZ !Z Z !Z >Z !Z !Z \"Z :Z'[%YKZ6Y'\\%[)[$[*[%[)[%[)[%[%Y)Z&[.d'Z(Z#" - "Z(Z$Z(Z$Y'Y H[>Z @{ DY=b ;f -f -f ,e -f -f Ae7c ;e /b )c *c *c 'Y NX NX X E[ >XD` -c )c *b *c )c '\\ &bDX L" - "X0X GX0X GX0X GX0X KY)X KYE` ?Y*Y 8[4\\ K[3[ J\\4[ I[4\\ K[3[ 3X 8Z+Z AZ !U /m 6q N~o No 6o ?X.X 8_ " - "6Y3Z Z $Z 6Z +XCX 0X@X DZET>Q)W;W>W ?Y :X \"X IY 'b $X )X ;Z2Y 2Z @Z !Z 8YHZ ?Y " - "!Z 0[ CY1Y JZ1Z 5\\ \\ 'Z!Z FY LZHZ @Z/Y L[ %Z&[ NZ MZ .[ NZ(Z :Z \"Z 4ZA\\ 6Z 2YKX6YKY(YKZ7Z'[$[ NZ" - "2Z&[#Z#Z2[ JZ :Y 9Z(Z\"Z,Z1Z8XJX8Z%[D[ ZHY 1\\ *Z /[#['^EZE^$Z(Z+[;Z;Z.[#Z C[IXH[ (X ([HXI[ (" - "Z $k 9Z .Y*Z FY=Y .X ,\\ *UAnCU J^CW -VCmAV ?W>V *X IX (a /Y1Y HnEW KV 0X7W BW.X HW.W La3X " - "(Y ,ZHY 2YGY 2ZHZ 3YGY 1YHZ 3YGY @ZCZ 9[ LZ !Z Z !Z >Z !Z !Z \"Z :Z'\\&YJY6Y'[$[)[$[*[$[+[#[+[$[&[+\\([.e'Z(" - "Z#Z(Z$Z(Z$Y'Y GZ?Z ?| EY>c >l 4l 3l 2l 3l 4l Gl=h @k 5h /h /h /h )Y Y NX Y E[ ?XFd 1g .h /h /h /h )\\ )hHX " - "LY0X HY0X GX0X GX0Y LZ+Y KYGd AY*Y 9[EXD[ M[1[ L[1[ K[1[ M[1[ 4X 8Z+Y A[ !T /n 6q N~o q 8q @X.X 8` 7" - "Y3Y Z $Z 5Z +XCX 0X@X DYDT EW;W?X ?Y :X #Y IY %^ \"X )X k 5}\"~W KY0Z ?YGZ 1[ *Z /Z\"[(]CZD^%Z(Z+[;Z;Z.[#[ CYHXGY 'X 'YGXHY 'Z &o" - " ;Z /[,[ FZ?Y -X +\\ +UBoBU LZ>W -UBnAU >W@W *X JX 'c 1Y1Y HnEW KV /W7W BW.W GW/X Lc5W 'Y ," - "YFY 4ZGY 2YFY 3YGZ 3YFY 3YGZ AZCZ 9Z KZ !Z Z !Z >Z !Z !Z \"Z :Z&[&YJZ7Y'[#[*Z\"Z+[#[+[#[+[#[&[-\\'[/YM[(Z(Z#" - "Z(Z$Z(Z$Y'Y G[A[ ?} FY?] :p 8q 8q 7q 8q 8p LqAl Do 9l 3l 3l 3l +Y Y NX Y #i @XHh 5k 2l 3l 3k 2l +\\ +lKX KY0" - "X HY0X GX0X GX0Y KY,Z KYIh CZ,Z :ZCXC[ [/[ N[.Z MZ.[ [/[ 5X 7Y,Z AZ !U /o 7p M~n s :s AX.X 8` 7Z4Y Y" - " #Z 5Z +XCX 0W?X EYCT EW;W@X >Z ;X #Y HX #Z X *X ;Z1Z 3Z @Z !Z 9XFZ ?Y \"Z /Z " - "BY2Z KZ0[ [/Z 4t =YJj 3q >kJY >o 8r ;kJY GYJk .Y NX 0X5\\ 6Y FY" - "JiBi$YJk 8o ?YJj 9kJX ;YJc Z !Z !Z \"Z :Z&[&YIZ8Y([\"[+[\"[,[\"Z+Z!Z,[\"[%[/\\" - "&Z/YL[(Z(Z#Z(Z$Z(Z$Y'Y F[BZ >Z@d GY@\\ :t ;t t TAU NX;W )P9P =UAWAYAU >XDX )X LX HY 3Y1Y HnEW KV /W7W " - "AP9P 9W0X FW0X ?Y8W &Y -YEZ 5YEY 4ZFZ 5YEY 4ZEY 5YEY BZBZ :[ KZ !Z Z !Z >Z !Z !Z \"Z :Z%['YIZ8Y([!Z+Z![,Z![-" - "[![-[!Z$[1\\&[/XJZ(Z(Z#Z(Z$Z(Z$Y'Y EZCZ =Z;` HYA[ 8u oLX ;YLe ?u VAW?XAU ?ZHY (X MX EX 4Y1Y HnE" - "W KV /W7W AQ:Q :W0W EW1X Z !Z !Z \"Z :Z%['YHZ" - "9Y(Z Z+Z Z-[![-[![-Z [$[3\\%[0XI[)Z(Z#Z(Z$Z(Z$Y'Y E[E[ =Z9^ HYBZ 6v =v >w =w >v =v\"vIt Lt >t ;t ;t ;t /Y Y N" - "X Y *r BXKn qMY GYMp 0Y NX 0X8[ 2Y FYMoIp'YMq ?v BYMp ?qMX ;YMf ?u U@W?XAU >j (X " - " NX CX 5Y1Y HnEW KV /W7W AR;R ;W1X EW1W :XZ " - "!Z !Z \"Z :Z$Z'YHZ9Y)[ [-[ [.[ Z-Z NZ-Z [#[5\\$Z0XH[)Z(Z#Z(Z$Z(Z$Y'Y D[FZ w ?x >x ?w >w#wKv Nu ?v" - " =v =v =v 0Y Y NX Y +s BXLp >u \\ DX.X :c 7Z7Z!Y \"Z 4Z +XCX C~d&XBT DW=XB" - "X :[ >X $Y FY +f &X +X ;Z/Z 4Z AZ !Z ;YDZ ?YFP -Z?Q BZ ?Z5Z JZ/Z 5Z \"[ Gj Ii ;[\"X1Q,W\"YCZ BZ1" - "Z MZ \"Z$[!Z MZ /Z LZ(Z :Z \"Z 4ZH] 0Z 2YHX;XHY(YHZ:Z)Z N[!Z2Z([ NZ%Z2Z I[ ;Y 9Z(Z Z1Z,Z;XGW;Z N[L[ 4[H[ #\\" - " 1X MX AY BZ&Z 8^Ga AYN[H_ " - "YDY *X )b 6UDY%U V9W ,SU@W>W@T =h 'X X AW 5Y1Y HnEW KV /X9X ASZ !Z !Z \"Z :Z$Z'YGZ:Y)[ NZ-[ [.Z N[.Z NZ.[ NZ\"[7\\$[1XFZ)Z(Z#Z(" - "Z$Z(Z$Y'Y CZGZ ;Z6\\ IYCY 4^Ga ?^Ga @_Hb ?^Ga ?^Ga ?^Ga$^GaMaI`!bH\\ @aI` ?aI` ?aI` ?aI` 1Y Y NX Y ,u CXM^Nb" - " @aKa >aJa ?aJa ?aKa =`Ja 1\\ 0`Ic GY0X HY0X GX0X GX0Y IY0Z IYN[H_ FZ0Z X>Y&X#X%YJT9TIY&Y.TJY&X#X 8X 5Y0" - "Z CZ ;P4U 1w 9l J~m#z B[;[ EX.X :d 7Y7Y X )~Q #Z +XCX C~d&XBT DW=XCX 9\\ ?X $Y FY " - "-j (X +X ;Z/Z 4Z AZ \"Z :XCZ ?YM_ 5ZE^ IZ >Y6Z IZ0[ 5Z \"[ Jj Ci ?\\\"X6\\2X#YBY BZ1Z MZ \"Z$[!Z " - "MZ 0[ LZ(Z :Z \"Z 4ZI] /Z 2YHX;XHY(YGZ;Z)Z N[!Z3[([ NZ%Z2Z H[ ^ BcB] >_?W C^CYNY C]A] 4Y /]Bc GYNYD^ 2Y NX 0X;\\ 0Y FYNXC\\KYD](YNYC] A]B^ DcB] C^CYNX ;YNZDQ A\\" - ";V 5Y .Y1Y IY/Y&Y;_;Y\"Z;Z FZ0Y $[ 2Y X Y M];\\ F]E[JX IY9[ LY >ZKf =]=V CYNYC] K`2Z 5^ 9Y1Y!Z\"Z!^JZM^" - " K~Y!Y@X@Y E]C^ CaHl\"~W LY.Z BYBY .\\ 0Z 1Z M[-[>Z>[(Z(Z*Z;Z<[0[ N[$[ W@U =f &X !X @W 5Y1Y HnEW KV /X9X AT=T =W2X DW2W 8W=X $Y .YBY 8ZC" - "Z 7YBY 8ZCZ 7YBY 8ZBY FZ@Z ;Z IZ !Z Z !Z >Z !Z !Z \"Z :Z$[(YGZ:Y)[ NZ-Z MZ.Z N[/[ N[/[ NZ![9\\#[2YFZ)Z(Z#Z(Z" - "$Z(Z$Y'Y C[I[ ;Z5\\ JYCY 4X=^ @X=] @Y=] ?Y>^ @X=^ @X=^%X=l@\\\"_?W A]@\\ @]@\\ @^A\\ @^A\\ 1Y Y NX Y -w DXNY" - "C] A^C^ ?^C^ A^B] @^C^ ?^C^ 2\\ 1^C_ FY0X HY0X GX0X GX0Y IY0Y HcB] FY0Y ;X=X=Y(Y#Y'YJV;VIX&X.VJY(Y#Y 9W 4Z1" - "Z DZ =S4U 2y 9j I~l#{ BZ9Z EX.X :d 7Z8Y!Y *~R #Z +XCX C~d'YBT DX?XBW 7\\ @X $Y FY " - "/ZNVNZ *X ,X :Z/Z 4Z AZ #Z :XBZ ?o 9ZGc MZ =Z8[ HY0\\ 6Z \"[ Li >j C\\\"X8aGVBW$ZBZ CZ2Z LZ \"Z#Z!" - "Z MZ 0[ LZ(Z :Z \"Z 4ZJ] .Z 2YHXY 9Z(Z NZ2Z,Z\\ @^:T C\\?b D\\=\\ 5Y 0\\>a Ga?\\ 2Y NX 0X<\\ /Y Fa@\\MX@[(b@\\ B]?\\ Da?] D\\?a ;b 1Z6" - "S 5Y .Y1Y IZ1Z&Y;_;X![=Z DY1Y #[ 2Y X Y `>` I\\B[KX IY:\\ LY ?ZDa ?\\7R Cb?\\ F[3Y 5_ 9Y1Y\"Z Y!]IYJ] L" - "~Y!Y@X@Y F\\?\\ D^Ai\"~W LY.Z CZBZ .\\ 1Z 1Z LZ.[=Z>[(Z(Z*Z;Z<[0[ N[%\\ XAU V ?W3X CW3X 8X>W #Y /Z" - "BZ 9YAY 8ZBZ 9YAY 8ZBZ 9YAY FZ@Z ;Z IZ !Z Z !Z >Z !Z !Z \"Z :Z$[(YFZ;Y)Z MZ-Z MZ/[ MZ/[ N[/Z M[![;\\\"[3YE[*" - "Z(Z#Z(Z$Z(Z$Y'Y B[JZ :Z4[ JYCX 3U8\\ @U8\\ AV8\\ @U7\\ AU7[ @U8\\%U8h=\\$]9T B\\=\\ B\\=\\ B\\=\\ B\\<[ 2Y Y " - "NX Y .x Da?\\ C]?] A]?] B\\?] B]?] A]?] 3\\ 2]?] FY0X HY0X GX0X GX0Y IZ1Y Ha?] GY1Z ~d W5T 2{ 9i H~k$} DZ7Z FX.X :d 7Z9Z!X )~R #Z 0~d&XBT DX?XCX 6\\ " - " =Y EY 0ZMVMZ +X ,X :Z/Z 4Z B[ %\\ :XBZ ?q ;YHg Z \\ 0Z 6Y.Z CYAZ -\\ 2Z 1Z LZ.[=Z=[)Z(Z*Z;ZW>X@T ;a #X #X =W 6Y1Y GmEW KV .X;X @W@W @W3W BW4X 6W?X #Y /Y@Y :" - "ZAY 8Y@Y 9YAZ 9Y@Y 9YAZ GZ@Z ;Z IZ !Z Z !Z >Z !Z !Z \"Z :Z#Z(YFZ;Y)Z M[/[ MZ/[ MZ/Z LZ/Z M[ [=\\!Z3YD[*Z(Z#Z" - "(Z$Z(Z$Y'Y AZKZ 9Z4[ JYDY 3R3[ AR3[ BS3Z @S4[ AS4[ AR3[&R3e:[&]6R C\\:[ D\\:[ D\\:[ D\\:[ 3Y Y NX Y /_B] E_<" - "[ C[;[ B\\<\\ C\\<\\ C[;\\ C\\<\\ 3\\ 3\\<\\ FY0X HY0X GX0X GX0Y HY2Z H`<[ FY2Y ;X~d#Z6U 3} :h G~k%~P EY5Y FX.X ;ZNY 6Y9Z!X *~R \"Z 0~d&YCT CXAXBW 5] " - " >Y EY 2ZKVKZ -X ,X :Z/Z 4Z BZ &] :XAZ ?s =YJk #[ ;[=[ FZ1\\ 6Z \"[ #j L~d Ki J\\!X:hKVAW%Y@Y CZ5\\ L" - "[ \"Z#Z!Z MZ 0Z KZ(Z :Z \"Z 4ZL] ,Z 2YGX=XGY(YEZ=Z*[ M[\"Z4['Z LZ&Z4[ F` BY 9Z(Z MZ4Z*Z=XEW=Z Jd .ZLZ #\\ .X" - " LX BY JQ1[ D_:[ B\\ ([9_ F[7Z 6Y 1[:_ G^9Z 3Y NX 0X>\\ -Y F^;b;Z)_:Z D[:\\ F_:[ G[9^ ;_ /Y EY .Y1Y " - "HY2Z$Y=a=Y NZ@[ BY3Z %[ 0Y X Y \"eCd L[>YLX HY>^ IY AY=] @Z &_:Z DY4Y 5a :Y1Y\"Z Z$\\GYG\\ EY9Y IY@X@Y G" - "Z9[ G\\;[ 0Y 5Y.Z DZ@Y ,\\ 3Z 1Z LZ.ZUDX!T\"XW>X@U :] !X $X Z !Z !Z \"Z :Z#Z(YEZ~d&^7U 4~ 9f E~i%~R GY4Y FX.X ;ZNZ 7Y9Y!X )~R \"Z NW?W BYCT CYBXCX 6_ ?Y EZ 5ZI" - "VIZ /X ,X :Z.Y 4Z C[ )_ :YAZ ?t >YKn %Z 9\\A\\ EZ1\\ 6Z \"[ &j I~d Hi N\\ W:jLVAW&Z@Z DZ8^ KZ !Z#[\"Z " - " MZ 0Z KZ(Z :Z \"Z 4ZM] +Z 2YGY?XFY(YEZ=Z*Z L[\"Z4['Z LZ&Z4[ Fc EY 9Z(Z MZ5Z)Z>XDW=Z Ic .[NZ #\\ -X KX CY " - " )Z D^8[ D\\ '[8^ FZ5Z 7Y 2[8^ G]8Z 3Y NX 0X?[ +Y F]9`9Y)^9Z E[8[ F^8Z GZ8^ ;^ .Y EY .Y1Y GY3Y#Y=WNX=Y M" - "ZAZ AY3Y %[ /Y X Y #gEf N[W>W?U 7W <~d BX ;W 6Y1Y GmEW KV -X=X ?YBY BW4W AW5X 5W@W !Y 0Y?Z ;Y?Y :Z@Z ;Y?Y :Z?Y ;Y" - "?Y HZ?Z <[ IZ !Z Z !Z >Z !Z !Z \"Z :Z#Z(YEZY D~P JZ !Z#[\"~Q Dy Z K~] :Z \"Z 4ZN] *Z 2YFX?XF" - "Y(YDZ>Z*Z L[\"Z5\\([ LZ&Z5\\ Eg JY 9Z(Z MZ5Z)Z>XDX>Z Ib ,f $\\ ,X KX CY (Y D]6Z D[ '[7^ GZ4Z 7Y 2Z6] " - "G]7Z 4Y NX 0X@[ *Y F]8^8Z*]7Z FZ6[ G]6Z I[7] ;] -X DY .Y1Y GY3Y#Y=WNX=X L[CZ ?Y4Y &[ .X NX Y $iGh Z:XNX" - " GYHg HY CY8\\ CY $]7Z DY6Y 4b ;Y1Y#Z MZ&[EYE[ FY9Y IY@X@Y HZ7[ I[7[ 2Y 5~V DY>Y +\\ 5Z 2Z KZ/[W>W?U K~d CX ;X " - " 6Y1Y FlEW KV -Y?Y ?ZCZ CW5X AW5W 5XAX !Y 0Y>Y Y Y ;Y?Z JZ>~Q3[ I~Q G~Q F~Q G~Q 5Z !Z !Z " - "\"Z :Z#Z(YDZ=Y*[ LZ/Z L[0Z L[0Z LZ0[ LZ L[C\\ N[5X@Z*Z(Z#Z(Z$Z(Z$Y'Y ?e 7Z3[ KYDY @Y Y !Z Y Y Y 4_4Y)[ %Z3" - "Y GZ3Y FZ4Y FZ4Y 4Y Y NX Y 1[8Z F\\7Z F[7[ EZ6[ G[6[ G[6Z EZ6[ Y D~ IZ !Z#[\"~Q Dy![ K~] :Z \"Z 4h )Z 2YFX@YFY(YDZ>Z*Z KZ\"Z5\\([ LZ&Z6\\ Ck Y 9Z(Z LZ6Z(" - "Z?XDX?Z G` *d #[ +X KX CY 'Y E]6[ F[ &Z5] GY2Y 7Y 3Z4\\ G\\6Z 4Y NX 0XA[ )Y F\\7]6Y*\\5Y G[5Z G\\5Z I" - "Z5\\ ;] -X DY .Y1Y GZ5Z#Y>XMW>Y K[E[ ?Y5Y &[ .Y NX Y $XIZHZIY!Z:XNX GYHf GY DY6[ CY $\\5Y CX6Y 5c ;Y1Y#" - "Z MZ&[EYDZ FY9Y IY@X@Y IZ5Z IZ5Z 2Y 5~V EZ>Y *[ 5Z 2Z KZ/[Z EiKh 6X /XC^ BTDX U\"YA\\ 4ZCZ N~d &U>W?X>T K~d EY :W 5Y1Y EkEW KV ,YAY =ZCZ DW6X @W6" - "X 5W@W 'Z>Y Z =Y=Y ;Y>Z =Z>Y JZ>~Q3Z H~Q G~Q F~Q G~Q 5Z !Z !Z \"Z :Z#[)YDZ=Y*[ LZ/Z KZ0Z L[1[ LZ0[ L" - "Z K[E\\ M[6Y@Z*Z(Z#Z(Z$Z(Z$Y'Y >d 7Z2Z KYDY @Y Y Y NY Y !Y 4^3Z*Z $Z3Z HZ3Z HZ3Z HZ2Y 5Y Y NX Y 2[6Z G" - "\\6Y FZ5[ G[5Z GZ5[ GZ5[ G[5Z =[:_ HY0X HY0X GX0X GX0Y GZ5Y F\\5Z GY5Z Z6Y &[ .Y NX Y %WEYJYEX#Z8a GYHe FY DX4[ DY $\\5Y CY8Z 5d Y*Z KZ/Z KZ0Z L[1[ L[1[ LZ J[G\\ L[7Y?Z*Z(Z#Z(Z$Z(Z$" - "Y'Y >c 6Z2Z KYDY ?Y X NX NY Y Y 4\\1Y+[ %Z1Y HY1Y HY1Y HY1Y 5Y Y NX Y 3[5Z G[5Z HZ3Z GZ4[ HZ4Z HZ3Z GZ" - "4[ >Z9` IY0X HY0X GX0X GX0Y FY6Z F\\4Z GY6Y ;W9X9W-X JX,WD[I\\DW,W1[DW-X JX =X 1Y6Z <~d'RKY:U 5~U J" - "~T$~g'~X KY1X GX.X Z ?y DgF` *Z 2k >Z4^ 6Z \"[ 1j >~d =i -[ LW=\\C_?W)YZ=Z =YZ=Z =YZ=Z LZ=~Q3Z H~Q G~Q F~Q G~Q" - " 5Z !Z !Z \"Z Ew5[)YCZ>Y*Z KZ/Z KZ0Z KZ1[ L[1Z KZ I[I\\ K[8Y>[+Z(Z#Z(Z$Z(Z$Y'Y =a 5Z2Z KYDY ?Y Y X MX Y Y" - " 4\\1Y+Z $Y0Y IZ1Y IZ1Y IZ0X 5Y Y NX Y 3Z3Y GZ3Y HZ3Z HZ2Z IZ2Z IZ3Z GZ3Z >Z:a IY0X HY0X GX0X GX0Y FZ7Y E[" - "3Z GY6Y ;W9X9W-W HW,WC[K\\CW,W2[CW-W HW =X 1Z7Z <~d NX:U 5~V M~X%~e&~Y LX0Y HX.X =ZJY 6Y=Z W " - " NZ 3Y X@X ?]IT ?hCW 7h2X ;Y CY 7TAVAT 1X .X 8Z.Y 4Z G\\ 6g 5X=Z ?X?a EeB^ +Z /f ;[5" - "^ 4i ;~d :i 1[ LWr *Y " - "9Z(Z KZ8Z'Z@XBX@Y D\\ &` $\\ )X JX DY &X E[2Z HZ %Z3\\ IZ/X 8Y 4Z2[ GZ3Y 4Y NX 0XE\\ &Y FZ4[5Y*[4Z IZ" - "2Z H[2Y KY2[ ;[ +X DY .Y1Y FZ7Z!Y?WLX?X H[IZ ;Y7Y '[ ,Y NX NY *Q NV@WLW?U#Z8` FYHd .^FY EX2[ DX $[3Y CX8Y" - " 5YMY [/[IuI[.\\ 4X 4\\ =X =\\$\\" - " =X MZAU -Z &X8Y G~W 6X 0W<\\ FUEX MT iNW 8[D[ K~d &T=WE\\QZZeBX] ,Z 1j <[7_ 7i 8~d 7i 5[ KW=Z=" - "\\?W*Y:Y F{ FZ !Z\"Z\"~Q Dy![1j&~] :Z \"Z 4e &Z 2YDXCXDY(YBZ@Z*Z KZ\"Z[/[IuI[/\\ 3X 3\\ >X >\\\"\\ >X MZAU -Z 'X6X 5c " - "%X 1X;\\ GUEX MT NgMW 9[D[ J~d &T=m;T K~d In 4TA[ 4Y1Y BhEW 3Z DX )i 5[D[ IX9W5Z3W8WFj?TA[BX5Z KY" - ";Z @Z;Z ?Y:Y @Z;Z ?Z;Y ?Y;Z NZ<~Q3Z H~Q G~Q F~Q G~Q 5Z !Z !Z \"Z Ew5[)YAY?Y*Z KZ/Z KZ1[ KZ1[ L[1Z KZ G[M\\ IZ8" - "X<[+Z(Z#Z(Z$Z(Z$Y'Y <_ 4Z2Z KYD[ @X NX Y NY X NX 3Z/Y-Z $Z/Y KZ/Y KZ/Y KZ/Y 6Y Y NX Y 4Z2Z HZ3Y IZ1Z I" - "Z1Z JY1Z JZ1Z IZ1Z @Z;XNZ JY0X HY0X GX0X GX0Y EY8Y D[2Z GY8Y ;X9X8W.W HW-W@hAW-X4[@W.W:[:W =X 0Z9Z I" - "[ 7YY ~m 4Z 3Y W?X >g =cAW?]'[K\\5Y ;Y CZ %V M" - "X /X 7Y-Z 5Z H[ 4l ;XZ>Z.[IuI[0\\ 2X 2\\ ?X ?\\ \\ ?X MY@U 8y ;X6X 4a $X 1X9[ HUEX MT MeLW :[D[ I~d &T=l:T " - "K~d Io 5m 3Y1Y AgEW 3Z Nl 2g 3[D[%lDX5Z>mDXFk@mAW5[ LZ:Y @Y:Z ?Y:Y @Z:Y ?Y:Z AZ:Y NZ<~Q3Z H~Q G~Q F~Q G" - "~Q 5Z !Z !Z \"Z Ew5[)YAZ@Y*Z KZ/Z KZ1[ KZ1[ L[1Z K[ Gh HZ9X;[+Z(Z#Z(Z$Z(Z$Y'Y ;] 3Z2Z KYC[ AX NX Y NY Y X" - " 3Y.Y-Z $Y.Y KY.Y KY.Y KY.Y 6Y Y NX Y 4Z1Y HY2Y IZ1Z IY0Z KZ0Z KZ1Z IY0Z @Y;XMZ JY0X HY0X GX0X GX0Y DY9Y D" - "Z0Y GY9Z ;W8X8W.W HW-W?f?W.W4[?W.W:[:W =X 0Z9Y HZ 5X_@XAa*[I\\6Y ;Y CZ %V MX /X 7Y-Z 5Z I[ 3n >X;Z ] G`9\\ .Z 4s @[9` " - " =i /i ;Z IV=Y9Z>V+Z:Z G~P JZ !Z\"Z\"~Q Dy!Z1l'~] :Z \"Z 4g (Z 2YDYEXCY(YAZAZ*Z KZ\"}$Z K['z 5r /Y 9Z(Z JZ;Z" - "$ZAW@WAZ F_ %\\ $[ &X IX EY &Y FZ0Y IZ %Y/Z IY.Y 9Y 4Y0Z GY1Y 5Y NX 0XH[ \"Y FY3Z3Y+Z2Y JZ0Z IZ0Y MY0" - "Z ;Z *Z FY .Y1Y DY9Y MYAWJXAY F[MZ 8Z:Y )[ +Z MX N[ 7g1U U<^;U&Z6^ EYHj 9gJY FX/Y CY &Z2Y BYY1Y%Z" - " J[*ZBYBZ HY9Y IY@X@Y KY0Z MY/Y 4Y 6~W GZ:Z ,[ 6Z 2Z KZ/Z;Z;Z*Z(Z([>Z?[.ZHuI[1\\ 1X 1\\ @X @\\ M\\ @X NZ" - "@U 8y ;W4X 5` #X 1X8Z HUEX MT LbJW ;ZC[ H~d &T=j8U L~d Io 5l 2Y1Y @fEW 3Z Nl 0c 0[CZ&lDW5[>mEXE\\N^" - "AlAX6\\ LZ:Z AY9Y @Z:Z AY9Y @Z:Z AY9Z!Z;~Q3Z H~Q G~Q F~Q G~Q 5Z !Z !Z \"Z Ew5[)Y@ZAY*Z KZ/Z KZ1[ KZ1[ L[1Z K" - "[ Ff GZ:X:[+Z(Z#Z(Z$Z(Z$Y'Y :\\ 3Z2Z KYC\\ BY X NX NY Y X 3Y-X-Y #Y-X KY-X KY-X KY-X 6Y Y NX Y 5Z0Y HY" - "2Y IY/Y JZ0Z KZ0Z KY/Z KZ/Y AZ;WKY JY0X HY0X GX0X GX0Y DY:Z DZ0Y FY:Y :WK~KW.WK}KW-W>d>W.W5[>W.W:[:W =X /" - "Y:Z IZ 4Y=T 6~[%~b'~_%~\\ NY/X HX.X >ZHY 6Y?Y N~m 4Z 3Y !X@X ;l @[>WBe,ZG\\7Y ;Y" - " CZ %V ;~c LX 7Y-Z 5Z J\\ 2n @Y;Z N\\ G`8\\ /Z 5u A\\V+Y8Y G~R LZ !Z\"Z\"~Q" - " Dy![2l'~] :Z \"Z 4h )Z 2YCXEXCY(Y@ZBZ*Z KZ\"|#Z K['x 0q 1Y 9Z(Z IZY1Y%Z IZ*YAYBZ HY9Y IY@X@Y KY/Y MY/Y 4Y 6~W GY9Z " - "-[ 5Z 2[ LZ/Z;Z;Z*Z(Z'[?Z?[.[IuI[2~n BX B~n AX A~m AX NZ@U 8y dEW 3Z Nl ._ ,ZCZ'lEX6\\>mEWDVCZBkAX6] LY8Y BZ9Z AY8Y BZ9Z AY8Y BZ9Z!Z;~Q3Z H~Q " - "G~Q F~Q G~Q 5Z !Z !Z \"Z Ew5[)Y@ZAY*Z KZ/Z KZ1[ KZ1[ L[1Z KZ Ee FZ;Y:[+Z(Z#Z(Z$Z(Z$Y'Y :[ 2Z2Z KYB\\ CY X NX" - " NY Y Y 4Y-Y.Y #Y-X KY-X KY-Y LY-Y 7Y Y NX Y 5Z0Z IY2Y JZ/Z KZ/Y KY/Z KY/Z KZ/Y#~d$ZX /Z;Z JZ 2X>U 6~\\'~c&~^$~Z MY/X HX.X >YGZ 7Z@Y " - "N~m 4Z 3Y !X@X :n 'WBg.ZE\\8X :Y CZ %V <~e NX 6Y-Y 4Z K\\ #a AX:Z M\\ H_6[ 0Z" - " 6aI` A]?c ?f $f ?Z IW>Y7Y>V,Z8Z HZ8` MZ !Z\"Z\"Z MZ 1[2l'Z(Z :Z \"Z 4ZN] *Z 2YCXFYCY(Y@ZBZ*Z KZ\"{\"Z " - "K['v +o 2Y 9Z(Z IZq:X !U:[9U&Y5] DY?d =jLX FY/Z C[ " - ")Y1Y AX=Z 6ZIY >Y1Y%Z IZ*YAYAY HY9Y IY@X@Y KY/Y NZ/Z 5Y 5Y-Y HZ8Y .[ 4Z 1Z LZ/Z;Z;Z*Z(Z'[?Z@[-[ L[3~o BX B~o BX" - " B~o BX NZ@U 8y mFXDS?YBi?W5] CY 4Z8Y BY7Y BZ8Z CY7Y AY8Z CZ8Y!Y:Z Z !Z !Z \"Z Ew5[)Y?ZBY*Z KZ/Z KZ1[ KZ" - "1[ L[1Z KZ Dc E[=Y9[+Z(Z#Z(Z$Z(Z$Y'Y 9Z 2Z2Z KYB^ &i 0i 1i /i 0i 0i Ej-Y/Z $Z-Y MZ-Y MZ-Y LY-Y 7Y Y NX Y 5Y/" - "Z IY1X JZ/Z KZ/Z LY.Y LZ/Z KZ/Z$~d$Z=WIZ KY0X HY0X GX0X GX0Y CYX .Y;Y JZ 1Y?U 6~\\(~e'~]\"~X LX.X HX.X >YFY 7ZAZ N~m 4Z 3Y !W?X 9p +XCi0ZC\\9X " - " :Y CZ %V <~e NX 6Z.Y 4Z L\\ M^ CY:Z L[ H^4Z 0Z 7^A^ C_Ce ?c Mc @Z HW>X6Y>V,Y7Z HZ5^ NZ !Z\"" - "Z\"Z MZ 1[2l'Z(Z :Z \"Z 4ZM] +Z 2YBXGXBY(Y?ZCZ*Z KZ\"z![ LZ&w 'k 3Y 9Z(Z IZ=Z\"ZCX@XCZ Gc &Z &\\ $X HX FY " - " >q FY.Y JY $Y/Z JY,X 9Y 5Y.Y GY1Y 5Y NX 0XL\\ NY FY3Z3Y+Y1Y JY.Z JY/Z NY/Y ;Y (^ KY .Y1Y CY;Y KYCXIXCY " - "Bc 4Y\\IYMX FY/Z B\\ +Y1Y AY>Y 5ZIZ ?Y1Y%Z IZ*YAYAY HY9Y IY@X@Y KY/Y NZ" - "/Z 5Y 5Y-Y HZ8Z 0\\ 4Z 1Z LZ/Z;Z;Z*Z(Z&[@Z@[-[ L[4~p BX B~o BX B~p CX NY?U 8y mFWCQ;XAe>X6UNW CY 4Y7Z DZ7Y BZ8Z CY7Z CZ7" - "Y CY7Z#Z:Z Z !Z !Z \"Z :Z#[)Y?ZBY*Z KZ/Z KZ0Z KZ1[ L[1Z KZ Ca D[>Y8[+Z(Z#Z(Z$Z(Z$Y'Y 9Z 2Z3[ " - "KYA^ /q 9r 9q 7q 8q 9r Mq,Y/Z $Y,Y MY,Y MY,Y MZ-Y 7Y Y NX Y 5Y.Y IY1X JZ/Z KY.Z LY.Y LZ/Z KY.Z$~d$Y=XIZ KY0X" - " HY0X GX0X GX0Y CYX .YW-Y6Y HZ2\\ Z !Z\"Z\"Z MZ 1[2l'Z(Z :Z \"Z 4ZL] ,Z 2YBXGXBY(Y?Z" - "CZ*Z KZ\"x N[ LZ&x #f 3Y 9Z(Z HZ>Z\"ZCW>WCZ Hd &Z &[ #X HX FY At FY.Y JY $Y/Z JY,Y :Y 5Y.Y GY1Y 5Y NX" - " 0XM\\ MY FY3Y2Y+Y1Y JY.Z JY.Y Z/Y ;Y (b Y .Y1Y CY;Y KYCWHXCY Bb 3Y=Y *[ 6e JX Ke KzF^ !U9Y7T'Z4[ CY7] @[E" - "XNX GZ.Y Ai 9Y1Y AY>Y 5YHZ ?Y1Y&[ IZ+ZAYAY HY9Y IY@X@Y KY/Y NZ.Y 5Y 5Y-Y IZ6Y 0[ 3Z 1Z LZ/Z;Z;Z*Z(Z&\\AZA[,[ L[" - "4~p BX B~o BX C~q CX NY?U 8y Z !Z !Z \"Z :Z#[)Y>ZCY*Z K" - "Z/Z KZ0Z L[1[ L[1Z KZ B_ C[>X7[+Z(Z#Z(Z$Z(Z$Y'Y 9Z 2Z3[ KY@_ 5u XHZ KY0X HY0X GX0X GX0Y BY=Y BY.Y FY=Z 9WK~KW/WJ}JW.W:\\:W.W" - "9[:W/W9[9W >X .Z=Y JZ /X@U 6~^*~g&~Y N~V KX.Y IX.X ?ZFZ 7ZBY L~l 4Z 3Y \"X@X 3n /X" - "CZIZ2Z@\\W.Z6" - "Z IZ1[ Z !Z#[\"Z MZ 1[2l'Z(Z :Z \"Z 4ZK] -Z 2YBXHYBY(Y>ZDZ*Z KZ\"v L[ LZ&z !c 4Y 9Z(Z HZ>Z\"ZDX>XDY Ge 'Z '[ " - "\"X GX GY Dw FY.Y JY %Z/Z J~W :Y 5Y.Y GY1Y 5Y NX 0XN\\ LY FY3Y2Y+Y1Y JY.Z JY.Y Z/Y ;Y 'e $Y .Y1Y CZ=Z" - " KYDXGWDY @a 3Z>Y +[ 5d IX Ic L~d !U8X7T'Z4[ CY5\\ AZCa GY-Y @h 9Y1Y @X?Z 6ZGY ?Y1Y&[9X9Z+ZAYAZ IY9Y IY@X@Y " - "KY/Z Y-Y 5Y 5Y.Z IZ6Z 2[ 2Z 1Z M[/Z;Z<[*Z(Z%[AZB\\,[ LZ3~p BX B~o BX C~q CX NY?U 8y Z !Z !Z \"Z :Z#[)Y>ZCY*Z KZ/Z KZ0Z L[1[ L[1[ LZ A] B[?X6Z*Z(Z#Z(Z$Z(Z$Y'Y 9Z 2Z3[ KY?" - "_ 8w ?x ?w =w >w >w$~u/Y #~W M~W M~W M~W 7Y Y NX Y 6Z.Y IX0X JY-Y KY.Z MZ.Z MY-Y KY-Y$~d$Y?XFY KY0X HY0X GX0" - "X GX0Y BY>Z BY.Y EY>Y 8WK~KW/WJ}JW.W;]:W.W:[9W/W9[9W >X -Y>Z KZ .YAU 6~^*~g%~W L~T JX.Y IX.X ?YEZ 7Z" - "CZ L~k :y KY \"X@X 0m 1WCYEY3Y>\\=X 9Y BY %V <~e =l X 5Z.Y 4Z \\ E[ GY8Z JZ I]" - "2Z 2Z 8[7[ BqMZ ?^ C^ @Y GV=W4X>V-Y5Z IZ0[!Z !Z#[\"Z MZ 1[2l'Z(Z :Z \"Z 4ZJ] .Z 2YAXIXAY(Y=YDZ*Z L[\"s" - " I[ LZ&[Cc Na 5Y 9Z(Z HZ?Z YDX>XEZ Hg (Z (\\ \"X GX GY Fy FY.Y KZ %Z/Z J~W :Y 5Y.Y GY1Y 5Y NX 0e KY" - " FY3Y2Y+Y1Y KZ.Z JY.Y Y.Y ;Y &h (Y .Y1Y BY=Y IXDXGWDY ?_ 1Y?Z ,[ 4b GX Ga L~c T6V6T'Z4[ CY4\\ CZ@_ GY-Y >f " - "9Y1Y @Y@Y 5YFZ @Y1Y&Z8X9[,ZAYAZ IY9Y IY@X@Y KX.Z Y-Y 5Y 5Y.Z IY5Z 3[ 1Z 1Z M[/[WEY9T -X EY1Y 1WEW 3Z 6ZCZ 7X7" - "UKV HW*W KX6ULW CY 5Y5Z FZ5Z EY4Y FZ5Z EZ5Y EY5Z%Z9Z Z !Z !Z \"Z :Z#Z(Y=ZDY*[ LZ/Z KZ0Z L[0Z " - "LZ0[ LZ A] B[@X5Z*Z(Z#Z(Z$Z(Z$Y'Y 9Z 2Z4[ JY>` Y 8WK~KW/WJ}JW.W<_;W.W;[8W/W9[9W >X -Z?Z " - " LZ -YBU 5~^*~h%~U J~R IX.Y IX.X @ZDY 6YCZ LW 'y JY \"W?X ,j 3WCYCY4Y=\\>X 9Y CZ" - " %V <~e =l X 5Z.Y 4Z !\\ C[ IY7Z JZ I]2Z 3[ 9[5[ BoLZ ?a Ia @Y HW>X3W>V.Z4Y IZ/Z!Z !Z#[\"Z MZ 0" - "Z Z'Z(Z :Z \"Z 4ZI] /Z 2YAXIXAY(Y=ZEZ*Z L[\"o DZ LZ&Z<^ M_ 5Y 9Z(Z GZ@Z ZEX>XEZ I[MZ (Z )\\ !X GX GY " - "Gz FY.Y KZ %Y-Y J~W :Y 5Y.Y GY1Y 5Y NX 0c IY FY3Y2Y+Y1Y KZ.Z JY.Y Y.Y ;Y %j +Y .Y1Y BY=Y IYEXGXEY >] 0Y?Y ,[ " - "3` EX E_ L\\Cx NT6V6T'Z4Z BY2Z CY>^ GY-Y ;c 9Y1Y @YAZ 6ZEY @Y1Y&Z8X9[,ZAYAZ IY9Y IY@X@Y KX.Z Y-Y 5Y 5Y.Z JZ" - "4Y 4\\ 1Z 1[ NZ.[" - "WDX:U -X EY1Y 1WEW 3Z 5YBY 7W6UKV IX*W KW6UKW CY 6Z4Y FZ5Z FZ4Z GZ4Y EY4Z GZ4Y%Y8Z <[ IZ !Z " - " Z !Z >Z !Z !Z \"Z :Z#Z(Y=ZDY*[ LZ/Z L[0Z L[0Z LZ0[ LZ B_ BZAY5Z*Z(Z#Z(Z$Z(Z$Y'Y 9Z 2Z5\\ JY=` ?{ B{ Bz @z B{ " - "B{'~x/Y #~W M~W M~W M~W 7Y Y NX Y 6Z.Y IX0X JY-Y LZ-Y MZ.Z MY-Y KY-Y$~d$Y@WDY KY0X HY0X GX0X GX0Y AY@Z AY.Y " - "DY@Z 8WK~KW/WJ}JW.W=aX ,Y?Y LZ +XBU 6~_+~i%~U I~P HX.Y IX.X @ZDZ 7YCY KX " - " (y JY \"W?W (h 5XCXAX5Z<\\@Y 9Y CZ $T ;~e =l X 5Z/Z 4Z \"\\ AZ IX6Z JZ I\\1[ 4Z 8Z3Z AmKZ" - " ?d d AZ HW>X3W>V.Z4Z JZ.Z\"[ \"Z#[\"Z MZ 0Z Z'Z(Z :Z \"Z 4ZH] 0Z 2YAYKX@Y(YWCX;U -X EY1Y 1WEW 3Z Is 0YAX 8W6UJV IW)W" - " LX7UJW CY 6Z4Z GY3Y FZ4Z GY3Y FZ4Z GY3Z'Z8Z <[ IZ !Z Z !Z >Z !Z !Z \"Z :Z#Z(Yc=W.W=[6W/X:[:X >X ,Y@Z M[ " - "+YCT 5~`,~i$~S H~P HX.Y IX.X @YCZ 7ZDY KX )y HX #X@X (TNc 6WCX@X5Y:\\AX 8Y CZ :~e" - " =l !X 4Z/Z 4Z #\\ @[ KY6Z IZ I[0Z 4Z 9Z2[ @jJZ ?f %g AZ HW>X3W>V.Y2Y JZ.Z\"[ \"Z#Z!Z MZ 0Z Z'Z(Z" - " :Z \"Z 4ZG] 1Z 2Y@XKX@Y(YWBXZ !Z !Z \"Z :Z#Z(YW.W>[5W.W:[:W =W +ZAY LZ *YDU 5~`,~i#~Q F} GX.Y IX.X AZBY 7ZEZ KX " - ")y HX 6~e 9TJ_ 7XCX?X6Y9\\BX 8Y CZ KX Nl !X 4Z/Z 4Z $\\ >Z LY5Z IZ I[0Z 5Z 8Z1Z >fHY =h " - " +i @Z HW>X3W?W/Z2Z KZ.[#[ \"Z#Z!Z MZ 0Z Z'Z(Z :Z \"Z 4ZF] 2Z 2Y@XLY@Y(Y;ZGZ*[ MZ!Z /Z M[&Z7[ K\\ 6Y 9Z(Z FZ" - "BZ MYFXY FY.Y KZ %Y-Y K~X :Y 5Y.Y GY1Y 5Y NX 0e KY FY3Y2Y+Y1Y KZ-Y JY.Y" - " Y-X ;Y !m 2Y .Y1Y AZAZ GYGXEXGY >] .ZBY -[ 1e JX Ke LU4k IU8Y8T'Y2X AY0Y EX:[ FY-Z Ah 9Y1Y >XCZ 6YBY AY1Y&" - "Z8X8Z,Y@YAZ IY9Y IY@X@Y LY-Y Y-Y 5Y 5Z/Y JZ2Z 8[ .Z 0[!Z,[=Z=[)Z(Z\"]FZG]'Z M[1] 1X 1\\ @X @\\ L\\ AX DX 4" - "Z?U -Z (X4X H~W ;\\;W GTDX\"U s A[D[ 6X %T>WBXZ !Z !Z \"Z :Z$[(Y;ZFY)Z M[/[ MZ/[ MZ/Z M[/Z M[ Ee EZC" - "X3[*Z(Z#Z(Z$Z(Z$Y(Z 9Z 2Z8^ IY9` Fb=Y Eb=Y Eb=X Cb>Y Eb=Y Eb=Y*b=~V/Y #~W M~W M~W M~W 7Y Y NX Y 6Y-Z JX0X JY" - "-Y LZ-Y MY-Z MY-Y LZ-Y CZCXBY KY0X HY0X GX0X GX0Y @YBZ @Y.Y CYBY 6W8X8W.W HW-W@g@X.W?[4W.W:[:W =W *YBZ " - " MZ (XDU 5~`,~i\"~ D{ FX.Y IX.X AZBZ 7YEY IX +y GX 6~e 9TG] 8WBW>X6Y8\\DY 8Y CZ " - " KX Nl !X 4Z/Z 4Z %\\ =Z LX4Z IZ I[0Z 5Z 9Z0Z X3W?W/~S KZ-Z\"Z \"Z#Z!Z MZ 0[!Z" - "'Z(Z :Z \"Z 4ZE] 3Z 2Y?XMX?Y(Y;ZGZ)Z MZ!Z /[ N[&Z6[ K\\ 7Y 9Z(Z FZCZ LZGX^ .YCZ ." - "[ )_ KX L_ ES/e FU8Z9T'Z3X AY0Y FY:[ FY-Z Cj 9Y1Y >XCY 6ZBZ BY1Y&Z8X9[,Y@YAZ IY9Y IY@X@Y LY-Y Y-Y 5Y 5Z/Y J" - "Z2Z 9\\ .Z /Z!Z,\\>Z>[(Z(Z!]GZH^'[ N[0\\ 1X 2\\ ?X ?[ M\\ @X DX 4Z?U -Z 'W4W G~W :]>X GTDY#U s @[D[ 7" - "X %U?WAX>U ,X EY1Y 1WEW \"s 3ZC[ 9X7UHV KW(W MX7UHW CY 7~S J~S H~S I~S I~S I~S)} ;Z IZ !Z Z" - " !Z >Z !Z !Z \"Z :Z$[(Y;ZFY)Z MZ-Z MZ/[ N[/[ N[/Z MZ Eg F[EX2[*Z(Z#Z(Z$Z(Z$Y(Z 9Z 2Z9^ HY7_ G]8Y F^8Y F^8X D]8" - "Y E]8Y F^8Y+^8~V/Y #~W M~W M~W M~W 7Y Y NX Y 6Y-Z JX0X JY-Y LZ-Y MY-Z MY-Y LZ-Y BYDXAY KY0X HY0X GX0X GX0Y" - " @ZCY ?Y.Y CYBY 5W9X8W.W HW-WAiAW,WA[3W.W9Y9W >X *ZCZ 6~d IYET 4~`,~i!| By EX.Y IX.X AYAZ 7ZFY IX " - " Z 3X 6~e 9TF\\ 9WBX=W7Z7\\EX 7Y CZ KX Nl \"X 3Z/Z 4Z &\\ ;Z M~Z %Z I[0Z 6[ 9Z/" - "Y 8ZCZ 8i 6~d 5i ;Z HW>X3W?W0~T KZ-Z\"Z \"Z$[!Z MZ 0[!Z'Z(Z :Z \"Z 4ZD] 4Z 2Y?XMX?Y(Y:ZHZ)Z N[!Z /[ NZ%Z6[" - " J[ 7Y 9Z(Y DZDZ LZGW:WGZ K[GZ +Z -\\ LX EX IY L\\6Y FY.Y KZ %Y-Y K~W 9Y 5Y.Y GY1Y 5Y NX 0XM\\ MY " - "FY3Y2Y+Y1Y KZ.Z JY.Y Y-X ;Y Ji 4Y .Y1Y @YAY FYGWDXGX >` /YCY .[ $\\ LX M\\ AR+` CT9[:U'Z3X AY0Y FY9Z FY-Z " - "D` .Y1Y >YEZ 6YAZ BY1Y&Z8X9[,ZAYAZ IY9Y IY@X@Y LY.Z Y-Y 5Y 5Z/Y KZ1Z 9[ -Z /Z\"[+[>Z>[(Z(Z ^IZJ_&[ NZ.\\ 2X 3" - "\\ >X >[ \\ ?X DX 4Z?U -Z 'X6X G~W 9^@X GUDY$T Ns ?[CZ 8X %U?WAY?U ,X EY1Y 1WEW \"s 4" - "ZCZ 7W7UGV LX)X MW7UGW CY 8~T J~T I~S J~T I~T K~T*~ ;Z IZ !Z Z !Z >Z !Z !Z \"Z :Z$[(Y:ZGY)[ NZ-Z N[.Z N[/[ N" - "[/[ NZ Fi G[FX1Z)Z(Z#Z(Z$Z(Z$Z)Z 9Z 2ZX )YCY 5~d IYFU 4~`,~i!{ @x EX.Y IX.X AY@Y 7ZGZ IX Z 3X 6~e 9TD[ ;XBX=X8" - "Z6\\GY 7Y CY JX Nl \"X 2Y/Z 4Z '\\ :Z M~Z %Z I[0Z 6Z 8Z/Z \"Z 5i 9~d 8i 8Z HW>X3W?W0~U LZ-Z\"[ " - "#Z$[!Z MZ /Z!Z'Z(Z :Z \"Z 4ZC] 5Z 2Y?XNY?Y(Y:ZHZ)[ [!Z .Z NZ%Z5[ K[ 7Y 9Z(Y DZDY KZHX:XHY K[EZ ,Z .\\ KX EX" - " IY LZ4Y FY.Y KZ %Z.Y KZ X DX 4Z?U -Z 'X6X G~W " - "8^BX FUDY%U Ns =ZCZ 9X $U@W@X?T +X EY1Y 1WEW \"s 5ZCZ 7W7UFV LW(W MX8UFW CY 8~U K~T J~U K~" - "T J~U K~T*~ ;[ JZ !Z Z !Z >Z !Z !Z \"Z :Z$Z'Y9YGY)[ [-[ [.Z N[.Z NZ.[ NZ G\\L[ GZGX0Z)Z(Z#Z(Z$Z(Y#Z)Z 9Z 2~ " - "GY4] J[4Y G[4Y G[4X EZ4Y FZ4Y G[4Y,[4X 1Y #Y Y Y Y 9Y Y NX Y 6Y-Z JX0X JY-Y LZ-Y MZ.Z MY-Y KY-Y BYEW?Y" - " KY0X HY0X GX0X GX0Y ?YDY >Y.Y BYDY 4W9X9W-X JX,WD\\J[CW,WC[2W-X JX >X )YDZ 5~d HXFU 4~_+~i z @w DX.Y" - " IX.X BZ@Y 6YGZ IY Y @~e 9TCZ ;WAX=X8Y4\\HX 6Y CY JX Mj !X 2Y/Y 3Z (\\ 9Z" - " M~Z %Z I[0Z 6Z 8Z/Z \"Z 2i <~d ;i 5Z HW>X3W@W/~U LZ-[#[ #Z$Z Z MZ /Z!Z'Z(Z :Z \"Z 4ZB] 6Z 2Y>a>Y(Y9ZIZ)[ " - "Z Z .Z [%Z4Z JZ 7Y 9Z)Z DZEZ JYHX:XIZ KZD[ -Z /\\ JX EX IY MZ3Y FY.Y JY %Z/Z JY Z !Z !Z \"Z :Z%['Y9ZHY(Z [-[ Z" - "-[ Z-Z [-Z [ H\\J[ HZHY1[)Z(Z#Z(Z$Z(Y#Z)Z 9Z 2} FY2\\ KZ3Y GZ3Y GY3Y FZ3Y GZ3Y GZ3Y,Z3X 1Y #Y Y Y Y 9Y Y " - "NX Y 6Y-Z JX0X JY-Y KY.Z MZ.Z MY-Y KY-Y BYFX?Y KY0X HY0X GX0X GX0Y >YEY >Y.Y BYEZ 4X:X9W,W JW+WE\\H[EX,X" - "E[1W,W JW =X )ZEY 4~d HYHU 2~^+~i Nx >u CX.Y IX.X BY?Z 7ZHY GX Z A~e 9TCZ ~d >i 2Z GV>X3W@W0~V LZ-[\"Z " - "#Z%[ Z MZ /[\"Z'Z(Z :Z \"Z 4ZA] 7Z 2Y>a>Y(Y9ZIZ(Z Z Z .[![%Z4[ KZ 7Y 9Z)Z CZFZ JZIX:XIZ L[CZ -Z /[ IX DX J" - "Y MY2Y FY.Y JY %Z/Z JY Y CY1Y&Z9Y9Z+ZAYAY HY9Y IY@X@Y LZ/Y N" - "Y-Y 5Y 4Y0Z LZ.Y =[ *Z .[%Z(]AZA]'Z(Z L~\"[![+\\ 5X 6\\ JTEXET J[&\\ KSDXES $Y 3Y?U -Z &Y:Y F~W 5_GX DU" - "CZ9QAU DZCZ ;X $VAW?YBU +X EY1Y 1WEW DZCZ 6W7UEV NX)X MX8UEW DY 8~V L~V L~W M~V K~V M~V" - ",~P :Z JZ !Z Z !Z >Z !Z !Z \"Z :Z%['Y8ZIY(Z Z+Z Z-[![-[![-[![ I\\H[ I[JY0[(Y(Z#Z(Z$Z)Z#Z)Z 9Z 2| EY1\\ LY2Y " - "HZ2Y HZ3Y FY2Y GY2Y GY2Y-Z2X 1Y #Y Y Y Y 9Y Y NX Y 6Z.Y IX0X JY-Y KY.Z MZ.Z MY-Y KY.Z BYGX?Z KY1Y HY0X" - " GX0X GX0Y >YFZ >Y.Y AYFY 2W:X:X,W JW+XG\\F[FW+XF[1X,W JW =X (YEY 4~d GXHU 2kNRMk*tNq Mv Y 7ZIZ GY !Z A~e 9TBY `=Y(Y8ZJZ([\"[ Z " - ".[!Z$Z3Z KZ 7Y 9Z)Z CZGZ IZIW8WIZ M[AZ .Z 0\\ IX DX JY MY2Y FY.Y JY $Y/Z JY YEY CYIWBXIX @f 0YGZ 0[ LZ NX NY 'U>WMW?V&Z4Y AY/Y HY8Y" - " EZ.Y FZ %Y1Y Y CY1Y&[:Z:Z+ZAYAY HY9Y IY@X@Y LZ/Y NZ.Y 5Y 4Y0Y KZ.Z ?\\ *Z -['['\\AZB]&Z(Z K|![!Z)\\ 6" - "X 7\\ JVFXFV J[(\\ KUEXFU %Y 3Y?U -Z %YXCU *X EY1Y 1WEW" - " F[CZ 6X8UDV NW)X MX8UDW DY 8~W N~W L~W M~V L~W M~W-~P :[ KZ !Z Z !Z >Z !Z !Z \"Z :Z%['Y8ZIY([\"[+[" - "\"[,Z![-[!Z,[!Z I\\F[ J[KY/Z'Z)Z#Z)Z#Z)Z#Z)Z 9Z 2{ DY0[ MY1Y HY1Y HY2Y FY2Y HZ2Y HY1Y-Y2Y 1Z $Y Y Y Z :Y Y" - " NX Y 6Z.Y IX0X JZ.Y KY.Z MZ.Y LZ.Y KY.Z BYHX>Z KY1Y HY1Y GX0X GX0Y =YGY =Y.Y AYFY 2X;X:W+X LX*WH\\D[HX" - "*WG[0W+X LX =X (YFZ 4~d GYIU 2jLQLj*pNRNq Lt :q AX.Y IY0Y CZ>Y 6YIZ FX !Z A~e 9T" - "BZ >W?W;W8Z2\\MY 4Y DY JX 4X 1Z1Z 3Z +\\ 6Z M~Z %Z HZ0Z 8[ 7Y.Z #Z )i D~d Ci -Z GV=W4XAW/~W M" - "Z-[\"[ $Z&[ NZ MZ .Z\"Z'Z(Z :Z \"Z 4Z?] 9Z 2Y=_=Y(Y8ZJZ([\"[ Z -Z\"[$Z3[ L[ 8Y 9Z)Z BZHZ IZJX8XJY LZ@[ /Z 1\\" - " HX DX JY NY1Y FZ0Z JY $Y/Z JY YEY BXJXAWJY A[N[ 1YGY 0[ JY NX NY 'V@WLX@U$Y5[ BY/Y HX7X DZ.Y FY $Y1Y Z " - "/Z K_MZ BUC]BVBU A[D[ >X #VBW=XDU *X EY1Y 1WEW G[D[ 5W8UCV X*X LW8UCW EZ 8~W N~X M" - "~W N~X M~W N~X.~Q :[ KZ !Z Z !Z >Z !Z !Z \"Z :Z&[&Y7ZJY([\"[+[\"[,[\"Z+[#[+Z\"[ J\\D[ JZKX/['Z*[#[*Z#Z)Z#Z)Z" - " 9Z 2z CY/Z MY1Y HY2Z HY2Y GY1Y HY1Y HY1Y-Y2Z 2Z $Z !Z !Z !Z :Y Y NX Y 6Z.Y IX0X JZ/Z KY.Z LY.Y LZ/Z KY.Z " - " BYHW=Z KY1Y GX1Y GX1Y GX0Y =YHZ =Y/Z @YHY 1X;X;X*W LW)XJ\\B[IX*XI[0X*W LW Z 7ZJY EY !Z 1X@X &TAY ?X?W;W8Z1\\NX 3Y DY JX 5Y 0" - "Y1Z 3Z ,\\ 5Z M~Z %Z HZ0Z 8Z 6Y.Z #Z &i G~d Fi )X FV=X5XAW0~Y NZ-[!Z $Z&[ NZ MZ .[#Z'Z(Z :Z \"Z 4Z>] :Z 2" - "Y=_=Y(Y7ZKZ'Z#[ NZ -[#[$Z2[ M[ 8Y 9Z)Z BZHZ HYJX8XKZ M[?Z /Z 2\\ GX CX KY NY1Y FZ0Z JZ %Y/Z JZ =Y 4" - "Y0Z GY1Y 5Y NX 0XG\\ $Y FY3Y2Y+Y1Y JZ/Y IZ0Y MY/Y ;Y 8[ 8Y .Y1Y >ZGZ BYKXAXKY B[LZ 0YHY 1[ IY NX Z &VB" - "XKXBV$Y5[ BY/Y HX8Y CY/Z GY #Y1Y Z !Z !Z \"Z :Z&[&" - "Y7ZJY'[#Z)Z#[+[#[+[#[+[#[ K\\B[ K[MX.['Z*Z!Z*Z#Z)Z#Z)Z 9Z 2x AY.Z NY2Z HY2Z IY1Y GY1Y HY1Y HY2Z-X1Z 2Z $Z !Z !Z" - " !Z :Y Y NX Y 5Y/Z IX0X JZ/Z KZ/Y KY.Y LZ/Z KZ/Y AYIWW;W8Z0e 3Y EZ JX 5X /Z2Y 2Z -\\ 4Z M~Z %Z HZ0Z 8Z 6Z/Z $Z #j J~d Ii CW>X6Y" - "BX0~Y NZ-[![ %Z'\\ NZ MZ -Z#Z'Z(Z :Z \"Z 4Z=] ;Z 2Y<][ 0" - "Z 3\\ FX CX KY NY2Z FZ0Y IZ %Y/Z JZ =Y 4Y0Z GY1Y 5Y NX 0XF\\ %Y FY3Y2Y+Y1Y JZ/Y IZ0Y MY/Y ;Y 7Z 8Y" - " .Y2Z =YGY AYKW@XKY BZJZ 1YIY 1[ HY NX Y %WEYIYFW#Y5[ BY/Y HX8Y CY/Z GY #Y1Y ;XIY 6Y;Z EY1Y%Z:Z:Z*ZBYBZ " - "HY9Y IY@X@Y LZ/Y MY/Z 4Y 4Y2Y KZ,Z B[ 'Z +[+[#_FZF_$Z(Z Gt JZ$[%\\ 9X :\\ J\\IXI[ I\\/\\ K[HXI[ (Y 3Z@U -Z " - "%^F^ /Z X \"f >VBnCU >[D[ @X \"VCWZ !Z !Z \"Z :Z'[%Y6ZKY'[$[)[$[*[$[*[%[*[$[ K\\@[ Le.[&Z*Z!Z*Z\"Z*Z#Z*[ 9Z 2v " - "?Y.Z NY2Z HX1Z IY1Y GY1Y HY2Z HX1Z.Y1Z 1Y #Y Y Y Y :Y Y NX Y 5Y/Z IX0X IY/Z KZ/Y KY/Z KY/Z KZ/Y 7\\ 7ZKW" - ";Y IX1Y GX1Y GY2Y GY2Z YJX(XJY/X)X Y W;W7Y/c 2Y EY IX 5X /Z3Z 2Z .\\" - " 3Z M~Z &Z FY1Z 8[ 6Z/Z $Z i L~d Li @W>Y7YBW0Z*Y NZ-[![ %Z'[ MZ MZ -[$Z'Z(Z :Z \"Z 4Z<] Z !Z !Z \"Z :Z(\\%" - "Y6ZKY&[%[)\\&[)[%[)[%[)[%[ L\\>[ Ld.[&Z*Z!Z*Z\"Z+[\"Z+Z 8Z 2s YJY .X=X=Y(" - "X!X'YJWX.Y HY2Y CZW=X8ZC" - "W/Z*Z Z-Z N[ &Z(\\ MZ MZ -\\%Z'Z(Z :Z \"Z 4Z;] =Z 2Y<]Y 4Z2[ GY1Y 5Y NX 0XD\\ 'Y FY3Y2Y+Y1Y IY0Z IZ1Z MZ1Z ;Y 6Y" - " 8Y .Y2Z =ZIZ @XLX?WLY C[H[ 2YKZ 3[ EX NX Y $hFh\"Z7\\ BY0Y GX9Y BZ1Z FX \"Y1Y ;YKY 6Y9Y EY2Z%Z;[:Z*ZBYB" - "Y GY9Y IY@XAZ L[1Y LZ1Z 3Y 3Y3Y LZ*Z D[ &Z *[-[ aJZJa\"Z(Z Cl F\\'[\"\\ ;X <\\ F\\KXK\\ F\\3\\ H\\JXK\\ 'Y " - "2ZAU -Z 'z 1Z X Na ;V@jDV :ZCZ BX UDW;XIU 'X EY2Z 1WEW KZCZ 3X9U@V\"W*X LX9VAW H[ " - "8Z*Z\"Y)Y!Z*Z\"Z*Y!Z*Z\"Z*Z1Z3Z 8[ MZ !Z Z !Z >Z !Z !Z \"Z :Z(\\%Y5ZLY&[&['[&[([&[)\\'\\)[&[ L\\<[ Mc.[$Z,[!" - "[,[\"Z+Z!Z+Z 8Z 2n 7Y-Y NX1Z IY2[ IY2Z GY2Z HY2Z IY2[.Y2\\ 2Z $Z !Z !Z !Z ;Y Y NX Y 5Z0Y HX0X IZ1Z IY0Z KZ0" - "Y JZ1Z IZ1Z 7\\ 6YMX;Z IY3Z GY2Y GY2Y GY2Z ;YKY ;Z1Z >YJY .Y>X=X'Y#Y&XIU:UJY&YJU.X'Y#Y ;X &YJZ #Z JXLU" - " -dIQId%kKRKk El 2j >X.Y HY2Y CY;Z 7ZMZ BZ #Z 3X@X %TAX @WZ 2Y;[;Y(Y5ZMZ&\\([ LZ +['[\"Z0[ Z 7Y 8[,Z ?YKZ EYLX6XLY [:[ 2Z 5\\ DX BX LY NY3[ F[2Z HZ %Y1" - "[ IZ >Y 3Y2[ GY1Y 5Y NX 0XC\\ (Y FY3Y2Y+Y1Y IZ2Z H[2Z LY1Z ;Y 6Z 9Y .Y2Z Z !Z" - " !Z \"Z :Z)\\$Y5ZLY%[(\\'\\(['\\(['['['[(\\ M\\:[ Ma-[$Z,Z NZ,Z![,Z!Z,[ 8Z 2Z #Y-Y NX2[ IY2[ IY2Z GY3[ HX2[ IY2" - "[.Y2\\ 2Z $Z !Z !Z Y ;Y Y NX Y 5Z1Z HX0X IZ1Z IZ1Z JZ2Z JZ1Z IZ1Z 7\\ 6c:Z IY3Z GY3Z GY3Z GY3[ ;YKY ;[2Z =" - "YLY ,Y?X>Y&Y%Y%YIS8SJY$YJS.Y&Y%Y :X &ZKY #Z IYNU ,cISIb#jKRJi Cj 1i =X.Y GY4Y BY:Y 7ZMZ AZ " - " $[,P )W?X %TBY AXXMY DZDZ 2YLY 3[ DY X Y \"eCd NY8^ CY0Y GX:Y @Z2Z FX \"Y1Y :YMY 6Y7Y " - "FY2Z%[<\\a@V 7YBY CX NV LV BZ3Z 1WEW LYBY 2W8U?V#W+X KX9U" - "?W J[ 7Z(Y#Z)Z#Z(Z$Z)Z\"Y(Z$Z(Y2Z2Z 7\\\"P NZ !Z Z !Z >Z !Z !Z \"Z :Z*\\#Y4ZMY%\\)[%[)\\&[)\\'\\)\\'\\)[ M\\8" - "[ N`-[#Z,Z NZ,Z Z-[![-[ 8Z 2Z #Y-Y NX2[ IY2[ IY3[ GY3[ HY3[ HX2[.Y3^ 2Z $Z !Z !Z !Z ZMZ DZMW4WMZ![7Z 3Z 7\\ BX AX MY NY3" - "[ F\\4Z FZ &Z3\\ HZ ?Y 3Z4\\ GY1Y 5Y NX 0X@[ *Y FY3Y2Y+Y1Y HZ3Z H\\4Z KZ3[ ;Y 5Y 9Y -Y4[ ;YKY >YNX=WNY D[D[ " - "3YMY 3[ CY X Y !cAb MZ9^ CZ2Z GX:Y @Z3Z EX \"Y1Y :YMY 7Z7Y FZ4[$Z<\\Z !Z !Z \"Z :Z+]#Y4ZMY$[*\\%\\*[%\\+\\%\\+\\%\\+\\ N\\6[ N^-\\#[.[ N[.[ [.Z NZ-Z 7Z 2Z #Y-Y NY4\\ IY3" - "\\ IY3[ GY3[ HY4\\ HX3\\.Y3^ 2Z $Z !Z !Z !Z i i 2WZ4" - "Z EY #Y1Y 9XNZ 7Y6Z GZ4[$Z=]=['ZDYDZ FY9Y HZBXBZ K]5Z J[5[ 2Y 2Z7Y L[(Z H[ #Z '\\5[ F~ LZ(Z :Z :\\-\\ KW :X :" - "V >r >V/V @s #Z 2[CU -Z +[MeL[ 5Z X G\\ :W!V 3W@W 7V!W AZ4[ 1WEW LW@W 1W7s,X-" - "Y JX8t$\\ 7Z'Z%Z'Z$Z'Y%Z'Z$Z'Y%Z'Z4Z1Z 6\\&S NZ !Z Z !Z >Z !Z !Z \"Z :Z,]\"Y3ZNY$\\,\\#\\,\\$\\,\\$\\-\\$\\," - "\\ N\\4[ ]-\\![/Z LZ/[ N[/[ N[/[ 7Z 2Z #Y-Y NY4\\ HY5] IY4\\ GY4\\ HY4\\ HY4\\.Z5` 2Z $Z !Z !Z !Z =Y Y NX Y " - "3Z4Z GX0X H[5[ GZ4Z GZ4Z H[5[ GZ4[ 6\\ 5_9[ HZ5[ GZ5[ FY5[ FY5\\ :YNZ :\\4Z ;YNY )YAXAZ\"Z+Z!Z*Y Y*Z\"Z+Z 8" - "X $YMY %[ F^ '\\FSF\\ LcGRGc >f ,c :X.Y FZ7Y BY8Y 7e >[ %[1S -Y 'X@X ;Q:TCZ CX:X=X" - "5[.] /Y HY HX NZ GZ 'X +[8Z 0Z 4\\ 0[ 'Z M\\ CZ6[ 9Z 2[3[ '[ 0Y Y ?f f BX DW=\\C_J[.Z&Z\"Z0\\ " - "J\\(T'Z._ JZ MZ *])Z'Z(Z :Z \"Z 4Z6] BZ 2Y JY(Y3e#\\.\\ JZ )]/\\ NZ.[ NQ'[ 6Y 6[0[ =ZNZ CYNX4XNY!Z4[ 5Z 8[ @X" - " AX MY NY5] F]6Z DZ &Z5] G[ AY 2[8^ GY1Y 5Y NX 0X>[ ,Y FY3Y2Y+Y1Y H[6[ G]6Z IZ5\\ ;Y 6Y 8Y -Z6\\ ;Z" - "MZ =b=b EZ@Z 3d 5[ AY X Y L[:\\ IZ;` D[4Z FXZ5[ EY #Y1Y 9c 7Z5Y GZ5\\$[>^>['[EYE[ FY9Y HZBXCZ J]5Z " - "IZ5Z 1Y 1Y8Z LZ&Z J[ \"Z &\\8] E| KZ(Z :Z :]/] JU 9X 9T

q \"Z 1ZCU -Z ,[JaI[ 6Z X F\\ :W#V 1" - "V?V 7W#W @[5[ 1WEW LV?V 1X7s,W-Y JX7t%\\ 6Z&Z&Z'Z%Z&Z&Z'Z%Z&Z&Z&Y4Y0Z 5\\(T NZ !Z Z " - "!Z >Z !Z !Z \"Z :Z.^!Y3e#\\.\\!\\.\\#].\\#]/]#\\.\\ N\\2[ ]/]![0[ L[0[ M[0[ N\\1[ 6Z 2Z #Y-Y NY5] HY5] IZ6] GY" - "5] HY5] HY5]-Y5a 3[ %[ \"[ \"[ \"[ >Y Y NX Y 3Z5[ GX0X GZ5Z F[6[ G[6[ GZ5Z F[5Z 5\\ 4^9Z FY6\\ FY6\\ FY6\\ " - "FY6] 9c 9]6Z :d )[CXBZ Z-Z NZ-[ [-Z Z-Z 7X $YNZ %Z D] $VCSDW G`FSG` ;d +c :X.Y F[9Z CZ8Y 6d =\\ " - " '\\3T -Z (W?X ;Sd c @Z EW<_Ks-Z&Z\"Z1] J^,V'Z/_ IZ MZ )]*Z'Z(Z :Z \"Z 4Z5] CZ 2Y JY(Y2d#]0\\ IZ (]1] NZ-" - "Z NS*\\ 6Y 6[1[ Z 4c 5[ @Y X Y HS3V FZZ%ZEYF[ EY9Y GZCXD[ J^7Z H[7[ 1Y 1Z:Z KZ&Z K[ !Z %];] Bx IZ(Z :Z 9]1] HS 8X 8R :n :R+R U 6W%W ?[6\\ 1WEW LU>U 0W6s-X.X HW6t&\\ 5Z&Z'Z" - "%Z&Z&Z'Z%Z&Z&Z&Z&Z6Z0Z 4],V NZ !Z Z !Z >Z !Z !Z \"Z :Z0`!Y2d\"\\0]!]0\\!]0\\!]1]!]1] \\0[ ]1] N[2\\ L\\2[ L\\" - "2[ L[1[ 6Z 2Z #Y.Y MZ7^ HY6^ HY6] GZ6] HZ7^ HZ7^-Y6c 3[ %[ \"[ \"[ \"[ ?Y Y NX Y 3[7[ FX0X G[7[ E[7[ FZ7[ F" - "[7[ E[7[ 5\\ 4]9[ FZ8] FZ8] FZ8] FZ7] 9c 9]7[ 9b '[DXD[ N[/Z LZ/[ M[0[ N[/Z 6X $d %Z C\\ ?S 2\\ETD" - "\\ 9b )a 9X.Y E[<[ BY7Z 7c ;\\ '\\5U -Z (W?W :U>TE[ CX8X?X3\\3b 1Y IY GX NZ GZ (" - "X )[;[ /Z 5[ %Q-\\ &Z BQ/] AZ9\\ 9Z 0[6\\ (\\ /Z \"[ ;a ` =Z EX[ 4b 6[ ?Y X Y " - "FZ=b E]7Z EX=Z <[9\\ D[ %Y1Y 8a 6Y3Y H\\8]#[@WNW@[%[FYG\\ EY9Y G[DXD[ J_9[ G[9[ /Y 1Z;Z LZ%Z L\\ !Z $]=\\ >t GZ" - "(Z :Z 8]3] FQ 7X 7P 8l 8P)P :m Z 0[EU -Z .[?P?[ 8Z X D[ 9W(W -T\\8] 1WEW " - " LSZ !Z !Z \"Z :Z2a Y2d\"^3] N]3^ ]3" - "] N]3] N]3] \\.[!^3] M\\4\\ J\\4\\ K\\4\\ L\\4\\ 5Z 2Z #Y.Y MZ8_ HZ8_ HZ8^ FZ8^ HZ8_ HZ8_-Z8e-Q)\\ &\\-Q G\\-Q " - "G\\-Q G\\-Q 5Y Y NX Y 2[9\\ FX0X F[9[ D\\9[ E[8[ E[9[ D\\9[ 4\\ 3[9[ EZ9^ FZ9^ FZ9^ F[9^ 9b 8^9[ 8b &[2[" - " L\\3\\ K[2[ K[2[ L\\3\\ 6X #c &Z B\\ ?S /UATAT 4a '_ 8X.Y E\\>\\ BY6Y 7c :] (\\7V " - "-Z )X@X :W@TF[ BW7X?X3]6e 1X IY GX NZ GZ (X ([=[ .Z 6[ $S1^ &Z BS3^ @\\<\\ 8Z 0]9] FR6] .Z \"[ 8^ " - " ^ ;Z DW;lMc+Z$Z#Z4_ G_2Y'Z5c GZ MZ '^/\\'Z(Z :Z \"Z 4Z3] EZ 2Y JY(Y1c!^6^ HZ '^6^ LZ,Z X1] 5Y 5]6\\ :c Ab2a" - "\"Z0[ 7Z ;\\ >X @X NY MZ:` F_:[ B\\3P D[;` E\\1S 7Y 0\\>a GY1Y 5Y NX 0X;\\ 0Y FY3Y2Y+Y1Y F[:[ E_;\\ " - "F[;_ ;Y *S1Y 6Z .[;_ :e ;`;` G[<[ 5a 6[ >Y X Y F[?YNY F_:[ DX?Z :[;\\ B[ &Y1Y 8a 7Z3Y H]:^#\\BXNWA[#[" - "GYH\\ DY9Y F\\FXF\\ I`;[ F\\;\\ /Z 2[=Z KZ$Z N\\ Z #^A] :n DZ(Z :Z 7]5] +X Mj (k NZ 0\\FUBP ;Z /[,[ " - "9Z X CZ 8X+W *R;R 4X+X =]:^ 1WEW LR;R /X5s.W.X GW5t(\\ 4Z$Z(Z%Z'Z$Z(Z$Y'Z$Z(Z$Z" - "8Z/Z 3_2Y NZ !Z Z !Z >Z !Z !Z \"Z :Z5c NY1c!^6^ L^6^ M^6^ M]5] M^6^ \\,[#a7^ K\\6] I\\6\\ J]6\\ J\\6] 5Z 2Z #" - "Y/Z LZ:` H[:` H[:_ FZ:` GZ:` GZ:`-[:YN\\0S(\\4Q C\\0S F\\0S F\\0S F\\0S 5Y Y NX Y 1[:[ EX0X F\\;\\ C\\;[ C[:" - "[ D\\;\\ C\\;\\ 4\\ 3[:\\ DZ;_ EZ;_ EZ;_ EZ;` 8a 8_;\\ 7a %\\6\\ J\\5\\ I\\6\\ I\\6\\ J\\5\\ 5X #c 'Z " - "@[ @T JT _ %] 7X.Y D^D^ BZ6Y 6b 9_ *];X -Z )X@X :ZCTH] CX7YAX1^:h 2Y JY GX NZ" - " GZ (X (\\?\\ .Z 7\\ $W7_ %Z BV8` ?\\>] 9[ /];] ET9] -Z \"[ 5[ [ 8Z DX;jLb*Z$Z#Z7a E`7\\'Z9f FZ MZ &`4^" - "'Z(Z :Z \"Z 4Z2] FZ 2Y JY(Y1c _:_ GZ &_9^ KZ,[![6^ 4Y 4]9] 8b @a2a#[/Z 7Z ;[ =X @X NY M[\\ @]7R" - " D\\=a E]4U 7Y /]Bc GY1Y 5Y NX 0X:\\ 1Y FY3Y2Y+Y1Y E\\>] E`=\\ E\\=` ;Y *U5[ 6[ /\\>a 9c :_:` GZ:Z 4` 6[ >Y " - "X Y E[AYMZ G`<[ CX@Z 9\\=\\ A\\3Q EY1Y 7` 7Y2Z I^<_\"[BWMXC\\#]IYI\\ CY9Y F]GXG] Ia=\\ E\\=\\ .[ 2[?Z J" - "Z$Z N[ NZ \"^C^ 7g @Z(Z :Z 7_9_ +X Lh &i MZ /]HUDR ;Z .Y*Y 8Z X BZ 8Y/X (Q:Q 2X/Y " - " <^<` 2WEW LQ:Q .W MV(X/X GX NW\"\\ 3Z$Z)Z#Z(Z$Z)Z#Z(Z$Z)Z#Z8Z/Z 2`7\\ NZ !Z Z !Z >Z !Z !Z \"Z :" - "Z9f MY0b _:_ J_:_ K_:_ L_9_ L_9^ N[*[$c:^ J^:^ H^:^ I^:] H]9] 4Z 2Z #YIP7[ L[] C\\=\\ A\\=\\ 3\\ 2\\=\\ C[=` E[=` E[=" - "` E[=a 8a 8`=\\ 6` #]:] H]9] G]:] G]:] H]9] 4W !a 'Z ?Z ?U KT N] $] 7X.Y Cv AZ6Z 7a 7a " - " -_?Z -Z )W?X :^GTK_ CX5XAX0_>k 3Y JX FX NZ GZ )Y ']C] ?} I~S IZ=b %Z BZ>a =]B^ 8Z ._?^ DX" - "@_ ,Z \"[ 3Y X 5Z CW:gJ`)Z\"Z$~T Cb=_'~W E~S FZ %b:a'Z(Z :Z \"Z 4Z1] G~Q)Y JY(Y0b N`>` FZ %a?` JZ+Z!^_ 8b @a2a$[.[ 8Z <~` AX ?X Y L\\@c Fb@] ?^` H`>` I`>` Ja?a Ja?` LY(Y$f?` H_>_ F_>_ G_>_ H_>" - "_ 3Z 2Z #YIS;[ K\\?c G\\?c G\\?b E\\@c F\\@c G\\?c,\\?[L^9Y'^} I~S I~ $Z B| ;^F_ 7Z -aEa Dv +Z \"[ 0V U 2Z CX9dI^'Z\"Z$~S AfGd'~U C~S FZ $gGg&Z(Z :Z \"Z 4Z0] H" - "~Q)Y JY(Y0b McGd EZ $dGc IZ+[\"cEd 3Y 3cGc 7a ?`1a$Z,[ 9Z =~a AX ?X Y L^DZNY FYNZF_ =`CY B^EZNY CaB] 7" - "Y .qMY GY1Y 5Y NX 0X8\\ 3Y FY3Y2Y+Y1Y D_F_ CYNYE_ B^EZNX ;Y *]A^ 4k >^G[NY 8a 9_9^ H[8[ 5^ 6~P 2Y X Y " - " D^H[La NfH` AYD[ 6^E_ ?`?X EY1Y 7_ 7Y0Y IcFk(]HZLZI^ `Nk BY9Z E~Q GYNZE^ B_E_ ,e ;]G] J~c!~T FZ 3oDo @Z :Z(Z :" - "Z 5dGd )X Jd \"e KZ -`MUKY H~U IU&U 6Z X AY 5Z7Z LZ7Z ;~d 3cFk 8WEW " - " BW LV)X0X FW LW$\\ 2Z\"Z+[#Z)Z\"Z*Z\"Z*Z\"Z*Z\"Z:Z.~T*fGd N~T J~T I~S I~S 7Z !Z !Z \"Z :~U JY/a MdGc FcGd GcGd" - " HdGd HdGc JW&W$kGc FbFb DbFb FcFb FcGc 3Z 2Z #YIWB] I^DZNY F]D[NY F]D[NX E^DZNY F^DZNY F^E[NY+]D]J`@]&`BY AaA]" - " DaA] DaA] DaA] 5Y Y NX Y /_F_ CX0X D_E_ ?_F_ ?_F_ @_E_ ?_F_ 7aF_ @^FZMX D^FZMX D_GZMX D_G[NY 7_ 7YNYE_ 4^" - " dLd CdMd BdLd CdLd DeMd 2X !` %X =Y ?U LV MZ !Y 5X.Y As AZ4Y 6` 5~] )x -Z " - "*X@X 9} BX3YFZ-{L] 4Y LY FX NZ GZ )X $t >} I~S I} #Z B{ :v 7[ ,{ Cu *Z \"[ -S S 0Z BW8aG[%[\"Z$~R" - " ?~S'~T B~S FZ #~V%Z(Z :Z \"Z 4Z/] I~Q)Y JY(Y/a L~ DZ #~ HZ*Z\"~R 2Y 2} 5` ?`0_$[+Z 9Z =~a AX ?X Y KsN" - "Y FYNr ;u AqMY B{ 7Y -oLY GY1Y 5Y NX 0X7\\ 4Y FY3Y2Y+Y1Y Cv BYNr ArMX ;Y *y 2j >qMY 8a 8^9^ I[6Z 5^ 6~P 2Y X " - " Y CpK` N} ?YF[ 5w =x EY1Y 6] 7Z0Z J~Y(nJm M{ AY9\\ F~ FYMq @w *d ;r J~d!~T FZ 3oDo @Z :Z(Z :Z 4~ 'X " - " Ib c JZ ,u H~U HS$S 5Z X AY 4\\>\\ I]>\\ :~d 3~Y 8WEW CW KV)W0X FX LW" - "$[ 2[\"Z+Z!Z*Z\"Z+Z!Z*Z!Z,Z!Z:Z.~T)~S N~T J~T I~S I~S 7Z !Z !Z \"Z :~T IY/a L~ D~ E~ F~ E~ HU$U$~X D| B| D} D} " - "2Z 2Z #YIr HrMY FsMY FsMX DsNY ErMY FsMY+uH|%v @| C| C| C| 5Y Y NX Y .v BX0X Cw =w >v >w =w 8{ ?qMX CqMX C" - "qMX CqMY 6] 6YNr 3^ My Ay @y @z Ay 1X _ $V X !" - "Y JqMY FYMp 9t ApLY Az 7Y ,mKY GY1Y 5Y NX 0X6\\ 5Y FY3Y2Y+Y1Y Bt AYMp ?pLX ;Y *x 1j =oLY 8a 8]8^ IZ4Z 6" - "] 5~P 2Y X Y CoI_ N} ?[K] 3u ;w EY1Y 6] 7Y.Y JvM_'mJm Ly @Y9b K| EYLp ?u (c :p I~e\"~T FZ 3oDo @Z :Z(Z" - " :Z 2{ &X H` Ma IZ +t H~U GQ\"Q 4Z X AY 2aLb FaKa 8~d 3YNlN_ 8WEW " - "DX KV*W0o-W KW%[ 1Z Z,Z!Z+Z Z,Z!Z+Z Z,Z!Z;Z-~T'~P M~T J~T I~S I~S 7Z !Z !Z \"Z :~R GY.` K| B| C{ B{ B{ FS\"S$YM" - "{ Bz @z B{ B{ 1Z 2Z #YIq GqLY EqLY EqLX CqMY ErMY EqLY*sF{$u ?{ B{ B{ B{ 5Y Y NX Y -t AX0X Bu ;u pLX CpLX CpLX BoLY 6] 6YMp 1] Lv >w =v =v >w 0X _ #T ;X ?W MV LW LV 4X.Y ?n >Y3Z 7_ 1~Z " - " 't +Z *W?X 8y @X1j)vG] 5X MY EX NZ GZ *X !p <} I~S Iz Z By 6r 5Z )w As (Z \"[ " - " 5Z AX HZ Z%~ 9|$~P >~S FZ ~P\"Z(Z :Z \"Z 4Z-] K~Q)Y JY(Y.` Jy AZ x EZ)Z#~P 0Y /x 3_ =_0_%Z([ ;Z =~a AX " - ">X !Y JpLY FYLn 7s @nKY @y 7Y +kJY GY1Y 5Y NX 0X5\\ 6Y FY3Y2Y+Y1Y Ar @YLn =nKX ;Y *w /i x ?x @y 0Z 2Z #YIp EoKY DoKY DoKX BoLY DpLY DoKY)qCy#t =y @y @y @y 5Y Y NX Y ,r @X0X As 9s :r :s 9s 7z <" - "nKX BnKX BnKX BnKY 6] 6YLn 0\\ Jt ;s :t ;t ;s .X N] !R 9V >W NX LU KU 3X.Y >l =Y2Y 7_ /~X " - " %p )Z *W?W 4u @X/i(tE] 6Y NX DX NZ GZ *X m :} I~S Iy NZ Bw 2o 5Z 'u @r 'Z \"Z " - " 4Z AY J[ Z%} 6x\"} <~S FZ N| Z(Z :Z \"Z 4Z,] L~Q)Y JY(Y.` Hv @Z Mu DZ)[$~ /Y .u 0^ =^/_&['Z ;Z =~a AX >X" - " !Y InKY FYKl 5r ?lJY >w 7Y )hIY GY1Y 5Y NX 0X4\\ 7Y FY3Y2Y+Y1Y @p ?YKl ;lJX ;Y *v -h ;kJY 7_ 7]7\\ J[2" - "[ 7\\ 5~P 2Y X Y AkE] Nz :i .p 7u EY1Y 5[ 7Y,Y KYMiL_%iGj Hu >Y8a Hv BYJl :p $a 7k H~f\"~T FZ 3oDo @Z " - ":Z(Z :Z /u #X F\\ I] GZ )r H~U *Z X AY /p >o 4~d 3YMiK^ 8WEW EX " - "JV+W/o/X JW&Z 0[ Z-Z NZ-[ [.Z NZ,Z NZ.Z NZ=Z,~T$x I~T J~T I~S I~S 7Z !Z !Z \"Z :| BY-_ Hv p %Z \"Z " - " 4Z @X JZ MZ&{ 3u z 9~S FZ Lx MZ(Z :Z \"Z 4Z+] M~Q)Y JY(Y-_ Fr >Z Lr BZ(Z!y -Y -s /] <^.]&[&[ m >YJj 8iIX ;Y *u *f :iIY 7_ 6\\7" - "\\ K[0Z 6Z 4~P 2Y X Y ?hC\\ NYMm 8f +m 3s EY1Y 5[ 8Z,Y KYLgJ^$gEh Fs =Y8a Fr @YIi 7m !` 6i G~g#~T FZ 3o" - "Do @Z :Z(Z :Z .s \"X EZ G[ FZ 'p H~U *Z X AY ,k :k 2~d 3YLgJ^ 8WEW " - " EW IV,X/o/W IW&Z 0Z MZ/[ NZ-Z MZ.Z N[.Z MZ.Z MZ>Z,~T\"t G~T J~T I~S I~S 7Z !Z !Z \"Z :y ?Y-_ Fr 8r 9r :s :r " - " AXEr :r 8r :s :s -Z 2Z #YIn AkIY BkIY BkIX @jIY BkIY BkIY'l=t Mq :t ;t ;t ;t 3Y Y NX Y *m =X0X >m 3m 5n 5m" - " 3m 6XLm 7iHX @iHX @jIX @jIY 5[ 5YJj -Z El 3k 2l 3l 4l *X N\\ 5U ?Y Y KR HQ 1X.Y 9b 9Y1Z 7" - "] )~S \"j &Z +X@X -h ;X+c!l?\\ 6X Y DX Z FZ +X Kh 8} I~S Fr JZ As ,i 3[ $n ;m " - "#Z \"Y 3Z ?X KZ MZ&x -p Mu 4~S FZ Js JZ(Z :Z \"Z 4Z*] N~Q)Y JY(Y-_ Dn gB[ NYLj 5d (j 0q EY1Y 5Z 7Y+Z LYKdG]\"dBd Bo ;Y7` Dn >YHg 4i L^ 4e " - "E~g#~T FZ 3oDo @Z :Z(Z :Z ,n NX DX EY EZ %m G~U *Z X BZ )e 4e /~d 3YKeH] 8" - "WEW FW HV,W.o0X IW'Z /Z MZ/Z LZ.Z MZ/[ MZ.Z MZ/[ MZ>Y+~T p E~T J~T I~S I~S 7Z !Z !Z \"Z :u ;Y,^ Dn 4" - "n 5n 6o 6n @XBm 5n 4n 6o 6o +Z 2Z #YIl =gGY AhGY AhGX ?hHY @hHY @gGY%i:o Hm 7p 6o 6p 7p 1Y Y NX Y (i ;X0X " - "fGX >fGX >fGY 4Y 4YHf +Z Bg /g .g -g /g (X M[ 5T ?Z !Z JP 'X.Y 5" - "[ 6Y0Y 7] &~P Ne $Z +W?X '] 6W)a Mh<\\ 7Y !X CX Y EZ +X Id 6} I~S Cm HZ =l 'e " - "1Z i 6h !Z #Z 3Z ?Y M[ M['s &k Jo .~S FZ Gm GZ(Z :Z \"Z 4Z)] ~Q)Y JY(Y,^ Bi 9Z Gl AZ'Z Jm (Y (i )\\ " - ";].]'[#Z =Z =~a AX =X \"Y DdFY FYFb *h 6cFY 8j 0Y \"YAY GY1Y 5Y NX 0X1\\ :Y FY3Y2Y+Y1Y ;f :YFb 1cFX ;Y" - " $k ` 7cFY 6] 5[5Z KZ-[ 8Y 3~P 2Y X Y ;b=X NYJe 0` $e +l BY1Y 4Y 7Y*Y LYIaE[ b@a >k 9Y6_ Ah ;YFc 0e " - "FZ 2a D~i$~T FZ 3oDo @Z :Z(Z :Z )i LX CV CW DZ #h D~U *Z X -R9Z #[ *[ *~d 3" - "YIaE\\ 8WEW GX HV-W-o0W HW'Z 0Z L[0Z LZ/[ LZ0Z LZ/[ LZ0Z LZ?Z+~T Lj B~T J~T I~S I~S 7Z !Z !Z \"Z :o " - "5Y,^ Ai /h 0i 0i 0i >W?i 1j 0j 1j 1i (Z 2Z #YGh 9cEY ?dEY ?dEX =dFY >dFY >cEY#d5j Ch 1j 1j 1j 1j -Y Y NX Y" - " &e 9X0X :e ,f -f -e ,f 4XFe 0cEX a NU CZ N` 9X -T<[ " - " LYG]BX 5WEW %U HW NX MX GZ (d +b (b )b )a )b 9V;a " - ")c *c *c *c =a 4_ &^ %^ $^ &_ &_ :_/c RM] !R Z 5\\ " - " 9X ;X $Y HY NY 0Y 'X NY BY X !Y " - ":Y 8Y 4Y *Y 1Y EX 3Y CZ IU 3X -p " - " IY 8WEW #V &Z MV " - " 0U 'P ;Y 2Y >Z 8X " - " MT *X &X 9X DX " - " 5X ?\\%W ?Z 4\\ :X ;X $Y " - " IZ NY 0Y 'X NY BZ !X !Y :Y 8Y 4Y *Y 1Y EX 3Y " - " CZ IU 3X -o HY 8WEW \"V " - " 'Z LU 0V " - " CZ 2Y >Y 7X " - " MT )X 'X 9X DX 5W <\\(X ?" - "Z 3\\ ;Y e GX 2f KZ LY 0Y 'X !Y >" - "\\ %X &] 9Y 8Y 4Y *Y 1Y EX 3Y CZ IU 3" - "X $^ @Y 8WEW !V '\\:V ;V " - " 1W GZ 0Y @Z " - " FWHX LT 'X +W 7W " - " V 5b?c A[ -\\ ?e !f " - " f /X 0g 9Y 8Y 4Y *Y " - " 1Y EX 3Y CZ IU 3X 5Y " - " NV &\\=X ;V " - "1W GY /Y AZ EWHX " - " LT &W ,X 7V V 3~T " - " A] ,\\ @e !f d " - " %e -Y Nd @c " - " (m @c " - " +u $b -Y 'X 0d 2^ /X 0_ 1Y 8Y 4Y *Y " - " 1Y EX 3Y CZ IT 2X 5Y " - "-c !q Hd >c " - " $d ,Y Nd ?b " - " %g =" - "b *t #a ,Y 'X 0d " - " ,X /X 0Y +Y 8Y 4Y *Y 1Y EX 3Y CZ '" - "X 5Y -c Nm Fc " - " =c $c +Y Nc " - " >a " - " M\\ 8a \"~Y 1" - "r !` +Y 'X 0c 1X 1Y 8Y 4Y *Y 1Y EX 3Y " - " CZ &W 5Y -b Lj " - " Db std::printf(). - \note If configuration macro \c cimg_strict_warnings is set, this function throws a - \c CImgWarningException instead. - \warning As the first argument is a format string, it is highly recommended to write - \code - cimg::warn("%s",warning_message); - \endcode - instead of - \code - cimg::warn(warning_message); - \endcode - if \c warning_message can be arbitrary, to prevent nasty memory access. - **/ - inline void warn(const char *const format, ...) { - if (cimg::exception_mode()>=1) { - char *const message = new char[16384]; - std::va_list ap; - va_start(ap,format); - cimg_vsnprintf(message,16384,format,ap); - va_end(ap); -#ifdef cimg_strict_warnings - throw CImgWarningException(message); -#else - std::fprintf(cimg::output(),"\n%s[CImg] *** Warning ***%s%s\n",cimg::t_red,cimg::t_normal,message); -#endif - delete[] message; - } - } - - // Execute an external system command. - /** - \param command C-string containing the command line to execute. - \param module_name Module name. - \return Status value of the executed command, whose meaning is OS-dependent. - \note This function is similar to std::system() - but it does not open an extra console windows - on Windows-based systems. - **/ - inline int system(const char *const command, const char *const module_name=0, const bool is_verbose=false) { - cimg::unused(module_name); -#ifdef cimg_no_system_calls - return -1; -#else - if (is_verbose) return std::system(command); -#if cimg_OS==1 - const unsigned int l = (unsigned int)std::strlen(command); - if (l) { - char *const ncommand = new char[l + 24]; - std::memcpy(ncommand,command,l); - std::strcpy(ncommand + l," >/dev/null 2>&1"); // Make command silent - const int out_val = std::system(ncommand); - delete[] ncommand; - return out_val; - } else return -1; -#elif cimg_OS==2 - PROCESS_INFORMATION pi; - STARTUPINFOA si; - std::memset(&pi,0,sizeof(PROCESS_INFORMATION)); - std::memset(&si,0,sizeof(STARTUPINFO)); - GetStartupInfoA(&si); - si.cb = sizeof(si); - si.wShowWindow = SW_HIDE; - si.dwFlags |= SW_HIDE | STARTF_USESHOWWINDOW; - const BOOL res = CreateProcessA((LPCSTR)module_name,(LPSTR)command,0,0,FALSE,0,0,0,&si,&pi); - if (res) { - WaitForSingleObject(pi.hProcess,INFINITE); - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); - return 0; - } else { - char* lpMsgBuf; - - // Get the error message. - DWORD errorCode = GetLastError(); - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - 0,errorCode,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPSTR)&lpMsgBuf,0,0); - cimg::warn("cimg::system() : Command '%s' (module name '%s) failed with error %lu: %s", - module_name==0?"(null)":module_name, - command==0?"(null)":command, - errorCode,lpMsgBuf); - return -1; - } -#else - return std::system(command); -#endif -#endif - } - - //! Return a reference to a temporary variable of type T. - template - inline T& temporary(const T&) { - static T temp; - return temp; - } - - //! Exchange values of variables \c a and \c b. - template - inline void swap(T& a, T& b) { T t = a; a = b; b = t; } - - //! Exchange values of variables (\c a1,\c a2) and (\c b1,\c b2). - template - inline void swap(T1& a1, T1& b1, T2& a2, T2& b2) { - cimg::swap(a1,b1); cimg::swap(a2,b2); - } - - //! Exchange values of variables (\c a1,\c a2,\c a3) and (\c b1,\c b2,\c b3). - template - inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3) { - cimg::swap(a1,b1,a2,b2); cimg::swap(a3,b3); - } - - //! Exchange values of variables (\c a1,\c a2,...,\c a4) and (\c b1,\c b2,...,\c b4). - template - inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4) { - cimg::swap(a1,b1,a2,b2,a3,b3); cimg::swap(a4,b4); - } - - //! Exchange values of variables (\c a1,\c a2,...,\c a5) and (\c b1,\c b2,...,\c b5). - template - inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5) { - cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4); cimg::swap(a5,b5); - } - - //! Exchange values of variables (\c a1,\c a2,...,\c a6) and (\c b1,\c b2,...,\c b6). - template - inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6) { - cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5); cimg::swap(a6,b6); - } - - //! Exchange values of variables (\c a1,\c a2,...,\c a7) and (\c b1,\c b2,...,\c b7). - template - inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6, - T7& a7, T7& b7) { - cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6); cimg::swap(a7,b7); - } - - //! Exchange values of variables (\c a1,\c a2,...,\c a8) and (\c b1,\c b2,...,\c b8). - template - inline void swap(T1& a1, T1& b1, T2& a2, T2& b2, T3& a3, T3& b3, T4& a4, T4& b4, T5& a5, T5& b5, T6& a6, T6& b6, - T7& a7, T7& b7, T8& a8, T8& b8) { - cimg::swap(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6,a7,b7); cimg::swap(a8,b8); - } - - //! Return the endianness of the current architecture. - /** - \return \c false for Little Endian or \c true for Big Endian. - **/ - inline bool endianness() { - const int x = 1; - return ((unsigned char*)&x)[0]?false:true; - } - - //! Reverse endianness of all elements in a memory buffer. - /** - \param[in,out] buffer Memory buffer whose endianness must be reversed. - \param size Number of buffer elements to reverse. - **/ - template - inline void invert_endianness(T* const buffer, const cimg_ulong size) { - if (size) switch (sizeof(T)) { - case 1 : break; - case 2 : { - for (unsigned short *ptr = (unsigned short*)buffer + size; ptr>(unsigned short*)buffer; ) { - const unsigned short val = *(--ptr); - *ptr = (unsigned short)((val>>8) | ((val<<8))); - } - } break; - case 4 : { - for (unsigned int *ptr = (unsigned int*)buffer + size; ptr>(unsigned int*)buffer; ) { - const unsigned int val = *(--ptr); - *ptr = (val>>24) | ((val>>8)&0xff00) | ((val<<8)&0xff0000) | (val<<24); - } - } break; - case 8 : { - const cimg_uint64 - m0 = (cimg_uint64)0xff, m1 = m0<<8, m2 = m0<<16, m3 = m0<<24, - m4 = m0<<32, m5 = m0<<40, m6 = m0<<48, m7 = m0<<56; - for (cimg_uint64 *ptr = (cimg_uint64*)buffer + size; ptr>(cimg_uint64*)buffer; ) { - const cimg_uint64 val = *(--ptr); - *ptr = (((val&m7)>>56) | ((val&m6)>>40) | ((val&m5)>>24) | ((val&m4)>>8) | - ((val&m3)<<8) |((val&m2)<<24) | ((val&m1)<<40) | ((val&m0)<<56)); - } - } break; - default : { - for (T* ptr = buffer + size; ptr>buffer; ) { - unsigned char *pb = (unsigned char*)(--ptr), *pe = pb + sizeof(T); - for (int i = 0; i<(int)sizeof(T)/2; ++i) swap(*(pb++),*(--pe)); - } - } - } - } - inline void invert_endianness(bool* const, const cimg_ulong) {} - inline void invert_endianness(unsigned char* const, const cimg_ulong) {} - inline void invert_endianness(char* const, const cimg_ulong) {} - - //! Reverse endianness of a single variable. - /** - \param[in,out] a Variable to reverse. - \return Reference to reversed variable. - **/ - template - inline T& invert_endianness(T& a) { - invert_endianness(&a,1); - return a; - } - - // Conversion functions to get more precision when trying to store unsigned ints values as floats. - inline unsigned int float2uint(const float f) { - int tmp = 0; - std::memcpy(&tmp,&f,sizeof(float)); - if (tmp>=0) return (unsigned int)f; - unsigned int u; - // use memcpy instead of assignment to avoid undesired optimizations by C++-compiler. - std::memcpy(&u,&f,sizeof(float)); - return ((u)<<2)>>2; // set sign & exponent bit to 0 - } - - inline float uint2float(const unsigned int u) { - if (u<(1U<<19)) return (float)u; // Consider safe storage of unsigned int as floats until 19bits (i.e 524287) - float f; - const unsigned int v = u|(3U<<(8*sizeof(unsigned int)-2)); // set sign & exponent bit to 1 - // use memcpy instead of simple assignment to avoid undesired optimizations by C++-compiler. - std::memcpy(&f,&v,sizeof(float)); - return f; - } - - //! Return the value of a system timer, with a millisecond precision. - /** - \note The timer does not necessarily starts from \c 0. - **/ - inline cimg_uint64 time() { -#if cimg_OS==1 - struct timeval st_time; - gettimeofday(&st_time,0); - return (cimg_uint64)st_time.tv_sec*1000 + (cimg_uint64)st_time.tv_usec/1000; -#elif cimg_OS==2 - ULARGE_INTEGER ul; - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - ul.LowPart = ft.dwLowDateTime; - ul.HighPart = ft.dwHighDateTime; - return (cimg_uint64)ul.QuadPart/10000; -#else - return 0; -#endif - } - - // Implement a tic/toc mechanism to display elapsed time of algorithms. - inline cimg_uint64 tictoc(const bool is_tic); - - //! Start tic/toc timer for time measurement between code instructions. - /** - \return Current value of the timer (same value as time()). - **/ - inline cimg_uint64 tic() { - return cimg::tictoc(true); - } - - //! End tic/toc timer and displays elapsed time from last call to tic(). - /** - \return Time elapsed (in ms) since last call to tic(). - **/ - inline cimg_uint64 toc() { - return cimg::tictoc(false); - } - - //! Sleep for a given numbers of milliseconds. - /** - \param milliseconds Number of milliseconds to wait for. - \note This function frees the CPU resources during the sleeping time. - It can be used to temporize your program properly, without wasting CPU time. - **/ - inline void sleep(const unsigned int milliseconds) { -#if cimg_OS==1 - struct timespec tv; - tv.tv_sec = milliseconds/1000; - tv.tv_nsec = (milliseconds%1000)*1000000; - nanosleep(&tv,0); -#elif cimg_OS==2 - Sleep(milliseconds); -#else - cimg::unused(milliseconds); -#endif - } - - inline unsigned int wait(const unsigned int milliseconds, cimg_uint64 *const p_timer) { - if (!*p_timer) *p_timer = cimg::time(); - const cimg_uint64 current_time = cimg::time(); - if (current_time<*p_timer || current_time>=*p_timer + milliseconds) { *p_timer = current_time; return 0; } - const unsigned int time_diff = (unsigned int)(*p_timer + milliseconds - current_time); - *p_timer = current_time + time_diff; - cimg::sleep(time_diff); - return time_diff; - } - - //! Wait for a given number of milliseconds since the last call to wait(). - /** - \param milliseconds Number of milliseconds to wait for. - \return Number of milliseconds elapsed since the last call to wait(). - \note Same as sleep() with a waiting time computed with regard to the last call - of wait(). It may be used to temporize your program properly, without wasting CPU time. - **/ - inline unsigned int wait(const unsigned int milliseconds) { - cimg::mutex(3); - static cimg_uint64 timer = cimg::time(); - cimg::mutex(3,0); - return cimg::wait(milliseconds,&timer); - } - - // Custom random number generator (allow re-entrance). - inline cimg_uint64& rng() { // Used as a shared global number for rng - static cimg_uint64 rng = 0xB16B00B5U; - return rng; - } - - inline unsigned int _rand(cimg_uint64 *const p_rng) { - *p_rng = *p_rng*1103515245 + 12345U; - return (unsigned int)*p_rng; - } - - inline unsigned int _rand() { - cimg::mutex(4); - const unsigned int res = cimg::_rand(&cimg::rng()); - cimg::mutex(4,0); - return res; - } - - inline void srand(cimg_uint64 *const p_rng) { -#if cimg_OS==1 - *p_rng = cimg::time() + (cimg_uint64)getpid(); -#elif cimg_OS==2 - *p_rng = cimg::time() + (cimg_uint64)_getpid(); -#endif - } - - inline void srand() { - cimg::mutex(4); - cimg::srand(&cimg::rng()); - cimg::mutex(4,0); - } - - inline void srand(const cimg_uint64 seed) { - cimg::mutex(4); - cimg::rng() = seed; - cimg::mutex(4,0); - } - - inline double rand(const double val_min, const double val_max, cimg_uint64 *const p_rng) { - const double val = cimg::_rand(p_rng)/(double)~0U; - return val_min + (val_max - val_min)*val; - } - - inline double rand(const double val_min, const double val_max) { - cimg::mutex(4); - const double res = cimg::rand(val_min,val_max,&cimg::rng()); - cimg::mutex(4,0); - return res; - } - - inline double rand(const double val_max, cimg_uint64 *const p_rng) { - const double val = cimg::_rand(p_rng)/(double)~0U; - return val_max*val; - } - - inline double rand(const double val_max=1) { - cimg::mutex(4); - const double res = cimg::rand(val_max,&cimg::rng()); - cimg::mutex(4,0); - return res; - } - - inline double grand(cimg_uint64 *const p_rng) { - double x1, w; - do { - const double x2 = cimg::rand(-1,1,p_rng); - x1 = cimg::rand(-1,1,p_rng); - w = x1*x1 + x2*x2; - } while (w<=0 || w>=1.); - return x1*std::sqrt((-2*std::log(w))/w); - } - - inline double grand() { - cimg::mutex(4); - const double res = cimg::grand(&cimg::rng()); - cimg::mutex(4,0); - return res; - } - - inline unsigned int prand(const double z, cimg_uint64 *const p_rng) { - if (z<=1.e-10) return 0; - if (z>100) return (unsigned int)((std::sqrt(z) * cimg::grand(p_rng)) + z); - unsigned int k = 0; - const double y = std::exp(-z); - for (double s = 1.; s>=y; ++k) s*=cimg::rand(1,p_rng); - return k - 1; - } - - inline unsigned int prand(const double z) { - cimg::mutex(4); - const unsigned int res = cimg::prand(z,&cimg::rng()); - cimg::mutex(4,0); - return res; - } - - //! Cut (i.e. clamp) value in specified interval. - template - inline T cut(const T& val, const t& val_min, const t& val_max) { - return val<=val_min?(T)val_min:val>=val_max?(T)val_max:val; - } - - //! Bitwise-rotate value on the left. - template - inline T rol(const T& a, const unsigned int n=1) { - return n?(T)((a<>((sizeof(T)<<3) - n))):a; - } - - inline float rol(const float a, const unsigned int n=1) { - return (float)rol((int)a,n); - } - - inline double rol(const double a, const unsigned int n=1) { - return (double)rol((cimg_long)a,n); - } - - inline double rol(const long double a, const unsigned int n=1) { - return (double)rol((cimg_long)a,n); - } - -#ifdef cimg_use_half - inline half rol(const half a, const unsigned int n=1) { - return (half)rol((int)a,n); - } -#endif - - //! Bitwise-rotate value on the right. - template - inline T ror(const T& a, const unsigned int n=1) { - return n?(T)((a>>n)|(a<<((sizeof(T)<<3) - n))):a; - } - - inline float ror(const float a, const unsigned int n=1) { - return (float)ror((int)a,n); - } - - inline double ror(const double a, const unsigned int n=1) { - return (double)ror((cimg_long)a,n); - } - - inline double ror(const long double a, const unsigned int n=1) { - return (double)ror((cimg_long)a,n); - } - -#ifdef cimg_use_half - inline half ror(const half a, const unsigned int n=1) { - return (half)ror((int)a,n); - } -#endif - - //! Return absolute value of a value. - template - inline T abs(const T& a) { - return a>=0?a:-a; - } - inline bool abs(const bool a) { - return a; - } - inline int abs(const unsigned char a) { - return (int)a; - } - inline int abs(const unsigned short a) { - return (int)a; - } - inline int abs(const unsigned int a) { - return (int)a; - } - inline int abs(const int a) { - return std::abs(a); - } - inline cimg_int64 abs(const cimg_uint64 a) { - return (cimg_int64)a; - } - inline double abs(const double a) { - return std::fabs(a); - } - inline float abs(const float a) { - return (float)std::fabs((double)a); - } - - //! Return hyperbolic arcosine of a value. - inline double acosh(const double x) { -#if cimg_use_cpp11==1 && !defined(_MSC_VER) - return std::acosh(x); -#else - return std::log(x + std::sqrt(x*x - 1)); -#endif - } - - //! Return hyperbolic arcsine of a value. - inline double asinh(const double x) { -#if cimg_use_cpp11==1 && !defined(_MSC_VER) - return std::asinh(x); -#else - return std::log(x + std::sqrt(x*x + 1)); -#endif - } - - //! Return hyperbolic arctangent of a value. - inline double atanh(const double x) { -#if cimg_use_cpp11==1 && !defined(_MSC_VER) - return std::atanh(x); -#else - return 0.5*std::log((1. + x)/(1. - x)); -#endif - } - - //! Return the sinc of a given value. - inline double sinc(const double x) { - return x?std::sin(x)/x:1; - } - - //! Return base-2 logarithm of a value. - inline double log2(const double x) { -#if cimg_use_cpp11==1 && !defined(_MSC_VER) - return std::log2(x); -#else - const double base2 = std::log(2.); - return std::log(x)/base2; -#endif - } - - //! Return square of a value. - template - inline T sqr(const T& val) { - return val*val; - } - - // Return inverse of error function. - template - inline T erfinv(const T& val) { - const T - sgn = val<0?-1:1, - x = (1 - val)*(1 + val), - lnx = std::log(x), - tt1 = (T)(2/(cimg::PI*0.147) + 0.5*lnx), - tt2 = lnx/(T)0.147; - return sgn*std::sqrt(-tt1 + std::sqrt(tt1*tt1 - tt2)); - } - - //! Return cubic root of a value. - template - inline double cbrt(const T& x) { -#if cimg_use_cpp11==1 - return std::cbrt(x); -#else - return x>=0?std::pow((double)x,1./3):-std::pow(-(double)x,1./3); -#endif - } - - template - inline T pow3(const T& val) { - return val*val*val; - } - template - inline T pow4(const T& val) { - return val*val*val*val; - } - - //! Return the minimum between three values. - template - inline t min(const t& a, const t& b, const t& c) { - return std::min(std::min(a,b),c); - } - - //! Return the minimum between four values. - template - inline t min(const t& a, const t& b, const t& c, const t& d) { - return std::min(std::min(a,b),std::min(c,d)); - } - - //! Return the minabs between two values. - template - inline t minabs(const t& a, const t& b) { - return cimg::abs(b) - inline t minabs(const t& a, const t& b, const t& abs_b) { - return abs_b - inline t max(const t& a, const t& b, const t& c) { - return std::max(std::max(a,b),c); - } - - //! Return the maximum between four values. - template - inline t max(const t& a, const t& b, const t& c, const t& d) { - return std::max(std::max(a,b),std::max(c,d)); - } - - //! Return the maxabs between two values. - template - inline t maxabs(const t& a, const t& b) { - return cimg::abs(b)>cimg::abs(a)?b:a; - } - - template - inline t maxabs(const t& a, const t& b, const t& abs_b) { - return abs_b>cimg::abs(a)?b:a; - } - - //! Return the sign of a value. - template - inline T sign(const T& x) { - return (T)(cimg::type::is_nan(x)?0:x<0?-1:x>0); - } - - //! Return the nearest power of 2 higher than given value. - template - inline cimg_uint64 nearest_pow2(const T& x) { - cimg_uint64 i = 1; - while (x>i) i<<=1; - return i; - } - - //! Return the modulo of a value. - /** - \param x Input value. - \param m Modulo value. - \note This modulo function accepts negative and floating-points modulo numbers, as well as variables of any type. - **/ - template - inline T mod(const T& x, const T& m) { - if (!m) throw CImgArgumentException("cimg::mod(): Specified modulo value is 0."); - const double dx = (double)x, dm = (double)m; - if (!cimg::type::is_finite(dm)) return x; - if (cimg::type::is_finite(dx)) return (T)(dx - dm * std::floor(dx / dm)); - return (T)0; - } - inline int mod(const bool x, const bool m) { - if (!m) throw CImgArgumentException("cimg::mod(): Specified modulo value is 0."); - return x?1:0; - } - inline int mod(const unsigned char x, const unsigned char m) { - if (!m) throw CImgArgumentException("cimg::mod(): Specified modulo value is 0."); - return x%m; - } - inline int mod(const char x, const char m) { - if (!m) throw CImgArgumentException("cimg::mod(): Specified modulo value is 0."); -#if defined(CHAR_MAX) && CHAR_MAX==255 - return x%m; -#else - return x>=0?x%m:(x%m?m + x%m:0); -#endif - } - inline int mod(const unsigned short x, const unsigned short m) { - if (!m) throw CImgArgumentException("cimg::mod(): Specified modulo value is 0."); - return (int)(x%m); - } - inline int mod(const short x, const short m) { - if (!m) throw CImgArgumentException("cimg::mod(): Specified modulo value is 0."); - return (int)(x>=0?x%m:(x%m?m + x%m:0)); - } - inline int mod(const unsigned int x, const unsigned int m) { - if (!m) throw CImgArgumentException("cimg::mod(): Specified modulo value is 0."); - return (int)(x%m); - } - inline int mod(const int x, const int m) { - if (!m) throw CImgArgumentException("cimg::mod(): Specified modulo value is 0."); - return (int)(x>=0?x%m:(x%m?m + x%m:0)); - } - inline cimg_int64 mod(const cimg_uint64 x, const cimg_uint64 m) { - if (!m) throw CImgArgumentException("cimg::mod(): Specified modulo value is 0."); - return (cimg_int64)(x%m); - } - inline cimg_int64 mod(const cimg_int64 x, const cimg_int64 m) { - if (!m) throw CImgArgumentException("cimg::mod(): Specified modulo value is 0."); - return (cimg_int64)(x>=0?x%m:(x%m?m + x%m:0)); - } - - //! Return the min-mod of two values. - /** - \note minmod(\p a,\p b) is defined to be: - - minmod(\p a,\p b) = min(\p a,\p b), if \p a and \p b have the same sign. - - minmod(\p a,\p b) = 0, if \p a and \p b have different signs. - **/ - template - inline T minmod(const T& a, const T& b) { - return a*b<=0?0:(a>0?(a - inline T round(const T& x) { - return (T)std::floor((_cimg_Tfloat)x + 0.5f); - } - - template - inline int uiround(const T x) { - return cimg::type::is_float()?(int)(x + 0.5f):(int)x; - } - - //! Return rounded value. - /** - \param x Value to be rounded. - \param y Rounding precision. - \param rounding_type Type of rounding operation (\c 0 = nearest, \c -1 = backward, \c 1 = forward). - \return Rounded value, having the same type as input value \c x. - **/ - template - inline T round(const T& x, const double y, const int rounding_type=0) { - if (y<=0) return x; - if (y==1) switch (rounding_type) { - case 0 : return cimg::round(x); - case 1 : return (T)std::ceil((_cimg_Tfloat)x); - default : return (T)std::floor((_cimg_Tfloat)x); - } - const double sx = (double)x/y, floor = std::floor(sx), delta = sx - floor; - return (T)(y*(rounding_type<0?floor:rounding_type>0?std::ceil(sx):delta<0.5?floor:std::ceil(sx))); - } - - // Code to compute fast median from 2,3,5,7,9,13,25 and 49 values. - // (contribution by RawTherapee: http://rawtherapee.com/). - template - inline T median(T val0, T val1) { - return (val0 + val1)/2; - } - - template - inline T median(T val0, T val1, T val2) { - return std::max(std::min(val0,val1),std::min(val2,std::max(val0,val1))); - } - - template - inline T median(T val0, T val1, T val2, T val3, T val4) { - T tmp = std::min(val0,val1); - val1 = std::max(val0,val1); val0 = tmp; tmp = std::min(val3,val4); val4 = std::max(val3,val4); - val3 = std::max(val0,tmp); val1 = std::min(val1,val4); tmp = std::min(val1,val2); val2 = std::max(val1,val2); - val1 = tmp; tmp = std::min(val2,val3); - return std::max(val1,tmp); - } - - template - inline T median(T val0, T val1, T val2, T val3, T val4, T val5, T val6) { - T tmp = std::min(val0,val5); - val5 = std::max(val0,val5); val0 = tmp; tmp = std::min(val0,val3); val3 = std::max(val0,val3); val0 = tmp; - tmp = std::min(val1,val6); val6 = std::max(val1,val6); val1 = tmp; tmp = std::min(val2,val4); - val4 = std::max(val2,val4); val2 = tmp; val1 = std::max(val0,val1); tmp = std::min(val3,val5); - val5 = std::max(val3,val5); val3 = tmp; tmp = std::min(val2,val6); val6 = std::max(val2,val6); - val3 = std::max(tmp,val3); val3 = std::min(val3,val6); tmp = std::min(val4,val5); val4 = std::max(val1,tmp); - tmp = std::min(val1,tmp); val3 = std::max(tmp,val3); - return std::min(val3,val4); - } - - template - inline T median(T val0, T val1, T val2, T val3, T val4, T val5, T val6, T val7, T val8) { - T tmp = std::min(val1,val2); - val2 = std::max(val1,val2); val1 = tmp; tmp = std::min(val4,val5); - val5 = std::max(val4,val5); val4 = tmp; tmp = std::min(val7,val8); - val8 = std::max(val7,val8); val7 = tmp; tmp = std::min(val0,val1); - val1 = std::max(val0,val1); val0 = tmp; tmp = std::min(val3,val4); - val4 = std::max(val3,val4); val3 = tmp; tmp = std::min(val6,val7); - val7 = std::max(val6,val7); val6 = tmp; tmp = std::min(val1,val2); - val2 = std::max(val1,val2); val1 = tmp; tmp = std::min(val4,val5); - val5 = std::max(val4,val5); val4 = tmp; tmp = std::min(val7,val8); - val8 = std::max(val7,val8); val3 = std::max(val0,val3); val5 = std::min(val5,val8); - val7 = std::max(val4,tmp); tmp = std::min(val4,tmp); val6 = std::max(val3,val6); - val4 = std::max(val1,tmp); val2 = std::min(val2,val5); val4 = std::min(val4,val7); - tmp = std::min(val4,val2); val2 = std::max(val4,val2); val4 = std::max(val6,tmp); - return std::min(val4,val2); - } - - template - inline T median(T val0, T val1, T val2, T val3, T val4, T val5, T val6, T val7, T val8, T val9, T val10, T val11, - T val12) { - T tmp = std::min(val1,val7); - val7 = std::max(val1,val7); val1 = tmp; tmp = std::min(val9,val11); val11 = std::max(val9,val11); val9 = tmp; - tmp = std::min(val3,val4); val4 = std::max(val3,val4); val3 = tmp; tmp = std::min(val5,val8); - val8 = std::max(val5,val8); val5 = tmp; tmp = std::min(val0,val12); val12 = std::max(val0,val12); - val0 = tmp; tmp = std::min(val2,val6); val6 = std::max(val2,val6); val2 = tmp; tmp = std::min(val0,val1); - val1 = std::max(val0,val1); val0 = tmp; tmp = std::min(val2,val3); val3 = std::max(val2,val3); val2 = tmp; - tmp = std::min(val4,val6); val6 = std::max(val4,val6); val4 = tmp; tmp = std::min(val8,val11); - val11 = std::max(val8,val11); val8 = tmp; tmp = std::min(val7,val12); val12 = std::max(val7,val12); val7 = tmp; - tmp = std::min(val5,val9); val9 = std::max(val5,val9); val5 = tmp; tmp = std::min(val0,val2); - val2 = std::max(val0,val2); val0 = tmp; tmp = std::min(val3,val7); val7 = std::max(val3,val7); val3 = tmp; - tmp = std::min(val10,val11); val11 = std::max(val10,val11); val10 = tmp; tmp = std::min(val1,val4); - val4 = std::max(val1,val4); val1 = tmp; tmp = std::min(val6,val12); val12 = std::max(val6,val12); val6 = tmp; - tmp = std::min(val7,val8); val8 = std::max(val7,val8); val7 = tmp; val11 = std::min(val11,val12); - tmp = std::min(val4,val9); val9 = std::max(val4,val9); val4 = tmp; tmp = std::min(val6,val10); - val10 = std::max(val6,val10); val6 = tmp; tmp = std::min(val3,val4); val4 = std::max(val3,val4); val3 = tmp; - tmp = std::min(val5,val6); val6 = std::max(val5,val6); val5 = tmp; val8 = std::min(val8,val9); - val10 = std::min(val10,val11); tmp = std::min(val1,val7); val7 = std::max(val1,val7); val1 = tmp; - tmp = std::min(val2,val6); val6 = std::max(val2,val6); val2 = tmp; val3 = std::max(val1,val3); - tmp = std::min(val4,val7); val7 = std::max(val4,val7); val4 = tmp; val8 = std::min(val8,val10); - val5 = std::max(val0,val5); val5 = std::max(val2,val5); tmp = std::min(val6,val8); val8 = std::max(val6,val8); - val5 = std::max(val3,val5); val7 = std::min(val7,val8); val6 = std::max(val4,tmp); tmp = std::min(val4,tmp); - val5 = std::max(tmp,val5); val6 = std::min(val6,val7); - return std::max(val5,val6); - } - - template - inline T median(T val0, T val1, T val2, T val3, T val4, - T val5, T val6, T val7, T val8, T val9, - T val10, T val11, T val12, T val13, T val14, - T val15, T val16, T val17, T val18, T val19, - T val20, T val21, T val22, T val23, T val24) { - T tmp = std::min(val0,val1); - val1 = std::max(val0,val1); val0 = tmp; tmp = std::min(val3,val4); val4 = std::max(val3,val4); - val3 = tmp; tmp = std::min(val2,val4); val4 = std::max(val2,val4); val2 = std::min(tmp,val3); - val3 = std::max(tmp,val3); tmp = std::min(val6,val7); val7 = std::max(val6,val7); val6 = tmp; - tmp = std::min(val5,val7); val7 = std::max(val5,val7); val5 = std::min(tmp,val6); val6 = std::max(tmp,val6); - tmp = std::min(val9,val10); val10 = std::max(val9,val10); val9 = tmp; tmp = std::min(val8,val10); - val10 = std::max(val8,val10); val8 = std::min(tmp,val9); val9 = std::max(tmp,val9); - tmp = std::min(val12,val13); val13 = std::max(val12,val13); val12 = tmp; tmp = std::min(val11,val13); - val13 = std::max(val11,val13); val11 = std::min(tmp,val12); val12 = std::max(tmp,val12); - tmp = std::min(val15,val16); val16 = std::max(val15,val16); val15 = tmp; tmp = std::min(val14,val16); - val16 = std::max(val14,val16); val14 = std::min(tmp,val15); val15 = std::max(tmp,val15); - tmp = std::min(val18,val19); val19 = std::max(val18,val19); val18 = tmp; tmp = std::min(val17,val19); - val19 = std::max(val17,val19); val17 = std::min(tmp,val18); val18 = std::max(tmp,val18); - tmp = std::min(val21,val22); val22 = std::max(val21,val22); val21 = tmp; tmp = std::min(val20,val22); - val22 = std::max(val20,val22); val20 = std::min(tmp,val21); val21 = std::max(tmp,val21); - tmp = std::min(val23,val24); val24 = std::max(val23,val24); val23 = tmp; tmp = std::min(val2,val5); - val5 = std::max(val2,val5); val2 = tmp; tmp = std::min(val3,val6); val6 = std::max(val3,val6); val3 = tmp; - tmp = std::min(val0,val6); val6 = std::max(val0,val6); val0 = std::min(tmp,val3); val3 = std::max(tmp,val3); - tmp = std::min(val4,val7); val7 = std::max(val4,val7); val4 = tmp; tmp = std::min(val1,val7); - val7 = std::max(val1,val7); val1 = std::min(tmp,val4); val4 = std::max(tmp,val4); tmp = std::min(val11,val14); - val14 = std::max(val11,val14); val11 = tmp; tmp = std::min(val8,val14); val14 = std::max(val8,val14); - val8 = std::min(tmp,val11); val11 = std::max(tmp,val11); tmp = std::min(val12,val15); - val15 = std::max(val12,val15); val12 = tmp; tmp = std::min(val9,val15); val15 = std::max(val9,val15); - val9 = std::min(tmp,val12); val12 = std::max(tmp,val12); tmp = std::min(val13,val16); - val16 = std::max(val13,val16); val13 = tmp; tmp = std::min(val10,val16); val16 = std::max(val10,val16); - val10 = std::min(tmp,val13); val13 = std::max(tmp,val13); tmp = std::min(val20,val23); - val23 = std::max(val20,val23); val20 = tmp; tmp = std::min(val17,val23); val23 = std::max(val17,val23); - val17 = std::min(tmp,val20); val20 = std::max(tmp,val20); tmp = std::min(val21,val24); - val24 = std::max(val21,val24); val21 = tmp; tmp = std::min(val18,val24); val24 = std::max(val18,val24); - val18 = std::min(tmp,val21); val21 = std::max(tmp,val21); tmp = std::min(val19,val22); - val22 = std::max(val19,val22); val19 = tmp; val17 = std::max(val8,val17); tmp = std::min(val9,val18); - val18 = std::max(val9,val18); val9 = tmp; tmp = std::min(val0,val18); val18 = std::max(val0,val18); - val9 = std::max(tmp,val9); tmp = std::min(val10,val19); val19 = std::max(val10,val19); val10 = tmp; - tmp = std::min(val1,val19); val19 = std::max(val1,val19); val1 = std::min(tmp,val10); - val10 = std::max(tmp,val10); tmp = std::min(val11,val20); val20 = std::max(val11,val20); val11 = tmp; - tmp = std::min(val2,val20); val20 = std::max(val2,val20); val11 = std::max(tmp,val11); - tmp = std::min(val12,val21); val21 = std::max(val12,val21); val12 = tmp; tmp = std::min(val3,val21); - val21 = std::max(val3,val21); val3 = std::min(tmp,val12); val12 = std::max(tmp,val12); - tmp = std::min(val13,val22); val22 = std::max(val13,val22); val4 = std::min(val4,val22); - val13 = std::max(val4,tmp); tmp = std::min(val4,tmp); val4 = tmp; tmp = std::min(val14,val23); - val23 = std::max(val14,val23); val14 = tmp; tmp = std::min(val5,val23); val23 = std::max(val5,val23); - val5 = std::min(tmp,val14); val14 = std::max(tmp,val14); tmp = std::min(val15,val24); - val24 = std::max(val15,val24); val15 = tmp; val6 = std::min(val6,val24); tmp = std::min(val6,val15); - val15 = std::max(val6,val15); val6 = tmp; tmp = std::min(val7,val16); val7 = std::min(tmp,val19); - tmp = std::min(val13,val21); val15 = std::min(val15,val23); tmp = std::min(val7,tmp); - val7 = std::min(tmp,val15); val9 = std::max(val1,val9); val11 = std::max(val3,val11); - val17 = std::max(val5,val17); val17 = std::max(val11,val17); val17 = std::max(val9,val17); - tmp = std::min(val4,val10); val10 = std::max(val4,val10); val4 = tmp; tmp = std::min(val6,val12); - val12 = std::max(val6,val12); val6 = tmp; tmp = std::min(val7,val14); val14 = std::max(val7,val14); - val7 = tmp; tmp = std::min(val4,val6); val6 = std::max(val4,val6); val7 = std::max(tmp,val7); - tmp = std::min(val12,val14); val14 = std::max(val12,val14); val12 = tmp; val10 = std::min(val10,val14); - tmp = std::min(val6,val7); val7 = std::max(val6,val7); val6 = tmp; tmp = std::min(val10,val12); - val12 = std::max(val10,val12); val10 = std::max(val6,tmp); tmp = std::min(val6,tmp); - val17 = std::max(tmp,val17); tmp = std::min(val12,val17); val17 = std::max(val12,val17); val12 = tmp; - val7 = std::min(val7,val17); tmp = std::min(val7,val10); val10 = std::max(val7,val10); val7 = tmp; - tmp = std::min(val12,val18); val18 = std::max(val12,val18); val12 = std::max(val7,tmp); - val10 = std::min(val10,val18); tmp = std::min(val12,val20); val20 = std::max(val12,val20); val12 = tmp; - tmp = std::min(val10,val20); - return std::max(tmp,val12); - } - - template - inline T median(T val0, T val1, T val2, T val3, T val4, T val5, T val6, - T val7, T val8, T val9, T val10, T val11, T val12, T val13, - T val14, T val15, T val16, T val17, T val18, T val19, T val20, - T val21, T val22, T val23, T val24, T val25, T val26, T val27, - T val28, T val29, T val30, T val31, T val32, T val33, T val34, - T val35, T val36, T val37, T val38, T val39, T val40, T val41, - T val42, T val43, T val44, T val45, T val46, T val47, T val48) { - T tmp = std::min(val0,val32); - val32 = std::max(val0,val32); val0 = tmp; tmp = std::min(val1,val33); val33 = std::max(val1,val33); val1 = tmp; - tmp = std::min(val2,val34); val34 = std::max(val2,val34); val2 = tmp; tmp = std::min(val3,val35); - val35 = std::max(val3,val35); val3 = tmp; tmp = std::min(val4,val36); val36 = std::max(val4,val36); val4 = tmp; - tmp = std::min(val5,val37); val37 = std::max(val5,val37); val5 = tmp; tmp = std::min(val6,val38); - val38 = std::max(val6,val38); val6 = tmp; tmp = std::min(val7,val39); val39 = std::max(val7,val39); val7 = tmp; - tmp = std::min(val8,val40); val40 = std::max(val8,val40); val8 = tmp; tmp = std::min(val9,val41); - val41 = std::max(val9,val41); val9 = tmp; tmp = std::min(val10,val42); val42 = std::max(val10,val42); - val10 = tmp; tmp = std::min(val11,val43); val43 = std::max(val11,val43); val11 = tmp; - tmp = std::min(val12,val44); val44 = std::max(val12,val44); val12 = tmp; tmp = std::min(val13,val45); - val45 = std::max(val13,val45); val13 = tmp; tmp = std::min(val14,val46); val46 = std::max(val14,val46); - val14 = tmp; tmp = std::min(val15,val47); val47 = std::max(val15,val47); val15 = tmp; - tmp = std::min(val16,val48); val48 = std::max(val16,val48); val16 = tmp; tmp = std::min(val0,val16); - val16 = std::max(val0,val16); val0 = tmp; tmp = std::min(val1,val17); val17 = std::max(val1,val17); - val1 = tmp; tmp = std::min(val2,val18); val18 = std::max(val2,val18); val2 = tmp; tmp = std::min(val3,val19); - val19 = std::max(val3,val19); val3 = tmp; tmp = std::min(val4,val20); val20 = std::max(val4,val20); val4 = tmp; - tmp = std::min(val5,val21); val21 = std::max(val5,val21); val5 = tmp; tmp = std::min(val6,val22); - val22 = std::max(val6,val22); val6 = tmp; tmp = std::min(val7,val23); val23 = std::max(val7,val23); val7 = tmp; - tmp = std::min(val8,val24); val24 = std::max(val8,val24); val8 = tmp; tmp = std::min(val9,val25); - val25 = std::max(val9,val25); val9 = tmp; tmp = std::min(val10,val26); val26 = std::max(val10,val26); - val10 = tmp; tmp = std::min(val11,val27); val27 = std::max(val11,val27); val11 = tmp; - tmp = std::min(val12,val28); val28 = std::max(val12,val28); val12 = tmp; tmp = std::min(val13,val29); - val29 = std::max(val13,val29); val13 = tmp; tmp = std::min(val14,val30); val30 = std::max(val14,val30); - val14 = tmp; tmp = std::min(val15,val31); val31 = std::max(val15,val31); val15 = tmp; - tmp = std::min(val32,val48); val48 = std::max(val32,val48); val32 = tmp; tmp = std::min(val16,val32); - val32 = std::max(val16,val32); val16 = tmp; tmp = std::min(val17,val33); val33 = std::max(val17,val33); - val17 = tmp; tmp = std::min(val18,val34); val34 = std::max(val18,val34); val18 = tmp; - tmp = std::min(val19,val35); val35 = std::max(val19,val35); val19 = tmp; tmp = std::min(val20,val36); - val36 = std::max(val20,val36); val20 = tmp; tmp = std::min(val21,val37); val37 = std::max(val21,val37); - val21 = tmp; tmp = std::min(val22,val38); val38 = std::max(val22,val38); val22 = tmp; - tmp = std::min(val23,val39); val39 = std::max(val23,val39); val23 = tmp; tmp = std::min(val24,val40); - val40 = std::max(val24,val40); val24 = tmp; tmp = std::min(val25,val41); val41 = std::max(val25,val41); - val25 = tmp; tmp = std::min(val26,val42); val42 = std::max(val26,val42); val26 = tmp; - tmp = std::min(val27,val43); val43 = std::max(val27,val43); val27 = tmp; tmp = std::min(val28,val44); - val44 = std::max(val28,val44); val28 = tmp; tmp = std::min(val29,val45); val45 = std::max(val29,val45); - val29 = tmp; tmp = std::min(val30,val46); val46 = std::max(val30,val46); val30 = tmp; - tmp = std::min(val31,val47); val47 = std::max(val31,val47); val31 = tmp; tmp = std::min(val0,val8); - val8 = std::max(val0,val8); val0 = tmp; tmp = std::min(val1,val9); val9 = std::max(val1,val9); val1 = tmp; - tmp = std::min(val2,val10); val10 = std::max(val2,val10); val2 = tmp; tmp = std::min(val3,val11); - val11 = std::max(val3,val11); val3 = tmp; tmp = std::min(val4,val12); val12 = std::max(val4,val12); val4 = tmp; - tmp = std::min(val5,val13); val13 = std::max(val5,val13); val5 = tmp; tmp = std::min(val6,val14); - val14 = std::max(val6,val14); val6 = tmp; tmp = std::min(val7,val15); val15 = std::max(val7,val15); val7 = tmp; - tmp = std::min(val16,val24); val24 = std::max(val16,val24); val16 = tmp; tmp = std::min(val17,val25); - val25 = std::max(val17,val25); val17 = tmp; tmp = std::min(val18,val26); val26 = std::max(val18,val26); - val18 = tmp; tmp = std::min(val19,val27); val27 = std::max(val19,val27); val19 = tmp; - tmp = std::min(val20,val28); val28 = std::max(val20,val28); val20 = tmp; tmp = std::min(val21,val29); - val29 = std::max(val21,val29); val21 = tmp; tmp = std::min(val22,val30); val30 = std::max(val22,val30); - val22 = tmp; tmp = std::min(val23,val31); val31 = std::max(val23,val31); val23 = tmp; - tmp = std::min(val32,val40); val40 = std::max(val32,val40); val32 = tmp; tmp = std::min(val33,val41); - val41 = std::max(val33,val41); val33 = tmp; tmp = std::min(val34,val42); val42 = std::max(val34,val42); - val34 = tmp; tmp = std::min(val35,val43); val43 = std::max(val35,val43); val35 = tmp; - tmp = std::min(val36,val44); val44 = std::max(val36,val44); val36 = tmp; tmp = std::min(val37,val45); - val45 = std::max(val37,val45); val37 = tmp; tmp = std::min(val38,val46); val46 = std::max(val38,val46); - val38 = tmp; tmp = std::min(val39,val47); val47 = std::max(val39,val47); val39 = tmp; - tmp = std::min(val8,val32); val32 = std::max(val8,val32); val8 = tmp; tmp = std::min(val9,val33); - val33 = std::max(val9,val33); val9 = tmp; tmp = std::min(val10,val34); val34 = std::max(val10,val34); - val10 = tmp; tmp = std::min(val11,val35); val35 = std::max(val11,val35); val11 = tmp; - tmp = std::min(val12,val36); val36 = std::max(val12,val36); val12 = tmp; tmp = std::min(val13,val37); - val37 = std::max(val13,val37); val13 = tmp; tmp = std::min(val14,val38); val38 = std::max(val14,val38); - val14 = tmp; tmp = std::min(val15,val39); val39 = std::max(val15,val39); val15 = tmp; - tmp = std::min(val24,val48); val48 = std::max(val24,val48); val24 = tmp; tmp = std::min(val8,val16); - val16 = std::max(val8,val16); val8 = tmp; tmp = std::min(val9,val17); val17 = std::max(val9,val17); - val9 = tmp; tmp = std::min(val10,val18); val18 = std::max(val10,val18); val10 = tmp; - tmp = std::min(val11,val19); val19 = std::max(val11,val19); val11 = tmp; tmp = std::min(val12,val20); - val20 = std::max(val12,val20); val12 = tmp; tmp = std::min(val13,val21); val21 = std::max(val13,val21); - val13 = tmp; tmp = std::min(val14,val22); val22 = std::max(val14,val22); val14 = tmp; - tmp = std::min(val15,val23); val23 = std::max(val15,val23); val15 = tmp; tmp = std::min(val24,val32); - val32 = std::max(val24,val32); val24 = tmp; tmp = std::min(val25,val33); val33 = std::max(val25,val33); - val25 = tmp; tmp = std::min(val26,val34); val34 = std::max(val26,val34); val26 = tmp; - tmp = std::min(val27,val35); val35 = std::max(val27,val35); val27 = tmp; tmp = std::min(val28,val36); - val36 = std::max(val28,val36); val28 = tmp; tmp = std::min(val29,val37); val37 = std::max(val29,val37); - val29 = tmp; tmp = std::min(val30,val38); val38 = std::max(val30,val38); val30 = tmp; - tmp = std::min(val31,val39); val39 = std::max(val31,val39); val31 = tmp; tmp = std::min(val40,val48); - val48 = std::max(val40,val48); val40 = tmp; tmp = std::min(val0,val4); val4 = std::max(val0,val4); - val0 = tmp; tmp = std::min(val1,val5); val5 = std::max(val1,val5); val1 = tmp; tmp = std::min(val2,val6); - val6 = std::max(val2,val6); val2 = tmp; tmp = std::min(val3,val7); val7 = std::max(val3,val7); val3 = tmp; - tmp = std::min(val8,val12); val12 = std::max(val8,val12); val8 = tmp; tmp = std::min(val9,val13); - val13 = std::max(val9,val13); val9 = tmp; tmp = std::min(val10,val14); val14 = std::max(val10,val14); - val10 = tmp; tmp = std::min(val11,val15); val15 = std::max(val11,val15); val11 = tmp; - tmp = std::min(val16,val20); val20 = std::max(val16,val20); val16 = tmp; tmp = std::min(val17,val21); - val21 = std::max(val17,val21); val17 = tmp; tmp = std::min(val18,val22); val22 = std::max(val18,val22); - val18 = tmp; tmp = std::min(val19,val23); val23 = std::max(val19,val23); val19 = tmp; - tmp = std::min(val24,val28); val28 = std::max(val24,val28); val24 = tmp; tmp = std::min(val25,val29); - val29 = std::max(val25,val29); val25 = tmp; tmp = std::min(val26,val30); val30 = std::max(val26,val30); - val26 = tmp; tmp = std::min(val27,val31); val31 = std::max(val27,val31); val27 = tmp; - tmp = std::min(val32,val36); val36 = std::max(val32,val36); val32 = tmp; tmp = std::min(val33,val37); - val37 = std::max(val33,val37); val33 = tmp; tmp = std::min(val34,val38); val38 = std::max(val34,val38); - val34 = tmp; tmp = std::min(val35,val39); val39 = std::max(val35,val39); val35 = tmp; - tmp = std::min(val40,val44); val44 = std::max(val40,val44); val40 = tmp; tmp = std::min(val41,val45); - val45 = std::max(val41,val45); val41 = tmp; tmp = std::min(val42,val46); val46 = std::max(val42,val46); - val42 = tmp; tmp = std::min(val43,val47); val47 = std::max(val43,val47); val43 = tmp; - tmp = std::min(val4,val32); val32 = std::max(val4,val32); val4 = tmp; tmp = std::min(val5,val33); - val33 = std::max(val5,val33); val5 = tmp; tmp = std::min(val6,val34); val34 = std::max(val6,val34); - val6 = tmp; tmp = std::min(val7,val35); val35 = std::max(val7,val35); val7 = tmp; - tmp = std::min(val12,val40); val40 = std::max(val12,val40); val12 = tmp; tmp = std::min(val13,val41); - val41 = std::max(val13,val41); val13 = tmp; tmp = std::min(val14,val42); val42 = std::max(val14,val42); - val14 = tmp; tmp = std::min(val15,val43); val43 = std::max(val15,val43); val15 = tmp; - tmp = std::min(val20,val48); val48 = std::max(val20,val48); val20 = tmp; tmp = std::min(val4,val16); - val16 = std::max(val4,val16); val4 = tmp; tmp = std::min(val5,val17); val17 = std::max(val5,val17); - val5 = tmp; tmp = std::min(val6,val18); val18 = std::max(val6,val18); val6 = tmp; - tmp = std::min(val7,val19); val19 = std::max(val7,val19); val7 = tmp; tmp = std::min(val12,val24); - val24 = std::max(val12,val24); val12 = tmp; tmp = std::min(val13,val25); val25 = std::max(val13,val25); - val13 = tmp; tmp = std::min(val14,val26); val26 = std::max(val14,val26); val14 = tmp; - tmp = std::min(val15,val27); val27 = std::max(val15,val27); val15 = tmp; tmp = std::min(val20,val32); - val32 = std::max(val20,val32); val20 = tmp; tmp = std::min(val21,val33); val33 = std::max(val21,val33); - val21 = tmp; tmp = std::min(val22,val34); val34 = std::max(val22,val34); val22 = tmp; - tmp = std::min(val23,val35); val35 = std::max(val23,val35); val23 = tmp; tmp = std::min(val28,val40); - val40 = std::max(val28,val40); val28 = tmp; tmp = std::min(val29,val41); val41 = std::max(val29,val41); - val29 = tmp; tmp = std::min(val30,val42); val42 = std::max(val30,val42); val30 = tmp; - tmp = std::min(val31,val43); val43 = std::max(val31,val43); val31 = tmp; tmp = std::min(val36,val48); - val48 = std::max(val36,val48); val36 = tmp; tmp = std::min(val4,val8); val8 = std::max(val4,val8); - val4 = tmp; tmp = std::min(val5,val9); val9 = std::max(val5,val9); val5 = tmp; tmp = std::min(val6,val10); - val10 = std::max(val6,val10); val6 = tmp; tmp = std::min(val7,val11); val11 = std::max(val7,val11); val7 = tmp; - tmp = std::min(val12,val16); val16 = std::max(val12,val16); val12 = tmp; tmp = std::min(val13,val17); - val17 = std::max(val13,val17); val13 = tmp; tmp = std::min(val14,val18); val18 = std::max(val14,val18); - val14 = tmp; tmp = std::min(val15,val19); val19 = std::max(val15,val19); val15 = tmp; - tmp = std::min(val20,val24); val24 = std::max(val20,val24); val20 = tmp; tmp = std::min(val21,val25); - val25 = std::max(val21,val25); val21 = tmp; tmp = std::min(val22,val26); val26 = std::max(val22,val26); - val22 = tmp; tmp = std::min(val23,val27); val27 = std::max(val23,val27); val23 = tmp; - tmp = std::min(val28,val32); val32 = std::max(val28,val32); val28 = tmp; tmp = std::min(val29,val33); - val33 = std::max(val29,val33); val29 = tmp; tmp = std::min(val30,val34); val34 = std::max(val30,val34); - val30 = tmp; tmp = std::min(val31,val35); val35 = std::max(val31,val35); val31 = tmp; - tmp = std::min(val36,val40); val40 = std::max(val36,val40); val36 = tmp; tmp = std::min(val37,val41); - val41 = std::max(val37,val41); val37 = tmp; tmp = std::min(val38,val42); val42 = std::max(val38,val42); - val38 = tmp; tmp = std::min(val39,val43); val43 = std::max(val39,val43); val39 = tmp; - tmp = std::min(val44,val48); val48 = std::max(val44,val48); val44 = tmp; tmp = std::min(val0,val2); - val2 = std::max(val0,val2); val0 = tmp; tmp = std::min(val1,val3); val3 = std::max(val1,val3); val1 = tmp; - tmp = std::min(val4,val6); val6 = std::max(val4,val6); val4 = tmp; tmp = std::min(val5,val7); - val7 = std::max(val5,val7); val5 = tmp; tmp = std::min(val8,val10); val10 = std::max(val8,val10); val8 = tmp; - tmp = std::min(val9,val11); val11 = std::max(val9,val11); val9 = tmp; tmp = std::min(val12,val14); - val14 = std::max(val12,val14); val12 = tmp; tmp = std::min(val13,val15); val15 = std::max(val13,val15); - val13 = tmp; tmp = std::min(val16,val18); val18 = std::max(val16,val18); val16 = tmp; - tmp = std::min(val17,val19); val19 = std::max(val17,val19); val17 = tmp; tmp = std::min(val20,val22); - val22 = std::max(val20,val22); val20 = tmp; tmp = std::min(val21,val23); val23 = std::max(val21,val23); - val21 = tmp; tmp = std::min(val24,val26); val26 = std::max(val24,val26); val24 = tmp; - tmp = std::min(val25,val27); val27 = std::max(val25,val27); val25 = tmp; tmp = std::min(val28,val30); - val30 = std::max(val28,val30); val28 = tmp; tmp = std::min(val29,val31); val31 = std::max(val29,val31); - val29 = tmp; tmp = std::min(val32,val34); val34 = std::max(val32,val34); val32 = tmp; - tmp = std::min(val33,val35); val35 = std::max(val33,val35); val33 = tmp; tmp = std::min(val36,val38); - val38 = std::max(val36,val38); val36 = tmp; tmp = std::min(val37,val39); val39 = std::max(val37,val39); - val37 = tmp; tmp = std::min(val40,val42); val42 = std::max(val40,val42); val40 = tmp; - tmp = std::min(val41,val43); val43 = std::max(val41,val43); val41 = tmp; tmp = std::min(val44,val46); - val46 = std::max(val44,val46); val44 = tmp; tmp = std::min(val45,val47); val47 = std::max(val45,val47); - val45 = tmp; tmp = std::min(val2,val32); val32 = std::max(val2,val32); val2 = tmp; tmp = std::min(val3,val33); - val33 = std::max(val3,val33); val3 = tmp; tmp = std::min(val6,val36); val36 = std::max(val6,val36); val6 = tmp; - tmp = std::min(val7,val37); val37 = std::max(val7,val37); val7 = tmp; tmp = std::min(val10,val40); - val40 = std::max(val10,val40); val10 = tmp; tmp = std::min(val11,val41); val41 = std::max(val11,val41); - val11 = tmp; tmp = std::min(val14,val44); val44 = std::max(val14,val44); val14 = tmp; - tmp = std::min(val15,val45); val45 = std::max(val15,val45); val15 = tmp; tmp = std::min(val18,val48); - val48 = std::max(val18,val48); val18 = tmp; tmp = std::min(val2,val16); val16 = std::max(val2,val16); - val2 = tmp; tmp = std::min(val3,val17); val17 = std::max(val3,val17); val3 = tmp; - tmp = std::min(val6,val20); val20 = std::max(val6,val20); val6 = tmp; tmp = std::min(val7,val21); - val21 = std::max(val7,val21); val7 = tmp; tmp = std::min(val10,val24); val24 = std::max(val10,val24); - val10 = tmp; tmp = std::min(val11,val25); val25 = std::max(val11,val25); val11 = tmp; - tmp = std::min(val14,val28); val28 = std::max(val14,val28); val14 = tmp; tmp = std::min(val15,val29); - val29 = std::max(val15,val29); val15 = tmp; tmp = std::min(val18,val32); val32 = std::max(val18,val32); - val18 = tmp; tmp = std::min(val19,val33); val33 = std::max(val19,val33); val19 = tmp; - tmp = std::min(val22,val36); val36 = std::max(val22,val36); val22 = tmp; tmp = std::min(val23,val37); - val37 = std::max(val23,val37); val23 = tmp; tmp = std::min(val26,val40); val40 = std::max(val26,val40); - val26 = tmp; tmp = std::min(val27,val41); val41 = std::max(val27,val41); val27 = tmp; - tmp = std::min(val30,val44); val44 = std::max(val30,val44); val30 = tmp; tmp = std::min(val31,val45); - val45 = std::max(val31,val45); val31 = tmp; tmp = std::min(val34,val48); val48 = std::max(val34,val48); - val34 = tmp; tmp = std::min(val2,val8); val8 = std::max(val2,val8); val2 = tmp; tmp = std::min(val3,val9); - val9 = std::max(val3,val9); val3 = tmp; tmp = std::min(val6,val12); val12 = std::max(val6,val12); val6 = tmp; - tmp = std::min(val7,val13); val13 = std::max(val7,val13); val7 = tmp; tmp = std::min(val10,val16); - val16 = std::max(val10,val16); val10 = tmp; tmp = std::min(val11,val17); val17 = std::max(val11,val17); - val11 = tmp; tmp = std::min(val14,val20); val20 = std::max(val14,val20); val14 = tmp; - tmp = std::min(val15,val21); val21 = std::max(val15,val21); val15 = tmp; tmp = std::min(val18,val24); - val24 = std::max(val18,val24); val18 = tmp; tmp = std::min(val19,val25); val25 = std::max(val19,val25); - val19 = tmp; tmp = std::min(val22,val28); val28 = std::max(val22,val28); val22 = tmp; - tmp = std::min(val23,val29); val29 = std::max(val23,val29); val23 = tmp; tmp = std::min(val26,val32); - val32 = std::max(val26,val32); val26 = tmp; tmp = std::min(val27,val33); val33 = std::max(val27,val33); - val27 = tmp; tmp = std::min(val30,val36); val36 = std::max(val30,val36); val30 = tmp; - tmp = std::min(val31,val37); val37 = std::max(val31,val37); val31 = tmp; tmp = std::min(val34,val40); - val40 = std::max(val34,val40); val34 = tmp; tmp = std::min(val35,val41); val41 = std::max(val35,val41); - val35 = tmp; tmp = std::min(val38,val44); val44 = std::max(val38,val44); val38 = tmp; - tmp = std::min(val39,val45); val45 = std::max(val39,val45); val39 = tmp; tmp = std::min(val42,val48); - val48 = std::max(val42,val48); val42 = tmp; tmp = std::min(val2,val4); val4 = std::max(val2,val4); - val2 = tmp; tmp = std::min(val3,val5); val5 = std::max(val3,val5); val3 = tmp; tmp = std::min(val6,val8); - val8 = std::max(val6,val8); val6 = tmp; tmp = std::min(val7,val9); val9 = std::max(val7,val9); val7 = tmp; - tmp = std::min(val10,val12); val12 = std::max(val10,val12); val10 = tmp; tmp = std::min(val11,val13); - val13 = std::max(val11,val13); val11 = tmp; tmp = std::min(val14,val16); val16 = std::max(val14,val16); - val14 = tmp; tmp = std::min(val15,val17); val17 = std::max(val15,val17); val15 = tmp; - tmp = std::min(val18,val20); val20 = std::max(val18,val20); val18 = tmp; tmp = std::min(val19,val21); - val21 = std::max(val19,val21); val19 = tmp; tmp = std::min(val22,val24); val24 = std::max(val22,val24); - val22 = tmp; tmp = std::min(val23,val25); val25 = std::max(val23,val25); val23 = tmp; - tmp = std::min(val26,val28); val28 = std::max(val26,val28); val26 = tmp; tmp = std::min(val27,val29); - val29 = std::max(val27,val29); val27 = tmp; tmp = std::min(val30,val32); val32 = std::max(val30,val32); - val30 = tmp; tmp = std::min(val31,val33); val33 = std::max(val31,val33); val31 = tmp; - tmp = std::min(val34,val36); val36 = std::max(val34,val36); val34 = tmp; tmp = std::min(val35,val37); - val37 = std::max(val35,val37); val35 = tmp; tmp = std::min(val38,val40); val40 = std::max(val38,val40); - val38 = tmp; tmp = std::min(val39,val41); val41 = std::max(val39,val41); val39 = tmp; - tmp = std::min(val42,val44); val44 = std::max(val42,val44); val42 = tmp; tmp = std::min(val43,val45); - val45 = std::max(val43,val45); val43 = tmp; tmp = std::min(val46,val48); val48 = std::max(val46,val48); - val46 = tmp; val1 = std::max(val0,val1); val3 = std::max(val2,val3); val5 = std::max(val4,val5); - val7 = std::max(val6,val7); val9 = std::max(val8,val9); val11 = std::max(val10,val11); - val13 = std::max(val12,val13); val15 = std::max(val14,val15); val17 = std::max(val16,val17); - val19 = std::max(val18,val19); val21 = std::max(val20,val21); val23 = std::max(val22,val23); - val24 = std::min(val24,val25); val26 = std::min(val26,val27); val28 = std::min(val28,val29); - val30 = std::min(val30,val31); val32 = std::min(val32,val33); val34 = std::min(val34,val35); - val36 = std::min(val36,val37); val38 = std::min(val38,val39); val40 = std::min(val40,val41); - val42 = std::min(val42,val43); val44 = std::min(val44,val45); val46 = std::min(val46,val47); - val32 = std::max(val1,val32); val34 = std::max(val3,val34); val36 = std::max(val5,val36); - val38 = std::max(val7,val38); val9 = std::min(val9,val40); val11 = std::min(val11,val42); - val13 = std::min(val13,val44); val15 = std::min(val15,val46); val17 = std::min(val17,val48); - val24 = std::max(val9,val24); val26 = std::max(val11,val26); val28 = std::max(val13,val28); - val30 = std::max(val15,val30); val17 = std::min(val17,val32); val19 = std::min(val19,val34); - val21 = std::min(val21,val36); val23 = std::min(val23,val38); val24 = std::max(val17,val24); - val26 = std::max(val19,val26); val21 = std::min(val21,val28); val23 = std::min(val23,val30); - val24 = std::max(val21,val24); val23 = std::min(val23,val26); - return std::max(val23,val24); - } - - //! Return sqrt(x^2 + y^2). - template - inline T hypot(const T x, const T y) { - return std::sqrt(x*x + y*y); - } - - template - inline T hypot(const T x, const T y, const T z) { - return std::sqrt(x*x + y*y + z*z); - } - - template - inline T _hypot(const T x, const T y) { // Slower but more precise version - T nx = cimg::abs(x), ny = cimg::abs(y), t; - if (nx0) { t/=nx; return nx*std::sqrt(1 + t*t); } - return 0; - } - - //! Return the factorial of n - inline double factorial(const int n) { - if (n<0) return cimg::type::nan(); - if (n<2) return 1; - double res = 2; - for (int i = 3; i<=n; ++i) res*=i; - return res; - } - - //! Return the number of permutations of k objects in a set of n objects. - inline double permutations(const int k, const int n, const bool with_order) { - if (n<0 || k<0) return cimg::type::nan(); - if (k>n) return 0; - double res = 1; - for (int i = n; i>=n - k + 1; --i) res*=i; - return with_order?res:res/cimg::factorial(k); - } - - inline double _fibonacci(int exp) { - double - base = (1 + std::sqrt(5.))/2, - result = 1/std::sqrt(5.); - while (exp) { - if (exp&1) result*=base; - exp>>=1; - base*=base; - } - return result; - } - - //! Calculate fibonacci number. - // (Precise up to n = 78, less precise for n>78). - inline double fibonacci(const int n) { - if (n<0) return cimg::type::nan(); - if (n<3) return 1; - if (n<11) { - cimg_uint64 fn1 = 1, fn2 = 1, fn = 0; - for (int i = 3; i<=n; ++i) { fn = fn1 + fn2; fn2 = fn1; fn1 = fn; } - return (double)fn; - } - if (n<75) // precise up to n = 74, faster than the integer calculation above for n>10 - return (double)((cimg_uint64)(_fibonacci(n) + 0.5)); - - if (n<94) { // precise up to n = 78, less precise for n>78 up to n = 93, overflows for n>93 - cimg_uint64 - fn1 = ((cimg_uint64)303836)<<32 | 3861581201UL, // 1304969544928657ULL (avoid C++98 warning with ULL) - fn2 = ((cimg_uint64)187781)<<32 | 2279239217UL, // 806515533049393ULL - fn = 0; - for (int i = 75; i<=n; ++i) { fn = fn1 + fn2; fn2 = fn1; fn1 = fn; } - return (double)fn; - } - return _fibonacci(n); // Not precise, but better than the wrong overflowing calculation - } - - //! Calculate greatest common divisor. - inline long gcd(long a, long b) { - while (a) { const long c = a; a = b%a; b = c; } - return b; - } - - //! Convert character to lower case. - inline char lowercase(const char x) { - return (char)((x<'A'||x>'Z')?x:x - 'A' + 'a'); - } - inline double lowercase(const double x) { - return (double)((x<'A'||x>'Z')?x:x - 'A' + 'a'); - } - - //! Convert C-string to lower case. - inline void lowercase(char *const str) { - if (str) for (char *ptr = str; *ptr; ++ptr) *ptr = lowercase(*ptr); - } - - //! Convert character to upper case. - inline char uppercase(const char x) { - return (char)((x<'a'||x>'z')?x:x - 'a' + 'A'); - } - - inline double uppercase(const double x) { - return (double)((x<'a'||x>'z')?x:x - 'a' + 'A'); - } - - //! Convert C-string to upper case. - inline void uppercase(char *const str) { - if (str) for (char *ptr = str; *ptr; ++ptr) *ptr = uppercase(*ptr); - } - - //! Return \c true if input character is blank (space, tab, or non-printable character). - inline bool is_blank(const char c) { - return (unsigned char)c<=' '; - } - - //! Read value in a C-string. - /** - \param str C-string containing the float value to read. - \return Read value. - \note Same as std::atof() extended to manage the retrieval of fractions from C-strings, - as in "1/2". - **/ - inline double atof(const char *const str) { - double x = 0, y = 1; - return str && cimg_sscanf(str,"%lf/%lf",&x,&y)>0?x/y:0; - } - - //! Compare the first \p l characters of two C-strings, ignoring the case. - /** - \param str1 C-string. - \param str2 C-string. - \param l Number of characters to compare. - \return \c 0 if the two strings are equal, something else otherwise. - \note This function has to be defined since it is not provided by all C++-compilers (not ANSI). - **/ - inline int strncasecmp(const char *const str1, const char *const str2, const int l) { - if (!l) return 0; - if (!str1) return str2?-1:0; - const char *nstr1 = str1, *nstr2 = str2; - int k, diff = 0; for (k = 0; kp && str[q]==delimiter; ) { --q; if (!is_iterative) break; } - } - const int n = q - p + 1; - if (n!=l) { std::memmove(str,str + p,(unsigned int)n); str[n] = 0; return true; } - return false; - } - - //! Remove white spaces on the start and/or end of a C-string. - inline bool strpare(char *const str, const bool is_symmetric, const bool is_iterative) { - if (!str) return false; - const int l = (int)std::strlen(str); - int p, q; - if (is_symmetric) for (p = 0, q = l - 1; pp && is_blank(str[q]); ) { --q; if (!is_iterative) break; } - } - const int n = q - p + 1; - if (n!=l) { std::memmove(str,str + p,(unsigned int)n); str[n] = 0; return true; } - return false; - } - - //! Replace reserved characters (for Windows filename) by another character. - /** - \param[in,out] str C-string to work with (modified at output). - \param[in] c Replacement character. - **/ - inline void strwindows_reserved(char *const str, const char c='_') { - for (char *s = str; *s; ++s) { - const char i = *s; - if (i=='<' || i=='>' || i==':' || i=='\"' || i=='/' || i=='\\' || i=='|' || i=='?' || i=='*') *s = c; - } - } - - //! Replace escape sequences in C-strings by character values. - /** - \param[in,out] str C-string to work with (modified at output). - **/ - inline void strunescape(char *const str) { -#define cimg_strunescape(ci,co) case ci : *nd = co; ++ns; break; - - unsigned char val = 0; - for (char *ns = str, *nd = str; *ns || (bool)(*nd = 0); ++nd) if (*ns=='\\') switch (*(++ns)) { - cimg_strunescape('a','\a'); - cimg_strunescape('b','\b'); - cimg_strunescape('e',0x1B); - cimg_strunescape('f','\f'); - cimg_strunescape('n','\n'); - cimg_strunescape('r','\r'); - cimg_strunescape('t','\t'); - cimg_strunescape('v','\v'); - cimg_strunescape('\\','\\'); - cimg_strunescape('\'','\''); - cimg_strunescape('\"','\"'); - cimg_strunescape('\?','\?'); - case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : - val = (unsigned char)(*(ns++) - '0'); - if (*ns>='0' && *ns<='7') (val<<=3)|=*(ns++) - '0'; - if (*ns>='0' && *ns<='7') (val<<=3)|=*(ns++) - '0'; - *nd = (char)val; - break; - case 'x' : { - char c = lowercase(*(++ns)); - if ((c>='0' && c<='9') || (c>='a' && c<='f')) { - val = (unsigned char)(c<='9'?c - '0':c - 'a' + 10); - c = lowercase(*(++ns)); - if ((c>='0' && c<='9') || (c>='a' && c<='f')) { - (val<<=4)|=(c<='9'?c - '0':c - 'a' + 10); - ++ns; - } - *nd = (char)val; - } else *nd = c; - } break; - case 'u' : { // UTF-8 BMP - char c1, c2, c3, c4; - if ((((c1 = lowercase(ns[1]))>='0' && c1<='9') || (c1>='a' && c1<='f')) && - (((c2 = lowercase(ns[2]))>='0' && c2<='9') || (c2>='a' && c2<='f')) && - (((c3 = lowercase(ns[3]))>='0' && c3<='9') || (c3>='a' && c3<='f')) && - (((c4 = lowercase(ns[4]))>='0' && c4<='9') || (c4>='a' && c4<='f'))) { - c1 = (c1<='9'?c1 - '0':c1 - 'a' + 10); - c2 = (c2<='9'?c2 - '0':c2 - 'a' + 10); - c3 = (c3<='9'?c3 - '0':c3 - 'a' + 10); - c4 = (c4<='9'?c4 - '0':c4 - 'a' + 10); - const unsigned int ival = - ((unsigned int)c1<<12) | ((unsigned int)c2<<8) | ((unsigned int)c3<<4) | c4; - if (ival<=0x007f) *nd = (char)ival; - else if (ival<=0x07ff) { - *(nd++) = (char)((ival>>6)|0xc0); - *nd = (char)((ival&0x3f)|0x80); - } else { - *(nd++) = (char)((ival>>12)|0xe0); - *(nd++) = (char)(((ival>>6)&0x3f)|0x80); - *nd = (char)((ival&0x3f)|0x80); - } - ns+=5; - } else *nd = *(ns++); - } break; - case 'U' : { // UTF-8 astral planes - char c1, c2, c3, c4, c5, c6, c7, c8; - if ((((c1 = lowercase(ns[1]))>='0' && c1<='9') || (c1>='a' && c1<='f')) && - (((c2 = lowercase(ns[2]))>='0' && c2<='9') || (c2>='a' && c2<='f')) && - (((c3 = lowercase(ns[3]))>='0' && c3<='9') || (c3>='a' && c3<='f')) && - (((c4 = lowercase(ns[4]))>='0' && c4<='9') || (c4>='a' && c4<='f')) && - (((c5 = lowercase(ns[5]))>='0' && c5<='9') || (c5>='a' && c5<='f')) && - (((c6 = lowercase(ns[6]))>='0' && c6<='9') || (c6>='a' && c6<='f')) && - (((c7 = lowercase(ns[7]))>='0' && c7<='9') || (c7>='a' && c7<='f')) && - (((c8 = lowercase(ns[8]))>='0' && c8<='9') || (c8>='a' && c8<='f'))) { - c1 = (c1<='9'?c1 - '0':c1 - 'a' + 10); - c2 = (c2<='9'?c2 - '0':c2 - 'a' + 10); - c3 = (c3<='9'?c3 - '0':c3 - 'a' + 10); - c4 = (c4<='9'?c4 - '0':c4 - 'a' + 10); - c5 = (c5<='9'?c5 - '0':c5 - 'a' + 10); - c6 = (c6<='9'?c6 - '0':c6 - 'a' + 10); - c7 = (c7<='9'?c7 - '0':c7 - 'a' + 10); - c8 = (c8<='9'?c8 - '0':c8 - 'a' + 10); - const unsigned int ival = - ((unsigned int)c1<<28) | ((unsigned int)c2<<24) | ((unsigned int)c3<<20) | ((unsigned int)c4<<16) | - ((unsigned int)c5<<12) | ((unsigned int)c6<<8) | ((unsigned int)c7<<4) | (unsigned int)c8; - if (ival<=0x007f) *nd = (char)ival; - else if (ival<=0x07ff) { - *(nd++) = (char)((ival>>6)|0xc0); - *nd = (char)((ival&0x3f)|0x80); - } else if (ival<=0xffff) { - *(nd++) = (char)((ival>>12)|0xe0); - *(nd++) = (char)(((ival>>6)&0x3f)|0x80); - *nd = (char)((ival&0x3f)|0x80); - } else { - *(nd++) = (char)((ival>>18)|0xf0); - *(nd++) = (char)(((ival>>12)&0x3f)|0x80); - *(nd++) = (char)(((ival>>6)&0x3f)|0x80); - *nd = (char)((ival&0x3f)|0x80); - } - ns+=9; - } else *nd = *(ns++); - } break; - default : if (*ns) *nd = *(ns++); - } - else *nd = *(ns++); - } - - // Return a temporary string describing the size of a memory buffer. - inline const char *strbuffersize(const cimg_ulong size); - - // Return string that identifies the running OS. - inline const char *stros() { -#if defined(linux) || defined(__linux) || defined(__linux__) - static const char *const str = "Linux"; -#elif defined(sun) || defined(__sun) - static const char *const str = "Sun OS"; -#elif defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined (__DragonFly__) - static const char *const str = "BSD"; -#elif defined(sgi) || defined(__sgi) - static const char *const str = "Irix"; -#elif defined(__MACOSX__) || defined(__APPLE__) - static const char *const str = "Mac OS"; -#elif defined(unix) || defined(__unix) || defined(__unix__) - static const char *const str = "Generic Unix"; -#elif defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || \ - defined(WIN64) || defined(_WIN64) || defined(__WIN64__) - static const char *const str = "Windows"; -#else - const char - *const _str1 = std::getenv("OSTYPE"), - *const _str2 = _str1?_str1:std::getenv("OS"), - *const str = _str2?_str2:"Unknown OS"; -#endif - return str; - } - - //! Return the basename of a filename. - inline const char* basename(const char *const s, const char separator=cimg_file_separator) { - const char *p = 0, *np = s; - while (np>=s && (p=np)) np = std::strchr(np,separator) + 1; - return p; - } - - // Return a random filename. - inline const char* filenamerand() { - cimg::mutex(6); - static char randomid[9]; - for (unsigned int k = 0; k<8; ++k) { - const int v = (int)cimg::rand(65535)%3; - randomid[k] = (char)(v==0?('0' + ((int)cimg::rand(65535)%10)): - (v==1?('a' + ((int)cimg::rand(65535)%26)): - ('A' + ((int)cimg::rand(65535)%26)))); - } - cimg::mutex(6,0); - return randomid; - } - - // Convert filename as a Windows-style filename (short path name). - inline void winformat_string(char *const str) { - if (str && *str) { -#if cimg_OS==2 - char *const nstr = new char[MAX_PATH]; - if (GetShortPathNameA(str,nstr,MAX_PATH)) std::strcpy(str,nstr); - delete[] nstr; -#endif - } - } - - // Open a file (similar to std:: fopen(), but with wide character support on Windows). - inline std::FILE *std_fopen(const char *const path, const char *const mode); - - - //! Open a file. - /** - \param path Path of the filename to open. - \param mode C-string describing the opening mode. - \return Opened file. - \note Same as std::fopen() but throw a \c CImgIOException when - the specified file cannot be opened, instead of returning \c 0. - **/ - inline std::FILE *fopen(const char *const path, const char *const mode) { - if (!path) - throw CImgArgumentException("cimg::fopen(): Specified file path is (null)."); - if (!mode) - throw CImgArgumentException("cimg::fopen(): File '%s', specified mode is (null).", - path); - std::FILE *res = 0; - if (*path=='-' && (!path[1] || path[1]=='.')) { - res = (*mode=='r')?cimg::_stdin():cimg::_stdout(); -#if cimg_OS==2 - if (*mode && mode[1]=='b') { // Force stdin/stdout to be in binary mode -#ifdef __BORLANDC__ - if (setmode(_fileno(res),0x8000)==-1) res = 0; -#else - if (_setmode(_fileno(res),0x8000)==-1) res = 0; -#endif - } -#endif - } else res = cimg::std_fopen(path,mode); - if (!res) throw CImgIOException("cimg::fopen(): Failed to open file '%s' with mode '%s'.", - path,mode); - return res; - } - - //! Close a file. - /** - \param file File to close. - \return \c 0 if file has been closed properly, something else otherwise. - \note Same as std::fclose() but display a warning message if - the file has not been closed properly. - **/ - inline int fclose(std::FILE *file) { - if (!file) { warn("cimg::fclose(): Specified file is (null)."); return 0; } - if (file==cimg::_stdin(false) || file==cimg::_stdout(false)) return 0; - const int errn = std::fclose(file); - if (errn!=0) warn("cimg::fclose(): Error code %d returned during file closing.", - errn); - return errn; - } - - //! Version of 'fseek()' that supports >=64bits offsets everywhere (for Windows). - inline int fseek(FILE *stream, cimg_long offset, int origin) { -#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) - return _fseeki64(stream,(__int64)offset,origin); -#else - return std::fseek(stream,offset,origin); -#endif - } - - //! Version of 'ftell()' that supports >=64bits offsets everywhere (for Windows). - inline cimg_long ftell(FILE *stream) { -#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) - return (cimg_long)_ftelli64(stream); -#else - return (cimg_long)std::ftell(stream); -#endif - } - - // Get the file or directory attributes with support for UTF-8 paths (Windows only). -#if cimg_OS==2 - inline DWORD win_getfileattributes(const char *const path); -#endif - - //! Check if a path is a directory. - /** - \param path Specified path to test. - **/ - inline bool is_directory(const char *const path) { - if (!path || !*path) return false; -#if cimg_OS==1 - struct stat st_buf; - return (!stat(path,&st_buf) && S_ISDIR(st_buf.st_mode)); -#elif cimg_OS==2 - const DWORD res = win_getfileattributes(path); - return res!=INVALID_FILE_ATTRIBUTES && (res&FILE_ATTRIBUTE_DIRECTORY); -#else - return false; -#endif - } - - //! Check if a path is a file. - /** - \param path Specified path to test. - **/ - inline bool is_file(const char *const path) { - if (!path || !*path) return false; -#if cimg_OS==2 - const DWORD res = cimg::win_getfileattributes(path); - return res!=INVALID_FILE_ATTRIBUTES && !(res&FILE_ATTRIBUTE_DIRECTORY); -#else - std::FILE *const file = cimg::std_fopen(path,"rb"); - if (!file) return false; - cimg::fclose(file); - return !is_directory(path); -#endif - } - - //! Get file size. - /** - \param filename Specified filename to get size from. - \return File size or '-1' if file does not exist. - **/ - inline cimg_int64 fsize(const char *const filename) { - std::FILE *const file = cimg::std_fopen(filename,"rb"); - if (!file) return (cimg_int64)-1; - std::fseek(file,0,SEEK_END); - const cimg_int64 siz = (cimg_int64)std::ftell(file); - cimg::fclose(file); - return siz; - } - - //! Get last write time of a given file or directory (multiple-attributes version). - /** - \param path Specified path to get attributes from. - \param[in,out] attr Type of requested time attributes. - Can be { 0=year | 1=month | 2=day | 3=day of week | 4=hour | 5=minute | 6=second } - Replaced by read attributes after return (or -1 if an error occurred). - \param nb_attr Number of attributes to read/write. - \return Latest read attribute. - **/ - template - inline int fdate(const char *const path, T *attr, const unsigned int nb_attr) { -#define _cimg_fdate_err() for (unsigned int i = 0; i - inline int date(T *attr, const unsigned int nb_attr) { - int res = -1; - cimg::mutex(6); -#if cimg_OS==2 - SYSTEMTIME st; - GetLocalTime(&st); - for (unsigned int i = 0; itm_year + 1900: - attr[i]==1?st->tm_mon + 1: - attr[i]==2?st->tm_mday: - attr[i]==3?st->tm_wday: - attr[i]==4?st->tm_hour: - attr[i]==5?st->tm_min: - attr[i]==6?st->tm_sec: - attr[i]==7?_st.tv_usec/1000:-1); - attr[i] = (T)res; - } -#endif - cimg::mutex(6,0); - return res; - } - - //! Get current local time (single-attribute version). - /** - \param attr Type of requested time attribute. - Can be { 0=year | 1=month | 2=day | 3=day of week | 4=hour | 5=minute | 6=second | - 7=millisecond } - \return Specified attribute or -1 if an error occurred. - **/ - inline int date(unsigned int attr) { - int out = (int)attr; - return date(&out,1); - } - - // Get/set path to the \c curl binary. - inline const char *curl_path(const char *const user_path=0, const bool reinit_path=false); - - // Get/set path to the \c dcraw binary. - inline const char *dcraw_path(const char *const user_path=0, const bool reinit_path=false); - - // Get/set path to the FFMPEG's \c ffmpeg binary. - inline const char *ffmpeg_path(const char *const user_path=0, const bool reinit_path=false); - - // Get/set path to the GraphicsMagick's \c gm binary. - inline const char* graphicsmagick_path(const char *const user_path=0, const bool reinit_path=false); - - // Get/set path to the \c gunzip binary. - inline const char *gunzip_path(const char *const user_path=0, const bool reinit_path=false); - - // Get/set path to the \c gzip binary. - inline const char *gzip_path(const char *const user_path=0, const bool reinit_path=false); - - // Get/set path to the ImageMagick's \c convert binary. - inline const char* imagemagick_path(const char *const user_path=0, const bool reinit_path=false); - - // Get/set path to the Medcon's \c medcon binary. - inline const char* medcon_path(const char *const user_path=0, const bool reinit_path=false); - - // Get/set path to store temporary files. - inline const char* temporary_path(const char *const user_path=0, const bool reinit_path=false); - - // Get/set path to the \c wget binary. - inline const char *wget_path(const char *const user_path=0, const bool reinit_path=false); - -#if cimg_OS==2 - // Get/set path to the \c powershell binary. - inline const char *powershell_path(const char *const user_path=0, const bool reinit_path=false); -#endif - - //! Split filename into two C-strings \c body and \c extension. - /** - filename and body must not overlap! - **/ - inline const char *split_filename(const char *const filename, char *const body=0) { - if (!filename) { if (body) *body = 0; return ""; } - const char * p = std::strrchr(filename,'.'); - if (!p || std::strchr(p,'/') || std::strchr(p,'\\')) { // No extension. - if (body) std::strcpy(body,filename); - return filename + std::strlen(filename); - } - const unsigned int l = (unsigned int)(p - filename); - if (body) { if (l) std::memcpy(body,filename,l); body[l] = 0; } - return p + 1; - } - - // Generate a numbered version of a filename. - inline char* number_filename(const char *const filename, const int number, - const unsigned int digits, char *const str); - - //! Read data from file. - /** - \param[out] ptr Pointer to memory buffer that will contain the binary data read from file. - \param nmemb Number of elements to read. - \param stream File to read data from. - \return Number of read elements. - \note Same as std::fread() but may display warning message if all elements could not be read. - **/ - template - inline size_t fread(T *const ptr, const size_t nmemb, std::FILE *stream) { - if (!ptr || !stream) - throw CImgArgumentException("cimg::fread(): Invalid reading request of %u %s%s from file %p to buffer %p.", - nmemb,cimg::type::string(),nmemb>1?"s":"",stream,ptr); - if (!nmemb) return 0; - const size_t wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T); - size_t to_read = nmemb, al_read = 0, l_to_read = 0, l_al_read = 0; - do { - l_to_read = (to_read*sizeof(T))0); - if (to_read>0) - warn("cimg::fread(): Only %lu/%lu elements could be read from file.", - (unsigned long)al_read,(unsigned long)nmemb); - return al_read; - } - - //! Write data to file. - /** - \param ptr Pointer to memory buffer containing the binary data to write on file. - \param nmemb Number of elements to write. - \param[out] stream File to write data on. - \return Number of written elements. - \note Similar to std::fwrite but may display warning messages if all elements could not be written. - **/ - template - inline size_t fwrite(const T *ptr, const size_t nmemb, std::FILE *stream) { - if (!ptr || !stream) - throw CImgArgumentException("cimg::fwrite(): Invalid writing request of %u %s%s from buffer %p to file %p.", - nmemb,cimg::type::string(),nmemb>1?"s":"",ptr,stream); - if (!nmemb) return 0; - const size_t wlimitT = 63*1024*1024, wlimit = wlimitT/sizeof(T); - size_t to_write = nmemb, al_write = 0, l_to_write = 0, l_al_write = 0; - do { - l_to_write = (to_write*sizeof(T))0); - if (to_write>0) - warn("cimg::fwrite(): Only %lu/%lu elements could be written in file.", - (unsigned long)al_write,(unsigned long)nmemb); - return al_write; - } - - //! Create an empty file. - /** - \param file Input file (can be \c 0 if \c filename is set). - \param filename Filename, as a C-string (can be \c 0 if \c file is set). - **/ - inline void fempty(std::FILE *const file, const char *const filename) { - if (!file && !filename) - throw CImgArgumentException("cimg::fempty(): Specified filename is (null)."); - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - if (!file) cimg::fclose(nfile); - } - - // Try to guess format from an image file. - inline const char *ftype(std::FILE *const file, const char *const filename); - - // Get or set load from network mode (can be { 0=disabled | 1=enabled }). - inline bool& network_mode(const bool value, const bool is_set) { - static bool mode = true; - if (is_set) { cimg::mutex(0); mode = value; cimg::mutex(0,0); } - return mode; - } - - inline bool& network_mode() { - return network_mode(false,false); - } - - // Load file from network as a local temporary file. - inline char *load_network(const char *const url, char *const filename_local, - const unsigned int timeout=0, const bool try_fallback=false, - const char *const referer=0); - - //! Return options specified on the command line. - inline const char* option(const char *const name, const int argc, const char *const *const argv, - const char *const _default, const char *const usage, const bool reset_static) { - static bool first = true, visu = false; - if (reset_static) { first = true; return 0; } - const char *res = 0; - if (first) { - first = false; - visu = cimg::option("-h",argc,argv,(char*)0,(char*)0,false)!=0; - visu |= cimg::option("-help",argc,argv,(char*)0,(char*)0,false)!=0; - visu |= cimg::option("--help",argc,argv,(char*)0,(char*)0,false)!=0; - } - if (!name && visu) { - if (usage) { - std::fprintf(cimg::output(),"\n %s%s%s",cimg::t_red,cimg::basename(argv[0]),cimg::t_normal); - std::fprintf(cimg::output(),": %s",usage); - std::fprintf(cimg::output()," (%s, %s)\n\n",cimg_date,cimg_time); - } - if (_default) std::fprintf(cimg::output(),"%s\n",_default); - } - if (name) { - if (argc>0) { - int k = 0; - while (k Operating System: %s%-13s%s %s('cimg_OS'=%d)%s\n", - cimg::t_bold, - cimg_OS==1?"Unix":(cimg_OS==2?"Windows":"Unknown"), - cimg::t_normal,cimg::t_green, - cimg_OS, - cimg::t_normal); - - std::fprintf(cimg::output()," > CPU endianness: %s%s Endian%s\n", - cimg::t_bold, - cimg::endianness()?"Big":"Little", - cimg::t_normal); - - std::fprintf(cimg::output()," > Verbosity mode: %s%-13s%s %s('cimg_verbosity'=%d)%s\n", - cimg::t_bold, - cimg_verbosity==0?"Quiet": - cimg_verbosity==1?"Console": - cimg_verbosity==2?"Dialog": - cimg_verbosity==3?"Console+Warnings":"Dialog+Warnings", - cimg::t_normal,cimg::t_green, - cimg_verbosity, - cimg::t_normal); - - std::fprintf(cimg::output()," > Stricts warnings: %s%-13s%s %s('cimg_strict_warnings' %s)%s\n", - cimg::t_bold, -#ifdef cimg_strict_warnings - "Yes",cimg::t_normal,cimg::t_green,"defined", -#else - "No",cimg::t_normal,cimg::t_green,"undefined", -#endif - cimg::t_normal); - - std::fprintf(cimg::output()," > Support for C++11: %s%-13s%s %s('cimg_use_cpp11'=%d)%s\n", - cimg::t_bold, - cimg_use_cpp11?"Yes":"No", - cimg::t_normal,cimg::t_green, - (int)cimg_use_cpp11, - cimg::t_normal); - - std::fprintf(cimg::output()," > Using VT100 messages: %s%-13s%s %s('cimg_use_vt100' %s)%s\n", - cimg::t_bold, -#ifdef cimg_use_vt100 - "Yes",cimg::t_normal,cimg::t_green,"defined", -#else - "No",cimg::t_normal,cimg::t_green,"undefined", -#endif - cimg::t_normal); - - std::fprintf(cimg::output()," > Display type: %s%-13s%s %s('cimg_display'=%d)%s\n", - cimg::t_bold, - cimg_display==0?"No display":cimg_display==1?"X11":cimg_display==2?"Windows GDI":"Unknown", - cimg::t_normal,cimg::t_green, - (int)cimg_display, - cimg::t_normal); - -#if cimg_display==1 - std::fprintf(cimg::output()," > Using XShm for X11: %s%-13s%s %s('cimg_use_xshm' %s)%s\n", - cimg::t_bold, -#ifdef cimg_use_xshm - "Yes",cimg::t_normal,cimg::t_green,"defined", -#else - "No",cimg::t_normal,cimg::t_green,"undefined", -#endif - cimg::t_normal); - - std::fprintf(cimg::output()," > Using XRand for X11: %s%-13s%s %s('cimg_use_xrandr' %s)%s\n", - cimg::t_bold, -#ifdef cimg_use_xrandr - "Yes",cimg::t_normal,cimg::t_green,"defined", -#else - "No",cimg::t_normal,cimg::t_green,"undefined", -#endif - cimg::t_normal); -#endif - std::fprintf(cimg::output()," > Using OpenMP: %s%-13s%s %s('cimg_use_openmp' %s)%s\n", - cimg::t_bold, -#if cimg_use_openmp!=0 - "Yes",cimg::t_normal,cimg::t_green,"defined", -#else - "No",cimg::t_normal,cimg::t_green,"undefined", -#endif - cimg::t_normal); - std::fprintf(cimg::output()," > Using PNG library: %s%-13s%s %s('cimg_use_png' %s)%s\n", - cimg::t_bold, -#ifdef cimg_use_png - "Yes",cimg::t_normal,cimg::t_green,"defined", -#else - "No",cimg::t_normal,cimg::t_green,"undefined", -#endif - cimg::t_normal); - std::fprintf(cimg::output()," > Using JPEG library: %s%-13s%s %s('cimg_use_jpeg' %s)%s\n", - cimg::t_bold, -#ifdef cimg_use_jpeg - "Yes",cimg::t_normal,cimg::t_green,"defined", -#else - "No",cimg::t_normal,cimg::t_green,"undefined", -#endif - cimg::t_normal); - - std::fprintf(cimg::output()," > Using TIFF library: %s%-13s%s %s('cimg_use_tiff' %s)%s\n", - cimg::t_bold, -#ifdef cimg_use_tiff - "Yes",cimg::t_normal,cimg::t_green,"defined", -#else - "No",cimg::t_normal,cimg::t_green,"undefined", -#endif - cimg::t_normal); - - std::fprintf(cimg::output()," > Using Magick++ library: %s%-13s%s %s('cimg_use_magick' %s)%s\n", - cimg::t_bold, -#ifdef cimg_use_magick - "Yes",cimg::t_normal,cimg::t_green,"defined", -#else - "No",cimg::t_normal,cimg::t_green,"undefined", -#endif - cimg::t_normal); - - std::fprintf(cimg::output()," > Using FFTW3 library: %s%-13s%s %s('cimg_use_fftw3' %s)%s\n", - cimg::t_bold, -#ifdef cimg_use_fftw3 - "Yes",cimg::t_normal,cimg::t_green,"defined", -#else - "No",cimg::t_normal,cimg::t_green,"undefined", -#endif - cimg::t_normal); - - std::fprintf(cimg::output()," > Using LAPACK library: %s%-13s%s %s('cimg_use_lapack' %s)%s\n", - cimg::t_bold, -#ifdef cimg_use_lapack - "Yes",cimg::t_normal,cimg::t_green,"defined", -#else - "No",cimg::t_normal,cimg::t_green,"undefined", -#endif - cimg::t_normal); - - char *const tmp = new char[1024]; - - cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::curl_path()); - std::fprintf(cimg::output()," > Path of 'curl': %s%-13s%s\n", - cimg::t_bold, - tmp, - cimg::t_normal); - - cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::dcraw_path()); - std::fprintf(cimg::output()," > Path of 'dcraw': %s%-13s%s\n", - cimg::t_bold, - tmp, - cimg::t_normal); - - cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::ffmpeg_path()); - std::fprintf(cimg::output()," > Path of 'ffmpeg': %s%-13s%s\n", - cimg::t_bold, - tmp, - cimg::t_normal); - - cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::graphicsmagick_path()); - std::fprintf(cimg::output()," > Path of 'graphicsmagick': %s%-13s%s\n", - cimg::t_bold, - tmp, - cimg::t_normal); - - cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::gunzip_path()); - std::fprintf(cimg::output()," > Path of 'gunzip': %s%-13s%s\n", - cimg::t_bold, - tmp, - cimg::t_normal); - - cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::gzip_path()); - std::fprintf(cimg::output()," > Path of 'gzip': %s%-13s%s\n", - cimg::t_bold, - tmp, - cimg::t_normal); - - cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::imagemagick_path()); - std::fprintf(cimg::output()," > Path of 'imagemagick': %s%-13s%s\n", - cimg::t_bold, - tmp, - cimg::t_normal); - - cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::medcon_path()); - std::fprintf(cimg::output()," > Path of 'medcon': %s%-13s%s\n", - cimg::t_bold, - tmp, - cimg::t_normal); - - cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::temporary_path()); - std::fprintf(cimg::output()," > Temporary path: %s%-13s%s\n", - cimg::t_bold, - tmp, - cimg::t_normal); - - cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::wget_path()); - std::fprintf(cimg::output()," > Path of 'wget': %s%-13s%s\n", - cimg::t_bold, - tmp, - cimg::t_normal); -#if cimg_OS==2 - cimg_snprintf(tmp,1024,"\"%.1020s\"",cimg::powershell_path()); - std::fprintf(cimg::output()," > Path of 'powershell_path': %s%-13s%s\n", - cimg::t_bold, - tmp, - cimg::t_normal); -#endif - - std::fprintf(cimg::output(),"\n"); - delete[] tmp; - } - - // Declare LAPACK function signatures if LAPACK support is enabled. -#ifdef cimg_use_lapack - template - inline void getrf(int &N, T *lapA, int *IPIV, int &INFO) { - dgetrf_(&N,&N,lapA,&N,IPIV,&INFO); - } - - inline void getrf(int &N, float *lapA, int *IPIV, int &INFO) { - sgetrf_(&N,&N,lapA,&N,IPIV,&INFO); - } - - template - inline void getri(int &N, T *lapA, int *IPIV, T* WORK, int &LWORK, int &INFO) { - dgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO); - } - - inline void getri(int &N, float *lapA, int *IPIV, float* WORK, int &LWORK, int &INFO) { - sgetri_(&N,lapA,&N,IPIV,WORK,&LWORK,&INFO); - } - - template - inline void gesvd(char &JOB, int &M, int &N, T *lapA, int &MN, - T *lapS, T *lapU, T *lapV, T *WORK, int &LWORK, int &INFO) { - dgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO); - } - - inline void gesvd(char &JOB, int &M, int &N, float *lapA, int &MN, - float *lapS, float *lapU, float *lapV, float *WORK, int &LWORK, int &INFO) { - sgesvd_(&JOB,&JOB,&M,&N,lapA,&MN,lapS,lapU,&M,lapV,&N,WORK,&LWORK,&INFO); - } - - template - inline void getrs(char &TRANS, int &N, T *lapA, int *IPIV, T *lapB, int &INFO) { - int one = 1; - dgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO); - } - - inline void getrs(char &TRANS, int &N, float *lapA, int *IPIV, float *lapB, int &INFO) { - int one = 1; - sgetrs_(&TRANS,&N,&one,lapA,&N,IPIV,lapB,&N,&INFO); - } - - template - inline void syev(char &JOB, char &UPLO, int &N, T *lapA, T *lapW, T *WORK, int &LWORK, int &INFO) { - dsyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO); - } - - inline void syev(char &JOB, char &UPLO, int &N, float *lapA, float *lapW, float *WORK, int &LWORK, int &INFO) { - ssyev_(&JOB,&UPLO,&N,lapA,&N,lapW,WORK,&LWORK,&INFO); - } - - template - inline void sgels(char & TRANS, int &M, int &N, int &NRHS, T* lapA, int &LDA, - T* lapB, int &LDB, T* WORK, int &LWORK, int &INFO) { - dgels_(&TRANS, &M, &N, &NRHS, lapA, &LDA, lapB, &LDB, WORK, &LWORK, &INFO); - } - - inline void sgels(char & TRANS, int &M, int &N, int &NRHS, float* lapA, int &LDA, - float* lapB, int &LDB, float* WORK, int &LWORK, int &INFO) { - sgels_(&TRANS, &M, &N, &NRHS, lapA, &LDA, lapB, &LDB, WORK, &LWORK, &INFO); - } - -#endif - - } // namespace cimg { ... - - /*------------------------------------------------ - # - # - # Definition of mathematical operators and - # external functions. - # - # - -------------------------------------------------*/ - -#define _cimg_create_operator(typ) \ - template \ - inline CImg::type> operator+(const typ val, const CImg& img) { \ - return img + val; \ - } \ - template \ - inline CImg::type> operator-(const typ val, const CImg& img) { \ - typedef typename cimg::superset::type Tt; \ - return CImg(img._width,img._height,img._depth,img._spectrum,val)-=img; \ - } \ - template \ - inline CImg::type> operator*(const typ val, const CImg& img) { \ - return img*val; \ - } \ - template \ - inline CImg::type> operator/(const typ val, const CImg& img) { \ - return val*img.get_invert(); \ - } \ - template \ - inline CImg::type> operator&(const typ val, const CImg& img) { \ - return img & val; \ - } \ - template \ - inline CImg::type> operator|(const typ val, const CImg& img) { \ - return img | val; \ - } \ - template \ - inline CImg::type> operator^(const typ val, const CImg& img) { \ - return img ^ val; \ - } \ - template \ - inline bool operator==(const typ val, const CImg& img) { \ - return img == val; \ - } \ - template \ - inline bool operator!=(const typ val, const CImg& img) { \ - return img != val; \ - } - - _cimg_create_operator(bool) - _cimg_create_operator(unsigned char) - _cimg_create_operator(char) - _cimg_create_operator(signed char) - _cimg_create_operator(unsigned short) - _cimg_create_operator(short) - _cimg_create_operator(unsigned int) - _cimg_create_operator(int) - _cimg_create_operator(cimg_uint64) - _cimg_create_operator(cimg_int64) - _cimg_create_operator(float) - _cimg_create_operator(double) - _cimg_create_operator(long double) - - template - inline CImg<_cimg_Tfloat> operator+(const char *const expression, const CImg& img) { - return img + expression; - } - - template - inline CImg<_cimg_Tfloat> operator-(const char *const expression, const CImg& img) { - return CImg<_cimg_Tfloat>(img,false).fill(expression,true)-=img; - } - - template - inline CImg<_cimg_Tfloat> operator*(const char *const expression, const CImg& img) { - return img*expression; - } - - template - inline CImg<_cimg_Tfloat> operator/(const char *const expression, const CImg& img) { - return expression*img.get_invert(); - } - - template - inline CImg operator&(const char *const expression, const CImg& img) { - return img & expression; - } - - template - inline CImg operator|(const char *const expression, const CImg& img) { - return img | expression; - } - - template - inline CImg operator^(const char *const expression, const CImg& img) { - return img ^ expression; - } - - template - inline bool operator==(const char *const expression, const CImg& img) { - return img==expression; - } - - template - inline bool operator!=(const char *const expression, const CImg& img) { - return img!=expression; - } - - template - inline CImg transpose(const CImg& instance) { - return instance.get_transpose(); - } - - template - inline CImg<_cimg_Tfloat> invert(const CImg& instance, const bool use_LU=false, const float lambda=0) { - return instance.get_invert(use_LU,lambda); - } - -#define _cimg_create_pointwise_function(name) \ - template \ - inline CImg<_cimg_Tfloat> name(const CImg& instance) { \ - return instance.get_##name(); \ - } - - _cimg_create_pointwise_function(sqr) - _cimg_create_pointwise_function(sqrt) - _cimg_create_pointwise_function(erf) - _cimg_create_pointwise_function(exp) - _cimg_create_pointwise_function(log) - _cimg_create_pointwise_function(log2) - _cimg_create_pointwise_function(log10) - _cimg_create_pointwise_function(abs) - _cimg_create_pointwise_function(sign) - _cimg_create_pointwise_function(cos) - _cimg_create_pointwise_function(sin) - _cimg_create_pointwise_function(sinc) - _cimg_create_pointwise_function(tan) - _cimg_create_pointwise_function(acos) - _cimg_create_pointwise_function(asin) - _cimg_create_pointwise_function(atan) - _cimg_create_pointwise_function(cosh) - _cimg_create_pointwise_function(sinh) - _cimg_create_pointwise_function(tanh) - _cimg_create_pointwise_function(acosh) - _cimg_create_pointwise_function(asinh) - _cimg_create_pointwise_function(atanh) - - /*----------------------------------- - # - # Define the CImgDisplay structure - # - ----------------------------------*/ - //! Allow the creation of windows, display images on them and manage user events (keyboard, mouse and windows events). - /** - CImgDisplay methods rely on a low-level graphic library to perform: it can be either \b X-Window - (X11, for Unix-based systems) or \b GDI32 (for Windows-based systems). - If both libraries are missing, CImgDisplay will not be able to display images on screen, and will enter - a minimal mode where warning messages will be outputted each time the program is trying to call one of the - CImgDisplay method. - - The configuration variable \c cimg_display tells about the graphic library used. - It is set automatically by \CImg when one of these graphic libraries has been detected. - But, you can override its value if necessary. Valid choices are: - - 0: Disable display capabilities. - - 1: Use \b X-Window (X11) library. - - 2: Use \b GDI32 library. - - Remember to link your program against \b X11 or \b GDI32 libraries if you use CImgDisplay. - **/ - struct CImgDisplay { - cimg_uint64 _timer, _fps_frames, _fps_timer; - unsigned int _width, _height, _normalization; - float _fps_fps, _min, _max; - bool _is_fullscreen; - char *_title; - unsigned int _window_width, _window_height, _button, *_keys, *_released_keys; - int _window_x, _window_y, _mouse_x, _mouse_y, _wheel; - bool _is_closed, _is_resized, _is_moved, _is_event, - _is_keyESC, _is_keyF1, _is_keyF2, _is_keyF3, _is_keyF4, _is_keyF5, _is_keyF6, _is_keyF7, - _is_keyF8, _is_keyF9, _is_keyF10, _is_keyF11, _is_keyF12, _is_keyPAUSE, _is_key1, _is_key2, - _is_key3, _is_key4, _is_key5, _is_key6, _is_key7, _is_key8, _is_key9, _is_key0, - _is_keyBACKSPACE, _is_keyINSERT, _is_keyHOME, _is_keyPAGEUP, _is_keyTAB, _is_keyQ, _is_keyW, _is_keyE, - _is_keyR, _is_keyT, _is_keyY, _is_keyU, _is_keyI, _is_keyO, _is_keyP, _is_keyDELETE, - _is_keyEND, _is_keyPAGEDOWN, _is_keyCAPSLOCK, _is_keyA, _is_keyS, _is_keyD, _is_keyF, _is_keyG, - _is_keyH, _is_keyJ, _is_keyK, _is_keyL, _is_keyENTER, _is_keySHIFTLEFT, _is_keyZ, _is_keyX, - _is_keyC, _is_keyV, _is_keyB, _is_keyN, _is_keyM, _is_keySHIFTRIGHT, _is_keyARROWUP, _is_keyCTRLLEFT, - _is_keyAPPLEFT, _is_keyALT, _is_keySPACE, _is_keyALTGR, _is_keyAPPRIGHT, _is_keyMENU, _is_keyCTRLRIGHT, - _is_keyARROWLEFT, _is_keyARROWDOWN, _is_keyARROWRIGHT, _is_keyPAD0, _is_keyPAD1, _is_keyPAD2, _is_keyPAD3, - _is_keyPAD4, _is_keyPAD5, _is_keyPAD6, _is_keyPAD7, _is_keyPAD8, _is_keyPAD9, _is_keyPADADD, _is_keyPADSUB, - _is_keyPADMUL, _is_keyPADDIV; - - //@} - //--------------------------- - // - //! \name Plugins - //@{ - //--------------------------- - -#ifdef cimgdisplay_plugin -#include cimgdisplay_plugin -#endif -#ifdef cimgdisplay_plugin1 -#include cimgdisplay_plugin1 -#endif -#ifdef cimgdisplay_plugin2 -#include cimgdisplay_plugin2 -#endif -#ifdef cimgdisplay_plugin3 -#include cimgdisplay_plugin3 -#endif -#ifdef cimgdisplay_plugin4 -#include cimgdisplay_plugin4 -#endif -#ifdef cimgdisplay_plugin5 -#include cimgdisplay_plugin5 -#endif -#ifdef cimgdisplay_plugin6 -#include cimgdisplay_plugin6 -#endif -#ifdef cimgdisplay_plugin7 -#include cimgdisplay_plugin7 -#endif -#ifdef cimgdisplay_plugin8 -#include cimgdisplay_plugin8 -#endif - - //@} - //-------------------------------------------------------- - // - //! \name Constructors / Destructor / Instance Management - //@{ - //-------------------------------------------------------- - - //! Destructor. - /** - \note If the associated window is visible on the screen, it is closed by the call to the destructor. - **/ - ~CImgDisplay() { - assign(); - delete[] _keys; - delete[] _released_keys; - } - - //! Construct an empty display. - /** - \note Constructing an empty CImgDisplay instance does not make a window appearing on the screen, until - display of valid data is performed. - \par Example - \code - CImgDisplay disp; // Does actually nothing - ... - disp.display(img); // Construct new window and display image in it - \endcode - **/ - CImgDisplay(): - _width(0),_height(0),_normalization(0), - _min(0),_max(0), - _is_fullscreen(false), - _title(0), - _window_width(0),_window_height(0),_button(0), - _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), - _window_x(cimg::type::min()),_window_y(cimg::type::min()), - _mouse_x(-1),_mouse_y(-1),_wheel(0), - _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { - assign(); - } - - //! Construct a display with specified dimensions. - /** \param width Window width. - \param height Window height. - \param title Window title. - \param normalization Normalization type - (0=none, 1=always, 2=once, 3=pixel type-dependent, see normalization()). - \param is_fullscreen Tells if fullscreen mode is enabled. - \param is_closed Tells if associated window is initially visible or not. - \note A black background is initially displayed on the associated window. - **/ - CImgDisplay(const unsigned int width, const unsigned int height, - const char *const title=0, const unsigned int normalization=3, - const bool is_fullscreen=false, const bool is_closed=false): - _width(0),_height(0),_normalization(0), - _min(0),_max(0), - _is_fullscreen(false), - _title(0), - _window_width(0),_window_height(0),_button(0), - _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), - _window_x(cimg::type::min()),_window_y(cimg::type::min()), - _mouse_x(-1),_mouse_y(-1),_wheel(0), - _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { - assign(width,height,title,normalization,is_fullscreen,is_closed); - } - - //! Construct a display from an image. - /** \param img Image used as a model to create the window. - \param title Window title. - \param normalization Normalization type - (0=none, 1=always, 2=once, 3=pixel type-dependent, see normalization()). - \param is_fullscreen Tells if fullscreen mode is enabled. - \param is_closed Tells if associated window is initially visible or not. - \note The pixels of the input image are initially displayed on the associated window. - **/ - template - explicit CImgDisplay(const CImg& img, - const char *const title=0, const unsigned int normalization=3, - const bool is_fullscreen=false, const bool is_closed=false): - _width(0),_height(0),_normalization(0), - _min(0),_max(0), - _is_fullscreen(false), - _title(0), - _window_width(0),_window_height(0),_button(0), - _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), - _window_x(cimg::type::min()),_window_y(cimg::type::min()), - _mouse_x(-1),_mouse_y(-1),_wheel(0), - _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { - assign(img,title,normalization,is_fullscreen,is_closed); - } - - //! Construct a display from an image list. - /** \param list The images list to display. - \param title Window title. - \param normalization Normalization type - (0=none, 1=always, 2=once, 3=pixel type-dependent, see normalization()). - \param is_fullscreen Tells if fullscreen mode is enabled. - \param is_closed Tells if associated window is initially visible or not. - \note All images of the list, appended along the X-axis, are initially displayed on the associated window. - **/ - template - explicit CImgDisplay(const CImgList& list, - const char *const title=0, const unsigned int normalization=3, - const bool is_fullscreen=false, const bool is_closed=false): - _width(0),_height(0),_normalization(0), - _min(0),_max(0), - _is_fullscreen(false), - _title(0), - _window_width(0),_window_height(0),_button(0), - _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), - _window_x(cimg::type::min()),_window_y(cimg::type::min()), - _mouse_x(-1),_mouse_y(-1),_wheel(0), - _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { - assign(list,title,normalization,is_fullscreen,is_closed); - } - - //! Construct a display as a copy of an existing one. - /** - \param disp Display instance to copy. - \note The pixel buffer of the input window is initially displayed on the associated window. - **/ - CImgDisplay(const CImgDisplay& disp): - _width(0),_height(0),_normalization(0), - _min(0),_max(0), - _is_fullscreen(false), - _title(0), - _window_width(0),_window_height(0),_button(0), - _keys(new unsigned int[128]),_released_keys(new unsigned int[128]), - _window_x(cimg::type::min()),_window_y(cimg::type::min()), - _mouse_x(-1),_mouse_y(-1),_wheel(0), - _is_closed(true),_is_resized(false),_is_moved(false),_is_event(false) { - assign(disp); - } - - //! Take a screenshot. - /** - \param[out] img Output screenshot. Can be empty on input - **/ - template - static void screenshot(CImg& img) { - return screenshot(0,0,cimg::type::max(),cimg::type::max(),img); - } - -#if cimg_display==0 - - static void _no_display_exception() { - throw CImgDisplayException("CImgDisplay(): No display available."); - } - - //! Destructor - Empty constructor \inplace. - /** - \note Replace the current instance by an empty display. - **/ - CImgDisplay& assign() { - return flush(); - } - - //! Construct a display with specified dimensions \inplace. - /** - **/ - CImgDisplay& assign(const unsigned int width, const unsigned int height, - const char *const title=0, const unsigned int normalization=3, - const bool is_fullscreen=false, const bool is_closed=false) { - cimg::unused(width,height,title,normalization,is_fullscreen,is_closed); - _no_display_exception(); - return assign(); - } - - //! Construct a display from an image \inplace. - /** - **/ - template - CImgDisplay& assign(const CImg& img, - const char *const title=0, const unsigned int normalization=3, - const bool is_fullscreen=false, const bool is_closed=false) { - _no_display_exception(); - return assign(img._width,img._height,title,normalization,is_fullscreen,is_closed); - } - - //! Construct a display from an image list \inplace. - /** - **/ - template - CImgDisplay& assign(const CImgList& list, - const char *const title=0, const unsigned int normalization=3, - const bool is_fullscreen=false, const bool is_closed=false) { - _no_display_exception(); - return assign(list._width,list._width,title,normalization,is_fullscreen,is_closed); - } - - //! Construct a display as a copy of another one \inplace. - /** - **/ - CImgDisplay& assign(const CImgDisplay &disp) { - _no_display_exception(); - return assign(disp._width,disp._height); - } - -#endif - - //! Return a reference to an empty display. - /** - \note Can be useful for writing function prototypes where one of the argument (of type CImgDisplay&) - must have a default value. - \par Example - \code - void foo(CImgDisplay& disp=CImgDisplay::empty()); - \endcode - **/ - static CImgDisplay& empty() { - static CImgDisplay _empty; - return _empty.assign(); - } - - //! Return a reference to an empty display \const. - static const CImgDisplay& const_empty() { - static const CImgDisplay _empty; - return _empty; - } - -#define cimg_fitscreen(dx,dy,dz) CImgDisplay::_fitscreen(dx,dy,dz,-25,-85,false), \ - CImgDisplay::_fitscreen(dx,dy,dz,-25,-85,true) - static unsigned int _fitscreen(const unsigned int dx, const unsigned int dy, const unsigned int dz, - const int dmin, const int dmax, const bool return_y) { - const int - u = CImgDisplay::screen_width(), - v = CImgDisplay::screen_height(); - const float - mw = dmin<0?cimg::round(u*-dmin/100.f):(float)dmin, - mh = dmin<0?cimg::round(v*-dmin/100.f):(float)dmin, - Mw = dmax<0?cimg::round(u*-dmax/100.f):(float)dmax, - Mh = dmax<0?cimg::round(v*-dmax/100.f):(float)dmax; - float - w = (float)std::max(1U,dx), - h = (float)std::max(1U,dy); - if (dz>1) { w+=dz; h+=dz; } - if (wMw) { h = h*Mw/w; w = Mw; } - if (h>Mh) { w = w*Mh/h; h = Mh; } - if (wdisp = img is equivalent to disp.display(img). - **/ - template - CImgDisplay& operator=(const CImg& img) { - return display(img); - } - - //! Display list of images on associated window. - /** - \note disp = list is equivalent to disp.display(list). - **/ - template - CImgDisplay& operator=(const CImgList& list) { - return display(list); - } - - //! Construct a display as a copy of another one \inplace. - /** - \note Equivalent to assign(const CImgDisplay&). - **/ - CImgDisplay& operator=(const CImgDisplay& disp) { - return assign(disp); - } - - //! Return \c false if display is empty, \c true otherwise. - /** - \note if (disp) { ... } is equivalent to if (!disp.is_empty()) { ... }. - **/ - operator bool() const { - return !is_empty(); - } - - //@} - //------------------------------------------ - // - //! \name Instance Checking - //@{ - //------------------------------------------ - - //! Return \c true if display is empty, \c false otherwise. - /** - **/ - bool is_empty() const { - return !(_width && _height); - } - - //! Return \c true if display is closed (i.e. not visible on the screen), \c false otherwise. - /** - \note - - When a user physically closes the associated window, the display is set to closed. - - A closed display is not destroyed. Its associated window can be show again on the screen using show(). - **/ - bool is_closed() const { - return _is_closed; - } - - //! Return \c true if display is visible (i.e. not closed by the user), \c false otherwise. - bool is_visible() const { - return !is_closed(); - } - - //! Return \c true if associated window has been resized on the screen, \c false otherwise. - /** - **/ - bool is_resized() const { - return _is_resized; - } - - //! Return \c true if associated window has been moved on the screen, \c false otherwise. - /** - **/ - bool is_moved() const { - return _is_moved; - } - - //! Return \c true if any event has occurred on the associated window, \c false otherwise. - /** - **/ - bool is_event() const { - return _is_event; - } - - //! Return \c true if current display is in fullscreen mode, \c false otherwise. - /** - **/ - bool is_fullscreen() const { - return _is_fullscreen; - } - - //! Return \c true if any key is being pressed on the associated window, \c false otherwise. - /** - \note The methods below do the same only for specific keys. - **/ - bool is_key() const { - return _is_keyESC || _is_keyF1 || _is_keyF2 || _is_keyF3 || - _is_keyF4 || _is_keyF5 || _is_keyF6 || _is_keyF7 || - _is_keyF8 || _is_keyF9 || _is_keyF10 || _is_keyF11 || - _is_keyF12 || _is_keyPAUSE || _is_key1 || _is_key2 || - _is_key3 || _is_key4 || _is_key5 || _is_key6 || - _is_key7 || _is_key8 || _is_key9 || _is_key0 || - _is_keyBACKSPACE || _is_keyINSERT || _is_keyHOME || - _is_keyPAGEUP || _is_keyTAB || _is_keyQ || _is_keyW || - _is_keyE || _is_keyR || _is_keyT || _is_keyY || - _is_keyU || _is_keyI || _is_keyO || _is_keyP || - _is_keyDELETE || _is_keyEND || _is_keyPAGEDOWN || - _is_keyCAPSLOCK || _is_keyA || _is_keyS || _is_keyD || - _is_keyF || _is_keyG || _is_keyH || _is_keyJ || - _is_keyK || _is_keyL || _is_keyENTER || - _is_keySHIFTLEFT || _is_keyZ || _is_keyX || _is_keyC || - _is_keyV || _is_keyB || _is_keyN || _is_keyM || - _is_keySHIFTRIGHT || _is_keyARROWUP || _is_keyCTRLLEFT || - _is_keyAPPLEFT || _is_keyALT || _is_keySPACE || _is_keyALTGR || - _is_keyAPPRIGHT || _is_keyMENU || _is_keyCTRLRIGHT || - _is_keyARROWLEFT || _is_keyARROWDOWN || _is_keyARROWRIGHT || - _is_keyPAD0 || _is_keyPAD1 || _is_keyPAD2 || - _is_keyPAD3 || _is_keyPAD4 || _is_keyPAD5 || - _is_keyPAD6 || _is_keyPAD7 || _is_keyPAD8 || - _is_keyPAD9 || _is_keyPADADD || _is_keyPADSUB || - _is_keyPADMUL || _is_keyPADDIV; - } - - //! Return \c true if key specified by given keycode is being pressed on the associated window, \c false otherwise. - /** - \param keycode Keycode to test. - \note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure - your code stay portable (see cimg::keyESC). - \par Example - \code - CImgDisplay disp(400,400); - while (!disp.is_closed()) { - if (disp.key(cimg::keyTAB)) { ... } // Equivalent to 'if (disp.is_keyTAB())' - disp.wait(); - } - \endcode - **/ - bool is_key(const unsigned int keycode) const { -#define _cimg_iskey_test(k) if (keycode==cimg::key##k) return _is_key##k; - _cimg_iskey_test(ESC); _cimg_iskey_test(F1); _cimg_iskey_test(F2); _cimg_iskey_test(F3); - _cimg_iskey_test(F4); _cimg_iskey_test(F5); _cimg_iskey_test(F6); _cimg_iskey_test(F7); - _cimg_iskey_test(F8); _cimg_iskey_test(F9); _cimg_iskey_test(F10); _cimg_iskey_test(F11); - _cimg_iskey_test(F12); _cimg_iskey_test(PAUSE); _cimg_iskey_test(1); _cimg_iskey_test(2); - _cimg_iskey_test(3); _cimg_iskey_test(4); _cimg_iskey_test(5); _cimg_iskey_test(6); - _cimg_iskey_test(7); _cimg_iskey_test(8); _cimg_iskey_test(9); _cimg_iskey_test(0); - _cimg_iskey_test(BACKSPACE); _cimg_iskey_test(INSERT); _cimg_iskey_test(HOME); - _cimg_iskey_test(PAGEUP); _cimg_iskey_test(TAB); _cimg_iskey_test(Q); _cimg_iskey_test(W); - _cimg_iskey_test(E); _cimg_iskey_test(R); _cimg_iskey_test(T); _cimg_iskey_test(Y); - _cimg_iskey_test(U); _cimg_iskey_test(I); _cimg_iskey_test(O); _cimg_iskey_test(P); - _cimg_iskey_test(DELETE); _cimg_iskey_test(END); _cimg_iskey_test(PAGEDOWN); - _cimg_iskey_test(CAPSLOCK); _cimg_iskey_test(A); _cimg_iskey_test(S); _cimg_iskey_test(D); - _cimg_iskey_test(F); _cimg_iskey_test(G); _cimg_iskey_test(H); _cimg_iskey_test(J); - _cimg_iskey_test(K); _cimg_iskey_test(L); _cimg_iskey_test(ENTER); - _cimg_iskey_test(SHIFTLEFT); _cimg_iskey_test(Z); _cimg_iskey_test(X); _cimg_iskey_test(C); - _cimg_iskey_test(V); _cimg_iskey_test(B); _cimg_iskey_test(N); _cimg_iskey_test(M); - _cimg_iskey_test(SHIFTRIGHT); _cimg_iskey_test(ARROWUP); _cimg_iskey_test(CTRLLEFT); - _cimg_iskey_test(APPLEFT); _cimg_iskey_test(ALT); _cimg_iskey_test(SPACE); _cimg_iskey_test(ALTGR); - _cimg_iskey_test(APPRIGHT); _cimg_iskey_test(MENU); _cimg_iskey_test(CTRLRIGHT); - _cimg_iskey_test(ARROWLEFT); _cimg_iskey_test(ARROWDOWN); _cimg_iskey_test(ARROWRIGHT); - _cimg_iskey_test(PAD0); _cimg_iskey_test(PAD1); _cimg_iskey_test(PAD2); - _cimg_iskey_test(PAD3); _cimg_iskey_test(PAD4); _cimg_iskey_test(PAD5); - _cimg_iskey_test(PAD6); _cimg_iskey_test(PAD7); _cimg_iskey_test(PAD8); - _cimg_iskey_test(PAD9); _cimg_iskey_test(PADADD); _cimg_iskey_test(PADSUB); - _cimg_iskey_test(PADMUL); _cimg_iskey_test(PADDIV); - return false; - } - - //! Return \c true if key specified by given keycode is being pressed on the associated window, \c false otherwise. - /** - \param keycode C-string containing the keycode label of the key to test. - \note Use it when the key you want to test can be dynamically set by the user. - \par Example - \code - CImgDisplay disp(400,400); - const char *const keycode = "TAB"; - while (!disp.is_closed()) { - if (disp.is_key(keycode)) { ... } // Equivalent to 'if (disp.is_keyTAB())' - disp.wait(); - } - \endcode - **/ - bool& is_key(const char *const keycode) { - static bool f = false; - f = false; -#define _cimg_iskey_test2(k) if (!cimg::strcasecmp(keycode,#k)) return _is_key##k; - _cimg_iskey_test2(ESC); _cimg_iskey_test2(F1); _cimg_iskey_test2(F2); _cimg_iskey_test2(F3); - _cimg_iskey_test2(F4); _cimg_iskey_test2(F5); _cimg_iskey_test2(F6); _cimg_iskey_test2(F7); - _cimg_iskey_test2(F8); _cimg_iskey_test2(F9); _cimg_iskey_test2(F10); _cimg_iskey_test2(F11); - _cimg_iskey_test2(F12); _cimg_iskey_test2(PAUSE); _cimg_iskey_test2(1); _cimg_iskey_test2(2); - _cimg_iskey_test2(3); _cimg_iskey_test2(4); _cimg_iskey_test2(5); _cimg_iskey_test2(6); - _cimg_iskey_test2(7); _cimg_iskey_test2(8); _cimg_iskey_test2(9); _cimg_iskey_test2(0); - _cimg_iskey_test2(BACKSPACE); _cimg_iskey_test2(INSERT); _cimg_iskey_test2(HOME); - _cimg_iskey_test2(PAGEUP); _cimg_iskey_test2(TAB); _cimg_iskey_test2(Q); _cimg_iskey_test2(W); - _cimg_iskey_test2(E); _cimg_iskey_test2(R); _cimg_iskey_test2(T); _cimg_iskey_test2(Y); - _cimg_iskey_test2(U); _cimg_iskey_test2(I); _cimg_iskey_test2(O); _cimg_iskey_test2(P); - _cimg_iskey_test2(DELETE); _cimg_iskey_test2(END); _cimg_iskey_test2(PAGEDOWN); - _cimg_iskey_test2(CAPSLOCK); _cimg_iskey_test2(A); _cimg_iskey_test2(S); _cimg_iskey_test2(D); - _cimg_iskey_test2(F); _cimg_iskey_test2(G); _cimg_iskey_test2(H); _cimg_iskey_test2(J); - _cimg_iskey_test2(K); _cimg_iskey_test2(L); _cimg_iskey_test2(ENTER); - _cimg_iskey_test2(SHIFTLEFT); _cimg_iskey_test2(Z); _cimg_iskey_test2(X); _cimg_iskey_test2(C); - _cimg_iskey_test2(V); _cimg_iskey_test2(B); _cimg_iskey_test2(N); _cimg_iskey_test2(M); - _cimg_iskey_test2(SHIFTRIGHT); _cimg_iskey_test2(ARROWUP); _cimg_iskey_test2(CTRLLEFT); - _cimg_iskey_test2(APPLEFT); _cimg_iskey_test2(ALT); _cimg_iskey_test2(SPACE); _cimg_iskey_test2(ALTGR); - _cimg_iskey_test2(APPRIGHT); _cimg_iskey_test2(MENU); _cimg_iskey_test2(CTRLRIGHT); - _cimg_iskey_test2(ARROWLEFT); _cimg_iskey_test2(ARROWDOWN); _cimg_iskey_test2(ARROWRIGHT); - _cimg_iskey_test2(PAD0); _cimg_iskey_test2(PAD1); _cimg_iskey_test2(PAD2); - _cimg_iskey_test2(PAD3); _cimg_iskey_test2(PAD4); _cimg_iskey_test2(PAD5); - _cimg_iskey_test2(PAD6); _cimg_iskey_test2(PAD7); _cimg_iskey_test2(PAD8); - _cimg_iskey_test2(PAD9); _cimg_iskey_test2(PADADD); _cimg_iskey_test2(PADSUB); - _cimg_iskey_test2(PADMUL); _cimg_iskey_test2(PADDIV); - return f; - } - - //! Return \c true if specified key sequence has been typed on the associated window, \c false otherwise. - /** - \param keycodes_sequence Buffer of keycodes to test. - \param length Number of keys in the \c keycodes_sequence buffer. - \param remove_sequence Tells if the key sequence must be removed from the key history, if found. - \note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure - your code stay portable (see cimg::keyESC). - \par Example - \code - CImgDisplay disp(400,400); - const unsigned int key_seq[] = { cimg::keyCTRLLEFT, cimg::keyD }; - while (!disp.is_closed()) { - if (disp.is_key_sequence(key_seq,2)) { ... } // Test for the 'CTRL+D' keyboard event - disp.wait(); - } - \endcode - **/ - bool is_key_sequence(const unsigned int *const keycodes_sequence, const unsigned int length, - const bool remove_sequence=false) { - if (keycodes_sequence && length) { - const unsigned int - *const ps_end = keycodes_sequence + length - 1, - *const pk_end = (unsigned int*)_keys + 1 + 128 - length, - k = *ps_end; - for (unsigned int *pk = (unsigned int*)_keys; pk[0,255]. - If the range of values of the data to display is different, a normalization may be required for displaying - the data in a correct way. The normalization type can be one of: - - \c 0: Value normalization is disabled. It is then assumed that all input data to be displayed by the - CImgDisplay instance have values in range [0,255]. - - \c 1: Value normalization is always performed (this is the default behavior). - Before displaying an input image, its values will be (virtually) stretched - in range [0,255], so that the contrast of the displayed pixels will be maximum. - Use this mode for images whose minimum and maximum values are not prescribed to known values - (e.g. float-valued images). - Note that when normalized versions of images are computed for display purposes, the actual values of these - images are not modified. - - \c 2: Value normalization is performed once (on the first image display), then the same normalization - coefficients are kept for next displayed frames. - - \c 3: Value normalization depends on the pixel type of the data to display. For integer pixel types, - the normalization is done regarding the minimum/maximum values of the type (no normalization occurs then - for unsigned char). - For float-valued pixel types, the normalization is done regarding the minimum/maximum value of the image - data instead. - **/ - unsigned int normalization() const { - return _normalization; - } - - //! Return title of the associated window as a C-string. - /** - \note Window title may be not visible, depending on the used window manager or if the current display is - in fullscreen mode. - **/ - const char *title() const { - return _title?_title:""; - } - - //! Return width of the associated window. - /** - \note The width of the display (i.e. the width of the pixel data buffer associated to the CImgDisplay instance) - may be different from the actual width of the associated window. - **/ - int window_width() const { - return (int)_window_width; - } - - //! Return height of the associated window. - /** - \note The height of the display (i.e. the height of the pixel data buffer associated to the CImgDisplay instance) - may be different from the actual height of the associated window. - **/ - int window_height() const { - return (int)_window_height; - } - - //! Return X-coordinate of the associated window. - /** - \note The returned coordinate corresponds to the location of the upper-left corner of the associated window. - **/ - int window_x() const { - return _window_x; - } - - //! Return Y-coordinate of the associated window. - /** - \note The returned coordinate corresponds to the location of the upper-left corner of the associated window. - **/ - int window_y() const { - return _window_y; - } - - //! Return X-coordinate of the mouse pointer. - /** - \note - - If the mouse pointer is outside window area, \c -1 is returned. - - Otherwise, the returned value is in the range [0,width()-1]. - **/ - int mouse_x() const { - return _mouse_x; - } - - //! Return Y-coordinate of the mouse pointer. - /** - \note - - If the mouse pointer is outside window area, \c -1 is returned. - - Otherwise, the returned value is in the range [0,height()-1]. - **/ - int mouse_y() const { - return _mouse_y; - } - - //! Return current state of the mouse buttons. - /** - \note Three mouse buttons can be managed. If one button is pressed, its corresponding bit in the returned - value is set: - - bit \c 0 (value \c 0x1): State of the left mouse button. - - bit \c 1 (value \c 0x2): State of the right mouse button. - - bit \c 2 (value \c 0x4): State of the middle mouse button. - - Several bits can be activated if more than one button are pressed at the same time. - \par Example - \code - CImgDisplay disp(400,400); - while (!disp.is_closed()) { - if (disp.button()&1) { // Left button clicked - ... - } - if (disp.button()&2) { // Right button clicked - ... - } - if (disp.button()&4) { // Middle button clicked - ... - } - disp.wait(); - } - \endcode - **/ - unsigned int button() const { - return _button; - } - - //! Return current state of the mouse wheel. - /** - \note - - The returned value can be positive or negative depending on whether the mouse wheel has been scrolled - forward or backward. - - Scrolling the wheel forward add \c 1 to the wheel value. - - Scrolling the wheel backward subtract \c 1 to the wheel value. - - The returned value cumulates the number of forward of backward scrolls since the creation of the display, - or since the last reset of the wheel value (using set_wheel()). It is strongly recommended to quickly reset - the wheel counter when an action has been performed regarding the current wheel value. - Otherwise, the returned wheel value may be for instance \c 0 despite the fact that many scrolls have been done - (as many in forward as in backward directions). - \par Example - \code - CImgDisplay disp(400,400); - while (!disp.is_closed()) { - if (disp.wheel()) { - int counter = disp.wheel(); // Read the state of the mouse wheel - ... // Do what you want with 'counter' - disp.set_wheel(); // Reset the wheel value to 0 - } - disp.wait(); - } - \endcode - **/ - int wheel() const { - return _wheel; - } - - //! Return one entry from the pressed keys history. - /** - \param pos Index to read from the pressed keys history (index \c 0 corresponds to latest entry). - \return Keycode of a pressed key or \c 0 for a released key. - \note - - Each CImgDisplay stores a history of the pressed keys in a buffer of size \c 128. When a new key is pressed, - its keycode is stored in the pressed keys history. When a key is released, \c 0 is put instead. - This means that up to the 64 last pressed keys may be read from the pressed keys history. - When a new value is stored, the pressed keys history is shifted so that the latest entry is always - stored at position \c 0. - - Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure - your code stay portable (see cimg::keyESC). - **/ - unsigned int& key(const unsigned int pos=0) const { - static unsigned int key0; - return pos<128?_keys[pos]:(key0 = 0); - - } - - //! Return one entry from the released keys history. - /** - \param pos Index to read from the released keys history (index \c 0 corresponds to latest entry). - \return Keycode of a released key or \c 0 for a pressed key. - \note - - Each CImgDisplay stores a history of the released keys in a buffer of size \c 128. When a new key is released, - its keycode is stored in the pressed keys history. When a key is pressed, \c 0 is put instead. - This means that up to the 64 last released keys may be read from the released keys history. - When a new value is stored, the released keys history is shifted so that the latest entry is always - stored at position \c 0. - - Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure - your code stay portable (see cimg::keyESC). - **/ - unsigned int& released_key(const unsigned int pos=0) const { - static unsigned int key0; - return pos<128?_released_keys[pos]:(key0 = 0); - } - - //! Return keycode corresponding to the specified string. - /** - \note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure - your code stay portable (see cimg::keyESC). - \par Example - \code - const unsigned int keyTAB = CImgDisplay::keycode("TAB"); // Return cimg::keyTAB - \endcode - **/ - static unsigned int keycode(const char *const keycode) { -#define _cimg_keycode(k) if (!cimg::strcasecmp(keycode,#k)) return cimg::key##k; - _cimg_keycode(ESC); _cimg_keycode(F1); _cimg_keycode(F2); _cimg_keycode(F3); - _cimg_keycode(F4); _cimg_keycode(F5); _cimg_keycode(F6); _cimg_keycode(F7); - _cimg_keycode(F8); _cimg_keycode(F9); _cimg_keycode(F10); _cimg_keycode(F11); - _cimg_keycode(F12); _cimg_keycode(PAUSE); _cimg_keycode(1); _cimg_keycode(2); - _cimg_keycode(3); _cimg_keycode(4); _cimg_keycode(5); _cimg_keycode(6); - _cimg_keycode(7); _cimg_keycode(8); _cimg_keycode(9); _cimg_keycode(0); - _cimg_keycode(BACKSPACE); _cimg_keycode(INSERT); _cimg_keycode(HOME); - _cimg_keycode(PAGEUP); _cimg_keycode(TAB); _cimg_keycode(Q); _cimg_keycode(W); - _cimg_keycode(E); _cimg_keycode(R); _cimg_keycode(T); _cimg_keycode(Y); - _cimg_keycode(U); _cimg_keycode(I); _cimg_keycode(O); _cimg_keycode(P); - _cimg_keycode(DELETE); _cimg_keycode(END); _cimg_keycode(PAGEDOWN); - _cimg_keycode(CAPSLOCK); _cimg_keycode(A); _cimg_keycode(S); _cimg_keycode(D); - _cimg_keycode(F); _cimg_keycode(G); _cimg_keycode(H); _cimg_keycode(J); - _cimg_keycode(K); _cimg_keycode(L); _cimg_keycode(ENTER); - _cimg_keycode(SHIFTLEFT); _cimg_keycode(Z); _cimg_keycode(X); _cimg_keycode(C); - _cimg_keycode(V); _cimg_keycode(B); _cimg_keycode(N); _cimg_keycode(M); - _cimg_keycode(SHIFTRIGHT); _cimg_keycode(ARROWUP); _cimg_keycode(CTRLLEFT); - _cimg_keycode(APPLEFT); _cimg_keycode(ALT); _cimg_keycode(SPACE); _cimg_keycode(ALTGR); - _cimg_keycode(APPRIGHT); _cimg_keycode(MENU); _cimg_keycode(CTRLRIGHT); - _cimg_keycode(ARROWLEFT); _cimg_keycode(ARROWDOWN); _cimg_keycode(ARROWRIGHT); - _cimg_keycode(PAD0); _cimg_keycode(PAD1); _cimg_keycode(PAD2); - _cimg_keycode(PAD3); _cimg_keycode(PAD4); _cimg_keycode(PAD5); - _cimg_keycode(PAD6); _cimg_keycode(PAD7); _cimg_keycode(PAD8); - _cimg_keycode(PAD9); _cimg_keycode(PADADD); _cimg_keycode(PADSUB); - _cimg_keycode(PADMUL); _cimg_keycode(PADDIV); - return 0; - } - - //! Return the current refresh rate, in frames per second. - /** - \note Returns a significant value when the current instance is used to display successive frames. - It measures the delay between successive calls to frames_per_second(). - **/ - float frames_per_second() { - if (!_fps_timer) _fps_timer = cimg::time(); - const float delta = (float)((cimg::time() - _fps_timer)/1000.f); - ++_fps_frames; - if (delta>=1) { - _fps_fps = _fps_frames/delta; - _fps_frames = 0; - _fps_timer = cimg::time(); - } - return _fps_fps; - } - - // Move current display window so that its content stays inside the current screen. - CImgDisplay& move_inside_screen() { - if (is_empty()) return *this; - const int - x0 = window_x(), - y0 = window_y(), - x1 = x0 + window_width() - 1, - y1 = y0 + window_height() - 1, - sw = CImgDisplay::screen_width(), - sh = CImgDisplay::screen_height(); - if (x0<0 || y0<0 || x1>=sw || y1>=sh) - move(std::max(0,std::min(x0,sw - x1 + x0)), - std::max(0,std::min(y0,sh - y1 + y0))); - return *this; - } - - //@} - //--------------------------------------- - // - //! \name Window Manipulation - //@{ - //--------------------------------------- - -#if cimg_display==0 - - //! Display image on associated window. - /** - \param img Input image to display. - \note This method returns immediately. - **/ - template - CImgDisplay& display(const CImg& img) { - return assign(img); - } - -#endif - - //! Display list of images on associated window. - /** - \param list List of images to display. - \param axis Axis used to append the images along, for the visualization (can be \c x, \c y, \c z or \c c). - \param align Relative position of aligned images when displaying lists with images of different sizes - (\c 0 for upper-left, \c 0.5 for centering and \c 1 for lower-right). - \note This method returns immediately. - **/ - template - CImgDisplay& display(const CImgList& list, const char axis='x', const float align=0) { - if (list._width==1) { - const CImg& img = list[0]; - if (img._depth==1 && (img._spectrum==1 || img._spectrum>=3) && _normalization!=1) return display(img); - } - CImgList::ucharT> visu(list._width); - unsigned int dims = 0; - cimglist_for(list,l) { - const CImg& img = list._data[l]; - img._get_select(*this,_normalization,(img._width - 1)/2,(img._height - 1)/2, - (img._depth - 1)/2).move_to(visu[l]); - dims = std::max(dims,visu[l]._spectrum); - } - cimglist_for(list,l) if (visu[l]._spectrumimg.width() become equal, as well as height() and - img.height(). - - The associated window is also resized to specified dimensions. - **/ - template - CImgDisplay& resize(const CImg& img, const bool force_redraw=true) { - return resize(img._width,img._height,force_redraw); - } - - //! Resize display to the size of another CImgDisplay instance. - /** - \param disp Input display to take size from. - \param force_redraw Tells if the previous window content must be resized and updated as well. - \note - - Calling this method ensures that width() and disp.width() become equal, as well as height() and - disp.height(). - - The associated window is also resized to specified dimensions. - **/ - CImgDisplay& resize(const CImgDisplay& disp, const bool force_redraw=true) { - return resize(disp.width(),disp.height(),force_redraw); - } - - // [internal] Render pixel buffer with size (wd,hd) from source buffer of size (ws,hs). - template - static void _render_resize(const T *ptrs, const unsigned int ws, const unsigned int hs, - t *ptrd, const unsigned int wd, const unsigned int hd) { - typedef typename cimg::last::type ulongT; - const ulongT one = (ulongT)1; - CImg off_x(wd), off_y(hd + 1); - if (wd==ws) off_x.fill(1); - else { - ulongT *poff_x = off_x._data, curr = 0; - for (unsigned int x = 0; xstd::printf(). - \warning As the first argument is a format string, it is highly recommended to write - \code - disp.set_title("%s",window_title); - \endcode - instead of - \code - disp.set_title(window_title); - \endcode - if \c window_title can be arbitrary, to prevent nasty memory access. - **/ - CImgDisplay& set_title(const char *const format, ...) { - return assign(0,0,format); - } - -#endif - - //! Enable or disable fullscreen mode. - /** - \param is_fullscreen Tells is the fullscreen mode must be activated or not. - \param force_redraw Tells if the previous window content must be displayed as well. - \note - - When the fullscreen mode is enabled, the associated window fills the entire screen but the size of the - current display is not modified. - - The screen resolution may be switched to fit the associated window size and ensure it appears the largest - as possible. - For X-Window (X11) users, the configuration flag \c cimg_use_xrandr has to be set to allow the screen - resolution change (requires the X11 extensions to be enabled). - **/ - CImgDisplay& set_fullscreen(const bool is_fullscreen, const bool force_redraw=true) { - if (is_empty() || _is_fullscreen==is_fullscreen) return *this; - return toggle_fullscreen(force_redraw); - } - -#if cimg_display==0 - - //! Toggle fullscreen mode. - /** - \param force_redraw Tells if the previous window content must be displayed as well. - \note Enable fullscreen mode if it was not enabled, and disable it otherwise. - **/ - CImgDisplay& toggle_fullscreen(const bool force_redraw=true) { - return assign(_width,_height,0,3,force_redraw); - } - - //! Show mouse pointer. - /** - \note Depending on the window manager behavior, this method may not succeed - (no exceptions are thrown nevertheless). - **/ - CImgDisplay& show_mouse() { - return assign(); - } - - //! Hide mouse pointer. - /** - \note Depending on the window manager behavior, this method may not succeed - (no exceptions are thrown nevertheless). - **/ - CImgDisplay& hide_mouse() { - return assign(); - } - - //! Move mouse pointer to a specified location. - /** - \note Depending on the window manager behavior, this method may not succeed - (no exceptions are thrown nevertheless). - **/ - CImgDisplay& set_mouse(const int pos_x, const int pos_y) { - return assign(pos_x,pos_y); - } - -#endif - - //! Simulate a mouse button release event. - /** - \note All mouse buttons are considered released at the same time. - **/ - CImgDisplay& set_button() { - _button = 0; - _is_event = true; -#if cimg_display==1 - pthread_cond_broadcast(&cimg::X11_attr().wait_event); -#elif cimg_display==2 - SetEvent(cimg::Win32_attr().wait_event); -#endif - return *this; - } - - //! Simulate a mouse button press or release event. - /** - \param button Buttons event code, where each button is associated to a single bit. - \param is_pressed Tells if the mouse button is considered as pressed or released. - **/ - CImgDisplay& set_button(const unsigned int button, const bool is_pressed=true) { - const unsigned int buttoncode = button==1U?1U:button==2U?2U:button==3U?4U:0U; - if (is_pressed) _button |= buttoncode; else _button &= ~buttoncode; - _is_event = buttoncode?true:false; - if (buttoncode) { -#if cimg_display==1 - pthread_cond_broadcast(&cimg::X11_attr().wait_event); -#elif cimg_display==2 - SetEvent(cimg::Win32_attr().wait_event); -#endif - } - return *this; - } - - //! Flush all mouse wheel events. - /** - \note Make wheel() to return \c 0, if called afterwards. - **/ - CImgDisplay& set_wheel() { - _wheel = 0; - _is_event = true; -#if cimg_display==1 - pthread_cond_broadcast(&cimg::X11_attr().wait_event); -#elif cimg_display==2 - SetEvent(cimg::Win32_attr().wait_event); -#endif - return *this; - } - - //! Simulate a wheel event. - /** - \param amplitude Amplitude of the wheel scrolling to simulate. - \note Make wheel() to return \c amplitude, if called afterwards. - **/ - CImgDisplay& set_wheel(const int amplitude) { - _wheel+=amplitude; - _is_event = amplitude?true:false; - if (amplitude) { -#if cimg_display==1 - pthread_cond_broadcast(&cimg::X11_attr().wait_event); -#elif cimg_display==2 - SetEvent(cimg::Win32_attr().wait_event); -#endif - } - return *this; - } - - //! Flush all key events. - /** - \note Make key() to return \c 0, if called afterwards. - **/ - CImgDisplay& set_key() { - std::memset((void*)_keys,0,128*sizeof(unsigned int)); - std::memset((void*)_released_keys,0,128*sizeof(unsigned int)); - _is_keyESC = _is_keyF1 = _is_keyF2 = _is_keyF3 = _is_keyF4 = _is_keyF5 = _is_keyF6 = _is_keyF7 = _is_keyF8 = - _is_keyF9 = _is_keyF10 = _is_keyF11 = _is_keyF12 = _is_keyPAUSE = _is_key1 = _is_key2 = _is_key3 = _is_key4 = - _is_key5 = _is_key6 = _is_key7 = _is_key8 = _is_key9 = _is_key0 = _is_keyBACKSPACE = _is_keyINSERT = - _is_keyHOME = _is_keyPAGEUP = _is_keyTAB = _is_keyQ = _is_keyW = _is_keyE = _is_keyR = _is_keyT = _is_keyY = - _is_keyU = _is_keyI = _is_keyO = _is_keyP = _is_keyDELETE = _is_keyEND = _is_keyPAGEDOWN = _is_keyCAPSLOCK = - _is_keyA = _is_keyS = _is_keyD = _is_keyF = _is_keyG = _is_keyH = _is_keyJ = _is_keyK = _is_keyL = - _is_keyENTER = _is_keySHIFTLEFT = _is_keyZ = _is_keyX = _is_keyC = _is_keyV = _is_keyB = _is_keyN = - _is_keyM = _is_keySHIFTRIGHT = _is_keyARROWUP = _is_keyCTRLLEFT = _is_keyAPPLEFT = _is_keyALT = _is_keySPACE = - _is_keyALTGR = _is_keyAPPRIGHT = _is_keyMENU = _is_keyCTRLRIGHT = _is_keyARROWLEFT = _is_keyARROWDOWN = - _is_keyARROWRIGHT = _is_keyPAD0 = _is_keyPAD1 = _is_keyPAD2 = _is_keyPAD3 = _is_keyPAD4 = _is_keyPAD5 = - _is_keyPAD6 = _is_keyPAD7 = _is_keyPAD8 = _is_keyPAD9 = _is_keyPADADD = _is_keyPADSUB = _is_keyPADMUL = - _is_keyPADDIV = false; - _is_event = true; -#if cimg_display==1 - pthread_cond_broadcast(&cimg::X11_attr().wait_event); -#elif cimg_display==2 - SetEvent(cimg::Win32_attr().wait_event); -#endif - return *this; - } - - //! Simulate a keyboard press/release event. - /** - \param keycode Keycode of the associated key. - \param is_pressed Tells if the key is considered as pressed or released. - \note Keycode constants are defined in the cimg namespace and are architecture-dependent. Use them to ensure - your code stay portable (see cimg::keyESC). - **/ - CImgDisplay& set_key(const unsigned int keycode, const bool is_pressed=true) { -#define _cimg_set_key(k) if (keycode==cimg::key##k) _is_key##k = is_pressed; - _cimg_set_key(ESC); _cimg_set_key(F1); _cimg_set_key(F2); _cimg_set_key(F3); - _cimg_set_key(F4); _cimg_set_key(F5); _cimg_set_key(F6); _cimg_set_key(F7); - _cimg_set_key(F8); _cimg_set_key(F9); _cimg_set_key(F10); _cimg_set_key(F11); - _cimg_set_key(F12); _cimg_set_key(PAUSE); _cimg_set_key(1); _cimg_set_key(2); - _cimg_set_key(3); _cimg_set_key(4); _cimg_set_key(5); _cimg_set_key(6); - _cimg_set_key(7); _cimg_set_key(8); _cimg_set_key(9); _cimg_set_key(0); - _cimg_set_key(BACKSPACE); _cimg_set_key(INSERT); _cimg_set_key(HOME); - _cimg_set_key(PAGEUP); _cimg_set_key(TAB); _cimg_set_key(Q); _cimg_set_key(W); - _cimg_set_key(E); _cimg_set_key(R); _cimg_set_key(T); _cimg_set_key(Y); - _cimg_set_key(U); _cimg_set_key(I); _cimg_set_key(O); _cimg_set_key(P); - _cimg_set_key(DELETE); _cimg_set_key(END); _cimg_set_key(PAGEDOWN); - _cimg_set_key(CAPSLOCK); _cimg_set_key(A); _cimg_set_key(S); _cimg_set_key(D); - _cimg_set_key(F); _cimg_set_key(G); _cimg_set_key(H); _cimg_set_key(J); - _cimg_set_key(K); _cimg_set_key(L); _cimg_set_key(ENTER); - _cimg_set_key(SHIFTLEFT); _cimg_set_key(Z); _cimg_set_key(X); _cimg_set_key(C); - _cimg_set_key(V); _cimg_set_key(B); _cimg_set_key(N); _cimg_set_key(M); - _cimg_set_key(SHIFTRIGHT); _cimg_set_key(ARROWUP); _cimg_set_key(CTRLLEFT); - _cimg_set_key(APPLEFT); _cimg_set_key(ALT); _cimg_set_key(SPACE); _cimg_set_key(ALTGR); - _cimg_set_key(APPRIGHT); _cimg_set_key(MENU); _cimg_set_key(CTRLRIGHT); - _cimg_set_key(ARROWLEFT); _cimg_set_key(ARROWDOWN); _cimg_set_key(ARROWRIGHT); - _cimg_set_key(PAD0); _cimg_set_key(PAD1); _cimg_set_key(PAD2); - _cimg_set_key(PAD3); _cimg_set_key(PAD4); _cimg_set_key(PAD5); - _cimg_set_key(PAD6); _cimg_set_key(PAD7); _cimg_set_key(PAD8); - _cimg_set_key(PAD9); _cimg_set_key(PADADD); _cimg_set_key(PADSUB); - _cimg_set_key(PADMUL); _cimg_set_key(PADDIV); - if (is_pressed) { - if (*_keys) - std::memmove((void*)(_keys + 1),(void*)_keys,127*sizeof(unsigned int)); - *_keys = keycode; - if (*_released_keys) { - std::memmove((void*)(_released_keys + 1),(void*)_released_keys,127*sizeof(unsigned int)); - *_released_keys = 0; - } - } else { - if (*_keys) { - std::memmove((void*)(_keys + 1),(void*)_keys,127*sizeof(unsigned int)); - *_keys = 0; - } - if (*_released_keys) - std::memmove((void*)(_released_keys + 1),(void*)_released_keys,127*sizeof(unsigned int)); - *_released_keys = keycode; - } - _is_event = keycode?true:false; - if (keycode) { -#if cimg_display==1 - pthread_cond_broadcast(&cimg::X11_attr().wait_event); -#elif cimg_display==2 - SetEvent(cimg::Win32_attr().wait_event); -#endif - } - return *this; - } - - //! Flush all display events. - /** - \note Remove all passed events from the current display. - **/ - CImgDisplay& flush() { - set_key().set_button().set_wheel(); - _is_resized = _is_moved = _is_event = false; - _fps_timer = _fps_frames = _timer = 0; - _fps_fps = 0; - return *this; - } - - //! Wait for any user event occurring on the current display. - CImgDisplay& wait() { - wait(*this); - return *this; - } - - //! Wait for a given number of milliseconds since the last call to wait(). - /** - \param milliseconds Number of milliseconds to wait for. - \note Similar to cimg::wait(). - **/ - CImgDisplay& wait(const unsigned int milliseconds) { - cimg::wait(milliseconds,&_timer); - return *this; - } - - //! Wait for any event occurring on the display \c disp1. - static void wait(CImgDisplay& disp1) { - disp1._is_event = false; - while (!disp1._is_closed && !disp1._is_event) wait_all(); - } - - //! Wait for any event occurring either on the display \c disp1 or \c disp2. - static void wait(CImgDisplay& disp1, CImgDisplay& disp2) { - disp1._is_event = disp2._is_event = false; - while ((!disp1._is_closed || !disp2._is_closed) && - !disp1._is_event && !disp2._is_event) wait_all(); - } - - //! Wait for any event occurring either on the display \c disp1, \c disp2 or \c disp3. - static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3) { - disp1._is_event = disp2._is_event = disp3._is_event = false; - while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed) && - !disp1._is_event && !disp2._is_event && !disp3._is_event) wait_all(); - } - - //! Wait for any event occurring either on the display \c disp1, \c disp2, \c disp3 or \c disp4. - static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4) { - disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = false; - while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed) && - !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event) wait_all(); - } - - //! Wait for any event occurring either on the display \c disp1, \c disp2, \c disp3, \c disp4 or \c disp5. - static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, - CImgDisplay& disp5) { - disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = false; - while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed) && - !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event) - wait_all(); - } - - //! Wait for any event occurring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp6. - static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, - CImgDisplay& disp6) { - disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = - disp6._is_event = false; - while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed || - !disp6._is_closed) && - !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && - !disp6._is_event) wait_all(); - } - - //! Wait for any event occurring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp7. - static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, - CImgDisplay& disp6, CImgDisplay& disp7) { - disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = - disp6._is_event = disp7._is_event = false; - while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed || - !disp6._is_closed || !disp7._is_closed) && - !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && - !disp6._is_event && !disp7._is_event) wait_all(); - } - - //! Wait for any event occurring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp8. - static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, - CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8) { - disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = - disp6._is_event = disp7._is_event = disp8._is_event = false; - while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed || - !disp6._is_closed || !disp7._is_closed || !disp8._is_closed) && - !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && - !disp6._is_event && !disp7._is_event && !disp8._is_event) wait_all(); - } - - //! Wait for any event occurring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp9. - static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, - CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9) { - disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = - disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = false; - while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed || - !disp6._is_closed || !disp7._is_closed || !disp8._is_closed || !disp9._is_closed) && - !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && - !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event) wait_all(); - } - - //! Wait for any event occurring either on the display \c disp1, \c disp2, \c disp3, \c disp4, ... \c disp10. - static void wait(CImgDisplay& disp1, CImgDisplay& disp2, CImgDisplay& disp3, CImgDisplay& disp4, CImgDisplay& disp5, - CImgDisplay& disp6, CImgDisplay& disp7, CImgDisplay& disp8, CImgDisplay& disp9, - CImgDisplay& disp10) { - disp1._is_event = disp2._is_event = disp3._is_event = disp4._is_event = disp5._is_event = - disp6._is_event = disp7._is_event = disp8._is_event = disp9._is_event = disp10._is_event = false; - while ((!disp1._is_closed || !disp2._is_closed || !disp3._is_closed || !disp4._is_closed || !disp5._is_closed || - !disp6._is_closed || !disp7._is_closed || !disp8._is_closed || !disp9._is_closed || !disp10._is_closed) && - !disp1._is_event && !disp2._is_event && !disp3._is_event && !disp4._is_event && !disp5._is_event && - !disp6._is_event && !disp7._is_event && !disp8._is_event && !disp9._is_event && !disp10._is_event) - wait_all(); - } - -#if cimg_display==0 - - //! Wait for any window event occurring in any opened CImgDisplay. - static void wait_all() { - return _no_display_exception(); - } - - //! Render image into internal display buffer. - /** - \param img Input image data to render. - \note - - Convert image data representation into the internal display buffer (architecture-dependent structure). - - The content of the associated window is not modified, until paint() is called. - - Should not be used for common CImgDisplay uses, since display() is more useful. - **/ - template - CImgDisplay& render(const CImg& img) { - return assign(img); - } - - //! Paint internal display buffer on associated window. - /** - \note - - Update the content of the associated window with the internal display buffer, e.g. after a render() call. - - Should not be used for common CImgDisplay uses, since display() is more useful. - **/ - CImgDisplay& paint() { - return assign(); - } - - - //! Take a snapshot of the current screen content. - /** - \param x0 X-coordinate of the upper left corner. - \param y0 Y-coordinate of the upper left corner. - \param x1 X-coordinate of the lower right corner. - \param y1 Y-coordinate of the lower right corner. - \param[out] img Output screenshot. Can be empty on input - **/ - template - static void screenshot(const int x0, const int y0, const int x1, const int y1, CImg& img) { - cimg::unused(x0,y0,x1,y1,&img); - _no_display_exception(); - } - - //! Take a snapshot of the associated window content. - /** - \param[out] img Output snapshot. Can be empty on input. - **/ - template - const CImgDisplay& snapshot(CImg& img) const { - cimg::unused(img); - _no_display_exception(); - return *this; - } -#endif - - // X11-based implementation - //-------------------------- -#if cimg_display==1 - - Atom _wm_window_atom, _wm_protocol_atom; - Window _window, _background_window; - Colormap _colormap; - XImage *_image; - void *_data; - -#ifdef cimg_use_xshm - XShmSegmentInfo *_shminfo; -#endif - - static int screen_width() { - Display *const dpy = cimg::X11_attr().display; - int res = 0; - if (!dpy) { - Display *const _dpy = XOpenDisplay(0); - if (!_dpy) - throw CImgDisplayException("CImgDisplay::screen_width(): Failed to open X11 display."); - res = DisplayWidth(_dpy,DefaultScreen(_dpy)); - XCloseDisplay(_dpy); - } else { - -#ifdef cimg_use_xrandr - if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution) - res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width; - else res = DisplayWidth(dpy,DefaultScreen(dpy)); -#else - res = DisplayWidth(dpy,DefaultScreen(dpy)); -#endif - } - return res; - } - - static int screen_height() { - Display *const dpy = cimg::X11_attr().display; - int res = 0; - if (!dpy) { - Display *const _dpy = XOpenDisplay(0); - if (!_dpy) - throw CImgDisplayException("CImgDisplay::screen_height(): Failed to open X11 display."); - res = DisplayHeight(_dpy,DefaultScreen(_dpy)); - XCloseDisplay(_dpy); - } else { - -#ifdef cimg_use_xrandr - if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution) - res = cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].height; - else res = DisplayHeight(dpy,DefaultScreen(dpy)); -#else - res = DisplayHeight(dpy,DefaultScreen(dpy)); -#endif - } - return res; - } - - static void wait_all() { - if (!cimg::X11_attr().display) return; - pthread_mutex_lock(&cimg::X11_attr().wait_event_mutex); - pthread_cond_wait(&cimg::X11_attr().wait_event,&cimg::X11_attr().wait_event_mutex); - pthread_mutex_unlock(&cimg::X11_attr().wait_event_mutex); - } - - void _handle_events(const XEvent *const pevent) { - Display *const dpy = cimg::X11_attr().display; - XEvent event = *pevent; - switch (event.type) { - case ClientMessage : { - if ((int)event.xclient.message_type==(int)_wm_protocol_atom && - (int)event.xclient.data.l[0]==(int)_wm_window_atom) { - XUnmapWindow(cimg::X11_attr().display,_window); - _is_closed = _is_event = true; - pthread_cond_broadcast(&cimg::X11_attr().wait_event); - } - } break; - case ConfigureNotify : { - while (XCheckWindowEvent(dpy,_window,StructureNotifyMask,&event)) {} - const unsigned int nw = event.xconfigure.width, nh = event.xconfigure.height; - const int nx = event.xconfigure.x, ny = event.xconfigure.y; - if (nw && nh && (nw!=_window_width || nh!=_window_height)) { - _window_width = nw; _window_height = nh; _mouse_x = _mouse_y = -1; - XResizeWindow(dpy,_window,_window_width,_window_height); - _is_resized = _is_event = true; - pthread_cond_broadcast(&cimg::X11_attr().wait_event); - } - if (nx!=_window_x || ny!=_window_y) { - _window_x = nx; - _window_y = ny; - _is_moved = _is_event = true; - pthread_cond_broadcast(&cimg::X11_attr().wait_event); - } - } break; - case Expose : { - while (XCheckWindowEvent(dpy,_window,ExposureMask,&event)) {} - _paint(false); - if (_is_fullscreen) { - XWindowAttributes attr; - do { - XGetWindowAttributes(dpy,_window,&attr); - if (attr.map_state!=IsViewable) { XSync(dpy,0); cimg::sleep(10); } - } while (attr.map_state!=IsViewable); - XSetInputFocus(dpy,_window,RevertToParent,CurrentTime); - } - } break; - case ButtonPress : { - do { - _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y; - if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1; - switch (event.xbutton.button) { - case 1 : set_button(1); break; - case 3 : set_button(2); break; - case 2 : set_button(3); break; - } - } while (XCheckWindowEvent(dpy,_window,ButtonPressMask,&event)); - } break; - case ButtonRelease : { - do { - _mouse_x = event.xmotion.x; _mouse_y = event.xmotion.y; - if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1; - switch (event.xbutton.button) { - case 1 : set_button(1,false); break; - case 3 : set_button(2,false); break; - case 2 : set_button(3,false); break; - case 4 : set_wheel(1); break; - case 5 : set_wheel(-1); break; - } - } while (XCheckWindowEvent(dpy,_window,ButtonReleaseMask,&event)); - } break; - case KeyPress : { - char tmp = 0; KeySym ksym; - XLookupString(&event.xkey,&tmp,1,&ksym,0); - set_key((unsigned int)ksym,true); - } break; - case KeyRelease : { - char keys_return[32]; // Check that the key has been physically unpressed - XQueryKeymap(dpy,keys_return); - const unsigned int kc = event.xkey.keycode, kc1 = kc/8, kc2 = kc%8; - const bool is_key_pressed = kc1>=32?false:(keys_return[kc1]>>kc2)&1; - if (!is_key_pressed) { - char tmp = 0; KeySym ksym; - XLookupString(&event.xkey,&tmp,1,&ksym,0); - set_key((unsigned int)ksym,false); - } - } break; - case EnterNotify: { - while (XCheckWindowEvent(dpy,_window,EnterWindowMask,&event)) {} - _mouse_x = event.xmotion.x; - _mouse_y = event.xmotion.y; - if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1; - } break; - case LeaveNotify : { - while (XCheckWindowEvent(dpy,_window,LeaveWindowMask,&event)) {} - _mouse_x = _mouse_y = -1; _is_event = true; - pthread_cond_broadcast(&cimg::X11_attr().wait_event); - } break; - case MotionNotify : { - while (XCheckWindowEvent(dpy,_window,PointerMotionMask,&event)) {} - _mouse_x = event.xmotion.x; - _mouse_y = event.xmotion.y; - if (_mouse_x<0 || _mouse_y<0 || _mouse_x>=width() || _mouse_y>=height()) _mouse_x = _mouse_y = -1; - _is_event = true; - pthread_cond_broadcast(&cimg::X11_attr().wait_event); - } break; - } - } - - static void* _events_thread(void *arg) { // Thread to manage events for all opened display windows - Display *const dpy = cimg::X11_attr().display; - XEvent event; - pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,0); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,0); - if (!arg) for ( ; ; ) { - cimg_lock_display(); - bool event_flag = XCheckTypedEvent(dpy,ClientMessage,&event); - if (!event_flag) event_flag = XCheckMaskEvent(dpy, - ExposureMask | StructureNotifyMask | ButtonPressMask | - KeyPressMask | PointerMotionMask | EnterWindowMask | - LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask,&event); - if (event_flag) - for (unsigned int i = 0; i_is_closed && event.xany.window==cimg::X11_attr().wins[i]->_window) - cimg::X11_attr().wins[i]->_handle_events(&event); - cimg_unlock_display(); - pthread_testcancel(); - cimg::sleep(8); - } - return 0; - } - - void _set_colormap(Colormap& cmap, const unsigned int dim) { - XColor *const colormap = new XColor[256]; - switch (dim) { - case 1 : { // colormap for greyscale images - for (unsigned int index = 0; index<256; ++index) { - colormap[index].pixel = index; - colormap[index].red = colormap[index].green = colormap[index].blue = (unsigned short)(index<<8); - colormap[index].flags = DoRed | DoGreen | DoBlue; - } - } break; - case 2 : { // colormap for RG images - for (unsigned int index = 0, r = 8; r<256; r+=16) - for (unsigned int g = 8; g<256; g+=16) { - colormap[index].pixel = index; - colormap[index].red = colormap[index].blue = (unsigned short)(r<<8); - colormap[index].green = (unsigned short)(g<<8); - colormap[index++].flags = DoRed | DoGreen | DoBlue; - } - } break; - default : { // colormap for RGB images - for (unsigned int index = 0, r = 16; r<256; r+=32) - for (unsigned int g = 16; g<256; g+=32) - for (unsigned int b = 32; b<256; b+=64) { - colormap[index].pixel = index; - colormap[index].red = (unsigned short)(r<<8); - colormap[index].green = (unsigned short)(g<<8); - colormap[index].blue = (unsigned short)(b<<8); - colormap[index++].flags = DoRed | DoGreen | DoBlue; - } - } - } - XStoreColors(cimg::X11_attr().display,cmap,colormap,256); - delete[] colormap; - } - - void _map_window() { - Display *const dpy = cimg::X11_attr().display; - bool is_exposed = false, is_mapped = false; - XWindowAttributes attr; - XEvent event; - XMapRaised(dpy,_window); - do { // Wait for the window to be mapped - XWindowEvent(dpy,_window,StructureNotifyMask | ExposureMask,&event); - switch (event.type) { - case MapNotify : is_mapped = true; break; - case Expose : is_exposed = true; break; - } - } while (!is_exposed || !is_mapped); - do { // Wait for the window to be visible - XGetWindowAttributes(dpy,_window,&attr); - if (attr.map_state!=IsViewable) { XSync(dpy,0); cimg::sleep(10); } - } while (attr.map_state!=IsViewable); - _window_x = attr.x; - _window_y = attr.y; - } - - void _paint(const bool wait_expose=true) { - if (_is_closed || !_image) return; - Display *const dpy = cimg::X11_attr().display; - if (wait_expose) { // Send an expose event sticked to display window to force repaint - XEvent event; - event.xexpose.type = Expose; - event.xexpose.serial = 0; - event.xexpose.send_event = 1; - event.xexpose.display = dpy; - event.xexpose.window = _window; - event.xexpose.x = 0; - event.xexpose.y = 0; - event.xexpose.width = width(); - event.xexpose.height = height(); - event.xexpose.count = 0; - XSendEvent(dpy,_window,0,0,&event); - } else { // Repaint directly (may be called from the expose event) - GC gc = DefaultGC(dpy,DefaultScreen(dpy)); - -#ifdef cimg_use_xshm - if (_shminfo) XShmPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height,1); - else XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height); -#else - XPutImage(dpy,_window,gc,_image,0,0,0,0,_width,_height); -#endif - } - } - - template - void _resize(T pixel_type, const unsigned int ndimx, const unsigned int ndimy, const bool force_redraw) { - Display *const dpy = cimg::X11_attr().display; - cimg::unused(pixel_type); - -#ifdef cimg_use_xshm - if (_shminfo) { - XShmSegmentInfo *const nshminfo = new XShmSegmentInfo; - XImage *const nimage = XShmCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)), - cimg::X11_attr().nb_bits,ZPixmap,0,nshminfo,ndimx,ndimy); - if (!nimage) { delete nshminfo; return; } - else { - nshminfo->shmid = shmget(IPC_PRIVATE,ndimx*ndimy*sizeof(T),IPC_CREAT | 0777); - if (nshminfo->shmid==-1) { XDestroyImage(nimage); delete nshminfo; return; } - else { - nshminfo->shmaddr = nimage->data = (char*)shmat(nshminfo->shmid,0,0); - if (nshminfo->shmaddr==(char*)-1) { - shmctl(nshminfo->shmid,IPC_RMID,0); XDestroyImage(nimage); delete nshminfo; return; - } else { - nshminfo->readOnly = 0; - cimg::X11_attr().is_shm_enabled = true; - XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm); - XShmAttach(dpy,nshminfo); - XFlush(dpy); - XSetErrorHandler(oldXErrorHandler); - if (!cimg::X11_attr().is_shm_enabled) { - shmdt(nshminfo->shmaddr); - shmctl(nshminfo->shmid,IPC_RMID,0); - XDestroyImage(nimage); - delete nshminfo; - return; - } else { - T *const ndata = (T*)nimage->data; - if (force_redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy); - else std::memset(ndata,0,sizeof(T)*ndimx*ndimy); - XShmDetach(dpy,_shminfo); - XDestroyImage(_image); - shmdt(_shminfo->shmaddr); - shmctl(_shminfo->shmid,IPC_RMID,0); - delete _shminfo; - _shminfo = nshminfo; - _image = nimage; - _data = (void*)ndata; - } - } - } - } - } else -#endif - { - T *ndata = (T*)std::malloc(ndimx*ndimy*sizeof(T)); - if (force_redraw) _render_resize((T*)_data,_width,_height,ndata,ndimx,ndimy); - else std::memset(ndata,0,sizeof(T)*ndimx*ndimy); - _data = (void*)ndata; - XDestroyImage(_image); - _image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)), - cimg::X11_attr().nb_bits,ZPixmap,0,(char*)_data,ndimx,ndimy,8,0); - } - } - - void _init_fullscreen() { - if (!_is_fullscreen || _is_closed) return; - Display *const dpy = cimg::X11_attr().display; - _background_window = 0; - -#ifdef cimg_use_xrandr - int foo; - if (XRRQueryExtension(dpy,&foo,&foo)) { - XRRRotations(dpy,DefaultScreen(dpy),&cimg::X11_attr().curr_rotation); - if (!cimg::X11_attr().resolutions) { - cimg::X11_attr().resolutions = XRRSizes(dpy,DefaultScreen(dpy),&foo); - cimg::X11_attr().nb_resolutions = (unsigned int)foo; - } - if (cimg::X11_attr().resolutions) { - cimg::X11_attr().curr_resolution = 0; - for (unsigned int i = 0; i=_width && nh>=_height && - nw<=(unsigned int)(cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].width) && - nh<=(unsigned int)(cimg::X11_attr().resolutions[cimg::X11_attr().curr_resolution].height)) - cimg::X11_attr().curr_resolution = i; - } - if (cimg::X11_attr().curr_resolution>0) { - XRRScreenConfiguration *config = XRRGetScreenInfo(dpy,DefaultRootWindow(dpy)); - XRRSetScreenConfig(dpy,config,DefaultRootWindow(dpy), - cimg::X11_attr().curr_resolution,cimg::X11_attr().curr_rotation,CurrentTime); - XRRFreeScreenConfigInfo(config); - XSync(dpy,0); - } - } - } - if (!cimg::X11_attr().resolutions) - cimg::warn(_cimgdisplay_instance - "init_fullscreen(): Xrandr extension not supported by the X server.", - cimgdisplay_instance); -#endif - - const unsigned int sx = screen_width(), sy = screen_height(); - if (sx==_width && sy==_height) return; - XSetWindowAttributes attr_set; - - attr_set.background_pixel = XBlackPixel(dpy,XDefaultScreen(dpy)); - attr_set.override_redirect = 1; - _background_window = XCreateWindow(dpy,DefaultRootWindow(dpy),0,0,sx,sy,0,0, - InputOutput,CopyFromParent,CWBackPixel | CWOverrideRedirect,&attr_set); - XEvent event; - XSelectInput(dpy,_background_window,StructureNotifyMask); - XMapRaised(dpy,_background_window); - do XWindowEvent(dpy,_background_window,StructureNotifyMask,&event); - while (event.type!=MapNotify); - - XWindowAttributes attr; - do { - XGetWindowAttributes(dpy,_background_window,&attr); - if (attr.map_state!=IsViewable) { XSync(dpy,0); cimg::sleep(10); } - } while (attr.map_state!=IsViewable); - } - - void _desinit_fullscreen() { - if (!_is_fullscreen) return; - Display *const dpy = cimg::X11_attr().display; - XUngrabKeyboard(dpy,CurrentTime); - -#ifdef cimg_use_xrandr - if (cimg::X11_attr().resolutions && cimg::X11_attr().curr_resolution) { - XRRScreenConfiguration *config = XRRGetScreenInfo(dpy,DefaultRootWindow(dpy)); - XRRSetScreenConfig(dpy,config,DefaultRootWindow(dpy),0,cimg::X11_attr().curr_rotation,CurrentTime); - XRRFreeScreenConfigInfo(config); - XSync(dpy,0); - cimg::X11_attr().curr_resolution = 0; - } -#endif - if (_background_window) XDestroyWindow(dpy,_background_window); - _background_window = 0; - _is_fullscreen = false; - } - - static int _assign_xshm(Display *dpy, XErrorEvent *error) { - cimg::unused(dpy,error); - cimg::X11_attr().is_shm_enabled = false; - return 0; - } - - void _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0, - const unsigned int normalization_type=3, - const bool fullscreen_flag=false, const bool closed_flag=false) { - cimg::mutex(14); - - // Allocate space for window title - const char *const nptitle = ptitle?ptitle:""; - const unsigned int s = (unsigned int)std::strlen(nptitle) + 1; - char *const tmp_title = s?new char[s]:0; - if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char)); - - // Destroy previous display window if existing - if (!is_empty()) assign(); - - // Open X11 display and retrieve graphical properties. - Display* &dpy = cimg::X11_attr().display; - if (!dpy) { - dpy = XOpenDisplay(0); - if (!dpy) - throw CImgDisplayException(_cimgdisplay_instance - "assign(): Failed to open X11 display.", - cimgdisplay_instance); - - cimg::X11_attr().nb_bits = DefaultDepth(dpy,DefaultScreen(dpy)); - if (cimg::X11_attr().nb_bits!=8 && cimg::X11_attr().nb_bits!=16 && - cimg::X11_attr().nb_bits!=24 && cimg::X11_attr().nb_bits!=32) - throw CImgDisplayException(_cimgdisplay_instance - "assign(): Invalid %u bits screen mode detected " - "(only 8, 16, 24 and 32 bits modes are managed).", - cimgdisplay_instance, - cimg::X11_attr().nb_bits); - XVisualInfo vtemplate; - vtemplate.visualid = XVisualIDFromVisual(DefaultVisual(dpy,DefaultScreen(dpy))); - int nb_visuals; - XVisualInfo *vinfo = XGetVisualInfo(dpy,VisualIDMask,&vtemplate,&nb_visuals); - if (vinfo && vinfo->red_maskblue_mask) cimg::X11_attr().is_blue_first = true; - cimg::X11_attr().byte_order = ImageByteOrder(dpy); - XFree(vinfo); - - cimg_lock_display(); - cimg::X11_attr().events_thread = new pthread_t; - pthread_create(cimg::X11_attr().events_thread,0,_events_thread,0); - } else cimg_lock_display(); - - // Set display variables. - _width = std::min(dimw,(unsigned int)screen_width()); - _height = std::min(dimh,(unsigned int)screen_height()); - _normalization = normalization_type<4?normalization_type:3; - _is_fullscreen = fullscreen_flag; - _window_x = _window_y = cimg::type::min(); - _is_closed = closed_flag; - _title = tmp_title; - flush(); - - // Create X11 window (and LUT, if 8bits display) - if (_is_fullscreen) { - if (!_is_closed) _init_fullscreen(); - const unsigned int sx = screen_width(), sy = screen_height(); - XSetWindowAttributes attr_set; - attr_set.override_redirect = 1; - _window = XCreateWindow(dpy,DefaultRootWindow(dpy),(sx - _width)/2,(sy - _height)/2,_width,_height,0,0, - InputOutput,CopyFromParent,CWOverrideRedirect,&attr_set); - } else - _window = XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,_width,_height,0,0L,0L); - - XSelectInput(dpy,_window, - ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | PointerMotionMask | - EnterWindowMask | LeaveWindowMask | ButtonReleaseMask | KeyReleaseMask); - - XStoreName(dpy,_window,_title?_title:" "); - if (cimg::X11_attr().nb_bits==8) { - _colormap = XCreateColormap(dpy,_window,DefaultVisual(dpy,DefaultScreen(dpy)),AllocAll); - _set_colormap(_colormap,3); - XSetWindowColormap(dpy,_window,_colormap); - } - - static const char *const _window_class = cimg_appname; - XClassHint *const window_class = XAllocClassHint(); - window_class->res_name = (char*)_window_class; - window_class->res_class = (char*)_window_class; - XSetClassHint(dpy,_window,window_class); - XFree(window_class); - - _window_width = _width; - _window_height = _height; - - // Create XImage -#ifdef cimg_use_xshm - _shminfo = 0; - if (XShmQueryExtension(dpy)) { - _shminfo = new XShmSegmentInfo; - _image = XShmCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits, - ZPixmap,0,_shminfo,_width,_height); - if (!_image) { delete _shminfo; _shminfo = 0; } - else { - _shminfo->shmid = shmget(IPC_PRIVATE,_image->bytes_per_line*_image->height,IPC_CREAT|0777); - if (_shminfo->shmid==-1) { XDestroyImage(_image); delete _shminfo; _shminfo = 0; } - else { - _shminfo->shmaddr = _image->data = (char*)(_data = shmat(_shminfo->shmid,0,0)); - if (_shminfo->shmaddr==(char*)-1) { - shmctl(_shminfo->shmid,IPC_RMID,0); XDestroyImage(_image); delete _shminfo; _shminfo = 0; - } else { - _shminfo->readOnly = 0; - cimg::X11_attr().is_shm_enabled = true; - XErrorHandler oldXErrorHandler = XSetErrorHandler(_assign_xshm); - XShmAttach(dpy,_shminfo); - XSync(dpy,0); - XSetErrorHandler(oldXErrorHandler); - if (!cimg::X11_attr().is_shm_enabled) { - shmdt(_shminfo->shmaddr); shmctl(_shminfo->shmid,IPC_RMID,0); XDestroyImage(_image); - delete _shminfo; _shminfo = 0; - } - } - } - } - } - if (!_shminfo) -#endif - { - const cimg_ulong buf_size = (cimg_ulong)_width*_height*(cimg::X11_attr().nb_bits==8?1: - (cimg::X11_attr().nb_bits==16?2:4)); - _data = std::malloc(buf_size); - _image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),cimg::X11_attr().nb_bits, - ZPixmap,0,(char*)_data,_width,_height,8,0); - } - - _wm_window_atom = XInternAtom(dpy,"WM_DELETE_WINDOW",0); - _wm_protocol_atom = XInternAtom(dpy,"WM_PROTOCOLS",0); - XSetWMProtocols(dpy,_window,&_wm_window_atom,1); - - if (_is_fullscreen) XGrabKeyboard(dpy,_window,1,GrabModeAsync,GrabModeAsync,CurrentTime); - cimg::X11_attr().wins[cimg::X11_attr().nb_wins++]=this; - if (!_is_closed) _map_window(); else _window_x = _window_y = cimg::type::min(); - cimg_unlock_display(); - cimg::mutex(14,0); - } - - CImgDisplay& assign() { - if (is_empty()) return flush(); - Display *const dpy = cimg::X11_attr().display; - cimg_lock_display(); - - // Remove display window from event thread list. - unsigned int i; - for (i = 0; ishmaddr); - shmctl(_shminfo->shmid,IPC_RMID,0); - delete _shminfo; - _shminfo = 0; - } -#endif - - XDestroyImage(_image); - if (cimg::X11_attr().nb_bits==8) XFreeColormap(dpy,_colormap); - XDestroyWindow(dpy,_window); - XSync(dpy,0); - _window = 0; _colormap = 0; _data = 0; _image = 0; - - // Reset display variables. - delete[] _title; - _width = _height = _normalization = _window_width = _window_height = 0; - _window_x = _window_y = cimg::type::min(); - _is_fullscreen = false; - _is_closed = true; - _min = _max = 0; - _title = 0; - flush(); - - cimg_unlock_display(); - return *this; - } - - CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *const title=0, - const unsigned int normalization_type=3, - const bool fullscreen_flag=false, const bool closed_flag=false) { - if (!dimw || !dimh) return assign(); - _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag); - _min = _max = 0; - std::memset(_data,0,(cimg::X11_attr().nb_bits==8?sizeof(unsigned char): - (cimg::X11_attr().nb_bits==16?sizeof(unsigned short):sizeof(unsigned int)))* - (size_t)_width*_height); - return paint(); - } - - template - CImgDisplay& assign(const CImg& img, const char *const title=0, - const unsigned int normalization_type=3, - const bool fullscreen_flag=false, const bool closed_flag=false) { - if (!img) return assign(); - CImg tmp; - const CImg& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2, - (img._height - 1)/2, - (img._depth - 1)/2)); - _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); - if (_normalization==2) _min = (float)nimg.min_max(_max); - return render(nimg).paint(); - } - - template - CImgDisplay& assign(const CImgList& list, const char *const title=0, - const unsigned int normalization_type=3, - const bool fullscreen_flag=false, const bool closed_flag=false) { - if (!list) return assign(); - CImg tmp; - const CImg img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2, - (img._height - 1)/2, - (img._depth - 1)/2)); - _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); - if (_normalization==2) _min = (float)nimg.min_max(_max); - return render(nimg).paint(); - } - - CImgDisplay& assign(const CImgDisplay& disp) { - if (!disp) return assign(); - _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed); - std::memcpy(_data,disp._data,(cimg::X11_attr().nb_bits==8?sizeof(unsigned char): - cimg::X11_attr().nb_bits==16?sizeof(unsigned short): - sizeof(unsigned int))*(size_t)_width*_height); - return paint(); - } - - CImgDisplay& resize(const int nwidth, const int nheight, const bool force_redraw=true) { - if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign(); - if (is_empty()) return assign(nwidth,nheight); - Display *const dpy = cimg::X11_attr().display; - const unsigned int - tmpdimx = (nwidth>0)?nwidth:(-nwidth*width()/100), - tmpdimy = (nheight>0)?nheight:(-nheight*height()/100), - dimx = tmpdimx?tmpdimx:1, - dimy = tmpdimy?tmpdimy:1; - if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) { - show(); - cimg_lock_display(); - if (_window_width!=dimx || _window_height!=dimy) { - XWindowAttributes attr; - for (unsigned int i = 0; i<10; ++i) { - XResizeWindow(dpy,_window,dimx,dimy); - XGetWindowAttributes(dpy,_window,&attr); - if (attr.width==(int)dimx && attr.height==(int)dimy) break; - cimg::wait(5,&_timer); - } - } - if (_width!=dimx || _height!=dimy) switch (cimg::X11_attr().nb_bits) { - case 8 : { unsigned char pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break; - case 16 : { unsigned short pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } break; - default : { unsigned int pixel_type = 0; _resize(pixel_type,dimx,dimy,force_redraw); } - } - _window_width = _width = dimx; _window_height = _height = dimy; - cimg_unlock_display(); - } - _is_resized = false; - if (_is_fullscreen) move((screen_width() - _width)/2,(screen_height() - _height)/2); - if (force_redraw) return paint(); - return *this; - } - - CImgDisplay& toggle_fullscreen(const bool force_redraw=true) { - if (is_empty()) return *this; - if (force_redraw) { - const cimg_ulong buf_size = (cimg_ulong)_width*_height* - (cimg::X11_attr().nb_bits==8?1:(cimg::X11_attr().nb_bits==16?2:4)); - void *image_data = std::malloc(buf_size); - std::memcpy(image_data,_data,buf_size); - assign(_width,_height,_title,_normalization,!_is_fullscreen,false); - std::memcpy(_data,image_data,buf_size); - std::free(image_data); - return paint(); - } - return assign(_width,_height,_title,_normalization,!_is_fullscreen,false); - } - - CImgDisplay& show() { - if (is_empty() || !_is_closed) return *this; - cimg_lock_display(); - _is_closed = false; - if (_is_fullscreen) _init_fullscreen(); - _map_window(); - cimg_unlock_display(); - return paint(); - } - - CImgDisplay& close() { - if (is_empty() || _is_closed) return *this; - Display *const dpy = cimg::X11_attr().display; - cimg_lock_display(); - if (_is_fullscreen) _desinit_fullscreen(); - XUnmapWindow(dpy,_window); - _window_x = _window_y = cimg::type::min(); - _is_closed = true; - cimg_unlock_display(); - return *this; - } - - CImgDisplay& move(const int posx, const int posy) { - if (is_empty()) return *this; - show(); - if (_window_x!=posx || _window_y!=posy) { - Display *const dpy = cimg::X11_attr().display; - cimg_lock_display(); - XMoveWindow(dpy,_window,posx,posy); - _window_x = posx; - _window_y = posy; - cimg_unlock_display(); - } - _is_moved = false; - return paint(); - } - - CImgDisplay& show_mouse() { - if (is_empty()) return *this; - Display *const dpy = cimg::X11_attr().display; - cimg_lock_display(); - XUndefineCursor(dpy,_window); - cimg_unlock_display(); - return *this; - } - - CImgDisplay& hide_mouse() { - if (is_empty()) return *this; - Display *const dpy = cimg::X11_attr().display; - cimg_lock_display(); - static const char pix_data[8] = { 0 }; - XColor col; - col.red = col.green = col.blue = 0; - Pixmap pix = XCreateBitmapFromData(dpy,_window,pix_data,8,8); - Cursor cur = XCreatePixmapCursor(dpy,pix,pix,&col,&col,0,0); - XFreePixmap(dpy,pix); - XDefineCursor(dpy,_window,cur); - cimg_unlock_display(); - return *this; - } - - CImgDisplay& set_mouse(const int posx, const int posy) { - if (is_empty() || _is_closed) return *this; - Display *const dpy = cimg::X11_attr().display; - cimg_lock_display(); - XWarpPointer(dpy,0L,_window,0,0,0,0,posx,posy); - _mouse_x = posx; _mouse_y = posy; - _is_moved = false; - XSync(dpy,0); - cimg_unlock_display(); - return *this; - } - - CImgDisplay& set_title(const char *const format, ...) { - if (is_empty()) return *this; - char *const tmp = new char[1024]; - va_list ap; - va_start(ap, format); - cimg_vsnprintf(tmp,1024,format,ap); - va_end(ap); - if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; } - delete[] _title; - const unsigned int s = (unsigned int)std::strlen(tmp) + 1; - _title = new char[s]; - std::memcpy(_title,tmp,s*sizeof(char)); - Display *const dpy = cimg::X11_attr().display; - cimg_lock_display(); - XStoreName(dpy,_window,tmp); - cimg_unlock_display(); - delete[] tmp; - return *this; - } - - template - CImgDisplay& display(const CImg& img) { - if (!img) - throw CImgArgumentException(_cimgdisplay_instance - "display(): Empty specified image.", - cimgdisplay_instance); - if (is_empty()) return assign(img); - return render(img).paint(false); - } - - CImgDisplay& paint(const bool wait_expose=true) { - if (is_empty()) return *this; - cimg_lock_display(); - _paint(wait_expose); - cimg_unlock_display(); - return *this; - } - - template - CImgDisplay& render(const CImg& img, const bool flag8=false) { - if (!img) - throw CImgArgumentException(_cimgdisplay_instance - "render(): Empty specified image.", - cimgdisplay_instance); - if (is_empty()) return *this; - if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2, - (img._depth - 1)/2)); - if (cimg::X11_attr().nb_bits==8 && (img._width!=_width || img._height!=_height)) - return render(img.get_resize(_width,_height,1,-100,1)); - if (cimg::X11_attr().nb_bits==8 && !flag8 && img._spectrum==3) { - static const CImg::ucharT> default_colormap = CImg::ucharT>::default_LUT256(); - return render(img.get_index(default_colormap,1,false)); - } - - const T - *data1 = img._data, - *data2 = (img._spectrum>1)?img.data(0,0,0,1):data1, - *data3 = (img._spectrum>2)?img.data(0,0,0,2):data1; - - if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3); - cimg_lock_display(); - - if (!_normalization || (_normalization==3 && cimg::type::string()==cimg::type::string())) { - _min = _max = 0; - switch (cimg::X11_attr().nb_bits) { - case 8 : { // 256 colormap, no normalization - _set_colormap(_colormap,img._spectrum); - unsigned char - *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data: - new unsigned char[(size_t)img._width*img._height], - *ptrd = (unsigned char*)ndata; - switch (img._spectrum) { - case 1 : - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) - (*ptrd++) = (unsigned char)*(data1++); - break; - case 2 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char - R = (unsigned char)*(data1++), - G = (unsigned char)*(data2++); - (*ptrd++) = (R&0xf0) | (G>>4); - } break; - default : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char - R = (unsigned char)*(data1++), - G = (unsigned char)*(data2++), - B = (unsigned char)*(data3++); - (*ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6); - } - } - if (ndata!=_data) { - _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height); - delete[] ndata; - } - } break; - case 16 : { // 16 bits colors, no normalization - unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data: - new unsigned short[(size_t)img._width*img._height]; - unsigned char *ptrd = (unsigned char*)ndata; - const unsigned int M = 248; - switch (img._spectrum) { - case 1 : - if (cimg::X11_attr().byte_order) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)*(data1++), G = val>>2; - ptrd[0] = (val&M) | (G>>3); - ptrd[1] = (G<<5) | (G>>1); - ptrd+=2; - } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)*(data1++), G = val>>2; - ptrd[0] = (G<<5) | (G>>1); - ptrd[1] = (val&M) | (G>>3); - ptrd+=2; - } - break; - case 2 : - if (cimg::X11_attr().byte_order) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)*(data2++)>>2; - ptrd[0] = ((unsigned char)*(data1++)&M) | (G>>3); - ptrd[1] = (G<<5); - ptrd+=2; - } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)*(data2++)>>2; - ptrd[0] = (G<<5); - ptrd[1] = ((unsigned char)*(data1++)&M) | (G>>3); - ptrd+=2; - } - break; - default : - if (cimg::X11_attr().byte_order) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)*(data2++)>>2; - ptrd[0] = ((unsigned char)*(data1++)&M) | (G>>3); - ptrd[1] = (G<<5) | ((unsigned char)*(data3++)>>3); - ptrd+=2; - } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)*(data2++)>>2; - ptrd[0] = (G<<5) | ((unsigned char)*(data3++)>>3); - ptrd[1] = ((unsigned char)*(data1++)&M) | (G>>3); - ptrd+=2; - } - } - if (ndata!=_data) { - _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height); - delete[] ndata; - } - } break; - default : { // 24 bits colors, no normalization - unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data: - new unsigned int[(size_t)img._width*img._height]; - if (sizeof(int)==4) { // 32 bits int uses optimized version - unsigned int *ptrd = ndata; - switch (img._spectrum) { - case 1 : - if (cimg::X11_attr().byte_order==cimg::endianness()) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)*(data1++); - *(ptrd++) = (val<<16) | (val<<8) | val; - } - else - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)*(data1++); - *(ptrd++) = (val<<16) | (val<<8) | val; - } - break; - case 2 : - if (cimg::X11_attr().byte_order==cimg::endianness()) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) - *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8); - else - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) - *(ptrd++) = ((unsigned char)*(data2++)<<16) | ((unsigned char)*(data1++)<<8); - break; - default : - if (cimg::X11_attr().byte_order==cimg::endianness()) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) - *(ptrd++) = ((unsigned char)*(data1++)<<16) | ((unsigned char)*(data2++)<<8) | - (unsigned char)*(data3++); - else - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) - *(ptrd++) = ((unsigned char)*(data3++)<<24) | ((unsigned char)*(data2++)<<16) | - ((unsigned char)*(data1++)<<8); - } - } else { - unsigned char *ptrd = (unsigned char*)ndata; - switch (img._spectrum) { - case 1 : - if (cimg::X11_attr().byte_order) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - ptrd[0] = 0; - ptrd[1] = (unsigned char)*(data1++); - ptrd[2] = 0; - ptrd[3] = 0; - ptrd+=4; - } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - ptrd[0] = 0; - ptrd[1] = 0; - ptrd[2] = (unsigned char)*(data1++); - ptrd[3] = 0; - ptrd+=4; - } - break; - case 2 : - if (cimg::X11_attr().byte_order) cimg::swap(data1,data2); - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - ptrd[0] = 0; - ptrd[1] = (unsigned char)*(data2++); - ptrd[2] = (unsigned char)*(data1++); - ptrd[3] = 0; - ptrd+=4; - } - break; - default : - if (cimg::X11_attr().byte_order) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - ptrd[0] = 0; - ptrd[1] = (unsigned char)*(data1++); - ptrd[2] = (unsigned char)*(data2++); - ptrd[3] = (unsigned char)*(data3++); - ptrd+=4; - } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - ptrd[0] = (unsigned char)*(data3++); - ptrd[1] = (unsigned char)*(data2++); - ptrd[2] = (unsigned char)*(data1++); - ptrd[3] = 0; - ptrd+=4; - } - } - } - if (ndata!=_data) { - _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height); - delete[] ndata; - } - } - } - } else { - if (_normalization==3) { - if (sizeof(T)>1 && cimg::type::string()!=cimg::type::string()) _min = (float)img.min_max(_max); - else { _min = (float)cimg::type::min(); _max = (float)cimg::type::max(); } - } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max); - const float delta = _max - _min, mm = 255/(delta?delta:1.f); - switch (cimg::X11_attr().nb_bits) { - case 8 : { // 256 colormap, with normalization - _set_colormap(_colormap,img._spectrum); - unsigned char *const ndata = (img._width==_width && img._height==_height)?(unsigned char*)_data: - new unsigned char[(size_t)img._width*img._height]; - unsigned char *ptrd = (unsigned char*)ndata; - switch (img._spectrum) { - case 1 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char R = (unsigned char)((*(data1++) - _min)*mm); - *(ptrd++) = R; - } break; - case 2 : for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char - R = (unsigned char)((*(data1++) - _min)*mm), - G = (unsigned char)((*(data2++) - _min)*mm); - (*ptrd++) = (R&0xf0) | (G>>4); - } break; - default : - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char - R = (unsigned char)((*(data1++) - _min)*mm), - G = (unsigned char)((*(data2++) - _min)*mm), - B = (unsigned char)((*(data3++) - _min)*mm); - *(ptrd++) = (R&0xe0) | ((G>>5)<<2) | (B>>6); - } - } - if (ndata!=_data) { - _render_resize(ndata,img._width,img._height,(unsigned char*)_data,_width,_height); - delete[] ndata; - } - } break; - case 16 : { // 16 bits colors, with normalization - unsigned short *const ndata = (img._width==_width && img._height==_height)?(unsigned short*)_data: - new unsigned short[(size_t)img._width*img._height]; - unsigned char *ptrd = (unsigned char*)ndata; - const unsigned int M = 248; - switch (img._spectrum) { - case 1 : - if (cimg::X11_attr().byte_order) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2; - ptrd[0] = (val&M) | (G>>3); - ptrd[1] = (G<<5) | (val>>3); - ptrd+=2; - } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++) - _min)*mm), G = val>>2; - ptrd[0] = (G<<5) | (val>>3); - ptrd[1] = (val&M) | (G>>3); - ptrd+=2; - } - break; - case 2 : - if (cimg::X11_attr().byte_order) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2; - ptrd[0] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3); - ptrd[1] = (G<<5); - ptrd+=2; - } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2; - ptrd[0] = (G<<5); - ptrd[1] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3); - ptrd+=2; - } - break; - default : - if (cimg::X11_attr().byte_order) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2; - ptrd[0] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3); - ptrd[1] = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3); - ptrd+=2; - } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char G = (unsigned char)((*(data2++) - _min)*mm)>>2; - ptrd[0] = (G<<5) | ((unsigned char)((*(data3++) - _min)*mm)>>3); - ptrd[1] = ((unsigned char)((*(data1++) - _min)*mm)&M) | (G>>3); - ptrd+=2; - } - } - if (ndata!=_data) { - _render_resize(ndata,img._width,img._height,(unsigned short*)_data,_width,_height); - delete[] ndata; - } - } break; - default : { // 24 bits colors, with normalization - unsigned int *const ndata = (img._width==_width && img._height==_height)?(unsigned int*)_data: - new unsigned int[(size_t)img._width*img._height]; - if (sizeof(int)==4) { // 32 bits int uses optimized version - unsigned int *ptrd = ndata; - switch (img._spectrum) { - case 1 : - if (cimg::X11_attr().byte_order==cimg::endianness()) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); - *(ptrd++) = (val<<16) | (val<<8) | val; - } - else - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); - *(ptrd++) = (val<<24) | (val<<16) | (val<<8); - } - break; - case 2 : - if (cimg::X11_attr().byte_order==cimg::endianness()) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) - *(ptrd++) = - ((unsigned char)((*(data1++) - _min)*mm)<<16) | - ((unsigned char)((*(data2++) - _min)*mm)<<8); - else - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) - *(ptrd++) = - ((unsigned char)((*(data2++) - _min)*mm)<<16) | - ((unsigned char)((*(data1++) - _min)*mm)<<8); - break; - default : - if (cimg::X11_attr().byte_order==cimg::endianness()) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) - *(ptrd++) = - ((unsigned char)((*(data1++) - _min)*mm)<<16) | - ((unsigned char)((*(data2++) - _min)*mm)<<8) | - (unsigned char)((*(data3++) - _min)*mm); - else - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) - *(ptrd++) = - ((unsigned char)((*(data3++) - _min)*mm)<<24) | - ((unsigned char)((*(data2++) - _min)*mm)<<16) | - ((unsigned char)((*(data1++) - _min)*mm)<<8); - } - } else { - unsigned char *ptrd = (unsigned char*)ndata; - switch (img._spectrum) { - case 1 : - if (cimg::X11_attr().byte_order) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); - ptrd[0] = 0; - ptrd[1] = val; - ptrd[2] = val; - ptrd[3] = val; - ptrd+=4; - } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); - ptrd[0] = val; - ptrd[1] = val; - ptrd[2] = val; - ptrd[3] = 0; - ptrd+=4; - } - break; - case 2 : - if (cimg::X11_attr().byte_order) cimg::swap(data1,data2); - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - ptrd[0] = 0; - ptrd[1] = (unsigned char)((*(data2++) - _min)*mm); - ptrd[2] = (unsigned char)((*(data1++) - _min)*mm); - ptrd[3] = 0; - ptrd+=4; - } - break; - default : - if (cimg::X11_attr().byte_order) - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - ptrd[0] = 0; - ptrd[1] = (unsigned char)((*(data1++) - _min)*mm); - ptrd[2] = (unsigned char)((*(data2++) - _min)*mm); - ptrd[3] = (unsigned char)((*(data3++) - _min)*mm); - ptrd+=4; - } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - ptrd[0] = (unsigned char)((*(data3++) - _min)*mm); - ptrd[1] = (unsigned char)((*(data2++) - _min)*mm); - ptrd[2] = (unsigned char)((*(data1++) - _min)*mm); - ptrd[3] = 0; - ptrd+=4; - } - } - } - if (ndata!=_data) { - _render_resize(ndata,img._width,img._height,(unsigned int*)_data,_width,_height); - delete[] ndata; - } - } - } - } - cimg_unlock_display(); - return *this; - } - - template - static void screenshot(const int x0, const int y0, const int x1, const int y1, CImg& img) { - img.assign(); - Display *dpy = cimg::X11_attr().display; - cimg_lock_display(); - if (!dpy) { - dpy = XOpenDisplay(0); - if (!dpy) - throw CImgDisplayException("CImgDisplay::screenshot(): Failed to open X11 display."); - } - Window root = DefaultRootWindow(dpy); - XWindowAttributes gwa; - XGetWindowAttributes(dpy,root,&gwa); - const int width = gwa.width, height = gwa.height; - int _x0 = x0, _y0 = y0, _x1 = x1, _y1 = y1; - if (_x0>_x1) cimg::swap(_x0,_x1); - if (_y0>_y1) cimg::swap(_y0,_y1); - - XImage *image = 0; - if (_x1>=0 && _x0=0 && _y0red_mask, - green_mask = image->green_mask, - blue_mask = image->blue_mask; - img.assign(image->width,image->height,1,3); - T *pR = img.data(0,0,0,0), *pG = img.data(0,0,0,1), *pB = img.data(0,0,0,2); - cimg_forXY(img,x,y) { - const unsigned long pixel = XGetPixel(image,x,y); - *(pR++) = (T)((pixel & red_mask)>>16); - *(pG++) = (T)((pixel & green_mask)>>8); - *(pB++) = (T)(pixel & blue_mask); - } - XDestroyImage(image); - } - } - if (!cimg::X11_attr().display) XCloseDisplay(dpy); - cimg_unlock_display(); - if (img.is_empty()) - throw CImgDisplayException("CImgDisplay::screenshot(): Failed to take screenshot " - "with coordinates (%d,%d)-(%d,%d).", - x0,y0,x1,y1); - } - - template - const CImgDisplay& snapshot(CImg& img) const { - if (is_empty()) { img.assign(); return *this; } - const unsigned char *ptrs = (unsigned char*)_data; - img.assign(_width,_height,1,3); - T - *data1 = img.data(0,0,0,0), - *data2 = img.data(0,0,0,1), - *data3 = img.data(0,0,0,2); - if (cimg::X11_attr().is_blue_first) cimg::swap(data1,data3); - switch (cimg::X11_attr().nb_bits) { - case 8 : { - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = *(ptrs++); - *(data1++) = (T)(val&0xe0); - *(data2++) = (T)((val&0x1c)<<3); - *(data3++) = (T)(val<<6); - } - } break; - case 16 : { - if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char - val0 = ptrs[0], - val1 = ptrs[1]; - ptrs+=2; - *(data1++) = (T)(val0&0xf8); - *(data2++) = (T)((val0<<5) | ((val1&0xe0)>>5)); - *(data3++) = (T)(val1<<3); - } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned short - val0 = ptrs[0], - val1 = ptrs[1]; - ptrs+=2; - *(data1++) = (T)(val1&0xf8); - *(data2++) = (T)((val1<<5) | ((val0&0xe0)>>5)); - *(data3++) = (T)(val0<<3); - } - } break; - default : { - if (cimg::X11_attr().byte_order) for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - ++ptrs; - *(data1++) = (T)ptrs[0]; - *(data2++) = (T)ptrs[1]; - *(data3++) = (T)ptrs[2]; - ptrs+=3; - } else for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - *(data3++) = (T)ptrs[0]; - *(data2++) = (T)ptrs[1]; - *(data1++) = (T)ptrs[2]; - ptrs+=3; - ++ptrs; - } - } - } - return *this; - } - - // Windows-based implementation. - //------------------------------- -#elif cimg_display==2 - - bool _is_mouse_tracked, _is_cursor_visible; - HANDLE _thread, _is_created, _mutex; - HWND _window, _background_window; - CLIENTCREATESTRUCT _ccs; - unsigned int *_data; - DEVMODE _curr_mode; - BITMAPINFO _bmi; - HDC _hdc; - - static int screen_width() { - DEVMODE mode; - mode.dmSize = sizeof(DEVMODE); - mode.dmDriverExtra = 0; - EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode); - return (int)mode.dmPelsWidth; - } - - static int screen_height() { - DEVMODE mode; - mode.dmSize = sizeof(DEVMODE); - mode.dmDriverExtra = 0; - EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&mode); - return (int)mode.dmPelsHeight; - } - - static void wait_all() { - WaitForSingleObject(cimg::Win32_attr().wait_event,INFINITE); - } - - static LRESULT APIENTRY _handle_events(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) { -#ifdef _WIN64 - CImgDisplay *const disp = (CImgDisplay*)GetWindowLongPtr(window,GWLP_USERDATA); -#else - CImgDisplay *const disp = (CImgDisplay*)GetWindowLong(window,GWL_USERDATA); -#endif - MSG st_msg; - switch (msg) { - case WM_CLOSE : - disp->_mouse_x = disp->_mouse_y = -1; - disp->_window_x = disp->_window_y = cimg::type::min(); - disp->set_button().set_key(0).set_key(0,false)._is_closed = true; - ReleaseMutex(disp->_mutex); - ShowWindow(disp->_window,SW_HIDE); - disp->_is_event = true; - SetEvent(cimg::Win32_attr().wait_event); - return 0; - case WM_SIZE : { - while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {} - WaitForSingleObject(disp->_mutex,INFINITE); - const unsigned int nw = LOWORD(lParam),nh = HIWORD(lParam); - if (nw && nh && (nw!=disp->_width || nh!=disp->_height)) { - disp->_window_width = nw; - disp->_window_height = nh; - disp->_mouse_x = disp->_mouse_y = -1; - disp->_is_resized = disp->_is_event = true; - SetEvent(cimg::Win32_attr().wait_event); - } - ReleaseMutex(disp->_mutex); - } break; - case WM_MOVE : { - while (PeekMessage(&st_msg,window,WM_SIZE,WM_SIZE,PM_REMOVE)) {} - WaitForSingleObject(disp->_mutex,INFINITE); - const int nx = (int)(short)(LOWORD(lParam)), ny = (int)(short)(HIWORD(lParam)); - if (nx!=disp->_window_x || ny!=disp->_window_y) { - disp->_window_x = nx; - disp->_window_y = ny; - disp->_is_moved = disp->_is_event = true; - SetEvent(cimg::Win32_attr().wait_event); - } - ReleaseMutex(disp->_mutex); - } break; - case WM_PAINT : - disp->paint(); - cimg_lock_display(); - if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE_WIN)>=0); - cimg_unlock_display(); - break; - case WM_ERASEBKGND : - // return 0; - break; - case WM_KEYDOWN : - disp->set_key((unsigned int)wParam); - SetEvent(cimg::Win32_attr().wait_event); - break; - case WM_KEYUP : - disp->set_key((unsigned int)wParam,false); - SetEvent(cimg::Win32_attr().wait_event); - break; - case WM_MOUSEMOVE : { - while (PeekMessage(&st_msg,window,WM_MOUSEMOVE,WM_MOUSEMOVE,PM_REMOVE)) {} - disp->_mouse_x = LOWORD(lParam); - disp->_mouse_y = HIWORD(lParam); -#if (_WIN32_WINNT>=0x0400) && !defined(NOTRACKMOUSEEVENT) - if (!disp->_is_mouse_tracked) { - TRACKMOUSEEVENT tme; - tme.cbSize = sizeof(TRACKMOUSEEVENT); - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = disp->_window; - if (TrackMouseEvent(&tme)) disp->_is_mouse_tracked = true; - } -#endif - if (disp->_mouse_x<0 || disp->_mouse_y<0 || disp->_mouse_x>=disp->width() || disp->_mouse_y>=disp->height()) - disp->_mouse_x = disp->_mouse_y = -1; - disp->_is_event = true; - SetEvent(cimg::Win32_attr().wait_event); - cimg_lock_display(); - if (disp->_is_cursor_visible) while (ShowCursor(TRUE)<0); else while (ShowCursor(FALSE_WIN)>=0); - cimg_unlock_display(); - } break; - case WM_MOUSELEAVE : { - disp->_mouse_x = disp->_mouse_y = -1; - disp->_is_mouse_tracked = false; - cimg_lock_display(); - while (ShowCursor(TRUE)<0) {} - cimg_unlock_display(); - } break; - case WM_LBUTTONDOWN : - disp->set_button(1); - SetEvent(cimg::Win32_attr().wait_event); - break; - case WM_RBUTTONDOWN : - disp->set_button(2); - SetEvent(cimg::Win32_attr().wait_event); - break; - case WM_MBUTTONDOWN : - disp->set_button(3); - SetEvent(cimg::Win32_attr().wait_event); - break; - case WM_LBUTTONUP : - disp->set_button(1,false); - SetEvent(cimg::Win32_attr().wait_event); - break; - case WM_RBUTTONUP : - disp->set_button(2,false); - SetEvent(cimg::Win32_attr().wait_event); - break; - case WM_MBUTTONUP : - disp->set_button(3,false); - SetEvent(cimg::Win32_attr().wait_event); - break; - case 0x020A : // WM_MOUSEWHEEL: - disp->set_wheel((int)((short)HIWORD(wParam))/120); - SetEvent(cimg::Win32_attr().wait_event); - } - return DefWindowProc(window,msg,wParam,lParam); - } - - static DWORD WINAPI _events_thread(void* arg) { - CImgDisplay *const disp = (CImgDisplay*)(((void**)arg)[0]); - const char *const title = (const char*)(((void**)arg)[1]); - MSG msg; - delete[] (void**)arg; - disp->_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - disp->_bmi.bmiHeader.biWidth = disp->width(); - disp->_bmi.bmiHeader.biHeight = -disp->height(); - disp->_bmi.bmiHeader.biPlanes = 1; - disp->_bmi.bmiHeader.biBitCount = 32; - disp->_bmi.bmiHeader.biCompression = BI_RGB; - disp->_bmi.bmiHeader.biSizeImage = 0; - disp->_bmi.bmiHeader.biXPelsPerMeter = 1; - disp->_bmi.bmiHeader.biYPelsPerMeter = 1; - disp->_bmi.bmiHeader.biClrUsed = 0; - disp->_bmi.bmiHeader.biClrImportant = 0; - disp->_data = new unsigned int[(size_t)disp->_width*disp->_height]; - if (!disp->_is_fullscreen) { // Normal window - RECT rect; - rect.left = rect.top = 0; rect.right = (LONG)disp->_width - 1; rect.bottom = (LONG)disp->_height - 1; - AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); - const int - border1 = (int)((rect.right - rect.left + 1 - disp->_width)/2), - border2 = (int)(rect.bottom - rect.top + 1 - disp->_height - border1), - ww = disp->width() + 2*border1, - wh = disp->height() + border1 + border2, - sw = CImgDisplay::screen_width(), - sh = CImgDisplay::screen_height(); - int - wx = (int)cimg::round(cimg::rand(0,sw - ww -1)), - wy = (int)cimg::round(cimg::rand(64,sh - wh - 65)); - if (wx + ww>=sw) wx = sw - ww; - if (wy + wh>=sh) wy = sh - wh; - if (wx<0) wx = 0; - if (wy<0) wy = 0; - disp->_window = CreateWindowA("MDICLIENT",title?title:" ", - (DWORD)(WS_OVERLAPPEDWINDOW | (disp->_is_closed?0:WS_VISIBLE)), - wx,wy,ww,wh,0,0,0,&(disp->_ccs)); - if (!disp->_is_closed) { - GetWindowRect(disp->_window,&rect); - disp->_window_x = rect.left; - disp->_window_y = rect.top; - } else disp->_window_x = disp->_window_y = cimg::type::min(); - } else { // Fullscreen window - const unsigned int - sx = (unsigned int)screen_width(), - sy = (unsigned int)screen_height(); - disp->_window = CreateWindowA("MDICLIENT",title?title:" ", - (DWORD)(WS_POPUP | (disp->_is_closed?0:WS_VISIBLE)), - (int)(sx - disp->_width)/2, - (int)(sy - disp->_height)/2, - disp->width(),disp->height(),0,0,0,&(disp->_ccs)); - disp->_window_x = disp->_window_y = 0; - } - SetForegroundWindow(disp->_window); - disp->_hdc = GetDC(disp->_window); - disp->_window_width = disp->_width; - disp->_window_height = disp->_height; - disp->flush(); -#ifdef _WIN64 - SetWindowLongPtr(disp->_window,GWLP_USERDATA,(LONG_PTR)disp); - SetWindowLongPtr(disp->_window,GWLP_WNDPROC,(LONG_PTR)_handle_events); -#else - SetWindowLong(disp->_window,GWL_USERDATA,(LONG)disp); - SetWindowLong(disp->_window,GWL_WNDPROC,(LONG)_handle_events); -#endif - SetEvent(disp->_is_created); - while (GetMessage(&msg,0,0,0)) DispatchMessage(&msg); - return 0; - } - - CImgDisplay& _update_window_pos() { - if (_is_closed) _window_x = _window_y = cimg::type::min(); - else { - RECT rect; - rect.left = rect.top = 0; rect.right = (LONG)_width - 1; rect.bottom = (LONG)_height - 1; - AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); - GetWindowRect(_window,&rect); - _window_x = rect.left; - _window_y = rect.top; - } - return *this; - } - - void _init_fullscreen() { - _background_window = 0; - if (!_is_fullscreen || _is_closed) _curr_mode.dmSize = 0; - else { -/* DEVMODE mode; - unsigned int imode = 0, ibest = 0, bestbpp = 0, bw = ~0U, bh = ~0U; - for (mode.dmSize = sizeof(DEVMODE), mode.dmDriverExtra = 0; EnumDisplaySettings(0,imode,&mode); ++imode) { - const unsigned int nw = mode.dmPelsWidth, nh = mode.dmPelsHeight; - if (nw>=_width && nh>=_height && mode.dmBitsPerPel>=bestbpp && nw<=bw && nh<=bh) { - bestbpp = mode.dmBitsPerPel; - ibest = imode; - bw = nw; bh = nh; - } - } - if (bestbpp) { - _curr_mode.dmSize = sizeof(DEVMODE); _curr_mode.dmDriverExtra = 0; - EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&_curr_mode); - EnumDisplaySettings(0,ibest,&mode); - ChangeDisplaySettings(&mode,0); - } else _curr_mode.dmSize = 0; -*/ - _curr_mode.dmSize = 0; - const unsigned int - sx = (unsigned int)screen_width(), - sy = (unsigned int)screen_height(); - if (sx!=_width || sy!=_height) { - CLIENTCREATESTRUCT background_ccs = { 0,0 }; - _background_window = CreateWindowA("MDICLIENT","",WS_POPUP | WS_VISIBLE, - 0,0,(int)sx,(int)sy,0,0,0,&background_ccs); - SetForegroundWindow(_background_window); - } - } - } - - void _desinit_fullscreen() { - if (!_is_fullscreen) return; - if (_background_window) DestroyWindow(_background_window); - _background_window = 0; - if (_curr_mode.dmSize) ChangeDisplaySettings(&_curr_mode,0); - _is_fullscreen = false; - } - - CImgDisplay& _assign(const unsigned int dimw, const unsigned int dimh, const char *const ptitle=0, - const unsigned int normalization_type=3, - const bool fullscreen_flag=false, const bool closed_flag=false) { - - // Allocate space for window title - const char *const nptitle = ptitle?ptitle:""; - const unsigned int s = (unsigned int)std::strlen(nptitle) + 1; - char *const tmp_title = s?new char[s]:0; - if (s) std::memcpy(tmp_title,nptitle,s*sizeof(char)); - - // Destroy previous window if existing - if (!is_empty()) assign(); - - // Set display variables - _width = std::min(dimw,(unsigned int)screen_width()); - _height = std::min(dimh,(unsigned int)screen_height()); - _normalization = normalization_type<4?normalization_type:3; - _is_fullscreen = fullscreen_flag; - _window_x = _window_y = cimg::type::min(); - _is_closed = closed_flag; - _is_cursor_visible = true; - _is_mouse_tracked = false; - _title = tmp_title; - flush(); - if (_is_fullscreen) _init_fullscreen(); - - // Create event thread - void *const arg = (void*)(new void*[2]); - ((void**)arg)[0] = (void*)this; - ((void**)arg)[1] = (void*)_title; - _mutex = CreateMutex(0,FALSE_WIN,0); - _is_created = CreateEvent(0,FALSE_WIN,FALSE_WIN,0); - _thread = CreateThread(0,0,_events_thread,arg,0,0); - WaitForSingleObject(_is_created,INFINITE); - return *this; - } - - CImgDisplay& assign() { - if (is_empty()) return flush(); - DestroyWindow(_window); - TerminateThread(_thread,0); - delete[] _data; - delete[] _title; - _data = 0; - _title = 0; - if (_is_fullscreen) _desinit_fullscreen(); - _width = _height = _normalization = _window_width = _window_height = 0; - _window_x = _window_y = cimg::type::min(); - _is_fullscreen = false; - _is_closed = true; - _min = _max = 0; - _title = 0; - flush(); - return *this; - } - - CImgDisplay& assign(const unsigned int dimw, const unsigned int dimh, const char *const title=0, - const unsigned int normalization_type=3, - const bool fullscreen_flag=false, const bool closed_flag=false) { - if (!dimw || !dimh) return assign(); - _assign(dimw,dimh,title,normalization_type,fullscreen_flag,closed_flag); - _min = _max = 0; - std::memset(_data,0,sizeof(unsigned int)*_width*_height); - return paint(); - } - - template - CImgDisplay& assign(const CImg& img, const char *const title=0, - const unsigned int normalization_type=3, - const bool fullscreen_flag=false, const bool closed_flag=false) { - if (!img) return assign(); - CImg tmp; - const CImg& nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2, - (img._height - 1)/2, - (img._depth - 1)/2)); - _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); - if (_normalization==2) _min = (float)nimg.min_max(_max); - return display(nimg); - } - - template - CImgDisplay& assign(const CImgList& list, const char *const title=0, - const unsigned int normalization_type=3, - const bool fullscreen_flag=false, const bool closed_flag=false) { - if (!list) return assign(); - CImg tmp; - const CImg img = list>'x', &nimg = (img._depth==1)?img:(tmp=img.get_projections2d((img._width - 1)/2, - (img._height - 1)/2, - (img._depth - 1)/2)); - _assign(nimg._width,nimg._height,title,normalization_type,fullscreen_flag,closed_flag); - if (_normalization==2) _min = (float)nimg.min_max(_max); - return display(nimg); - } - - CImgDisplay& assign(const CImgDisplay& disp) { - if (!disp) return assign(); - _assign(disp._width,disp._height,disp._title,disp._normalization,disp._is_fullscreen,disp._is_closed); - std::memcpy(_data,disp._data,sizeof(unsigned int)*_width*_height); - return paint(); - } - - CImgDisplay& resize(const int nwidth, const int nheight, const bool force_redraw=true) { - if (!nwidth || !nheight || (is_empty() && (nwidth<0 || nheight<0))) return assign(); - if (is_empty()) return assign((unsigned int)nwidth,(unsigned int)nheight); - const unsigned int - tmpdimx = (nwidth>0)?nwidth:(-nwidth*_width/100), - tmpdimy = (nheight>0)?nheight:(-nheight*_height/100), - dimx = tmpdimx?tmpdimx:1, - dimy = tmpdimy?tmpdimy:1; - if (_width!=dimx || _height!=dimy || _window_width!=dimx || _window_height!=dimy) { - if (_window_width!=dimx || _window_height!=dimy) { - RECT rect; rect.left = rect.top = 0; rect.right = (LONG)dimx - 1; rect.bottom = (LONG)dimy - 1; - AdjustWindowRect(&rect,WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,false); - const int cwidth = rect.right - rect.left + 1, cheight = rect.bottom - rect.top + 1; - SetWindowPos(_window,0,0,0,cwidth,cheight,SWP_NOMOVE | SWP_NOZORDER | SWP_NOCOPYBITS); - } - if (_width!=dimx || _height!=dimy) { - unsigned int *const ndata = new unsigned int[dimx*dimy]; - if (force_redraw) _render_resize(_data,_width,_height,ndata,dimx,dimy); - else std::memset(ndata,0x80,sizeof(unsigned int)*dimx*dimy); - delete[] _data; - _data = ndata; - _bmi.bmiHeader.biWidth = (LONG)dimx; - _bmi.bmiHeader.biHeight = -(int)dimy; - _width = dimx; - _height = dimy; - } - _window_width = dimx; _window_height = dimy; - show(); - } - _is_resized = false; - if (_is_fullscreen) move((screen_width() - width())/2,(screen_height() - height())/2); - if (force_redraw) return paint(); - return *this; - } - - CImgDisplay& toggle_fullscreen(const bool force_redraw=true) { - if (is_empty()) return *this; - if (force_redraw) { - const cimg_ulong buf_size = (cimg_ulong)_width*_height*4; - void *odata = std::malloc(buf_size); - if (odata) { - std::memcpy(odata,_data,buf_size); - assign(_width,_height,_title,_normalization,!_is_fullscreen,false); - std::memcpy(_data,odata,buf_size); - std::free(odata); - } - return paint(); - } - return assign(_width,_height,_title,_normalization,!_is_fullscreen,false); - } - - CImgDisplay& show() { - if (is_empty() || !_is_closed) return *this; - _is_closed = false; - if (_is_fullscreen) _init_fullscreen(); - ShowWindow(_window,SW_SHOW); - _update_window_pos(); - return paint(); - } - - CImgDisplay& close() { - if (is_empty() || _is_closed) return *this; - _is_closed = true; - if (_is_fullscreen) _desinit_fullscreen(); - ShowWindow(_window,SW_HIDE); - _window_x = _window_y = cimg::type::min(); - return *this; - } - - CImgDisplay& move(const int posx, const int posy) { - if (is_empty()) return *this; - if (_window_x!=posx || _window_y!=posy) { - SetWindowPos(_window,0,posx,posy,0,0,SWP_NOSIZE | SWP_NOZORDER); - _window_x = posx; - _window_y = posy; - } - show(); - _is_moved = false; - return *this; - } - - CImgDisplay& show_mouse() { - if (is_empty()) return *this; - _is_cursor_visible = true; - return *this; - } - - CImgDisplay& hide_mouse() { - if (is_empty()) return *this; - _is_cursor_visible = false; - return *this; - } - - CImgDisplay& set_mouse(const int posx, const int posy) { - if (is_empty() || _is_closed || posx<0 || posy<0) return *this; - if (!_is_closed) { - _update_window_pos(); - const int res = (int)SetCursorPos(_window_x + posx,_window_y + posy); - if (res) { _mouse_x = posx; _mouse_y = posy; } - } - return *this; - } - - CImgDisplay& set_title(const char *const format, ...) { - if (is_empty()) return *this; - char *const tmp = new char[1024]; - va_list ap; - va_start(ap, format); - cimg_vsnprintf(tmp,1024,format,ap); - va_end(ap); - if (!std::strcmp(_title,tmp)) { delete[] tmp; return *this; } - delete[] _title; - const unsigned int s = (unsigned int)std::strlen(tmp) + 1; - _title = new char[s]; - std::memcpy(_title,tmp,s*sizeof(char)); - SetWindowTextA(_window, tmp); - delete[] tmp; - return *this; - } - - template - CImgDisplay& display(const CImg& img) { - if (!img) - throw CImgArgumentException(_cimgdisplay_instance - "display(): Empty specified image.", - cimgdisplay_instance); - if (is_empty()) return assign(img); - return render(img).paint(); - } - - CImgDisplay& paint() { - if (_is_closed) return *this; - WaitForSingleObject(_mutex,INFINITE); - SetDIBitsToDevice(_hdc,0,0,_width,_height,0,0,0,_height,_data,&_bmi,DIB_RGB_COLORS); - ReleaseMutex(_mutex); - return *this; - } - - template - CImgDisplay& render(const CImg& img) { - if (!img) - throw CImgArgumentException(_cimgdisplay_instance - "render(): Empty specified image.", - cimgdisplay_instance); - - if (is_empty()) return *this; - if (img._depth!=1) return render(img.get_projections2d((img._width - 1)/2,(img._height - 1)/2, - (img._depth - 1)/2)); - - const T - *data1 = img._data, - *data2 = (img._spectrum>=2)?img.data(0,0,0,1):data1, - *data3 = (img._spectrum>=3)?img.data(0,0,0,2):data1; - - WaitForSingleObject(_mutex,INFINITE); - unsigned int - *const ndata = (img._width==_width && img._height==_height)?_data: - new unsigned int[(size_t)img._width*img._height], - *ptrd = ndata; - - if (!_normalization || (_normalization==3 && cimg::type::string()==cimg::type::string())) { - _min = _max = 0; - switch (img._spectrum) { - case 1 : { - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)*(data1++); - *(ptrd++) = (unsigned int)((val<<16) | (val<<8) | val); - } - } break; - case 2 : { - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char - R = (unsigned char)*(data1++), - G = (unsigned char)*(data2++); - *(ptrd++) = (unsigned int)((R<<16) | (G<<8)); - } - } break; - default : { - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char - R = (unsigned char)*(data1++), - G = (unsigned char)*(data2++), - B = (unsigned char)*(data3++); - *(ptrd++) = (unsigned int)((R<<16) | (G<<8) | B); - } - } - } - } else { - if (_normalization==3) { - if (cimg::type::is_float()) _min = (float)img.min_max(_max); - else { - _min = (float)cimg::type::min(); - _max = (float)cimg::type::max(); - } - } else if ((_min>_max) || _normalization==1) _min = (float)img.min_max(_max); - const float delta = _max - _min, mm = 255/(delta?delta:1.f); - switch (img._spectrum) { - case 1 : { - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char val = (unsigned char)((*(data1++) - _min)*mm); - *(ptrd++) = (unsigned int)((val<<16) | (val<<8) | val); - } - } break; - case 2 : { - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char - R = (unsigned char)((*(data1++) - _min)*mm), - G = (unsigned char)((*(data2++) - _min)*mm); - *(ptrd++) = (unsigned int)((R<<16) | (G<<8)); - } - } break; - default : { - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned char - R = (unsigned char)((*(data1++) - _min)*mm), - G = (unsigned char)((*(data2++) - _min)*mm), - B = (unsigned char)((*(data3++) - _min)*mm); - *(ptrd++) = (unsigned int)((R<<16) | (G<<8) | B); - } - } - } - } - if (ndata!=_data) { _render_resize(ndata,img._width,img._height,_data,_width,_height); delete[] ndata; } - ReleaseMutex(_mutex); - return *this; - } - - template - static void screenshot(const int x0, const int y0, const int x1, const int y1, CImg& img) { - img.assign(); - HDC hScreen = GetDC(GetDesktopWindow()); - if (hScreen) { - const int - width = GetDeviceCaps(hScreen,HORZRES), - height = GetDeviceCaps(hScreen,VERTRES); - int _x0 = x0, _y0 = y0, _x1 = x1, _y1 = y1; - if (_x0>_x1) cimg::swap(_x0,_x1); - if (_y0>_y1) cimg::swap(_y0,_y1); - if (_x1>=0 && _x0=0 && _y0 - const CImgDisplay& snapshot(CImg& img) const { - if (is_empty()) { img.assign(); return *this; } - const unsigned int *ptrs = _data; - img.assign(_width,_height,1,3); - T - *data1 = img.data(0,0,0,0), - *data2 = img.data(0,0,0,1), - *data3 = img.data(0,0,0,2); - for (cimg_ulong xy = (cimg_ulong)img._width*img._height; xy>0; --xy) { - const unsigned int val = *(ptrs++); - *(data1++) = (T)(unsigned char)(val>>16); - *(data2++) = (T)(unsigned char)((val>>8)&0xFF); - *(data3++) = (T)(unsigned char)(val&0xFF); - } - return *this; - } -#endif - - //@} - }; // struct CImgDisplay { ... - - /* - #-------------------------------------- - # - # - # - # Definition of the CImg structure - # - # - # - #-------------------------------------- - */ - - //! Class representing an image (up to 4 dimensions wide), each pixel being of type \c T. - /** - This is the main class of the %CImg Library. It declares and constructs - an image, allows access to its pixel values, and is able to perform various image operations. - - \par Image representation - - A %CImg image is defined as an instance of the container \c CImg, which contains a regular grid of pixels, - each pixel value being of type \c T. The image grid can have up to 4 dimensions: width, height, depth - and number of channels. - Usually, the three first dimensions are used to describe spatial coordinates (x,y,z), - while the number of channels is rather used as a vector-valued dimension - (it may describe the R,G,B color channels for instance). - If you need a fifth dimension, you can use image lists \c CImgList rather than simple images \c CImg. - - Thus, the \c CImg class is able to represent volumetric images of vector-valued pixels, - as well as images with less dimensions (1D scalar signal, 2D color images, ...). - Most member functions of the class CImg<\c T> are designed to handle this maximum case of (3+1) dimensions. - - Concerning the pixel value type \c T: - fully supported template types are the basic C++ types: unsigned char, char, short, unsigned int, int, - unsigned long, long, float, double, ... . - Typically, fast image display can be done using CImg images, - while complex image processing algorithms may be rather coded using CImg or CImg - images that have floating-point pixel values. The default value for the template T is \c float. - Using your own template types may be possible. However, you will certainly have to define the complete set - of arithmetic and logical operators for your class. - - \par Image structure - - The \c CImg structure contains \e six fields: - - \c _width defines the number of \a columns of the image (size along the X-axis). - - \c _height defines the number of \a rows of the image (size along the Y-axis). - - \c _depth defines the number of \a slices of the image (size along the Z-axis). - - \c _spectrum defines the number of \a channels of the image (size along the C-axis). - - \c _data defines a \a pointer to the \a pixel \a data (of type \c T). - - \c _is_shared is a boolean that tells if the memory buffer \c data is shared with - another image. - - You can access these fields publicly although it is recommended to use the dedicated functions - width(), height(), depth(), spectrum() and ptr() to do so. - Image dimensions are not limited to a specific range (as long as you got enough available memory). - A value of \e 1 usually means that the corresponding dimension is \a flat. - If one of the dimensions is \e 0, or if the data pointer is null, the image is considered as \e empty. - Empty images should not contain any pixel data and thus, will not be processed by CImg member functions - (a CImgInstanceException will be thrown instead). - Pixel data are stored in memory, in a non interlaced mode (See \ref cimg_storage). - - \par Image declaration and construction - - Declaring an image can be done by using one of the several available constructors. - Here is a list of the most used: - - - Construct images from arbitrary dimensions: - - CImg img; declares an empty image. - - CImg img(128,128); declares a 128x128 greyscale image with - \c unsigned \c char pixel values. - - CImg img(3,3); declares a 3x3 matrix with \c double coefficients. - - CImg img(256,256,1,3); declares a 256x256x1x3 (color) image - (colors are stored as an image with three channels). - - CImg img(128,128,128); declares a 128x128x128 volumetric and greyscale image - (with \c double pixel values). - - CImg<> img(128,128,128,3); declares a 128x128x128 volumetric color image - (with \c float pixels, which is the default value of the template parameter \c T). - - \b Note: images pixels are not automatically initialized to 0. You may use the function \c fill() to - do it, or use the specific constructor taking 5 parameters like this: - CImg<> img(128,128,128,3,0); declares a 128x128x128 volumetric color image with all pixel values to 0. - - - Construct images from filenames: - - CImg img("image.jpg"); reads a JPEG color image from the file "image.jpg". - - CImg img("analyze.hdr"); reads a volumetric image (ANALYZE7.5 format) from the - file "analyze.hdr". - - \b Note: You need to install ImageMagick - to be able to read common compressed image formats (JPG,PNG, ...) (See \ref cimg_files_io). - - - Construct images from C-style arrays: - - CImg img(data_buffer,256,256); constructs a 256x256 greyscale image from a \c int* buffer - \c data_buffer (of size 256x256=65536). - - CImg img(data_buffer,256,256,1,3); constructs a 256x256 color image - from a \c unsigned \c char* buffer \c data_buffer (where R,G,B channels follow each others). - - The complete list of constructors can be found here. - - \par Most useful functions - - The \c CImg class contains a lot of functions that operates on images. - Some of the most useful are: - - - operator()(): Read or write pixel values. - - display(): displays the image in a new window. - **/ - template - struct CImg { - - unsigned int _width, _height, _depth, _spectrum; - bool _is_shared; - T *_data; - - //! Simple iterator type, to loop through each pixel value of an image instance. - /** - \note - - The \c CImg::iterator type is defined to be a T*. - - You will seldom have to use iterators in %CImg, most classical operations - being achieved (often in a faster way) using methods of \c CImg. - \par Example - \code - CImg img("reference.jpg"); // Load image from file - // Set all pixels to '0', with a CImg iterator. - for (CImg::iterator it = img.begin(), it::const_iterator type is defined to be a \c const \c T*. - - You will seldom have to use iterators in %CImg, most classical operations - being achieved (often in a faster way) using methods of \c CImg. - \par Example - \code - const CImg img("reference.jpg"); // Load image from file - float sum = 0; - // Compute sum of all pixel values, with a CImg iterator. - for (CImg::iterator it = img.begin(), it::value_type type of a \c CImg is defined to be a \c T. - - \c CImg::value_type is actually not used in %CImg methods. It has been mainly defined for - compatibility with STL naming conventions. - **/ - typedef T value_type; - - // Define common types related to template type T. - typedef typename cimg::superset::type Tbool; - typedef typename cimg::superset::type Tuchar; - typedef typename cimg::superset::type Tchar; - typedef typename cimg::superset::type Tushort; - typedef typename cimg::superset::type Tshort; - typedef typename cimg::superset::type Tuint; - typedef typename cimg::superset::type Tint; - typedef typename cimg::superset::type Tulong; - typedef typename cimg::superset::type Tlong; - typedef typename cimg::superset::type Tfloat; - typedef typename cimg::superset::type Tdouble; - typedef typename cimg::last::type boolT; - typedef typename cimg::last::type ucharT; - typedef typename cimg::last::type charT; - typedef typename cimg::last::type ushortT; - typedef typename cimg::last::type shortT; - typedef typename cimg::last::type uintT; - typedef typename cimg::last::type intT; - typedef typename cimg::last::type ulongT; - typedef typename cimg::last::type longT; - typedef typename cimg::last::type uint64T; - typedef typename cimg::last::type int64T; - typedef typename cimg::last::type floatT; - typedef typename cimg::last::type doubleT; - - // Return 'dx*dy*dz*dc' as a 'size_t' and check no overflow occurs. - static size_t safe_size(const unsigned int dx, const unsigned int dy, - const unsigned int dz, const unsigned int dc) { - if (!(dx && dy && dz && dc)) return 0; - size_t siz = (size_t)dx, osiz = siz; - if ((dy==1 || (siz*=dy)>osiz) && - ((osiz = siz), dz==1 || (siz*=dz)>osiz) && - ((osiz = siz), dc==1 || (siz*=dc)>osiz) && - ((osiz = siz), sizeof(T)==1 || (siz*sizeof(T))>osiz)) { - if (siz > cimg_max_buf_size){ - throw CImgArgumentException("CImg<%s>::safe_size(): Specified size (%u,%u,%u,%u) exceeds maximum " - "allowed buffer size of %lu ", - pixel_type(),dx,dy,dz,dc,cimg_max_buf_size); - } - return siz; - } - throw CImgArgumentException("CImg<%s>::safe_size(): Specified size (%u,%u,%u,%u) overflows 'size_t'.", - pixel_type(),dx,dy,dz,dc); - } - - //@} - //--------------------------- - // - //! \name Plugins - //@{ - //--------------------------- -#ifdef cimg_plugin -#include cimg_plugin -#endif -#ifdef cimg_plugin1 -#include cimg_plugin1 -#endif -#ifdef cimg_plugin2 -#include cimg_plugin2 -#endif -#ifdef cimg_plugin3 -#include cimg_plugin3 -#endif -#ifdef cimg_plugin4 -#include cimg_plugin4 -#endif -#ifdef cimg_plugin5 -#include cimg_plugin5 -#endif -#ifdef cimg_plugin6 -#include cimg_plugin6 -#endif -#ifdef cimg_plugin7 -#include cimg_plugin7 -#endif -#ifdef cimg_plugin8 -#include cimg_plugin8 -#endif - - //@} - //--------------------------------------------------------- - // - //! \name Constructors / Destructor / Instance Management - //@{ - //--------------------------------------------------------- - - //! Destroy image. - /** - \note - - The pixel buffer data() is deallocated if necessary, e.g. for non-empty and non-shared image instances. - - Destroying an empty or shared image does nothing actually. - \warning - - When destroying a non-shared image, make sure that you will \e not operate on a remaining shared image - that shares its buffer with the destroyed instance, in order to avoid further invalid memory access - (to a deallocated buffer). - **/ - ~CImg() { - if (!_is_shared) delete[] _data; - } - - //! Construct empty image. - /** - \note - - An empty image has no pixel data and all of its dimensions width(), height(), depth(), spectrum() - are set to \c 0, as well as its pixel buffer pointer data(). - - An empty image may be re-assigned afterwards, e.g. with the family of - assign(unsigned int,unsigned int,unsigned int,unsigned int) methods, - or by operator=(const CImg&). In all cases, the type of pixels stays \c T. - - An empty image is never shared. - \par Example - \code - CImg img1, img2; // Construct two empty images - img1.assign(256,256,1,3); // Re-assign 'img1' to be a 256x256x1x3 (color) image - img2 = img1.get_rand(0,255); // Re-assign 'img2' to be a random-valued version of 'img1' - img2.assign(); // Re-assign 'img2' to be an empty image again - \endcode - **/ - CImg():_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) {} - - //! Construct image with specified size. - /** - \param size_x Image width(). - \param size_y Image height(). - \param size_z Image depth(). - \param size_c Image spectrum() (number of channels). - \note - - It is able to create only \e non-shared images, and allocates thus a pixel buffer data() - for each constructed image instance. - - Setting one dimension \c size_x,\c size_y,\c size_z or \c size_c to \c 0 leads to the construction of - an \e empty image. - - A \c CImgInstanceException is thrown when the pixel buffer cannot be allocated - (e.g. when requested size is too big for available memory). - \warning - - The allocated pixel buffer is \e not filled with a default value, and is likely to contain garbage values. - In order to initialize pixel values during construction (e.g. with \c 0), use constructor - CImg(unsigned int,unsigned int,unsigned int,unsigned int,T) instead. - \par Example - \code - CImg img1(256,256,1,3); // Construct a 256x256x1x3 (color) image, filled with garbage values - CImg img2(256,256,1,3,0); // Construct a 256x256x1x3 (color) image, filled with value '0' - \endcode - **/ - explicit CImg(const unsigned int size_x, const unsigned int size_y=1, - const unsigned int size_z=1, const unsigned int size_c=1): - _is_shared(false) { - const size_t siz = safe_size(size_x,size_y,size_z,size_c); - if (siz) { - _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; - try { _data = new T[siz]; } catch (...) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgInstanceException(_cimg_instance - "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", - cimg_instance, - cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), - size_x,size_y,size_z,size_c); - } - } else { _width = _height = _depth = _spectrum = 0; _data = 0; } - } - - //! Construct image with specified size and initialize pixel values. - /** - \param size_x Image width(). - \param size_y Image height(). - \param size_z Image depth(). - \param size_c Image spectrum() (number of channels). - \param value Initialization value. - \note - - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), - but it also fills the pixel buffer with the specified \c value. - \warning - - It cannot be used to construct a vector-valued image and initialize it with \e vector-valued pixels - (e.g. RGB vector, for color images). - For this task, you may use fillC() after construction. - **/ - CImg(const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c, const T& value): - _is_shared(false) { - const size_t siz = safe_size(size_x,size_y,size_z,size_c); - if (siz) { - _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; - try { _data = new T[siz]; } catch (...) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgInstanceException(_cimg_instance - "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", - cimg_instance, - cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), - size_x,size_y,size_z,size_c); - } - fill(value); - } else { _width = _height = _depth = _spectrum = 0; _data = 0; } - } - - //! Construct image with specified size and initialize pixel values from a sequence of integers. - /** - Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, - with pixels of type \c T, and initialize pixel - values from the specified sequence of integers \c value0,\c value1,\c ... - \param size_x Image width(). - \param size_y Image height(). - \param size_z Image depth(). - \param size_c Image spectrum() (number of channels). - \param value0 First value of the initialization sequence (must be an \e integer). - \param value1 Second value of the initialization sequence (must be an \e integer). - \param ... - \note - - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it also fills - the pixel buffer with a sequence of specified integer values. - \warning - - You must specify \e exactly \c size_x*\c size_y*\c size_z*\c size_c integers in the initialization sequence. - Otherwise, the constructor may crash or fill your image pixels with garbage. - \par Example - \code - const CImg img(2,2,1,3, // Construct a 2x2 color (RGB) image - 0,255,0,255, // Set the 4 values for the red component - 0,0,255,255, // Set the 4 values for the green component - 64,64,64,64); // Set the 4 values for the blue component - img.resize(150,150).display(); - \endcode - \image html ref_constructor1.jpg - **/ - CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, - const int value0, const int value1, ...): - _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { -#define _CImg_stdarg(img,a0,a1,N,t) { \ - size_t _siz = (size_t)N; \ - if (_siz--) { \ - va_list ap; \ - va_start(ap,a1); \ - T *ptrd = (img)._data; \ - *(ptrd++) = (T)a0; \ - if (_siz--) { \ - *(ptrd++) = (T)a1; \ - for ( ; _siz; --_siz) *(ptrd++) = (T)va_arg(ap,t); \ - } \ - va_end(ap); \ - } \ - } - assign(size_x,size_y,size_z,size_c); - _CImg_stdarg(*this,value0,value1,safe_size(size_x,size_y,size_z,size_c),int); - } - -#if cimg_use_cpp11==1 - //! Construct image with specified size and initialize pixel values from an initializer list of integers. - /** - Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, - with pixels of type \c T, and initialize pixel - values from the specified initializer list of integers { \c value0,\c value1,\c ... } - \param size_x Image width(). - \param size_y Image height(). - \param size_z Image depth(). - \param size_c Image spectrum() (number of channels). - \param { value0, value1, ... } Initialization list - \param repeat_values Tells if the value filling process is repeated over the image. - - \note - - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it also fills - the pixel buffer with a sequence of specified integer values. - \par Example - \code - const CImg img(2,2,1,3, // Construct a 2x2 color (RGB) image - { 0,255,0,255, // Set the 4 values for the red component - 0,0,255,255, // Set the 4 values for the green component - 64,64,64,64 }); // Set the 4 values for the blue component - img.resize(150,150).display(); - \endcode - \image html ref_constructor1.jpg - **/ - template - CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, - const std::initializer_list values, - const bool repeat_values=true): - _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { -#define _cimg_constructor_cpp11(repeat_values) \ - auto it = values.begin(); \ - size_t siz = size(); \ - if (repeat_values) for (T *ptrd = _data; siz--; ) { \ - *(ptrd++) = (T)(*(it++)); if (it==values.end()) it = values.begin(); } \ - else { siz = std::min(siz,values.size()); for (T *ptrd = _data; siz--; ) *(ptrd++) = (T)(*(it++)); } - assign(size_x,size_y,size_z,size_c); - _cimg_constructor_cpp11(repeat_values); - } - - template - CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, - std::initializer_list values, - const bool repeat_values=true): - _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { - assign(size_x,size_y,size_z); - _cimg_constructor_cpp11(repeat_values); - } - - template - CImg(const unsigned int size_x, const unsigned int size_y, - std::initializer_list values, - const bool repeat_values=true): - _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { - assign(size_x,size_y); - _cimg_constructor_cpp11(repeat_values); - } - - template - CImg(const unsigned int size_x, - std::initializer_list values, - const bool repeat_values=true):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { - assign(size_x); - _cimg_constructor_cpp11(repeat_values); - } - - //! Construct single channel 1D image with pixel values and width obtained from an initializer list of integers. - /** - Construct a new image instance of size \c width x \c 1 x \c 1 x \c 1, - with pixels of type \c T, and initialize pixel - values from the specified initializer list of integers { \c value0,\c value1,\c ... }. Image width is - given by the size of the initializer list. - \param { value0, value1, ... } Initialization list - \note - - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int) with height=1, depth=1, and spectrum=1, - but it also fills the pixel buffer with a sequence of specified integer values. - \par Example - \code - const CImg img = {10,20,30,20,10 }; // Construct a 5x1 image with one channel, and set its pixel values - img.resize(150,150).display(); - \endcode - \image html ref_constructor1.jpg - **/ - template - CImg(const std::initializer_list values): - _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { - assign(values.size(),1,1,1); - auto it = values.begin(); - unsigned int siz = _width; - for (T *ptrd = _data; siz--; ) *(ptrd++) = (T)(*(it++)); - } - - template - CImg& operator=(std::initializer_list values) { - _cimg_constructor_cpp11(siz>values.size()); - return *this; - } -#endif - - //! Construct image with specified size and initialize pixel values from a sequence of doubles. - /** - Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, - and initialize pixel values from the specified sequence of doubles \c value0,\c value1,\c ... - \param size_x Image width(). - \param size_y Image height(). - \param size_z Image depth(). - \param size_c Image spectrum() (number of channels). - \param value0 First value of the initialization sequence (must be a \e double). - \param value1 Second value of the initialization sequence (must be a \e double). - \param ... - \note - - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int,int,int,...), but - takes a sequence of double values instead of integers. - \warning - - You must specify \e exactly \c dx*\c dy*\c dz*\c dc doubles in the initialization sequence. - Otherwise, the constructor may crash or fill your image with garbage. - For instance, the code below will probably crash on most platforms: - \code - const CImg img(2,2,1,1, 0.5,0.5,255,255); // FAIL: The two last arguments are 'int', not 'double'! - \endcode - **/ - CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, - const double value0, const double value1, ...): - _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { - assign(size_x,size_y,size_z,size_c); - _CImg_stdarg(*this,value0,value1,safe_size(size_x,size_y,size_z,size_c),double); - } - - //! Construct image with specified size and initialize pixel values from a value string. - /** - Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, - and initializes pixel values from the specified string \c values. - \param size_x Image width(). - \param size_y Image height(). - \param size_z Image depth(). - \param size_c Image spectrum() (number of channels). - \param values Value string describing the way pixel values are set. - \param repeat_values Tells if the value filling process is repeated over the image. - \note - - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it also fills - the pixel buffer with values described in the value string \c values. - - Value string \c values may describe two different filling processes: - - Either \c values is a sequences of values assigned to the image pixels, as in "1,2,3,7,8,2". - In this case, set \c repeat_values to \c true to periodically fill the image with the value sequence. - - Either, \c values is a formula, as in "cos(x/10)*sin(y/20)". - In this case, parameter \c repeat_values is pointless. - - For both cases, specifying \c repeat_values is mandatory. - It disambiguates the possible overloading of constructor - CImg(unsigned int,unsigned int,unsigned int,unsigned int,T) with \c T being a const char*. - - A \c CImgArgumentException is thrown when an invalid value string \c values is specified. - \par Example - \code - const CImg img1(129,129,1,3,"0,64,128,192,255",true), // Construct image from a value sequence - img2(129,129,1,3,"if(c==0,255*abs(cos(x/10)),1.8*y)",false); // Construct image from a formula - (img1,img2).display(); - \endcode - \image html ref_constructor2.jpg - **/ - CImg(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z, const unsigned int size_c, - const char *const values, const bool repeat_values):_is_shared(false) { - const size_t siz = safe_size(size_x,size_y,size_z,size_c); - if (siz) { - _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; - try { _data = new T[siz]; } catch (...) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgInstanceException(_cimg_instance - "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", - cimg_instance, - cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), - size_x,size_y,size_z,size_c); - } - fill(values,repeat_values); - } else { _width = _height = _depth = _spectrum = 0; _data = 0; } - } - - //! Construct image with specified size and initialize pixel values from a memory buffer. - /** - Construct a new image instance of size \c size_x x \c size_y x \c size_z x \c size_c, with pixels of type \c T, - and initializes pixel values from the specified \c t* memory buffer. - \param values Pointer to the input memory buffer. - \param size_x Image width(). - \param size_y Image height(). - \param size_z Image depth(). - \param size_c Image spectrum() (number of channels). - \param is_shared Tells if input memory buffer must be shared by the current instance. - \note - - If \c is_shared is \c false, the image instance allocates its own pixel buffer, - and values from the specified input buffer are copied to the instance buffer. - If buffer types \c T and \c t are different, a regular static cast is performed during buffer copy. - - Otherwise, the image instance does \e not allocate a new buffer, and uses the input memory buffer as its - own pixel buffer. This case requires that types \c T and \c t are the same. Later, destroying such a shared - image will not deallocate the pixel buffer, this task being obviously charged to the initial buffer allocator. - - A \c CImgInstanceException is thrown when the pixel buffer cannot be allocated - (e.g. when requested size is too big for available memory). - \warning - - You must take care when operating on a shared image, since it may have an invalid pixel buffer pointer data() - (e.g. already deallocated). - \par Example - \code - unsigned char tab[256*256] = { 0 }; - CImg img1(tab,256,256,1,1,false), // Construct new non-shared image from buffer 'tab' - img2(tab,256,256,1,1,true); // Construct new shared-image from buffer 'tab' - tab[1024] = 255; // Here, 'img2' is indirectly modified, but not 'img1' - \endcode - **/ - template - CImg(const t *const values, const unsigned int size_x, const unsigned int size_y=1, - const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false):_is_shared(false) { - if (is_shared) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgArgumentException(_cimg_instance - "CImg(): Invalid construction request of a (%u,%u,%u,%u) shared instance " - "from a (%s*) buffer (pixel types are different).", - cimg_instance, - size_x,size_y,size_z,size_c,CImg::pixel_type()); - } - const size_t siz = safe_size(size_x,size_y,size_z,size_c); - if (values && siz) { - _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; - try { _data = new T[siz]; } catch (...) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgInstanceException(_cimg_instance - "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", - cimg_instance, - cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), - size_x,size_y,size_z,size_c); - - } - const t *ptrs = values; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++); - } else { _width = _height = _depth = _spectrum = 0; _data = 0; } - } - - //! Construct image with specified size and initialize pixel values from a memory buffer \specialization. - CImg(const T *const values, const unsigned int size_x, const unsigned int size_y=1, - const unsigned int size_z=1, const unsigned int size_c=1, const bool is_shared=false) { - const size_t siz = safe_size(size_x,size_y,size_z,size_c); - if (values && siz) { - _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = is_shared; - if (_is_shared) _data = const_cast(values); - else { - try { _data = new T[siz]; } catch (...) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgInstanceException(_cimg_instance - "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", - cimg_instance, - cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), - size_x,size_y,size_z,size_c); - } - std::memcpy(_data,values,siz*sizeof(T)); - } - } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; } - } - - //! Construct image from memory buffer with specified size and pixel ordering scheme. - template - CImg(const t *const values, const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c, - const char *const axes_order):_data(0),_is_shared(false) { - const size_t siz = safe_size(size_x,size_y,size_z,size_c); - if (values && siz) { - unsigned char s_code[4] = { 0,1,2,3 }, n_code[4] = { 0 }; - for (unsigned int l = 0; axes_order[l]; ++l) { - int c = cimg::lowercase(axes_order[l]); - if (l>=4 || (c!='x' && c!='y' && c!='z' && c!='c')) { *s_code = 4; break; } - else { ++n_code[c%=4]; s_code[l] = c; } - } - if (*axes_order && *s_code<4 && *n_code<=1 && n_code[1]<=1 && n_code[2]<=1 && n_code[3]<=1) { - const unsigned int code = (s_code[0]<<12) | (s_code[1]<<8) | (s_code[2]<<4) | (s_code[3]); - int s0 = 0, s1 = 0, s2 = 0, s3 = 0; - const char *inv_order = 0; - switch (code) { - case 0x0123 : inv_order = "xyzc"; s0 = size_x; s1 = size_y; s2 = size_z; s3 = size_c; break; // xyzc - case 0x0132 : inv_order = "xyzc"; s0 = size_x; s1 = size_y; s2 = size_c; s3 = size_z; break; // xycz - case 0x0213 : inv_order = "xzyc"; s0 = size_x; s1 = size_z; s2 = size_y; s3 = size_c; break; // xzyc - case 0x0231 : inv_order = "xcyz"; s0 = size_x; s1 = size_z; s2 = size_c; s3 = size_y; break; // xzcy - case 0x0312 : inv_order = "xzcy"; s0 = size_x; s1 = size_c; s2 = size_y; s3 = size_z; break; // xcyz - case 0x0321 : inv_order = "xczy"; s0 = size_x; s1 = size_c; s2 = size_z; s3 = size_y; break; // xczy - case 0x1023 : inv_order = "yxzc"; s0 = size_y; s1 = size_x; s2 = size_z; s3 = size_c; break; // yxzc - case 0x1032 : inv_order = "yxcz"; s0 = size_y; s1 = size_x; s2 = size_c; s3 = size_z; break; // yxcz - case 0x1203 : inv_order = "zxyc"; s0 = size_y; s1 = size_z; s2 = size_x; s3 = size_c; break; // yzxc - case 0x1230 : inv_order = "cxyz"; s0 = size_y; s1 = size_z; s2 = size_c; s3 = size_x; break; // yzcx - case 0x1302 : inv_order = "zxcy"; s0 = size_y; s1 = size_c; s2 = size_x; s3 = size_z; break; // ycxz - case 0x1320 : inv_order = "cxzy"; s0 = size_y; s1 = size_c; s2 = size_z; s3 = size_x; break; // yczx - case 0x2013 : inv_order = "yzxc"; s0 = size_z; s1 = size_x; s2 = size_y; s3 = size_c; break; // zxyc - case 0x2031 : inv_order = "ycxz"; s0 = size_z; s1 = size_x; s2 = size_c; s3 = size_y; break; // zxcy - case 0x2103 : inv_order = "zyxc"; s0 = size_z; s1 = size_y; s2 = size_x; s3 = size_c; break; // zyxc - case 0x2130 : inv_order = "cyxz"; s0 = size_z; s1 = size_y; s2 = size_c; s3 = size_x; break; // zycx - case 0x2301 : inv_order = "zcxy"; s0 = size_z; s1 = size_c; s2 = size_x; s3 = size_y; break; // zcxy - case 0x2310 : inv_order = "czxy"; s0 = size_z; s1 = size_c; s2 = size_y; s3 = size_x; break; // zcyx - case 0x3012 : inv_order = "yzcx"; s0 = size_c; s1 = size_x; s2 = size_y; s3 = size_z; break; // cxyz - case 0x3021 : inv_order = "yczx"; s0 = size_c; s1 = size_x; s2 = size_z; s3 = size_y; break; // cxzy - case 0x3102 : inv_order = "zycx"; s0 = size_c; s1 = size_y; s2 = size_x; s3 = size_z; break; // cyxz - case 0x3120 : inv_order = "cyzx"; s0 = size_c; s1 = size_y; s2 = size_z; s3 = size_x; break; // cyzx - case 0x3201 : inv_order = "zcyx"; s0 = size_c; s1 = size_z; s2 = size_x; s3 = size_y; break; // czxy - case 0x3210 : inv_order = "czyx"; s0 = size_c; s1 = size_z; s2 = size_y; s3 = size_x; break; // czyx - } - CImg(values,s0,s1,s2,s3,true).get_permute_axes(inv_order).move_to(*this); - } else { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgArgumentException(_cimg_instance - "CImg(): Invalid specified axes order '%s'.", - cimg_instance, - axes_order); - } - } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; } - } - - //! Construct image from reading an image file. - /** - Construct a new image instance with pixels of type \c T, and initialize pixel values with the data read from - an image file. - \param filename Filename, as a C-string. - \note - - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it reads the image - dimensions and pixel values from the specified image file. - - The recognition of the image file format by %CImg higlhy depends on the tools installed on your system - and on the external libraries you used to link your code against. - - Considered pixel type \c T should better fit the file format specification, or data loss may occur during - file load (e.g. constructing a \c CImg from a float-valued image file). - - A \c CImgIOException is thrown when the specified \c filename cannot be read, or if the file format is not - recognized. - \par Example - \code - const CImg img("reference.jpg"); - img.display(); - \endcode - \image html ref_image.jpg - **/ - explicit CImg(const char *const filename):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { - assign(filename); - } - - //! Construct image copy. - /** - Construct a new image instance with pixels of type \c T, as a copy of an existing \c CImg instance. - \param img Input image to copy. - \note - - Constructed copy has the same size width() x height() x depth() x spectrum() and pixel values as the - input image \c img. - - If input image \c img is \e shared and if types \c T and \c t are the same, the constructed copy is also - \e shared, and shares its pixel buffer with \c img. - Modifying a pixel value in the constructed copy will thus also modifies it in the input image \c img. - This behavior is needful to allow functions to return shared images. - - Otherwise, the constructed copy allocates its own pixel buffer, and copies pixel values from the input - image \c img into its buffer. The copied pixel values may be eventually statically casted if types \c T and - \c t are different. - - Constructing a copy from an image \c img when types \c t and \c T are the same is significantly faster than - with different types. - - A \c CImgInstanceException is thrown when the pixel buffer cannot be allocated - (e.g. not enough available memory). - **/ - template - CImg(const CImg& img):_is_shared(false) { - const size_t siz = (size_t)img.size(); - if (img._data && siz) { - _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; - try { _data = new T[siz]; } catch (...) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgInstanceException(_cimg_instance - "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", - cimg_instance, - cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum), - img._width,img._height,img._depth,img._spectrum); - } - const t *ptrs = img._data; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++); - } else { _width = _height = _depth = _spectrum = 0; _data = 0; } - } - - //! Construct image copy \specialization. - CImg(const CImg& img) { - const size_t siz = (size_t)img.size(); - if (img._data && siz) { - _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; - _is_shared = img._is_shared; - if (_is_shared) _data = const_cast(img._data); - else { - try { _data = new T[siz]; } catch (...) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgInstanceException(_cimg_instance - "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", - cimg_instance, - cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum), - img._width,img._height,img._depth,img._spectrum); - - } - std::memcpy(_data,img._data,siz*sizeof(T)); - } - } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; } - } - - //! Advanced copy constructor. - /** - Construct a new image instance with pixels of type \c T, as a copy of an existing \c CImg instance, - while forcing the shared state of the constructed copy. - \param img Input image to copy. - \param is_shared Tells about the shared state of the constructed copy. - \note - - Similar to CImg(const CImg&), except that it allows to decide the shared state of - the constructed image, which does not depend anymore on the shared state of the input image \c img: - - If \c is_shared is \c true, the constructed copy will share its pixel buffer with the input image \c img. - For that case, the pixel types \c T and \c t \e must be the same. - - If \c is_shared is \c false, the constructed copy will allocate its own pixel buffer, whether the input - image \c img is shared or not. - - A \c CImgArgumentException is thrown when a shared copy is requested with different pixel types \c T and \c t. - **/ - template - CImg(const CImg& img, const bool is_shared):_is_shared(false) { - if (is_shared) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgArgumentException(_cimg_instance - "CImg(): Invalid construction request of a shared instance from a " - "CImg<%s> image (%u,%u,%u,%u,%p) (pixel types are different).", - cimg_instance, - CImg::pixel_type(),img._width,img._height,img._depth,img._spectrum,img._data); - } - const size_t siz = (size_t)img.size(); - if (img._data && siz) { - _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; - try { _data = new T[siz]; } catch (...) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgInstanceException(_cimg_instance - "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", - cimg_instance, - cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum), - img._width,img._height,img._depth,img._spectrum); - } - const t *ptrs = img._data; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++); - } else { _width = _height = _depth = _spectrum = 0; _data = 0; } - } - - //! Advanced copy constructor \specialization. - CImg(const CImg& img, const bool is_shared) { - const size_t siz = (size_t)img.size(); - if (img._data && siz) { - _width = img._width; _height = img._height; _depth = img._depth; _spectrum = img._spectrum; - _is_shared = is_shared; - if (_is_shared) _data = const_cast(img._data); - else { - try { _data = new T[siz]; } catch (...) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgInstanceException(_cimg_instance - "CImg(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", - cimg_instance, - cimg::strbuffersize(sizeof(T)*img._width*img._height*img._depth*img._spectrum), - img._width,img._height,img._depth,img._spectrum); - } - std::memcpy(_data,img._data,siz*sizeof(T)); - } - } else { _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; } - } - - //! Construct image with dimensions borrowed from another image. - /** - Construct a new image instance with pixels of type \c T, and size get from some dimensions of an existing - \c CImg instance. - \param img Input image from which dimensions are borrowed. - \param dimensions C-string describing the image size along the X,Y,Z and C-dimensions. - \note - - Similar to CImg(unsigned int,unsigned int,unsigned int,unsigned int), but it takes the image dimensions - (\e not its pixel values) from an existing \c CImg instance. - - The allocated pixel buffer is \e not filled with a default value, and is likely to contain garbage values. - In order to initialize pixel values (e.g. with \c 0), use constructor CImg(const CImg&,const char*,T) - instead. - \par Example - \code - const CImg img1(256,128,1,3), // 'img1' is a 256x128x1x3 image - img2(img1,"xyzc"), // 'img2' is a 256x128x1x3 image - img3(img1,"y,x,z,c"), // 'img3' is a 128x256x1x3 image - img4(img1,"c,x,y,3",0), // 'img4' is a 3x128x256x3 image (with pixels initialized to '0') - \endcode - **/ - template - CImg(const CImg& img, const char *const dimensions): - _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { - assign(img,dimensions); - } - - //! Construct image with dimensions borrowed from another image and initialize pixel values. - /** - Construct a new image instance with pixels of type \c T, and size get from the dimensions of an existing - \c CImg instance, and set all pixel values to specified \c value. - \param img Input image from which dimensions are borrowed. - \param dimensions String describing the image size along the X,Y,Z and V-dimensions. - \param value Value used for initialization. - \note - - Similar to CImg(const CImg&,const char*), but it also fills the pixel buffer with the specified \c value. - **/ - template - CImg(const CImg& img, const char *const dimensions, const T& value): - _width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { - assign(img,dimensions).fill(value); - } - - //! Construct image from a display window. - /** - Construct a new image instance with pixels of type \c T, as a snapshot of an existing \c CImgDisplay instance. - \param disp Input display window. - \note - - The width() and height() of the constructed image instance are the same as the specified \c CImgDisplay. - - The depth() and spectrum() of the constructed image instance are respectively set to \c 1 and \c 3 - (i.e. a 2D color image). - - The image pixels are read as 8-bits RGB values. - **/ - explicit CImg(const CImgDisplay &disp):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { - disp.snapshot(*this); - } - - // Constructor and assignment operator for rvalue references (c++11). - // This avoids an additional image copy for methods returning new images. Can save RAM for big images ! -#if cimg_use_cpp11==1 - CImg(CImg&& img):_width(0),_height(0),_depth(0),_spectrum(0),_is_shared(false),_data(0) { - swap(img); - } - - CImg& operator=(CImg&& img) { - if (_is_shared) return assign(img); - return img.swap(*this); - } -#endif - - //! Construct empty image \inplace. - /** - In-place version of the default constructor CImg(). It simply resets the instance to an empty image. - **/ - CImg& assign() { - if (!_is_shared) delete[] _data; - _width = _height = _depth = _spectrum = 0; _is_shared = false; _data = 0; - return *this; - } - - //! Construct image with specified size \inplace. - /** - In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int). - **/ - CImg& assign(const unsigned int size_x, const unsigned int size_y=1, - const unsigned int size_z=1, const unsigned int size_c=1) { - const size_t siz = safe_size(size_x,size_y,size_z,size_c); - if (!siz) return assign(); - const size_t curr_siz = (size_t)size(); - if (siz!=curr_siz) { - if (_is_shared) - throw CImgArgumentException(_cimg_instance - "assign(): Invalid assignment request of shared instance from specified " - "image (%u,%u,%u,%u).", - cimg_instance, - size_x,size_y,size_z,size_c); - else { - delete[] _data; - try { _data = new T[siz]; } catch (...) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgInstanceException(_cimg_instance - "assign(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", - cimg_instance, - cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), - size_x,size_y,size_z,size_c); - } - } - } - _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; - return *this; - } - - //! Construct image with specified size and initialize pixel values \inplace. - /** - In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,T). - **/ - CImg& assign(const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c, const T& value) { - return assign(size_x,size_y,size_z,size_c).fill(value); - } - - //! Construct image with specified size and initialize pixel values from a sequence of integers \inplace. - /** - In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,int,int,...). - **/ - CImg& assign(const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c, - const int value0, const int value1, ...) { - assign(size_x,size_y,size_z,size_c); - _CImg_stdarg(*this,value0,value1,safe_size(size_x,size_y,size_z,size_c),int); - return *this; - } - - //! Construct image with specified size and initialize pixel values from a sequence of doubles \inplace. - /** - In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,double,double,...). - **/ - CImg& assign(const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c, - const double value0, const double value1, ...) { - assign(size_x,size_y,size_z,size_c); - _CImg_stdarg(*this,value0,value1,safe_size(size_x,size_y,size_z,size_c),double); - return *this; - } - - //! Construct image with specified size and initialize pixel values from a value string \inplace. - /** - In-place version of the constructor CImg(unsigned int,unsigned int,unsigned int,unsigned int,const char*,bool). - **/ - CImg& assign(const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c, - const char *const values, const bool repeat_values) { - return assign(size_x,size_y,size_z,size_c).fill(values,repeat_values); - } - - //! Construct image with specified size and initialize pixel values from a memory buffer \inplace. - /** - In-place version of the constructor CImg(const t*,unsigned int,unsigned int,unsigned int,unsigned int). - **/ - template - CImg& assign(const t *const values, const unsigned int size_x, const unsigned int size_y=1, - const unsigned int size_z=1, const unsigned int size_c=1) { - const size_t siz = safe_size(size_x,size_y,size_z,size_c); - if (!values || !siz) return assign(); - assign(size_x,size_y,size_z,size_c); - const t *ptrs = values; cimg_for(*this,ptrd,T) *ptrd = (T)*(ptrs++); - return *this; - } - - //! Construct image with specified size and initialize pixel values from a memory buffer \specialization. - CImg& assign(const T *const values, const unsigned int size_x, const unsigned int size_y=1, - const unsigned int size_z=1, const unsigned int size_c=1) { - const size_t siz = safe_size(size_x,size_y,size_z,size_c); - if (!values || !siz) return assign(); - const size_t curr_siz = (size_t)size(); - if (values==_data && siz==curr_siz) return assign(size_x,size_y,size_z,size_c); - if (_is_shared || values + siz<_data || values>=_data + size()) { - assign(size_x,size_y,size_z,size_c); - if (_is_shared) std::memmove((void*)_data,(void*)values,siz*sizeof(T)); - else std::memcpy((void*)_data,(void*)values,siz*sizeof(T)); - } else { - T *new_data = 0; - try { new_data = new T[siz]; } catch (...) { - _width = _height = _depth = _spectrum = 0; _data = 0; - throw CImgInstanceException(_cimg_instance - "assign(): Failed to allocate memory (%s) for image (%u,%u,%u,%u).", - cimg_instance, - cimg::strbuffersize(sizeof(T)*size_x*size_y*size_z*size_c), - size_x,size_y,size_z,size_c); - } - std::memcpy((void*)new_data,(void*)values,siz*sizeof(T)); - delete[] _data; _data = new_data; _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; - } - return *this; - } - - //! Construct image with specified size and initialize pixel values from a memory buffer \overloading. - template - CImg& assign(const t *const values, const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c, const bool is_shared) { - if (is_shared) - throw CImgArgumentException(_cimg_instance - "assign(): Invalid assignment request of shared instance from (%s*) buffer" - "(pixel types are different).", - cimg_instance, - CImg::pixel_type()); - return assign(values,size_x,size_y,size_z,size_c); - } - - //! Construct image with specified size and initialize pixel values from a memory buffer \overloading. - CImg& assign(const T *const values, const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c, const bool is_shared) { - const size_t siz = safe_size(size_x,size_y,size_z,size_c); - if (!values || !siz) return assign(); - if (!is_shared) { if (_is_shared) assign(); assign(values,size_x,size_y,size_z,size_c); } - else { - if (!_is_shared) { - if (values + siz<_data || values>=_data + size()) assign(); - else cimg::warn(_cimg_instance - "assign(): Shared image instance has overlapping memory.", - cimg_instance); - } - _width = size_x; _height = size_y; _depth = size_z; _spectrum = size_c; _is_shared = true; - _data = const_cast(values); - } - return *this; - } - - //! Construct image from memory buffer with specified size and pixel ordering scheme. - template - CImg& assign(const t *const values, const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c, - const char *const axes_order) { - CImg(values,size_x,size_y,size_z,size_c,axes_order).move_to(*this); - } - - //! Construct image from reading an image file \inplace. - /** - In-place version of the constructor CImg(const char*). - **/ - CImg& assign(const char *const filename) { - return load(filename); - } - - //! Construct image copy \inplace. - /** - In-place version of the constructor CImg(const CImg&). - **/ - template - CImg& assign(const CImg& img) { - return assign(img._data,img._width,img._height,img._depth,img._spectrum); - } - - //! In-place version of the advanced copy constructor. - /** - In-place version of the constructor CImg(const CImg&,bool). - **/ - template - CImg& assign(const CImg& img, const bool is_shared) { - return assign(img._data,img._width,img._height,img._depth,img._spectrum,is_shared); - } - - //! Construct image with dimensions borrowed from another image \inplace. - /** - In-place version of the constructor CImg(const CImg&,const char*). - **/ - template - CImg& assign(const CImg& img, const char *const dimensions) { - if (!dimensions || !*dimensions) return assign(img._width,img._height,img._depth,img._spectrum); - unsigned int siz[4] = { 0,1,1,1 }, k = 0; - CImg item(256); - for (const char *s = dimensions; *s && k<4; ++k) { - if (cimg_sscanf(s,"%255[^0-9%xyzvwhdcXYZVWHDC]",item._data)>0) s+=std::strlen(item); - if (*s) { - unsigned int val = 0; char sep = 0; - if (cimg_sscanf(s,"%u%c",&val,&sep)>0) { - if (sep=='%') siz[k] = val*(k==0?_width:k==1?_height:k==2?_depth:_spectrum)/100; - else siz[k] = val; - while (*s>='0' && *s<='9') ++s; - if (sep=='%') ++s; - } else switch (cimg::lowercase(*s)) { - case 'x' : case 'w' : siz[k] = img._width; ++s; break; - case 'y' : case 'h' : siz[k] = img._height; ++s; break; - case 'z' : case 'd' : siz[k] = img._depth; ++s; break; - case 'c' : case 's' : siz[k] = img._spectrum; ++s; break; - default : - throw CImgArgumentException(_cimg_instance - "assign(): Invalid character '%c' detected in specified dimension string '%s'.", - cimg_instance, - *s,dimensions); - } - } - } - return assign(siz[0],siz[1],siz[2],siz[3]); - } - - //! Construct image with dimensions borrowed from another image and initialize pixel values \inplace. - /** - In-place version of the constructor CImg(const CImg&,const char*,T). - **/ - template - CImg& assign(const CImg& img, const char *const dimensions, const T& value) { - return assign(img,dimensions).fill(value); - } - - //! Construct image from a display window \inplace. - /** - In-place version of the constructor CImg(const CImgDisplay&). - **/ - CImg& assign(const CImgDisplay &disp) { - disp.snapshot(*this); - return *this; - } - - //! Construct empty image \inplace. - /** - Equivalent to assign(). - \note - - It has been defined for compatibility with STL naming conventions. - **/ - CImg& clear() { - return assign(); - } - - //! Transfer content of an image instance into another one. - /** - Transfer the dimensions and the pixel buffer content of an image instance into another one, - and replace instance by an empty image. It avoids the copy of the pixel buffer - when possible. - \param img Destination image. - \note - - Pixel types \c T and \c t of source and destination images can be different, though the process is - designed to be instantaneous when \c T and \c t are the same. - \par Example - \code - CImg src(256,256,1,3,0), // Construct a 256x256x1x3 (color) image filled with value '0' - dest(16,16); // Construct a 16x16x1x1 (scalar) image - src.move_to(dest); // Now, 'src' is empty and 'dest' is the 256x256x1x3 image - \endcode - **/ - template - CImg& move_to(CImg& img) { - img.assign(*this); - assign(); - return img; - } - - //! Transfer content of an image instance into another one \specialization. - CImg& move_to(CImg& img) { - if (_is_shared || img._is_shared) img.assign(*this); - else swap(img); - assign(); - return img; - } - - //! Transfer content of an image instance into a new image in an image list. - /** - Transfer the dimensions and the pixel buffer content of an image instance - into a newly inserted image at position \c pos in specified \c CImgList instance. - \param list Destination list. - \param pos Position of the newly inserted image in the list. - \note - - When optional parameter \c pos is omitted, the image instance is transferred as a new - image at the end of the specified \c list. - - It is convenient to sequentially insert new images into image lists, with no - additional copies of memory buffer. - \par Example - \code - CImgList list; // Construct an empty image list - CImg img("reference.jpg"); // Read image from filename - img.move_to(list); // Transfer image content as a new item in the list (no buffer copy) - \endcode - **/ - template - CImgList& move_to(CImgList& list, const unsigned int pos=~0U) { - const unsigned int npos = pos>list._width?list._width:pos; - move_to(list.insert(1,npos)[npos]); - return list; - } - - //! Swap fields of two image instances. - /** - \param img Image to swap fields with. - \note - - It can be used to interchange the content of two images in a very fast way. Can be convenient when dealing - with algorithms requiring two swapping buffers. - \par Example - \code - CImg img1("lena.jpg"), - img2("milla.jpg"); - img1.swap(img2); // Now, 'img1' is 'milla' and 'img2' is 'lena' - \endcode - **/ - CImg& swap(CImg& img) { - cimg::swap(_width,img._width,_height,img._height,_depth,img._depth,_spectrum,img._spectrum); - cimg::swap(_data,img._data); - cimg::swap(_is_shared,img._is_shared); - return img; - } - - //! Return a reference to an empty image. - /** - \note - This function is useful mainly to declare optional parameters having type \c CImg in functions prototypes, - e.g. - \code - void f(const int x=0, const int y=0, const CImg& img=CImg::empty()); - \endcode - **/ - static CImg& empty() { - static CImg _empty; - return _empty.assign(); - } - - //! Return a reference to an empty image \const. - static const CImg& const_empty() { - static const CImg _empty; - return _empty; - } - - //@} - //------------------------------------------ - // - //! \name Overloaded Operators - //@{ - //------------------------------------------ - - //! Access to a pixel value. - /** - Return a reference to a located pixel value of the image instance, - being possibly \e const, whether the image instance is \e const or not. - This is the standard method to get/set pixel values in \c CImg images. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note - - Range of pixel coordinates start from (0,0,0,0) to - (width() - 1,height() - 1,depth() - 1,spectrum() - 1). - - Due to the particular arrangement of the pixel buffers defined in %CImg, you can omit one coordinate if the - corresponding dimension is equal to \c 1. - For instance, pixels of a 2D image (depth() equal to \c 1) can be accessed by img(x,y,c) instead of - img(x,y,0,c). - \warning - - There is \e no boundary checking done in this operator, to make it as fast as possible. - You \e must take care of out-of-bounds access by yourself, if necessary. - For debugging purposes, you may want to define macro \c 'cimg_verbosity'>=3 to enable additional boundary - checking operations in this operator. In that case, warning messages will be printed on the error output - when accessing out-of-bounds pixels. - \par Example - \code - CImg img(100,100,1,3,0); // Construct a 100x100x1x3 (color) image with pixels set to '0' - const float - valR = img(10,10,0,0), // Read red value at coordinates (10,10) - valG = img(10,10,0,1), // Read green value at coordinates (10,10) - valB = img(10,10,2), // Read blue value at coordinates (10,10) (Z-coordinate can be omitted) - avg = (valR + valG + valB)/3; // Compute average pixel value - img(10,10,0) = img(10,10,1) = img(10,10,2) = avg; // Replace the color pixel (10,10) by the average grey value - \endcode - **/ -#if cimg_verbosity>=3 - T& operator()(const unsigned int x, const unsigned int y=0, - const unsigned int z=0, const unsigned int c=0) { - const ulongT off = (ulongT)offset(x,y,z,c); - if (!_data || off>=size()) { - cimg::warn(_cimg_instance - "operator(): Invalid pixel request, at coordinates (%d,%d,%d,%d) [offset=%u].", - cimg_instance, - (int)x,(int)y,(int)z,(int)c,off); - return *_data; - } - else return _data[off]; - } - - //! Access to a pixel value \const. - const T& operator()(const unsigned int x, const unsigned int y=0, - const unsigned int z=0, const unsigned int c=0) const { - return const_cast*>(this)->operator()(x,y,z,c); - } - - //! Access to a pixel value. - /** - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \param wh Precomputed offset, must be equal to width()*\ref height(). - \param whd Precomputed offset, must be equal to width()*\ref height()*\ref depth(). - \note - - Similar to (but faster than) operator()(). - It uses precomputed offsets to optimize memory access. You may use it to optimize - the reading/writing of several pixel values in the same image (e.g. in a loop). - **/ - T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c, - const ulongT wh, const ulongT whd=0) { - cimg::unused(wh,whd); - return (*this)(x,y,z,c); - } - - //! Access to a pixel value \const. - const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c, - const ulongT wh, const ulongT whd=0) const { - cimg::unused(wh,whd); - return (*this)(x,y,z,c); - } -#else - T& operator()(const unsigned int x) { - return _data[x]; - } - - const T& operator()(const unsigned int x) const { - return _data[x]; - } - - T& operator()(const unsigned int x, const unsigned int y) { - return _data[x + y*_width]; - } - - const T& operator()(const unsigned int x, const unsigned int y) const { - return _data[x + y*_width]; - } - - T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) { - return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height]; - } - - const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z) const { - return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height]; - } - - T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c) { - return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height + c*(ulongT)_width*_height*_depth]; - } - - const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c) const { - return _data[x + y*(ulongT)_width + z*(ulongT)_width*_height + c*(ulongT)_width*_height*_depth]; - } - - T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int, - const ulongT wh) { - return _data[x + y*_width + z*wh]; - } - - const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int, - const ulongT wh) const { - return _data[x + y*_width + z*wh]; - } - - T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c, - const ulongT wh, const ulongT whd) { - return _data[x + y*_width + z*wh + c*whd]; - } - - const T& operator()(const unsigned int x, const unsigned int y, const unsigned int z, const unsigned int c, - const ulongT wh, const ulongT whd) const { - return _data[x + y*_width + z*wh + c*whd]; - } -#endif - - //! Implicitly cast an image into a \c T*. - /** - Implicitly cast a \c CImg instance into a \c T* or \c const \c T* pointer, whether the image instance - is \e const or not. The returned pointer points on the first value of the image pixel buffer. - \note - - It simply returns the pointer data() to the pixel buffer. - - This implicit conversion is convenient to test the empty state of images (data() being \c 0 in this case), e.g. - \code - CImg img1(100,100), img2; // 'img1' is a 100x100 image, 'img2' is an empty image - if (img1) { // Test succeeds, 'img1' is not an empty image - if (!img2) { // Test succeeds, 'img2' is an empty image - std::printf("'img1' is not empty, 'img2' is empty."); - } - } - \endcode - - It also allows to use brackets to access pixel values, without need for a \c CImg::operator[](), e.g. - \code - CImg img(100,100); - const float value = img[99]; // Access to value of the last pixel on the first row - img[510] = 255; // Set pixel value at (10,5) - \endcode - **/ - operator T*() { - return _data; - } - - //! Implicitly cast an image into a \c T* \const. - operator const T*() const { - return _data; - } - - //! Assign a value to all image pixels. - /** - Assign specified \c value to each pixel value of the image instance. - \param value Value that will be assigned to image pixels. - \note - - The image size is never modified. - - The \c value may be casted to pixel type \c T if necessary. - \par Example - \code - CImg img(100,100); // Declare image (with garbage values) - img = 0; // Set all pixel values to '0' - img = 1.2; // Set all pixel values to '1' (cast of '1.2' as a 'char') - \endcode - **/ - CImg& operator=(const T& value) { - return fill(value); - } - - //! Assign pixels values from a specified expression. - /** - Initialize all pixel values from the specified string \c expression. - \param expression Value string describing the way pixel values are set. - \note - - String parameter \c expression may describe different things: - - If \c expression is a list of values (as in \c "1,2,3,8,3,2"), or a formula (as in \c "(x*y)%255"), - the pixel values are set from specified \c expression and the image size is not modified. - - If \c expression is a filename (as in \c "reference.jpg"), the corresponding image file is loaded and - replace the image instance. The image size is modified if necessary. - \par Example - \code - CImg img1(100,100), img2(img1), img3(img1); // Declare 3 scalar images 100x100 with uninitialized values - img1 = "0,50,100,150,200,250,200,150,100,50"; // Set pixel values of 'img1' from a value sequence - img2 = "10*((x*y)%25)"; // Set pixel values of 'img2' from a formula - img3 = "reference.jpg"; // Set pixel values of 'img3' from a file (image size is modified) - (img1,img2,img3).display(); - \endcode - \image html ref_operator_eq.jpg - **/ - CImg& operator=(const char *const expression) { - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - try { - _fill(expression,true,1,0,0,"operator=",0); - } catch (CImgException&) { - cimg::exception_mode(omode); - load(expression); - } - cimg::exception_mode(omode); - return *this; - } - - //! Copy an image into the current image instance. - /** - Similar to the in-place copy constructor assign(const CImg&). - **/ - template - CImg& operator=(const CImg& img) { - return assign(img); - } - - //! Copy an image into the current image instance \specialization. - CImg& operator=(const CImg& img) { - return assign(img); - } - - //! Copy the content of a display window to the current image instance. - /** - Similar to assign(const CImgDisplay&). - **/ - CImg& operator=(const CImgDisplay& disp) { - disp.snapshot(*this); - return *this; - } - - //! In-place addition operator. - /** - Add specified \c value to all pixels of an image instance. - \param value Value to add. - \note - - Resulting pixel values are casted to fit the pixel type \c T. - For instance, adding \c 0.2 to a \c CImg is possible but does nothing indeed. - - Overflow values are treated as with standard C++ numeric types. For instance, - \code - CImg img(100,100,1,1,255); // Construct a 100x100 image with pixel values '255' - img+=1; // Add '1' to each pixels -> Overflow - // here all pixels of image 'img' are equal to '0'. - \endcode - - To prevent value overflow, you may want to consider pixel type \c T as \c float or \c double, - and use cut() after addition. - \par Example - \code - CImg img1("reference.jpg"); // Load a 8-bits RGB image (values in [0,255]) - CImg img2(img1); // Construct a float-valued copy of 'img1' - img2+=100; // Add '100' to pixel values -> goes out of [0,255] but no problems with floats - img2.cut(0,255); // Cut values in [0,255] to fit the 'unsigned char' constraint - img1 = img2; // Rewrite safe result in 'unsigned char' version 'img1' - const CImg img3 = (img1 + 100).cut(0,255); // Do the same in a more simple and elegant way - (img1,img2,img3).display(); - \endcode - \image html ref_operator_plus.jpg - **/ - template - CImg& operator+=(const t value) { - if (is_empty()) return *this; - cimg_openmp_for(*this,*ptr + value,524288); - return *this; - } - - //! In-place addition operator. - /** - Add values to image pixels, according to the specified string \c expression. - \param expression Value string describing the way pixel values are added. - \note - - Similar to operator=(const char*), except that it adds values to the pixels of the current image instance, - instead of assigning them. - **/ - CImg& operator+=(const char *const expression) { - return *this+=(+*this)._fill(expression,true,1,0,0,"operator+=",this); - } - - //! In-place addition operator. - /** - Add values to image pixels, according to the values of the input image \c img. - \param img Input image to add. - \note - - The size of the image instance is never modified. - - It is not mandatory that input image \c img has the same size as the image instance. - If less values are available in \c img, then the values are added periodically. For instance, adding one - WxH scalar image (spectrum() equal to \c 1) to one WxH color image (spectrum() equal to \c 3) - means each color channel will be incremented with the same values at the same locations. - \par Example - \code - CImg img1("reference.jpg"); // Load a RGB color image (img1.spectrum()==3) - // Construct a scalar shading (img2.spectrum()==1). - const CImg img2(img1.width(),img.height(),1,1,"255*(x/w)^2"); - img1+=img2; // Add shading to each channel of 'img1' - img1.cut(0,255); // Prevent [0,255] overflow - (img2,img1).display(); - \endcode - \image html ref_operator_plus1.jpg - **/ - template - CImg& operator+=(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return *this+=+img; - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs& operator++() { - if (is_empty()) return *this; - cimg_openmp_for(*this,*ptr + 1,524288); - return *this; - } - - //! In-place increment operator (postfix). - /** - Add \c 1 to all image pixels, and return a new copy of the initial (pre-incremented) image instance. - \note - - Use the prefixed version operator++() if you don't need a copy of the initial - (pre-incremented) image instance, since a useless image copy may be expensive in terms of memory usage. - **/ - CImg operator++(int) { - const CImg copy(*this,false); - ++*this; - return copy; - } - - //! Return a non-shared copy of the image instance. - /** - \note - - Use this operator to ensure you get a non-shared copy of an image instance with same pixel type \c T. - Indeed, the usual copy constructor CImg(const CImg&) returns a shared copy of a shared input image, - and it may be not desirable to work on a regular copy (e.g. for a resize operation) if you have no - information about the shared state of the input image. - - Writing \c (+img) is equivalent to \c CImg(img,false). - **/ - CImg operator+() const { - return CImg(*this,false); - } - - //! Addition operator. - /** - Similar to operator+=(const t), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - template - CImg<_cimg_Tt> operator+(const t value) const { - return CImg<_cimg_Tt>(*this,false)+=value; - } - - //! Addition operator. - /** - Similar to operator+=(const char*), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - CImg operator+(const char *const expression) const { - return CImg(*this,false)+=expression; - } - - //! Addition operator. - /** - Similar to operator+=(const CImg&), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - template - CImg<_cimg_Tt> operator+(const CImg& img) const { - return CImg<_cimg_Tt>(*this,false)+=img; - } - - //! In-place subtraction operator. - /** - Similar to operator+=(const t), except that it performs a subtraction instead of an addition. - **/ - template - CImg& operator-=(const t value) { - if (is_empty()) return *this; - cimg_openmp_for(*this,*ptr - value,524288); - return *this; - } - - //! In-place subtraction operator. - /** - Similar to operator+=(const char*), except that it performs a subtraction instead of an addition. - **/ - CImg& operator-=(const char *const expression) { - return *this-=(+*this)._fill(expression,true,1,0,0,"operator-=",this); - } - - //! In-place subtraction operator. - /** - Similar to operator+=(const CImg&), except that it performs a subtraction instead of an addition. - **/ - template - CImg& operator-=(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return *this-=+img; - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs& operator--() { - if (is_empty()) return *this; - cimg_openmp_for(*this,*ptr - 1,524288); - return *this; - } - - //! In-place decrement operator (postfix). - /** - Similar to operator++(int), except that it performs a decrement instead of an increment. - **/ - CImg operator--(int) { - const CImg copy(*this,false); - --*this; - return copy; - } - - //! Replace each pixel by its opposite value. - /** - \note - - If the computed opposite values are out-of-range, they are treated as with standard C++ numeric types. - For instance, the \c unsigned \c char opposite of \c 1 is \c 255. - \par Example - \code - const CImg - img1("reference.jpg"), // Load a RGB color image - img2 = -img1; // Compute its opposite (in 'unsigned char') - (img1,img2).display(); - \endcode - \image html ref_operator_minus.jpg - **/ - CImg operator-() const { - return CImg(_width,_height,_depth,_spectrum,(T)0)-=*this; - } - - //! Subtraction operator. - /** - Similar to operator-=(const t), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - template - CImg<_cimg_Tt> operator-(const t value) const { - return CImg<_cimg_Tt>(*this,false)-=value; - } - - //! Subtraction operator. - /** - Similar to operator-=(const char*), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - CImg operator-(const char *const expression) const { - return CImg(*this,false)-=expression; - } - - //! Subtraction operator. - /** - Similar to operator-=(const CImg&), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - template - CImg<_cimg_Tt> operator-(const CImg& img) const { - return CImg<_cimg_Tt>(*this,false)-=img; - } - - //! In-place multiplication operator. - /** - Similar to operator+=(const t), except that it performs a multiplication instead of an addition. - **/ - template - CImg& operator*=(const t value) { - if (is_empty()) return *this; - cimg_openmp_for(*this,*ptr * value,262144); - return *this; - } - - //! In-place multiplication operator. - /** - Similar to operator+=(const char*), except that it performs a multiplication instead of an addition. - **/ - CImg& operator*=(const char *const expression) { - return mul((+*this)._fill(expression,true,1,0,0,"operator*=",this)); - } - - //! In-place multiplication operator. - /** - Replace the image instance by the matrix multiplication between the image instance and the specified matrix - \c img. - \param img Second operand of the matrix multiplication. - \note - - It does \e not compute a pointwise multiplication between two images. For this purpose, use - mul(const CImg&) instead. - - The size of the image instance can be modified by this operator. - \par Example - \code - CImg A(2,2,1,1, 1,2,3,4); // Construct 2x2 matrix A = [1,2;3,4] - const CImg X(1,2,1,1, 1,2); // Construct 1x2 vector X = [1;2] - A*=X; // Assign matrix multiplication A*X to 'A' - // 'A' is now a 1x2 vector whose values are [5;11]. - \endcode - **/ - template - CImg& operator*=(const CImg& img) { - return ((*this)*img).move_to(*this); - } - - //! Multiplication operator. - /** - Similar to operator*=(const t), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - template - CImg<_cimg_Tt> operator*(const t value) const { - return CImg<_cimg_Tt>(*this,false)*=value; - } - - //! Multiplication operator. - /** - Similar to operator*=(const char*), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - CImg operator*(const char *const expression) const { - return CImg(*this,false)*=expression; - } - - //! Multiplication operator. - /** - Similar to operator*=(const CImg&), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - template - CImg<_cimg_Tt> operator*(const CImg& img) const { - typedef _cimg_Ttdouble Ttdouble; - typedef _cimg_Tt Tt; - if (_width!=img._height || _depth!=1 || _spectrum!=1) - throw CImgArgumentException(_cimg_instance - "operator*(): Invalid multiplication of instance by specified " - "matrix (%u,%u,%u,%u,%p).", - cimg_instance, - img._width,img._height,img._depth,img._spectrum,img._data); - CImg res(img._width,_height); - - // Check for common cases to optimize. - if (img._width==1) { // Matrix * Vector - if (_height==1) switch (_width) { // Vector^T * Vector - case 1 : - res[0] = (Tt)((Ttdouble)_data[0]*img[0]); - return res; - case 2 : - res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1]); - return res; - case 3 : - res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1] + - (Ttdouble)_data[2]*img[2]); - return res; - case 4 : - res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1] + - (Ttdouble)_data[2]*img[2] + (Ttdouble)_data[3]*img[3]); - return res; - default : { - Ttdouble val = 0; - cimg_pragma_openmp(parallel for reduction(+:val) cimg_openmp_if_size(size(),4096)) - cimg_forX(*this,i) val+=(Ttdouble)_data[i]*img[i]; - res[0] = val; - return res; - } - } else if (_height==_width) switch (_width) { // Square_matrix * Vector - case 2 : // 2x2_matrix * Vector - res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1]); - res[1] = (Tt)((Ttdouble)_data[2]*img[0] + (Ttdouble)_data[3]*img[1]); - return res; - case 3 : // 3x3_matrix * Vector - res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1] + - (Ttdouble)_data[2]*img[2]); - res[1] = (Tt)((Ttdouble)_data[3]*img[0] + (Ttdouble)_data[4]*img[1] + - (Ttdouble)_data[5]*img[2]); - res[2] = (Tt)((Ttdouble)_data[6]*img[0] + (Ttdouble)_data[7]*img[1] + - (Ttdouble)_data[8]*img[2]); - return res; - case 4 : // 4x4_matrix * Vector - res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[1] + - (Ttdouble)_data[2]*img[2] + (Ttdouble)_data[3]*img[3]); - res[1] = (Tt)((Ttdouble)_data[4]*img[0] + (Ttdouble)_data[5]*img[1] + - (Ttdouble)_data[6]*img[2] + (Ttdouble)_data[7]*img[3]); - res[2] = (Tt)((Ttdouble)_data[8]*img[0] + (Ttdouble)_data[9]*img[1] + - (Ttdouble)_data[10]*img[2] + (Ttdouble)_data[11]*img[3]); - res[3] = (Tt)((Ttdouble)_data[12]*img[0] + (Ttdouble)_data[13]*img[1] + - (Ttdouble)_data[14]*img[2] + (Ttdouble)_data[15]*img[3]); - return res; - } - } else if (_height==_width) { - if (img._height==img._width) switch (_width) { // Square_matrix * Square_matrix - case 2 : // 2x2_matrix * 2x2_matrix - res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[2]); - res[1] = (Tt)((Ttdouble)_data[0]*img[1] + (Ttdouble)_data[1]*img[3]); - res[2] = (Tt)((Ttdouble)_data[2]*img[0] + (Ttdouble)_data[3]*img[2]); - res[3] = (Tt)((Ttdouble)_data[2]*img[1] + (Ttdouble)_data[3]*img[3]); - return res; - case 3 : // 3x3_matrix * 3x3_matrix - res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[3] + - (Ttdouble)_data[2]*img[6]); - res[1] = (Tt)((Ttdouble)_data[0]*img[1] + (Ttdouble)_data[1]*img[4] + - (Ttdouble)_data[2]*img[7]); - res[2] = (Tt)((Ttdouble)_data[0]*img[2] + (Ttdouble)_data[1]*img[5] + - (Ttdouble)_data[2]*img[8]); - res[3] = (Tt)((Ttdouble)_data[3]*img[0] + (Ttdouble)_data[4]*img[3] + - (Ttdouble)_data[5]*img[6]); - res[4] = (Tt)((Ttdouble)_data[3]*img[1] + (Ttdouble)_data[4]*img[4] + - (Ttdouble)_data[5]*img[7]); - res[5] = (Tt)((Ttdouble)_data[3]*img[2] + (Ttdouble)_data[4]*img[5] + - (Ttdouble)_data[5]*img[8]); - res[6] = (Tt)((Ttdouble)_data[6]*img[0] + (Ttdouble)_data[7]*img[3] + - (Ttdouble)_data[8]*img[6]); - res[7] = (Tt)((Ttdouble)_data[6]*img[1] + (Ttdouble)_data[7]*img[4] + - (Ttdouble)_data[8]*img[7]); - res[8] = (Tt)((Ttdouble)_data[6]*img[2] + (Ttdouble)_data[7]*img[5] + - (Ttdouble)_data[8]*img[8]); - return res; - case 4 : // 4x4_matrix * 4x4_matrix - res[0] = (Tt)((Ttdouble)_data[0]*img[0] + (Ttdouble)_data[1]*img[4] + - (Ttdouble)_data[2]*img[8] + (Ttdouble)_data[3]*img[12]); - res[1] = (Tt)((Ttdouble)_data[0]*img[1] + (Ttdouble)_data[1]*img[5] + - (Ttdouble)_data[2]*img[9] + (Ttdouble)_data[3]*img[13]); - res[2] = (Tt)((Ttdouble)_data[0]*img[2] + (Ttdouble)_data[1]*img[6] + - (Ttdouble)_data[2]*img[10] + (Ttdouble)_data[3]*img[14]); - res[3] = (Tt)((Ttdouble)_data[0]*img[3] + (Ttdouble)_data[1]*img[7] + - (Ttdouble)_data[2]*img[11] + (Ttdouble)_data[3]*img[15]); - res[4] = (Tt)((Ttdouble)_data[4]*img[0] + (Ttdouble)_data[5]*img[4] + - (Ttdouble)_data[6]*img[8] + (Ttdouble)_data[7]*img[12]); - res[5] = (Tt)((Ttdouble)_data[4]*img[1] + (Ttdouble)_data[5]*img[5] + - (Ttdouble)_data[6]*img[9] + (Ttdouble)_data[7]*img[13]); - res[6] = (Tt)((Ttdouble)_data[4]*img[2] + (Ttdouble)_data[5]*img[6] + - (Ttdouble)_data[6]*img[10] + (Ttdouble)_data[7]*img[14]); - res[7] = (Tt)((Ttdouble)_data[4]*img[3] + (Ttdouble)_data[5]*img[7] + - (Ttdouble)_data[6]*img[11] + (Ttdouble)_data[7]*img[15]); - res[8] = (Tt)((Ttdouble)_data[8]*img[0] + (Ttdouble)_data[9]*img[4] + - (Ttdouble)_data[10]*img[8] + (Ttdouble)_data[11]*img[12]); - res[9] = (Tt)((Ttdouble)_data[8]*img[1] + (Ttdouble)_data[9]*img[5] + - (Ttdouble)_data[10]*img[9] + (Ttdouble)_data[11]*img[13]); - res[10] = (Tt)((Ttdouble)_data[8]*img[2] + (Ttdouble)_data[9]*img[6] + - (Ttdouble)_data[10]*img[10] + (Ttdouble)_data[11]*img[14]); - res[11] = (Tt)((Ttdouble)_data[8]*img[3] + (Ttdouble)_data[9]*img[7] + - (Ttdouble)_data[10]*img[11] + (Ttdouble)_data[11]*img[15]); - res[12] = (Tt)((Ttdouble)_data[12]*img[0] + (Ttdouble)_data[13]*img[4] + - (Ttdouble)_data[14]*img[8] + (Ttdouble)_data[15]*img[12]); - res[13] = (Tt)((Ttdouble)_data[12]*img[1] + (Ttdouble)_data[13]*img[5] + - (Ttdouble)_data[14]*img[9] + (Ttdouble)_data[15]*img[13]); - res[14] = (Tt)((Ttdouble)_data[12]*img[2] + (Ttdouble)_data[13]*img[6] + - (Ttdouble)_data[14]*img[10] + (Ttdouble)_data[15]*img[14]); - res[15] = (Tt)((Ttdouble)_data[12]*img[3] + (Ttdouble)_data[13]*img[7] + - (Ttdouble)_data[14]*img[11] + (Ttdouble)_data[15]*img[15]); - return res; - } else switch (_width) { // Square_matrix * Matrix - case 2 : { // 2x2_matrix * Matrix - const t *const ps0 = img.data(), *const ps1 = img.data(0,1); - Tt *const pd0 = res.data(), *const pd1 = res.data(0,1); - const Ttdouble - a0 = (Ttdouble)_data[0], a1 = (Ttdouble)_data[1], - a2 = (Ttdouble)_data[2], a3 = (Ttdouble)_data[3]; - cimg_pragma_openmp(parallel for cimg_openmp_if_size(img.width(),4096)) - cimg_forX(img,i) { - const Ttdouble x = (Ttdouble)ps0[i], y = (Ttdouble)ps1[i]; - pd0[i] = (Tt)(a0*x + a1*y); - pd1[i] = (Tt)(a2*x + a3*y); - } - return res; - } - case 3 : { // 3x3_matrix * Matrix - const t *const ps0 = img.data(), *const ps1 = img.data(0,1), *const ps2 = img.data(0,2); - Tt *const pd0 = res.data(), *const pd1 = res.data(0,1), *const pd2 = res.data(0,2); - const Ttdouble - a0 = (Ttdouble)_data[0], a1 = (Ttdouble)_data[1], a2 = (Ttdouble)_data[2], - a3 = (Ttdouble)_data[3], a4 = (Ttdouble)_data[4], a5 = (Ttdouble)_data[5], - a6 = (Ttdouble)_data[6], a7 = (Ttdouble)_data[7], a8 = (Ttdouble)_data[8]; - cimg_pragma_openmp(parallel for cimg_openmp_if_size(img.width(),1024)) - cimg_forX(img,i) { - const Ttdouble x = (Ttdouble)ps0[i], y = (Ttdouble)ps1[i], z = (Ttdouble)ps2[i]; - pd0[i] = (Tt)(a0*x + a1*y + a2*z); - pd1[i] = (Tt)(a3*x + a4*y + a5*z); - pd2[i] = (Tt)(a6*x + a7*y + a8*z); - } - return res; - } - case 4 : { // 4x4_matrix * Matrix - const t - *const ps0 = img.data(), *const ps1 = img.data(0,1), - *const ps2 = img.data(0,2), *const ps3 = img.data(0,3); - Tt - *const pd0 = res.data(), *const pd1 = res.data(0,1), - *const pd2 = res.data(0,2), *const pd3 = res.data(0,3); - const Ttdouble - a0 = (Ttdouble)_data[0], a1 = (Ttdouble)_data[1], a2 = (Ttdouble)_data[2], a3 = (Ttdouble)_data[3], - a4 = (Ttdouble)_data[4], a5 = (Ttdouble)_data[5], a6 = (Ttdouble)_data[6], a7 = (Ttdouble)_data[7], - a8 = (Ttdouble)_data[8], a9 = (Ttdouble)_data[9], a10 = (Ttdouble)_data[10], a11 = (Ttdouble)_data[11], - a12 = (Ttdouble)_data[12], a13 = (Ttdouble)_data[13], a14 = (Ttdouble)_data[14], - a15 = (Ttdouble)_data[15]; - cimg_pragma_openmp(parallel for cimg_openmp_if_size(img.width(),512)) - cimg_forX(img,i) { - const Ttdouble x = (Ttdouble)ps0[i], y = (Ttdouble)ps1[i], z = (Ttdouble)ps2[i], c = (Ttdouble)ps3[i]; - pd0[i] = (Tt)(a0*x + a1*y + a2*z + a3*c); - pd1[i] = (Tt)(a4*x + a5*y + a6*z + a7*c); - pd2[i] = (Tt)(a8*x + a9*y + a10*z + a11*c); - pd3[i] = (Tt)(a12*x + a13*y + a14*z + a15*c); - } - return res; - } - } - } - - // Fallback to generic version. -#if cimg_use_openmp!=0 - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(size()>(cimg_openmp_sizefactor)*1024 && - img.size()>(cimg_openmp_sizefactor)*1024)) - cimg_forXY(res,i,j) { - Ttdouble value = 0; - cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); - res(i,j) = (Tt)value; - } -#else - Tt *ptrd = res._data; - cimg_forXY(res,i,j) { - Ttdouble value = 0; - cimg_forX(*this,k) value+=(*this)(k,j)*img(i,k); - *(ptrd++) = (Tt)value; - } -#endif - return res; - } - - //! In-place division operator. - /** - Similar to operator+=(const t), except that it performs a division instead of an addition. - **/ - template - CImg& operator/=(const t value) { - if (is_empty()) return *this; - cimg_openmp_for(*this,*ptr / value,32768); - return *this; - } - - //! In-place division operator. - /** - Similar to operator+=(const char*), except that it performs a division instead of an addition. - **/ - CImg& operator/=(const char *const expression) { - return div((+*this)._fill(expression,true,1,0,0,"operator/=",this)); - } - - //! In-place division operator. - /** - Replace the image instance by the (right) matrix division between the image instance and the specified - matrix \c img. - \param img Second operand of the matrix division. - \note - - It does \e not compute a pointwise division between two images. For this purpose, use - div(const CImg&) instead. - - It returns the matrix operation \c A*inverse(img). - - The size of the image instance can be modified by this operator. - **/ - template - CImg& operator/=(const CImg& img) { - return (*this*img.get_invert()).move_to(*this); - } - - //! Division operator. - /** - Similar to operator/=(const t), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - template - CImg<_cimg_Tt> operator/(const t value) const { - return CImg<_cimg_Tt>(*this,false)/=value; - } - - //! Division operator. - /** - Similar to operator/=(const char*), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - CImg operator/(const char *const expression) const { - return CImg(*this,false)/=expression; - } - - //! Division operator. - /** - Similar to operator/=(const CImg&), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - template - CImg<_cimg_Tt> operator/(const CImg& img) const { - return (*this)*img.get_invert(); - } - - //! In-place modulo operator. - /** - Similar to operator+=(const t), except that it performs a modulo operation instead of an addition. - **/ - template - CImg& operator%=(const t value) { - if (is_empty()) return *this; - cimg_openmp_for(*this,cimg::mod(*ptr,(T)value),16384); - return *this; - } - - //! In-place modulo operator. - /** - Similar to operator+=(const char*), except that it performs a modulo operation instead of an addition. - **/ - CImg& operator%=(const char *const expression) { - return *this%=(+*this)._fill(expression,true,1,0,0,"operator%=",this); - } - - //! In-place modulo operator. - /** - Similar to operator+=(const CImg&), except that it performs a modulo operation instead of an addition. - **/ - template - CImg& operator%=(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return *this%=+img; - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg<_cimg_Tt> operator%(const t value) const { - return CImg<_cimg_Tt>(*this,false)%=value; - } - - //! Modulo operator. - /** - Similar to operator%=(const char*), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - CImg operator%(const char *const expression) const { - return CImg(*this,false)%=expression; - } - - //! Modulo operator. - /** - Similar to operator%=(const CImg&), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image may be a superset of the initial pixel type \c T, if necessary. - **/ - template - CImg<_cimg_Tt> operator%(const CImg& img) const { - return CImg<_cimg_Tt>(*this,false)%=img; - } - - //! In-place bitwise AND operator. - /** - Similar to operator+=(const t), except that it performs a bitwise AND operation instead of an addition. - **/ - template - CImg& operator&=(const t value) { - if (is_empty()) return *this; - cimg_openmp_for(*this,(longT)*ptr & (longT)value,32768); - return *this; - } - - //! In-place bitwise AND operator. - /** - Similar to operator+=(const char*), except that it performs a bitwise AND operation instead of an addition. - **/ - CImg& operator&=(const char *const expression) { - return *this&=(+*this)._fill(expression,true,1,0,0,"operator&=",this); - } - - //! In-place bitwise AND operator. - /** - Similar to operator+=(const CImg&), except that it performs a bitwise AND operation instead of an addition. - **/ - template - CImg& operator&=(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return *this&=+img; - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg operator&(const t value) const { - return (+*this)&=value; - } - - //! Bitwise AND operator. - /** - Similar to operator&=(const char*), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image is \c T. - **/ - CImg operator&(const char *const expression) const { - return (+*this)&=expression; - } - - //! Bitwise AND operator. - /** - Similar to operator&=(const CImg&), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image is \c T. - **/ - template - CImg operator&(const CImg& img) const { - return (+*this)&=img; - } - - //! In-place bitwise OR operator. - /** - Similar to operator+=(const t), except that it performs a bitwise OR operation instead of an addition. - **/ - template - CImg& operator|=(const t value) { - if (is_empty()) return *this; - cimg_openmp_for(*this,(longT)*ptr | (longT)value,32768); - return *this; - } - - //! In-place bitwise OR operator. - /** - Similar to operator+=(const char*), except that it performs a bitwise OR operation instead of an addition. - **/ - CImg& operator|=(const char *const expression) { - return *this|=(+*this)._fill(expression,true,1,0,0,"operator|=",this); - } - - //! In-place bitwise OR operator. - /** - Similar to operator+=(const CImg&), except that it performs a bitwise OR operation instead of an addition. - **/ - template - CImg& operator|=(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return *this|=+img; - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg operator|(const t value) const { - return (+*this)|=value; - } - - //! Bitwise OR operator. - /** - Similar to operator|=(const char*), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image is \c T. - **/ - CImg operator|(const char *const expression) const { - return (+*this)|=expression; - } - - //! Bitwise OR operator. - /** - Similar to operator|=(const CImg&), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image is \c T. - **/ - template - CImg operator|(const CImg& img) const { - return (+*this)|=img; - } - - //! In-place bitwise XOR operator. - /** - Similar to operator+=(const t), except that it performs a bitwise XOR operation instead of an addition. - \warning - - It does \e not compute the \e power of pixel values. For this purpose, use pow(const t) instead. - **/ - template - CImg& operator^=(const t value) { - if (is_empty()) return *this; - cimg_openmp_for(*this,(longT)*ptr ^ (longT)value,32768); - return *this; - } - - //! In-place bitwise XOR operator. - /** - Similar to operator+=(const char*), except that it performs a bitwise XOR operation instead of an addition. - \warning - - It does \e not compute the \e power of pixel values. For this purpose, use pow(const char*) instead. - **/ - CImg& operator^=(const char *const expression) { - return *this^=(+*this)._fill(expression,true,1,0,0,"operator^=",this); - } - - //! In-place bitwise XOR operator. - /** - Similar to operator+=(const CImg&), except that it performs a bitwise XOR operation instead of an addition. - \warning - - It does \e not compute the \e power of pixel values. For this purpose, use pow(const CImg&) instead. - **/ - template - CImg& operator^=(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return *this^=+img; - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg operator^(const t value) const { - return (+*this)^=value; - } - - //! Bitwise XOR operator. - /** - Similar to operator^=(const char*), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image is \c T. - **/ - CImg operator^(const char *const expression) const { - return (+*this)^=expression; - } - - //! Bitwise XOR operator. - /** - Similar to operator^=(const CImg&), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image is \c T. - **/ - template - CImg operator^(const CImg& img) const { - return (+*this)^=img; - } - - //! In-place bitwise left shift operator. - /** - Similar to operator+=(const t), except that it performs a bitwise left shift instead of an addition. - **/ - template - CImg& operator<<=(const t value) { - if (is_empty()) return *this; - cimg_openmp_for(*this,((longT)*ptr) << (int)value,65536); - return *this; - } - - //! In-place bitwise left shift operator. - /** - Similar to operator+=(const char*), except that it performs a bitwise left shift instead of an addition. - **/ - CImg& operator<<=(const char *const expression) { - return *this<<=(+*this)._fill(expression,true,1,0,0,"operator<<=",this); - } - - //! In-place bitwise left shift operator. - /** - Similar to operator+=(const CImg&), except that it performs a bitwise left shift instead of an addition. - **/ - template - CImg& operator<<=(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return *this^=+img; - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg operator<<(const t value) const { - return (+*this)<<=value; - } - - //! Bitwise left shift operator. - /** - Similar to operator<<=(const char*), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image is \c T. - **/ - CImg operator<<(const char *const expression) const { - return (+*this)<<=expression; - } - - //! Bitwise left shift operator. - /** - Similar to operator<<=(const CImg&), except that it returns a new image instance instead of - operating in-place. - The pixel type of the returned image is \c T. - **/ - template - CImg operator<<(const CImg& img) const { - return (+*this)<<=img; - } - - //! In-place bitwise right shift operator. - /** - Similar to operator+=(const t), except that it performs a bitwise right shift instead of an addition. - **/ - template - CImg& operator>>=(const t value) { - if (is_empty()) return *this; - cimg_openmp_for(*this,((longT)*ptr) >> (int)value,65536); - return *this; - } - - //! In-place bitwise right shift operator. - /** - Similar to operator+=(const char*), except that it performs a bitwise right shift instead of an addition. - **/ - CImg& operator>>=(const char *const expression) { - return *this>>=(+*this)._fill(expression,true,1,0,0,"operator>>=",this); - } - - //! In-place bitwise right shift operator. - /** - Similar to operator+=(const CImg&), except that it performs a bitwise right shift instead of an addition. - **/ - template - CImg& operator>>=(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return *this^=+img; - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs> (int)*(ptrs++)); - for (const t *ptrs = img._data; ptrd> (int)*(ptrs++)); - } - return *this; - } - - //! Bitwise right shift operator. - /** - Similar to operator>>=(const t), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image is \c T. - **/ - template - CImg operator>>(const t value) const { - return (+*this)>>=value; - } - - //! Bitwise right shift operator. - /** - Similar to operator>>=(const char*), except that it returns a new image instance instead of operating in-place. - The pixel type of the returned image is \c T. - **/ - CImg operator>>(const char *const expression) const { - return (+*this)>>=expression; - } - - //! Bitwise right shift operator. - /** - Similar to operator>>=(const CImg&), except that it returns a new image instance instead of - operating in-place. - The pixel type of the returned image is \c T. - **/ - template - CImg operator>>(const CImg& img) const { - return (+*this)>>=img; - } - - //! Bitwise inversion operator. - /** - Similar to operator-(), except that it compute the bitwise inverse instead of the opposite value. - **/ - CImg operator~() const { - CImg res(_width,_height,_depth,_spectrum); - const T *ptrs = _data; - cimg_for(res,ptrd,T) { const ulongT value = (ulongT)*(ptrs++); *ptrd = (T)~value; } - return res; - } - - //! Test if all pixels of an image have the same value. - /** - Return \c true is all pixels of the image instance are equal to the specified \c value. - \param value Reference value to compare with. - **/ - template - bool operator==(const t value) const { - if (is_empty()) return false; - typedef _cimg_Tt Tt; - bool is_equal = true; - for (T *ptrd = _data + size(); is_equal && ptrd>_data; is_equal = ((Tt)*(--ptrd)==(Tt)value)) {} - return is_equal; - } - - //! Test if all pixel values of an image follow a specified expression. - /** - Return \c true is all pixels of the image instance are equal to the specified \c expression. - \param expression Value string describing the way pixel values are compared. - **/ - bool operator==(const char *const expression) const { - return *this==(+*this)._fill(expression,true,1,0,0,"operator==",this); - } - - //! Test if two images have the same size and values. - /** - Return \c true if the image instance and the input image \c img have the same pixel values, - even if the dimensions of the two images do not match. It returns \c false otherwise. - \param img Input image to compare with. - \note - - The pixel buffer pointers data() of the two compared images do not have to be the same for operator==() - to return \c true. - Only the dimensions and the pixel values matter. Thus, the comparison can be \c true even for different - pixel types \c T and \c t. - \par Example - \code - const CImg img1(1,3,1,1, 0,1,2); // Construct a 1x3 vector [0;1;2] (with 'float' pixel values) - const CImg img2(1,3,1,1, 0,1,2); // Construct a 1x3 vector [0;1;2] (with 'char' pixel values) - if (img1==img2) { // Test succeeds, image dimensions and values are the same - std::printf("'img1' and 'img2' have same dimensions and values."); - } - \endcode - **/ - template - bool operator==(const CImg& img) const { - typedef _cimg_Tt Tt; - const ulongT siz = size(); - bool is_equal = true; - if (siz!=img.size()) return false; - t *ptrs = img._data + siz; - for (T *ptrd = _data + siz; is_equal && ptrd>_data; is_equal = ((Tt)*(--ptrd)==(Tt)*(--ptrs))) {} - return is_equal; - } - - //! Test if pixels of an image are all different from a value. - /** - Return \c true is all pixels of the image instance are different than the specified \c value. - \param value Reference value to compare with. - **/ - template - bool operator!=(const t value) const { - return !((*this)==value); - } - - //! Test if all pixel values of an image are different from a specified expression. - /** - Return \c true is all pixels of the image instance are different to the specified \c expression. - \param expression Value string describing the way pixel values are compared. - **/ - bool operator!=(const char *const expression) const { - return !((*this)==expression); - } - - //! Test if two images have different sizes or values. - /** - Return \c true if the image instance and the input image \c img have different dimensions or pixel values, - and \c false otherwise. - \param img Input image to compare with. - \note - - Writing \c img1!=img2 is equivalent to \c !(img1==img2). - **/ - template - bool operator!=(const CImg& img) const { - return !((*this)==img); - } - - //! Construct an image list from two images. - /** - Return a new list of image (\c CImgList instance) containing exactly two elements: - - A copy of the image instance, at position [\c 0]. - - A copy of the specified image \c img, at position [\c 1]. - - \param img Input image that will be the second image of the resulting list. - \note - - The family of operator,() is convenient to easily create list of images, but it is also \e quite \e slow - in practice (see warning below). - - Constructed lists contain no shared images. If image instance or input image \c img are shared, they are - inserted as new non-shared copies in the resulting list. - - The pixel type of the returned list may be a superset of the initial pixel type \c T, if necessary. - \warning - - Pipelining operator,() \c N times will perform \c N copies of the entire content of a (growing) image list. - This may become very expensive in terms of speed and used memory. You should avoid using this technique to - build a new CImgList instance from several images, if you are seeking for performance. - Fast insertions of images in an image list are possible with - CImgList::insert(const CImg&,unsigned int,bool) or move_to(CImgList&,unsigned int). - \par Example - \code - const CImg - img1("reference.jpg"), - img2 = img1.get_mirror('x'), - img3 = img2.get_blur(5); - const CImgList list = (img1,img2); // Create list of two elements from 'img1' and 'img2' - (list,img3).display(); // Display image list containing copies of 'img1','img2' and 'img3' - \endcode - \image html ref_operator_comma.jpg - **/ - template - CImgList<_cimg_Tt> operator,(const CImg& img) const { - return CImgList<_cimg_Tt>(*this,img); - } - - //! Construct an image list from image instance and an input image list. - /** - Return a new list of images (\c CImgList instance) containing exactly \c list.size() \c + \c 1 elements: - - A copy of the image instance, at position [\c 0]. - - A copy of the specified image list \c list, from positions [\c 1] to [\c list.size()]. - - \param list Input image list that will be appended to the image instance. - \note - - Similar to operator,(const CImg&) const, except that it takes an image list as an argument. - **/ - template - CImgList<_cimg_Tt> operator,(const CImgList& list) const { - return CImgList<_cimg_Tt>(list,false).insert(*this,0); - } - - //! Split image along specified axis. - /** - Return a new list of images (\c CImgList instance) containing the split components - of the instance image along the specified axis. - \param axis Splitting axis (can be '\c x','\c y','\c z' or '\c c') - \note - - Similar to get_split(char,int) const, with default second argument. - \par Example - \code - const CImg img("reference.jpg"); // Load a RGB color image - const CImgList list = (img<'c'); // Get a list of its three R,G,B channels - (img,list).display(); - \endcode - \image html ref_operator_less.jpg - **/ - CImgList operator<(const char axis) const { - return get_split(axis); - } - - //@} - //------------------------------------- - // - //! \name Instance Characteristics - //@{ - //------------------------------------- - - //! Return the type of image pixel values as a C string. - /** - Return a \c char* string containing the usual type name of the image pixel values - (i.e. a stringified version of the template parameter \c T). - \note - - The returned string does not contain any spaces. - - If the pixel type \c T does not correspond to a registered type, the string "unknown" is returned. - **/ - static const char* pixel_type() { - return cimg::type::string(); - } - - //! Return the number of image columns. - /** - Return the image width, i.e. the image dimension along the X-axis. - \note - - The width() of an empty image is equal to \c 0. - - width() is typically equal to \c 1 when considering images as \e vectors for matrix calculations. - - width() returns an \c int, although the image width is internally stored as an \c unsigned \c int. - Using an \c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving - \c unsigned \c int variables. - Access to the initial \c unsigned \c int variable is possible (though not recommended) by - (*this)._width. - **/ - int width() const { - return (int)_width; - } - - //! Return the number of image rows. - /** - Return the image height, i.e. the image dimension along the Y-axis. - \note - - The height() of an empty image is equal to \c 0. - - height() returns an \c int, although the image height is internally stored as an \c unsigned \c int. - Using an \c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving - \c unsigned \c int variables. - Access to the initial \c unsigned \c int variable is possible (though not recommended) by - (*this)._height. - **/ - int height() const { - return (int)_height; - } - - //! Return the number of image slices. - /** - Return the image depth, i.e. the image dimension along the Z-axis. - \note - - The depth() of an empty image is equal to \c 0. - - depth() is typically equal to \c 1 when considering usual 2D images. When depth()\c > \c 1, the image - is said to be \e volumetric. - - depth() returns an \c int, although the image depth is internally stored as an \c unsigned \c int. - Using an \c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving - \c unsigned \c int variables. - Access to the initial \c unsigned \c int variable is possible (though not recommended) by - (*this)._depth. - **/ - int depth() const { - return (int)_depth; - } - - //! Return the number of image channels. - /** - Return the number of image channels, i.e. the image dimension along the C-axis. - \note - - The spectrum() of an empty image is equal to \c 0. - - spectrum() is typically equal to \c 1 when considering scalar-valued images, to \c 3 - for RGB-coded color images, and to \c 4 for RGBA-coded color images (with alpha-channel). - The number of channels of an image instance is not limited. The meaning of the pixel values is not linked - up to the number of channels (e.g. a 4-channel image may indifferently stands for a RGBA or CMYK color image). - - spectrum() returns an \c int, although the image spectrum is internally stored as an \c unsigned \c int. - Using an \c int is safer and prevents arithmetic traps possibly encountered when doing calculations involving - \c unsigned \c int variables. - Access to the initial \c unsigned \c int variable is possible (though not recommended) by - (*this)._spectrum. - **/ - int spectrum() const { - return (int)_spectrum; - } - - //! Return the total number of pixel values. - /** - Return width()*\ref height()*\ref depth()*\ref spectrum(), - i.e. the total number of values of type \c T in the pixel buffer of the image instance. - \note - - The size() of an empty image is equal to \c 0. - - The allocated memory size for a pixel buffer of a non-shared \c CImg instance is equal to - size()*sizeof(T). - \par Example - \code - const CImg img(100,100,1,3); // Construct new 100x100 color image - if (img.size()==30000) // Test succeeds - std::printf("Pixel buffer uses %lu bytes", - img.size()*sizeof(float)); - \endcode - **/ - ulongT size() const { - return (ulongT)_width*_height*_depth*_spectrum; - } - - //! Return a pointer to the first pixel value. - /** - Return a \c T*, or a \c const \c T* pointer to the first value in the pixel buffer of the image instance, - whether the instance is \c const or not. - \note - - The data() of an empty image is equal to \c 0 (null pointer). - - The allocated pixel buffer for the image instance starts from \c data() - and goes to data()+\ref size() - 1 (included). - - To get the pointer to one particular location of the pixel buffer, use - data(unsigned int,unsigned int,unsigned int,unsigned int) instead. - **/ - T* data() { - return _data; - } - - //! Return a pointer to the first pixel value \const. - const T* data() const { - return _data; - } - - //! Return a pointer to a located pixel value. - /** - Return a \c T*, or a \c const \c T* pointer to the value located at (\c x,\c y,\c z,\c c) in the pixel buffer - of the image instance, - whether the instance is \c const or not. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note - - Writing \c img.data(x,y,z,c) is equivalent to &(img(x,y,z,c)). Thus, this method has the same - properties as operator()(unsigned int,unsigned int,unsigned int,unsigned int). - **/ -#if cimg_verbosity>=3 - T *data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) { - const ulongT off = (ulongT)offset(x,y,z,c); - if (off>=size()) - cimg::warn(_cimg_instance - "data(): Invalid pointer request, at coordinates (%u,%u,%u,%u) [offset=%u].", - cimg_instance, - x,y,z,c,off); - return _data + off; - } - - //! Return a pointer to a located pixel value \const. - const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const { - return const_cast*>(this)->data(x,y,z,c); - } -#else - T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) { - return _data + x + (ulongT)y*_width + (ulongT)z*_width*_height + (ulongT)c*_width*_height*_depth; - } - - const T* data(const unsigned int x, const unsigned int y=0, const unsigned int z=0, const unsigned int c=0) const { - return _data + x + (ulongT)y*_width + (ulongT)z*_width*_height + (ulongT)c*_width*_height*_depth; - } -#endif - - //! Return the offset to a located pixel value, with respect to the beginning of the pixel buffer. - /** - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note - - Writing \c img.data(x,y,z,c) is equivalent to &(img(x,y,z,c)) - img.data(). - Thus, this method has the same properties as operator()(unsigned int,unsigned int,unsigned int,unsigned int). - \par Example - \code - const CImg img(100,100,1,3); // Define a 100x100 RGB-color image - const long off = img.offset(10,10,0,2); // Get the offset of the blue value of the pixel located at (10,10) - const float val = img[off]; // Get the blue value of this pixel - \endcode - **/ - longT offset(const int x, const int y=0, const int z=0, const int c=0) const { - return x + (longT)y*_width + (longT)z*_width*_height + (longT)c*_width*_height*_depth; - } - - //! Return a CImg::iterator pointing to the first pixel value. - /** - \note - - Equivalent to data(). - - It has been mainly defined for compatibility with STL naming conventions. - **/ - iterator begin() { - return _data; - } - - //! Return a CImg::iterator pointing to the first value of the pixel buffer \const. - const_iterator begin() const { - return _data; - } - - //! Return a CImg::iterator pointing next to the last pixel value. - /** - \note - - Writing \c img.end() is equivalent to img.data() + img.size(). - - It has been mainly defined for compatibility with STL naming conventions. - \warning - - The returned iterator actually points to a value located \e outside the acceptable bounds of the pixel buffer. - Trying to read or write the content of the returned iterator will probably result in a crash. - Use it mainly as a strict upper bound for a CImg::iterator. - \par Example - \code - CImg img(100,100,1,3); // Define a 100x100 RGB color image - // 'img.end()' used below as an upper bound for the iterator. - for (CImg::iterator it = img.begin(); it::iterator pointing next to the last pixel value \const. - const_iterator end() const { - return _data + size(); - } - - //! Return a reference to the first pixel value. - /** - \note - - Writing \c img.front() is equivalent to img[0], or img(0,0,0,0). - - It has been mainly defined for compatibility with STL naming conventions. - **/ - T& front() { - return *_data; - } - - //! Return a reference to the first pixel value \const. - const T& front() const { - return *_data; - } - - //! Return a reference to the last pixel value. - /** - \note - - Writing \c img.back() is equivalent to img[img.size() - 1], or - img(img.width() - 1,img.height() - 1,img.depth() - 1,img.spectrum() - 1). - - It has been mainly defined for compatibility with STL naming conventions. - **/ - T& back() { - return *(_data + size() - 1); - } - - //! Return a reference to the last pixel value \const. - const T& back() const { - return *(_data + size() - 1); - } - - //! Access to a pixel value at a specified offset, using Dirichlet boundary conditions. - /** - Return a reference to the pixel value of the image instance located at a specified \c offset, - or to a specified default value in case of out-of-bounds access. - \param offset Offset to the desired pixel value. - \param out_value Default value returned if \c offset is outside image bounds. - \note - - Writing \c img.at(offset,out_value) is similar to img[offset], except that if \c offset - is outside bounds (e.g. \c offset<0 or \c offset>=img.size()), a reference to a value \c out_value - is safely returned instead. - - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when - you are \e not sure about the validity of the specified pixel offset. - **/ - T& at(const int offset, const T& out_value) { - return (offset<0 || offset>=(int)size())?(cimg::temporary(out_value)=out_value):(*this)[offset]; - } - - //! Access to a pixel value at a specified offset, using Dirichlet boundary conditions \const. - T at(const int offset, const T& out_value) const { - return (offset<0 || offset>=(int)size())?out_value:(*this)[offset]; - } - - //! Access to a pixel value at a specified offset, using Neumann boundary conditions. - /** - Return a reference to the pixel value of the image instance located at a specified \c offset, - or to the nearest pixel location in the image instance in case of out-of-bounds access. - \param offset Offset to the desired pixel value. - \note - - Similar to at(int,const T), except that an out-of-bounds access returns the value of the - nearest pixel in the image instance, regarding the specified offset, i.e. - - If \c offset<0, then \c img[0] is returned. - - If \c offset>=img.size(), then \c img[img.size() - 1] is returned. - - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when - you are \e not sure about the validity of the specified pixel offset. - - If you know your image instance is \e not empty, you may rather use the slightly faster method \c _at(int). - **/ - T& at(const int offset) { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "at(): Empty instance.", - cimg_instance); - return _at(offset); - } - - T& _at(const int offset) { - const unsigned int siz = (unsigned int)size(); - return (*this)[offset<0?0:(unsigned int)offset>=siz?siz - 1:offset]; - } - - //! Access to a pixel value at a specified offset, using Neumann boundary conditions \const. - const T& at(const int offset) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "at(): Empty instance.", - cimg_instance); - return _at(offset); - } - - const T& _at(const int offset) const { - const unsigned int siz = (unsigned int)size(); - return (*this)[offset<0?0:(unsigned int)offset>=siz?siz - 1:offset]; - } - - //! Access to a pixel value, using Dirichlet boundary conditions for the X-coordinate. - /** - Return a reference to the pixel value of the image instance located at (\c x,\c y,\c z,\c c), - or to a specified default value in case of out-of-bounds access along the X-axis. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \param out_value Default value returned if \c (\c x,\c y,\c z,\c c) is outside image bounds. - \note - - Similar to operator()(), except that an out-of-bounds access along the X-axis returns the specified value - \c out_value. - - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when - you are \e not sure about the validity of the specified pixel coordinates. - \warning - - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. - **/ - T& atX(const int x, const int y, const int z, const int c, const T& out_value) { - return (x<0 || x>=width())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c); - } - - //! Access to a pixel value, using Dirichlet boundary conditions for the X-coordinate \const. - T atX(const int x, const int y, const int z, const int c, const T& out_value) const { - return (x<0 || x>=width())?out_value:(*this)(x,y,z,c); - } - - //! Access to a pixel value, using Neumann boundary conditions for the X-coordinate. - /** - Return a reference to the pixel value of the image instance located at (\c x,\c y,\c z,\c c), - or to the nearest pixel location in the image instance in case of out-of-bounds access along the X-axis. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note - - Similar to at(int,int,int,int,const T), except that an out-of-bounds access returns the value of the - nearest pixel in the image instance, regarding the specified X-coordinate. - - Due to the additional boundary checking operation, this method is slower than operator()(). Use it when - you are \e not sure about the validity of the specified pixel coordinates. - - If you know your image instance is \e not empty, you may rather use the slightly faster method - \c _at(int,int,int,int). - \warning - - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. - **/ - T& atX(const int x, const int y=0, const int z=0, const int c=0) { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "atX(): Empty instance.", - cimg_instance); - return _atX(x,y,z,c); - } - - T& _atX(const int x, const int y=0, const int z=0, const int c=0) { - return (*this)(x<0?0:(x>=width()?width() - 1:x),y,z,c); - } - - //! Access to a pixel value, using Neumann boundary conditions for the X-coordinate \const. - const T& atX(const int x, const int y=0, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "atX(): Empty instance.", - cimg_instance); - return _atX(x,y,z,c); - } - - const T& _atX(const int x, const int y=0, const int z=0, const int c=0) const { - return (*this)(x<0?0:(x>=width()?width() - 1:x),y,z,c); - } - - //! Access to a pixel value, using Dirichlet boundary conditions for the X and Y-coordinates. - /** - Similar to atX(int,int,int,int,const T), except that boundary checking is performed both on X and Y-coordinates. - **/ - T& atXY(const int x, const int y, const int z, const int c, const T& out_value) { - return (x<0 || y<0 || x>=width() || y>=height())?(cimg::temporary(out_value)=out_value):(*this)(x,y,z,c); - } - - //! Access to a pixel value, using Dirichlet boundary conditions for the X and Y coordinates \const. - T atXY(const int x, const int y, const int z, const int c, const T& out_value) const { - return (x<0 || y<0 || x>=width() || y>=height())?out_value:(*this)(x,y,z,c); - } - - //! Access to a pixel value, using Neumann boundary conditions for the X and Y-coordinates. - /** - Similar to atX(int,int,int,int), except that boundary checking is performed both on X and Y-coordinates. - \note - - If you know your image instance is \e not empty, you may rather use the slightly faster method - \c _atXY(int,int,int,int). - **/ - T& atXY(const int x, const int y, const int z=0, const int c=0) { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "atXY(): Empty instance.", - cimg_instance); - return _atXY(x,y,z,c); - } - - T& _atXY(const int x, const int y, const int z=0, const int c=0) { - return (*this)(cimg::cut(x,0,width() - 1), - cimg::cut(y,0,height() - 1),z,c); - } - - //! Access to a pixel value, using Neumann boundary conditions for the X and Y-coordinates \const. - const T& atXY(const int x, const int y, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "atXY(): Empty instance.", - cimg_instance); - return _atXY(x,y,z,c); - } - - const T& _atXY(const int x, const int y, const int z=0, const int c=0) const { - return (*this)(cimg::cut(x,0,width() - 1), - cimg::cut(y,0,height() - 1),z,c); - } - - //! Access to a pixel value, using Dirichlet boundary conditions for the X,Y and Z-coordinates. - /** - Similar to atX(int,int,int,int,const T), except that boundary checking is performed both on - X,Y and Z-coordinates. - **/ - T& atXYZ(const int x, const int y, const int z, const int c, const T& out_value) { - return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())? - (cimg::temporary(out_value)=out_value):(*this)(x,y,z,c); - } - - //! Access to a pixel value, using Dirichlet boundary conditions for the X,Y and Z-coordinates \const. - T atXYZ(const int x, const int y, const int z, const int c, const T& out_value) const { - return (x<0 || y<0 || z<0 || x>=width() || y>=height() || z>=depth())?out_value:(*this)(x,y,z,c); - } - - //! Access to a pixel value, using Neumann boundary conditions for the X,Y and Z-coordinates. - /** - Similar to atX(int,int,int,int), except that boundary checking is performed both on X,Y and Z-coordinates. - \note - - If you know your image instance is \e not empty, you may rather use the slightly faster method - \c _atXYZ(int,int,int,int). - **/ - T& atXYZ(const int x, const int y, const int z, const int c=0) { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "atXYZ(): Empty instance.", - cimg_instance); - return _atXYZ(x,y,z,c); - } - - T& _atXYZ(const int x, const int y, const int z, const int c=0) { - return (*this)(cimg::cut(x,0,width() - 1), - cimg::cut(y,0,height() - 1), - cimg::cut(z,0,depth() - 1),c); - } - - //! Access to a pixel value, using Neumann boundary conditions for the X,Y and Z-coordinates \const. - const T& atXYZ(const int x, const int y, const int z, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "atXYZ(): Empty instance.", - cimg_instance); - return _atXYZ(x,y,z,c); - } - - const T& _atXYZ(const int x, const int y, const int z, const int c=0) const { - return (*this)(cimg::cut(x,0,width() - 1), - cimg::cut(y,0,height() - 1), - cimg::cut(z,0,depth() - 1),c); - } - - //! Access to a pixel value, using Dirichlet boundary conditions. - /** - Similar to atX(int,int,int,int,const T), except that boundary checking is performed on all - X,Y,Z and C-coordinates. - **/ - T& atXYZC(const int x, const int y, const int z, const int c, const T& out_value) { - return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())? - (cimg::temporary(out_value)=out_value):(*this)(x,y,z,c); - } - - //! Access to a pixel value, using Dirichlet boundary conditions \const. - T atXYZC(const int x, const int y, const int z, const int c, const T& out_value) const { - return (x<0 || y<0 || z<0 || c<0 || x>=width() || y>=height() || z>=depth() || c>=spectrum())?out_value: - (*this)(x,y,z,c); - } - - //! Access to a pixel value, using Neumann boundary conditions. - /** - Similar to atX(int,int,int,int), except that boundary checking is performed on all X,Y,Z and C-coordinates. - \note - - If you know your image instance is \e not empty, you may rather use the slightly faster method - \c _atXYZC(int,int,int,int). - **/ - T& atXYZC(const int x, const int y, const int z, const int c) { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "atXYZC(): Empty instance.", - cimg_instance); - return _atXYZC(x,y,z,c); - } - - T& _atXYZC(const int x, const int y, const int z, const int c) { - return (*this)(cimg::cut(x,0,width() - 1), - cimg::cut(y,0,height() - 1), - cimg::cut(z,0,depth() - 1), - cimg::cut(c,0,spectrum() - 1)); - } - - //! Access to a pixel value, using Neumann boundary conditions \const. - const T& atXYZC(const int x, const int y, const int z, const int c) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "atXYZC(): Empty instance.", - cimg_instance); - return _atXYZC(x,y,z,c); - } - - const T& _atXYZC(const int x, const int y, const int z, const int c) const { - return (*this)(cimg::cut(x,0,width() - 1), - cimg::cut(y,0,height() - 1), - cimg::cut(z,0,depth() - 1), - cimg::cut(c,0,spectrum() - 1)); - } - - //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for the X-coordinate. - /** - Return a linearly-interpolated pixel value of the image instance located at (\c fx,\c y,\c z,\c c), - or a specified default value in case of out-of-bounds access along the X-axis. - \param fx X-coordinate of the pixel value (float-valued). - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \param out_value Default value returned if \c (\c fx,\c y,\c z,\c c) is outside image bounds. - \note - - Similar to atX(int,int,int,int,const T), except that the returned pixel value is approximated by - a linear interpolation along the X-axis, if corresponding coordinates are not integers. - - The type of the returned pixel value is extended to \c float, if the pixel type \c T is not float-valued. - \warning - - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. - **/ - Tfloat linear_atX(const float fx, const int y, const int z, const int c, const T& out_value) const { - const int - x = (int)fx - (fx>=0?0:1), nx = x + 1; - const float - dx = fx - x; - const Tfloat - Ic = (Tfloat)atX(x,y,z,c,out_value), In = (Tfloat)atXY(nx,y,z,c,out_value); - return Ic + dx*(In - Ic); - } - - //! Return pixel value, using linear interpolation and Neumann boundary conditions for the X-coordinate. - /** - Return a linearly-interpolated pixel value of the image instance located at (\c fx,\c y,\c z,\c c), - or the value of the nearest pixel location in the image instance in case of out-of-bounds access along - the X-axis. - \param fx X-coordinate of the pixel value (float-valued). - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note - - Similar to linear_atX(float,int,int,int,const T) const, except that an out-of-bounds access returns - the value of the nearest pixel in the image instance, regarding the specified X-coordinate. - - If you know your image instance is \e not empty, you may rather use the slightly faster method - \c _linear_atX(float,int,int,int). - \warning - - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. - **/ - Tfloat linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "linear_atX(): Empty instance.", - cimg_instance); - - return _linear_atX(fx,y,z,c); - } - - Tfloat _linear_atX(const float fx, const int y=0, const int z=0, const int c=0) const { - const float - nfx = cimg::cut(fx,0,width() - 1); - const unsigned int - x = (unsigned int)nfx; - const float - dx = nfx - x; - const unsigned int - nx = dx>0?x + 1:x; - const Tfloat - Ic = (Tfloat)(*this)(x,y,z,c), In = (Tfloat)(*this)(nx,y,z,c); - return Ic + dx*(In - Ic); - } - - //! Return pixel value, using linear interpolation and periodic boundary conditions for the X-coordinate. - Tfloat linear_atX_p(const float fx, const int y=0, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "linear_atX_p(): Empty instance.", - cimg_instance); - - return _linear_atX_p(fx,y,z,c); - } - - Tfloat _linear_atX_p(const float fx, const int y=0, const int z=0, const int c=0) const { - const float - nfx = cimg::mod(fx,_width - 0.5f); - const unsigned int - x = (unsigned int)nfx; - const float - dx = nfx - x; - const unsigned int - nx = cimg::mod(x + 1,_width); - const Tfloat - Ic = (Tfloat)(*this)(x,y,z,c), In = (Tfloat)(*this)(nx,y,z,c); - return Ic + dx*(In - Ic); - } - - //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for the X and Y-coordinates. - /** - Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the - boundary checking are achieved both for X and Y-coordinates. - **/ - Tfloat linear_atXY(const float fx, const float fy, const int z, const int c, const T& out_value) const { - const int - x = (int)fx - (fx>=0?0:1), nx = x + 1, - y = (int)fy - (fy>=0?0:1), ny = y + 1; - const float - dx = fx - x, - dy = fy - y; - const Tfloat - Icc = (Tfloat)atXY(x,y,z,c,out_value), Inc = (Tfloat)atXY(nx,y,z,c,out_value), - Icn = (Tfloat)atXY(x,ny,z,c,out_value), Inn = (Tfloat)atXY(nx,ny,z,c,out_value); - return Icc + (Inc - Icc + (Icc + Inn - Icn - Inc)*dy)*dx + (Icn - Icc)*dy; - } - - //! Return pixel value, using linear interpolation and Neumann boundary conditions for the X and Y-coordinates. - /** - Similar to linear_atX(float,int,int,int) const, except that the linear interpolation and the boundary checking - are achieved both for X and Y-coordinates. - \note - - If you know your image instance is \e not empty, you may rather use the slightly faster method - \c _linear_atXY(float,float,int,int). - **/ - Tfloat linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "linear_atXY(): Empty instance.", - cimg_instance); - - return _linear_atXY(fx,fy,z,c); - } - - Tfloat _linear_atXY(const float fx, const float fy, const int z=0, const int c=0) const { - const float - nfx = cimg::cut(fx,0,width() - 1), - nfy = cimg::cut(fy,0,height() - 1); - const unsigned int - x = (unsigned int)nfx, - y = (unsigned int)nfy; - const float - dx = nfx - x, - dy = nfy - y; - const unsigned int - nx = dx>0?x + 1:x, - ny = dy>0?y + 1:y; - const Tfloat - Icc = (Tfloat)(*this)(x,y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c), - Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c); - return Icc + (Inc - Icc + (Icc + Inn - Icn - Inc)*dy)*dx + (Icn - Icc)*dy; - } - - //! Return pixel value, using linear interpolation and periodic boundary conditions for the X and Y-coordinates. - Tfloat linear_atXY_p(const float fx, const float fy, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "linear_atXY_p(): Empty instance.", - cimg_instance); - - return _linear_atXY_p(fx,fy,z,c); - } - - Tfloat _linear_atXY_p(const float fx, const float fy, const int z=0, const int c=0) const { - const float - nfx = cimg::mod(fx,_width - 0.5f), - nfy = cimg::mod(fy,_height - 0.5f); - const unsigned int - x = (unsigned int)nfx, - y = (unsigned int)nfy; - const float - dx = nfx - x, - dy = nfy - y; - const unsigned int - nx = cimg::mod(x + 1,_width), - ny = cimg::mod(y + 1,_height); - const Tfloat - Icc = (Tfloat)(*this)(x,y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c), - Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c); - return Icc + (Inc - Icc + (Icc + Inn - Icn - Inc)*dy)*dx + (Icn - Icc)*dy; - } - - //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for the X,Y and Z-coordinates. - /** - Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the - boundary checking are achieved both for X,Y and Z-coordinates. - **/ - Tfloat linear_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value) const { - const int - x = (int)fx - (fx>=0?0:1), nx = x + 1, - y = (int)fy - (fy>=0?0:1), ny = y + 1, - z = (int)fz - (fz>=0?0:1), nz = z + 1; - const float - dx = fx - x, - dy = fy - y, - dz = fz - z; - const Tfloat - Iccc = (Tfloat)atXYZ(x,y,z,c,out_value), Incc = (Tfloat)atXYZ(nx,y,z,c,out_value), - Icnc = (Tfloat)atXYZ(x,ny,z,c,out_value), Innc = (Tfloat)atXYZ(nx,ny,z,c,out_value), - Iccn = (Tfloat)atXYZ(x,y,nz,c,out_value), Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value), - Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value), Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value); - return Iccc + - (Incc - Iccc + - (Iccc + Innc - Icnc - Incc + - (Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)*dz)*dy + - (Iccc + Incn - Iccn - Incc)*dz)*dx + - (Icnc - Iccc + - (Iccc + Icnn - Iccn - Icnc)*dz)*dy + - (Iccn - Iccc)*dz; - } - - //! Return pixel value, using linear interpolation and Neumann boundary conditions for the X,Y and Z-coordinates. - /** - Similar to linear_atX(float,int,int,int) const, except that the linear interpolation and the boundary checking - are achieved both for X,Y and Z-coordinates. - \note - - If you know your image instance is \e not empty, you may rather use the slightly faster method - \c _linear_atXYZ(float,float,float,int). - **/ - Tfloat linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "linear_atXYZ(): Empty instance.", - cimg_instance); - - return _linear_atXYZ(fx,fy,fz,c); - } - - Tfloat _linear_atXYZ(const float fx, const float fy=0, const float fz=0, const int c=0) const { - const float - nfx = cimg::cut(fx,0,width() - 1), - nfy = cimg::cut(fy,0,height() - 1), - nfz = cimg::cut(fz,0,depth() - 1); - const unsigned int - x = (unsigned int)nfx, - y = (unsigned int)nfy, - z = (unsigned int)nfz; - const float - dx = nfx - x, - dy = nfy - y, - dz = nfz - z; - const unsigned int - nx = dx>0?x + 1:x, - ny = dy>0?y + 1:y, - nz = dz>0?z + 1:z; - const Tfloat - Iccc = (Tfloat)(*this)(x,y,z,c), Incc = (Tfloat)(*this)(nx,y,z,c), - Icnc = (Tfloat)(*this)(x,ny,z,c), Innc = (Tfloat)(*this)(nx,ny,z,c), - Iccn = (Tfloat)(*this)(x,y,nz,c), Incn = (Tfloat)(*this)(nx,y,nz,c), - Icnn = (Tfloat)(*this)(x,ny,nz,c), Innn = (Tfloat)(*this)(nx,ny,nz,c); - return Iccc + - (Incc - Iccc + - (Iccc + Innc - Icnc - Incc + - (Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)*dz)*dy + - (Iccc + Incn - Iccn - Incc)*dz)*dx + - (Icnc - Iccc + - (Iccc + Icnn - Iccn - Icnc)*dz)*dy + - (Iccn - Iccc)*dz; - } - - //! Return pixel value, using linear interpolation and periodic boundary conditions for the X,Y and Z-coordinates. - Tfloat linear_atXYZ_p(const float fx, const float fy=0, const float fz=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "linear_atXYZ_p(): Empty instance.", - cimg_instance); - - return _linear_atXYZ_p(fx,fy,fz,c); - } - - Tfloat _linear_atXYZ_p(const float fx, const float fy=0, const float fz=0, const int c=0) const { - const float - nfx = cimg::mod(fx,_width - 0.5f), - nfy = cimg::mod(fy,_height - 0.5f), - nfz = cimg::mod(fz,_depth - 0.5f); - const unsigned int - x = (unsigned int)nfx, - y = (unsigned int)nfy, - z = (unsigned int)nfz; - const float - dx = nfx - x, - dy = nfy - y, - dz = nfz - z; - const unsigned int - nx = cimg::mod(x + 1,_width), - ny = cimg::mod(y + 1,_height), - nz = cimg::mod(z + 1,_depth); - const Tfloat - Iccc = (Tfloat)(*this)(x,y,z,c), Incc = (Tfloat)(*this)(nx,y,z,c), - Icnc = (Tfloat)(*this)(x,ny,z,c), Innc = (Tfloat)(*this)(nx,ny,z,c), - Iccn = (Tfloat)(*this)(x,y,nz,c), Incn = (Tfloat)(*this)(nx,y,nz,c), - Icnn = (Tfloat)(*this)(x,ny,nz,c), Innn = (Tfloat)(*this)(nx,ny,nz,c); - return Iccc + - (Incc - Iccc + - (Iccc + Innc - Icnc - Incc + - (Iccn + Innn + Icnc + Incc - Icnn - Incn - Iccc - Innc)*dz)*dy + - (Iccc + Incn - Iccn - Incc)*dz)*dx + - (Icnc - Iccc + - (Iccc + Icnn - Iccn - Icnc)*dz)*dy + - (Iccn - Iccc)*dz; - } - - //! Return pixel value, using linear interpolation and Dirichlet boundary conditions for all X,Y,Z,C-coordinates. - /** - Similar to linear_atX(float,int,int,int,const T) const, except that the linear interpolation and the - boundary checking are achieved for all X,Y,Z and C-coordinates. - **/ - Tfloat linear_atXYZC(const float fx, const float fy, const float fz, const float fc, const T& out_value) const { - const int - x = (int)fx - (fx>=0?0:1), nx = x + 1, - y = (int)fy - (fy>=0?0:1), ny = y + 1, - z = (int)fz - (fz>=0?0:1), nz = z + 1, - c = (int)fc - (fc>=0?0:1), nc = c + 1; - const float - dx = fx - x, - dy = fy - y, - dz = fz - z, - dc = fc - c; - const Tfloat - Icccc = (Tfloat)atXYZC(x,y,z,c,out_value), Inccc = (Tfloat)atXYZC(nx,y,z,c,out_value), - Icncc = (Tfloat)atXYZC(x,ny,z,c,out_value), Inncc = (Tfloat)atXYZC(nx,ny,z,c,out_value), - Iccnc = (Tfloat)atXYZC(x,y,nz,c,out_value), Incnc = (Tfloat)atXYZC(nx,y,nz,c,out_value), - Icnnc = (Tfloat)atXYZC(x,ny,nz,c,out_value), Innnc = (Tfloat)atXYZC(nx,ny,nz,c,out_value), - Icccn = (Tfloat)atXYZC(x,y,z,nc,out_value), Inccn = (Tfloat)atXYZC(nx,y,z,nc,out_value), - Icncn = (Tfloat)atXYZC(x,ny,z,nc,out_value), Inncn = (Tfloat)atXYZC(nx,ny,z,nc,out_value), - Iccnn = (Tfloat)atXYZC(x,y,nz,nc,out_value), Incnn = (Tfloat)atXYZC(nx,y,nz,nc,out_value), - Icnnn = (Tfloat)atXYZC(x,ny,nz,nc,out_value), Innnn = (Tfloat)atXYZC(nx,ny,nz,nc,out_value); - return Icccc + - dx*(Inccc - Icccc + - dy*(Icccc + Inncc - Icncc - Inccc + - dz*(Iccnc + Innnc + Icncc + Inccc - Icnnc - Incnc - Icccc - Inncc + - dc*(Iccnn + Innnn + Icncn + Inccn + Icnnc + Incnc + Icccc + Inncc - - Icnnn - Incnn - Icccn - Inncn - Iccnc - Innnc - Icncc - Inccc)) + - dc*(Icccn + Inncn + Icncc + Inccc - Icncn - Inccn - Icccc - Inncc)) + - dz*(Icccc + Incnc - Iccnc - Inccc + - dc*(Icccn + Incnn + Iccnc + Inccc - Iccnn - Inccn - Icccc - Incnc)) + - dc*(Icccc + Inccn - Inccc - Icccn)) + - dy*(Icncc - Icccc + - dz*(Icccc + Icnnc - Iccnc - Icncc + - dc*(Icccn + Icnnn + Iccnc + Icncc - Iccnn - Icncn - Icccc - Icnnc)) + - dc*(Icccc + Icncn - Icncc - Icccn)) + - dz*(Iccnc - Icccc + - dc*(Icccc + Iccnn - Iccnc - Icccn)) + - dc*(Icccn -Icccc); - } - - //! Return pixel value, using linear interpolation and Neumann boundary conditions for all X,Y,Z and C-coordinates. - /** - Similar to linear_atX(float,int,int,int) const, except that the linear interpolation and the boundary checking - are achieved for all X,Y,Z and C-coordinates. - \note - - If you know your image instance is \e not empty, you may rather use the slightly faster method - \c _linear_atXYZC(float,float,float,float). - **/ - Tfloat linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "linear_atXYZC(): Empty instance.", - cimg_instance); - - return _linear_atXYZC(fx,fy,fz,fc); - } - - Tfloat _linear_atXYZC(const float fx, const float fy=0, const float fz=0, const float fc=0) const { - const float - nfx = cimg::cut(fx,0,width() - 1), - nfy = cimg::cut(fy,0,height() - 1), - nfz = cimg::cut(fz,0,depth() - 1), - nfc = cimg::cut(fc,0,spectrum() - 1); - const unsigned int - x = (unsigned int)nfx, - y = (unsigned int)nfy, - z = (unsigned int)nfz, - c = (unsigned int)nfc; - const float - dx = nfx - x, - dy = nfy - y, - dz = nfz - z, - dc = nfc - c; - const unsigned int - nx = dx>0?x + 1:x, - ny = dy>0?y + 1:y, - nz = dz>0?z + 1:z, - nc = dc>0?c + 1:c; - const Tfloat - Icccc = (Tfloat)(*this)(x,y,z,c), Inccc = (Tfloat)(*this)(nx,y,z,c), - Icncc = (Tfloat)(*this)(x,ny,z,c), Inncc = (Tfloat)(*this)(nx,ny,z,c), - Iccnc = (Tfloat)(*this)(x,y,nz,c), Incnc = (Tfloat)(*this)(nx,y,nz,c), - Icnnc = (Tfloat)(*this)(x,ny,nz,c), Innnc = (Tfloat)(*this)(nx,ny,nz,c), - Icccn = (Tfloat)(*this)(x,y,z,nc), Inccn = (Tfloat)(*this)(nx,y,z,nc), - Icncn = (Tfloat)(*this)(x,ny,z,nc), Inncn = (Tfloat)(*this)(nx,ny,z,nc), - Iccnn = (Tfloat)(*this)(x,y,nz,nc), Incnn = (Tfloat)(*this)(nx,y,nz,nc), - Icnnn = (Tfloat)(*this)(x,ny,nz,nc), Innnn = (Tfloat)(*this)(nx,ny,nz,nc); - return Icccc + - dx*(Inccc - Icccc + - dy*(Icccc + Inncc - Icncc - Inccc + - dz*(Iccnc + Innnc + Icncc + Inccc - Icnnc - Incnc - Icccc - Inncc + - dc*(Iccnn + Innnn + Icncn + Inccn + Icnnc + Incnc + Icccc + Inncc - - Icnnn - Incnn - Icccn - Inncn - Iccnc - Innnc - Icncc - Inccc)) + - dc*(Icccn + Inncn + Icncc + Inccc - Icncn - Inccn - Icccc - Inncc)) + - dz*(Icccc + Incnc - Iccnc - Inccc + - dc*(Icccn + Incnn + Iccnc + Inccc - Iccnn - Inccn - Icccc - Incnc)) + - dc*(Icccc + Inccn - Inccc - Icccn)) + - dy*(Icncc - Icccc + - dz*(Icccc + Icnnc - Iccnc - Icncc + - dc*(Icccn + Icnnn + Iccnc + Icncc - Iccnn - Icncn - Icccc - Icnnc)) + - dc*(Icccc + Icncn - Icncc - Icccn)) + - dz*(Iccnc - Icccc + - dc*(Icccc + Iccnn - Iccnc - Icccn)) + - dc*(Icccn - Icccc); - } - - //! Return pixel value, using linear interpolation and periodic boundary conditions for all X,Y,Z and C-coordinates. - Tfloat linear_atXYZC_p(const float fx, const float fy=0, const float fz=0, const float fc=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "linear_atXYZC_p(): Empty instance.", - cimg_instance); - - return _linear_atXYZC_p(fx,fy,fz,fc); - } - - Tfloat _linear_atXYZC_p(const float fx, const float fy=0, const float fz=0, const float fc=0) const { - const float - nfx = cimg::mod(fx,_width - 0.5f), - nfy = cimg::mod(fy,_height - 0.5f), - nfz = cimg::mod(fz,_depth - 0.5f), - nfc = cimg::mod(fc,_spectrum - 0.5f); - const unsigned int - x = (unsigned int)nfx, - y = (unsigned int)nfy, - z = (unsigned int)nfz, - c = (unsigned int)nfc; - const float - dx = nfx - x, - dy = nfy - y, - dz = nfz - z, - dc = nfc - c; - const unsigned int - nx = cimg::mod(x + 1,_width), - ny = cimg::mod(y + 1,_height), - nz = cimg::mod(z + 1,_depth), - nc = cimg::mod(c + 1,_spectrum); - const Tfloat - Icccc = (Tfloat)(*this)(x,y,z,c), Inccc = (Tfloat)(*this)(nx,y,z,c), - Icncc = (Tfloat)(*this)(x,ny,z,c), Inncc = (Tfloat)(*this)(nx,ny,z,c), - Iccnc = (Tfloat)(*this)(x,y,nz,c), Incnc = (Tfloat)(*this)(nx,y,nz,c), - Icnnc = (Tfloat)(*this)(x,ny,nz,c), Innnc = (Tfloat)(*this)(nx,ny,nz,c), - Icccn = (Tfloat)(*this)(x,y,z,nc), Inccn = (Tfloat)(*this)(nx,y,z,nc), - Icncn = (Tfloat)(*this)(x,ny,z,nc), Inncn = (Tfloat)(*this)(nx,ny,z,nc), - Iccnn = (Tfloat)(*this)(x,y,nz,nc), Incnn = (Tfloat)(*this)(nx,y,nz,nc), - Icnnn = (Tfloat)(*this)(x,ny,nz,nc), Innnn = (Tfloat)(*this)(nx,ny,nz,nc); - return Icccc + - dx*(Inccc - Icccc + - dy*(Icccc + Inncc - Icncc - Inccc + - dz*(Iccnc + Innnc + Icncc + Inccc - Icnnc - Incnc - Icccc - Inncc + - dc*(Iccnn + Innnn + Icncn + Inccn + Icnnc + Incnc + Icccc + Inncc - - Icnnn - Incnn - Icccn - Inncn - Iccnc - Innnc - Icncc - Inccc)) + - dc*(Icccn + Inncn + Icncc + Inccc - Icncn - Inccn - Icccc - Inncc)) + - dz*(Icccc + Incnc - Iccnc - Inccc + - dc*(Icccn + Incnn + Iccnc + Inccc - Iccnn - Inccn - Icccc - Incnc)) + - dc*(Icccc + Inccn - Inccc - Icccn)) + - dy*(Icncc - Icccc + - dz*(Icccc + Icnnc - Iccnc - Icncc + - dc*(Icccn + Icnnn + Iccnc + Icncc - Iccnn - Icncn - Icccc - Icnnc)) + - dc*(Icccc + Icncn - Icncc - Icccn)) + - dz*(Iccnc - Icccc + - dc*(Icccc + Iccnn - Iccnc - Icccn)) + - dc*(Icccn - Icccc); - } - - //! Return pixel value, using cubic interpolation and Dirichlet boundary conditions for the X-coordinate. - /** - Return a cubicly-interpolated pixel value of the image instance located at (\c fx,\c y,\c z,\c c), - or a specified default value in case of out-of-bounds access along the X-axis. - The cubic interpolation uses Hermite splines. - \param fx d X-coordinate of the pixel value (float-valued). - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \param out_value Default value returned if \c (\c fx,\c y,\c z,\c c) is outside image bounds. - \note - - Similar to linear_atX(float,int,int,int,const T) const, except that the returned pixel value is - approximated by a \e cubic interpolation along the X-axis. - - The type of the returned pixel value is extended to \c float, if the pixel type \c T is not float-valued. - \warning - - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. - **/ - Tfloat cubic_atX(const float fx, const int y, const int z, const int c, const T& out_value) const { - const int - x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2; - const float - dx = fx - x; - const Tfloat - Ip = (Tfloat)atX(px,y,z,c,out_value), Ic = (Tfloat)atX(x,y,z,c,out_value), - In = (Tfloat)atX(nx,y,z,c,out_value), Ia = (Tfloat)atX(ax,y,z,c,out_value); - return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia)); - } - - //! Return clamped pixel value, using cubic interpolation and Dirichlet boundary conditions for the X-coordinate. - /** - Similar to cubic_atX(float,int,int,int,const T) const, except that the return value is clamped to stay in the - min/max range of the datatype \c T. - **/ - T cubic_atX_c(const float fx, const int y, const int z, const int c, const T& out_value) const { - return cimg::type::cut(cubic_atX(fx,y,z,c,out_value)); - } - - //! Return pixel value, using cubic interpolation and Neumann boundary conditions for the X-coordinate. - /** - Return a cubicly-interpolated pixel value of the image instance located at (\c fx,\c y,\c z,\c c), - or the value of the nearest pixel location in the image instance in case of out-of-bounds access - along the X-axis. The cubic interpolation uses Hermite splines. - \param fx X-coordinate of the pixel value (float-valued). - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note - - Similar to cubic_atX(float,int,int,int,const T) const, except that the returned pixel value is - approximated by a cubic interpolation along the X-axis. - - If you know your image instance is \e not empty, you may rather use the slightly faster method - \c _cubic_atX(float,int,int,int). - \warning - - There is \e no boundary checking performed for the Y,Z and C-coordinates, so they must be inside image bounds. - **/ - Tfloat cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "cubic_atX(): Empty instance.", - cimg_instance); - return _cubic_atX(fx,y,z,c); - } - - Tfloat _cubic_atX(const float fx, const int y=0, const int z=0, const int c=0) const { - const float - nfx = cimg::type::is_nan(fx)?0:cimg::cut(fx,0,width() - 1); - const int - x = (int)nfx; - const float - dx = nfx - x; - const int - px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2; - const Tfloat - Ip = (Tfloat)(*this)(px,y,z,c), Ic = (Tfloat)(*this)(x,y,z,c), - In = (Tfloat)(*this)(nx,y,z,c), Ia = (Tfloat)(*this)(ax,y,z,c); - return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia)); - } - - //! Return clamped pixel value, using cubic interpolation and Neumann boundary conditions for the X-coordinate. - /** - Similar to cubic_atX(float,int,int,int) const, except that the return value is clamped to stay in the - min/max range of the datatype \c T. - **/ - T cubic_atX_c(const float fx, const int y, const int z, const int c) const { - return cimg::type::cut(cubic_atX(fx,y,z,c)); - } - - T _cubic_atX_c(const float fx, const int y, const int z, const int c) const { - return cimg::type::cut(_cubic_atX(fx,y,z,c)); - } - - //! Return pixel value, using cubic interpolation and periodic boundary conditions for the X-coordinate. - Tfloat cubic_atX_p(const float fx, const int y=0, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "cubic_atX_p(): Empty instance.", - cimg_instance); - return _cubic_atX_p(fx,y,z,c); - } - - Tfloat _cubic_atX_p(const float fx, const int y=0, const int z=0, const int c=0) const { - const float - nfx = cimg::type::is_nan(fx)?0:cimg::mod(fx,_width - 0.5f); - const int - x = (int)nfx; - const float - dx = nfx - x; - const int - px = cimg::mod(x - 1,width()), nx = cimg::mod(x + 1,width()), ax = cimg::mod(x + 2,width()); - const Tfloat - Ip = (Tfloat)(*this)(px,y,z,c), Ic = (Tfloat)(*this)(x,y,z,c), - In = (Tfloat)(*this)(nx,y,z,c), Ia = (Tfloat)(*this)(ax,y,z,c); - return Ic + 0.5f*(dx*(-Ip + In) + dx*dx*(2*Ip - 5*Ic + 4*In - Ia) + dx*dx*dx*(-Ip + 3*Ic - 3*In + Ia)); - } - - T cubic_atX_pc(const float fx, const int y, const int z, const int c) const { - return cimg::type::cut(cubic_atX_p(fx,y,z,c)); - } - - T _cubic_atX_pc(const float fx, const int y, const int z, const int c) const { - return cimg::type::cut(_cubic_atX_p(fx,y,z,c)); - } - - //! Return pixel value, using cubic interpolation and Dirichlet boundary conditions for the X and Y-coordinates. - /** - Similar to cubic_atX(float,int,int,int,const T) const, except that the cubic interpolation and boundary checking - are achieved both for X and Y-coordinates. - **/ - Tfloat cubic_atXY(const float fx, const float fy, const int z, const int c, const T& out_value) const { - const int - x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2, - y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2; - const float dx = fx - x, dy = fy - y; - const Tfloat - Ipp = (Tfloat)atXY(px,py,z,c,out_value), Icp = (Tfloat)atXY(x,py,z,c,out_value), - Inp = (Tfloat)atXY(nx,py,z,c,out_value), Iap = (Tfloat)atXY(ax,py,z,c,out_value), - Ip = Icp + 0.5f*(dx*(-Ipp + Inp) + dx*dx*(2*Ipp - 5*Icp + 4*Inp - Iap) + dx*dx*dx*(-Ipp + 3*Icp - 3*Inp + Iap)), - Ipc = (Tfloat)atXY(px,y,z,c,out_value), Icc = (Tfloat)atXY(x, y,z,c,out_value), - Inc = (Tfloat)atXY(nx,y,z,c,out_value), Iac = (Tfloat)atXY(ax,y,z,c,out_value), - Ic = Icc + 0.5f*(dx*(-Ipc + Inc) + dx*dx*(2*Ipc - 5*Icc + 4*Inc - Iac) + dx*dx*dx*(-Ipc + 3*Icc - 3*Inc + Iac)), - Ipn = (Tfloat)atXY(px,ny,z,c,out_value), Icn = (Tfloat)atXY(x,ny,z,c,out_value), - Inn = (Tfloat)atXY(nx,ny,z,c,out_value), Ian = (Tfloat)atXY(ax,ny,z,c,out_value), - In = Icn + 0.5f*(dx*(-Ipn + Inn) + dx*dx*(2*Ipn - 5*Icn + 4*Inn - Ian) + dx*dx*dx*(-Ipn + 3*Icn - 3*Inn + Ian)), - Ipa = (Tfloat)atXY(px,ay,z,c,out_value), Ica = (Tfloat)atXY(x,ay,z,c,out_value), - Ina = (Tfloat)atXY(nx,ay,z,c,out_value), Iaa = (Tfloat)atXY(ax,ay,z,c,out_value), - Ia = Ica + 0.5f*(dx*(-Ipa + Ina) + dx*dx*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dx*dx*dx*(-Ipa + 3*Ica - 3*Ina + Iaa)); - return Ic + 0.5f*(dy*(-Ip + In) + dy*dy*(2*Ip - 5*Ic + 4*In - Ia) + dy*dy*dy*(-Ip + 3*Ic - 3*In + Ia)); - } - - //! Return clamped pixel value, using cubic interpolation and Dirichlet boundary conditions for the X,Y-coordinates. - /** - Similar to cubic_atXY(float,float,int,int,const T) const, except that the return value is clamped to stay in the - min/max range of the datatype \c T. - **/ - T cubic_atXY_c(const float fx, const float fy, const int z, const int c, const T& out_value) const { - return cimg::type::cut(cubic_atXY(fx,fy,z,c,out_value)); - } - - //! Return pixel value, using cubic interpolation and Neumann boundary conditions for the X and Y-coordinates. - /** - Similar to cubic_atX(float,int,int,int) const, except that the cubic interpolation and boundary checking - are achieved for both X and Y-coordinates. - \note - - If you know your image instance is \e not empty, you may rather use the slightly faster method - \c _cubic_atXY(float,float,int,int). - **/ - Tfloat cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "cubic_atXY(): Empty instance.", - cimg_instance); - return _cubic_atXY(fx,fy,z,c); - } - - Tfloat _cubic_atXY(const float fx, const float fy, const int z=0, const int c=0) const { - const float - nfx = cimg::type::is_nan(fx)?0:cimg::cut(fx,0,width() - 1), - nfy = cimg::type::is_nan(fy)?0:cimg::cut(fy,0,height() - 1); - const int x = (int)nfx, y = (int)nfy; - const float dx = nfx - x, dy = nfy - y; - const int - px = x - 1<0?0:x - 1, nx = dx<=0?x:x + 1, ax = x + 2>=width()?width() - 1:x + 2, - py = y - 1<0?0:y - 1, ny = dy<=0?y:y + 1, ay = y + 2>=height()?height() - 1:y + 2; - const Tfloat - Ipp = (Tfloat)(*this)(px,py,z,c), Icp = (Tfloat)(*this)(x,py,z,c), Inp = (Tfloat)(*this)(nx,py,z,c), - Iap = (Tfloat)(*this)(ax,py,z,c), - Ip = Icp + 0.5f*(dx*(-Ipp + Inp) + dx*dx*(2*Ipp - 5*Icp + 4*Inp - Iap) + dx*dx*dx*(-Ipp + 3*Icp - 3*Inp + Iap)), - Ipc = (Tfloat)(*this)(px,y,z,c), Icc = (Tfloat)(*this)(x, y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c), - Iac = (Tfloat)(*this)(ax,y,z,c), - Ic = Icc + 0.5f*(dx*(-Ipc + Inc) + dx*dx*(2*Ipc - 5*Icc + 4*Inc - Iac) + dx*dx*dx*(-Ipc + 3*Icc - 3*Inc + Iac)), - Ipn = (Tfloat)(*this)(px,ny,z,c), Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c), - Ian = (Tfloat)(*this)(ax,ny,z,c), - In = Icn + 0.5f*(dx*(-Ipn + Inn) + dx*dx*(2*Ipn - 5*Icn + 4*Inn - Ian) + dx*dx*dx*(-Ipn + 3*Icn - 3*Inn + Ian)), - Ipa = (Tfloat)(*this)(px,ay,z,c), Ica = (Tfloat)(*this)(x,ay,z,c), Ina = (Tfloat)(*this)(nx,ay,z,c), - Iaa = (Tfloat)(*this)(ax,ay,z,c), - Ia = Ica + 0.5f*(dx*(-Ipa + Ina) + dx*dx*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dx*dx*dx*(-Ipa + 3*Ica - 3*Ina + Iaa)); - return Ic + 0.5f*(dy*(-Ip + In) + dy*dy*(2*Ip - 5*Ic + 4*In - Ia) + dy*dy*dy*(-Ip + 3*Ic - 3*In + Ia)); - } - - //! Return clamped pixel value, using cubic interpolation and Neumann boundary conditions for the X,Y-coordinates. - /** - Similar to cubic_atXY(float,float,int,int) const, except that the return value is clamped to stay in the - min/max range of the datatype \c T. - **/ - T cubic_atXY_c(const float fx, const float fy, const int z, const int c) const { - return cimg::type::cut(cubic_atXY(fx,fy,z,c)); - } - - T _cubic_atXY_c(const float fx, const float fy, const int z, const int c) const { - return cimg::type::cut(_cubic_atXY(fx,fy,z,c)); - } - - //! Return pixel value, using cubic interpolation and periodic boundary conditions for the X and Y-coordinates. - Tfloat cubic_atXY_p(const float fx, const float fy, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "cubic_atXY_p(): Empty instance.", - cimg_instance); - return _cubic_atXY_p(fx,fy,z,c); - } - - Tfloat _cubic_atXY_p(const float fx, const float fy, const int z=0, const int c=0) const { - const float - nfx = cimg::type::is_nan(fx)?0:cimg::mod(fx,_width - 0.5f), - nfy = cimg::type::is_nan(fy)?0:cimg::mod(fy,_height - 0.5f); - const int x = (int)nfx, y = (int)nfy; - const float dx = nfx - x, dy = nfy - y; - const int - px = cimg::mod(x - 1,width()), nx = cimg::mod(x + 1,width()), ax = cimg::mod(x + 2,width()), - py = cimg::mod(y - 1,height()), ny = cimg::mod(y + 1,height()), ay = cimg::mod(y + 2,height()); - const Tfloat - Ipp = (Tfloat)(*this)(px,py,z,c), Icp = (Tfloat)(*this)(x,py,z,c), Inp = (Tfloat)(*this)(nx,py,z,c), - Iap = (Tfloat)(*this)(ax,py,z,c), - Ip = Icp + 0.5f*(dx*(-Ipp + Inp) + dx*dx*(2*Ipp - 5*Icp + 4*Inp - Iap) + dx*dx*dx*(-Ipp + 3*Icp - 3*Inp + Iap)), - Ipc = (Tfloat)(*this)(px,y,z,c), Icc = (Tfloat)(*this)(x, y,z,c), Inc = (Tfloat)(*this)(nx,y,z,c), - Iac = (Tfloat)(*this)(ax,y,z,c), - Ic = Icc + 0.5f*(dx*(-Ipc + Inc) + dx*dx*(2*Ipc - 5*Icc + 4*Inc - Iac) + dx*dx*dx*(-Ipc + 3*Icc - 3*Inc + Iac)), - Ipn = (Tfloat)(*this)(px,ny,z,c), Icn = (Tfloat)(*this)(x,ny,z,c), Inn = (Tfloat)(*this)(nx,ny,z,c), - Ian = (Tfloat)(*this)(ax,ny,z,c), - In = Icn + 0.5f*(dx*(-Ipn + Inn) + dx*dx*(2*Ipn - 5*Icn + 4*Inn - Ian) + dx*dx*dx*(-Ipn + 3*Icn - 3*Inn + Ian)), - Ipa = (Tfloat)(*this)(px,ay,z,c), Ica = (Tfloat)(*this)(x,ay,z,c), Ina = (Tfloat)(*this)(nx,ay,z,c), - Iaa = (Tfloat)(*this)(ax,ay,z,c), - Ia = Ica + 0.5f*(dx*(-Ipa + Ina) + dx*dx*(2*Ipa - 5*Ica + 4*Ina - Iaa) + dx*dx*dx*(-Ipa + 3*Ica - 3*Ina + Iaa)); - return Ic + 0.5f*(dy*(-Ip + In) + dy*dy*(2*Ip - 5*Ic + 4*In - Ia) + dy*dy*dy*(-Ip + 3*Ic - 3*In + Ia)); - } - - T cubic_atXY_pc(const float fx, const float fy, const int z, const int c) const { - return cimg::type::cut(cubic_atXY_p(fx,fy,z,c)); - } - - T _cubic_atXY_pc(const float fx, const float fy, const int z, const int c) const { - return cimg::type::cut(_cubic_atXY_p(fx,fy,z,c)); - } - - //! Return pixel value, using cubic interpolation and Dirichlet boundary conditions for the X,Y and Z-coordinates. - /** - Similar to cubic_atX(float,int,int,int,const T) const, except that the cubic interpolation and boundary checking - are achieved both for X,Y and Z-coordinates. - **/ - Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c, const T& out_value) const { - const int - x = (int)fx - (fx>=0?0:1), px = x - 1, nx = x + 1, ax = x + 2, - y = (int)fy - (fy>=0?0:1), py = y - 1, ny = y + 1, ay = y + 2, - z = (int)fz - (fz>=0?0:1), pz = z - 1, nz = z + 1, az = z + 2; - const float dx = fx - x, dy = fy - y, dz = fz - z; - const Tfloat - Ippp = (Tfloat)atXYZ(px,py,pz,c,out_value), Icpp = (Tfloat)atXYZ(x,py,pz,c,out_value), - Inpp = (Tfloat)atXYZ(nx,py,pz,c,out_value), Iapp = (Tfloat)atXYZ(ax,py,pz,c,out_value), - Ipp = Icpp + 0.5f*(dx*(-Ippp + Inpp) + dx*dx*(2*Ippp - 5*Icpp + 4*Inpp - Iapp) + - dx*dx*dx*(-Ippp + 3*Icpp - 3*Inpp + Iapp)), - Ipcp = (Tfloat)atXYZ(px,y,pz,c,out_value), Iccp = (Tfloat)atXYZ(x, y,pz,c,out_value), - Incp = (Tfloat)atXYZ(nx,y,pz,c,out_value), Iacp = (Tfloat)atXYZ(ax,y,pz,c,out_value), - Icp = Iccp + 0.5f*(dx*(-Ipcp + Incp) + dx*dx*(2*Ipcp - 5*Iccp + 4*Incp - Iacp) + - dx*dx*dx*(-Ipcp + 3*Iccp - 3*Incp + Iacp)), - Ipnp = (Tfloat)atXYZ(px,ny,pz,c,out_value), Icnp = (Tfloat)atXYZ(x,ny,pz,c,out_value), - Innp = (Tfloat)atXYZ(nx,ny,pz,c,out_value), Ianp = (Tfloat)atXYZ(ax,ny,pz,c,out_value), - Inp = Icnp + 0.5f*(dx*(-Ipnp + Innp) + dx*dx*(2*Ipnp - 5*Icnp + 4*Innp - Ianp) + - dx*dx*dx*(-Ipnp + 3*Icnp - 3*Innp + Ianp)), - Ipap = (Tfloat)atXYZ(px,ay,pz,c,out_value), Icap = (Tfloat)atXYZ(x,ay,pz,c,out_value), - Inap = (Tfloat)atXYZ(nx,ay,pz,c,out_value), Iaap = (Tfloat)atXYZ(ax,ay,pz,c,out_value), - Iap = Icap + 0.5f*(dx*(-Ipap + Inap) + dx*dx*(2*Ipap - 5*Icap + 4*Inap - Iaap) + - dx*dx*dx*(-Ipap + 3*Icap - 3*Inap + Iaap)), - Ip = Icp + 0.5f*(dy*(-Ipp + Inp) + dy*dy*(2*Ipp - 5*Icp + 4*Inp - Iap) + - dy*dy*dy*(-Ipp + 3*Icp - 3*Inp + Iap)), - Ippc = (Tfloat)atXYZ(px,py,z,c,out_value), Icpc = (Tfloat)atXYZ(x,py,z,c,out_value), - Inpc = (Tfloat)atXYZ(nx,py,z,c,out_value), Iapc = (Tfloat)atXYZ(ax,py,z,c,out_value), - Ipc = Icpc + 0.5f*(dx*(-Ippc + Inpc) + dx*dx*(2*Ippc - 5*Icpc + 4*Inpc - Iapc) + - dx*dx*dx*(-Ippc + 3*Icpc - 3*Inpc + Iapc)), - Ipcc = (Tfloat)atXYZ(px,y,z,c,out_value), Iccc = (Tfloat)atXYZ(x, y,z,c,out_value), - Incc = (Tfloat)atXYZ(nx,y,z,c,out_value), Iacc = (Tfloat)atXYZ(ax,y,z,c,out_value), - Icc = Iccc + 0.5f*(dx*(-Ipcc + Incc) + dx*dx*(2*Ipcc - 5*Iccc + 4*Incc - Iacc) + - dx*dx*dx*(-Ipcc + 3*Iccc - 3*Incc + Iacc)), - Ipnc = (Tfloat)atXYZ(px,ny,z,c,out_value), Icnc = (Tfloat)atXYZ(x,ny,z,c,out_value), - Innc = (Tfloat)atXYZ(nx,ny,z,c,out_value), Ianc = (Tfloat)atXYZ(ax,ny,z,c,out_value), - Inc = Icnc + 0.5f*(dx*(-Ipnc + Innc) + dx*dx*(2*Ipnc - 5*Icnc + 4*Innc - Ianc) + - dx*dx*dx*(-Ipnc + 3*Icnc - 3*Innc + Ianc)), - Ipac = (Tfloat)atXYZ(px,ay,z,c,out_value), Icac = (Tfloat)atXYZ(x,ay,z,c,out_value), - Inac = (Tfloat)atXYZ(nx,ay,z,c,out_value), Iaac = (Tfloat)atXYZ(ax,ay,z,c,out_value), - Iac = Icac + 0.5f*(dx*(-Ipac + Inac) + dx*dx*(2*Ipac - 5*Icac + 4*Inac - Iaac) + - dx*dx*dx*(-Ipac + 3*Icac - 3*Inac + Iaac)), - Ic = Icc + 0.5f*(dy*(-Ipc + Inc) + dy*dy*(2*Ipc - 5*Icc + 4*Inc - Iac) + - dy*dy*dy*(-Ipc + 3*Icc - 3*Inc + Iac)), - Ippn = (Tfloat)atXYZ(px,py,nz,c,out_value), Icpn = (Tfloat)atXYZ(x,py,nz,c,out_value), - Inpn = (Tfloat)atXYZ(nx,py,nz,c,out_value), Iapn = (Tfloat)atXYZ(ax,py,nz,c,out_value), - Ipn = Icpn + 0.5f*(dx*(-Ippn + Inpn) + dx*dx*(2*Ippn - 5*Icpn + 4*Inpn - Iapn) + - dx*dx*dx*(-Ippn + 3*Icpn - 3*Inpn + Iapn)), - Ipcn = (Tfloat)atXYZ(px,y,nz,c,out_value), Iccn = (Tfloat)atXYZ(x, y,nz,c,out_value), - Incn = (Tfloat)atXYZ(nx,y,nz,c,out_value), Iacn = (Tfloat)atXYZ(ax,y,nz,c,out_value), - Icn = Iccn + 0.5f*(dx*(-Ipcn + Incn) + dx*dx*(2*Ipcn - 5*Iccn + 4*Incn - Iacn) + - dx*dx*dx*(-Ipcn + 3*Iccn - 3*Incn + Iacn)), - Ipnn = (Tfloat)atXYZ(px,ny,nz,c,out_value), Icnn = (Tfloat)atXYZ(x,ny,nz,c,out_value), - Innn = (Tfloat)atXYZ(nx,ny,nz,c,out_value), Iann = (Tfloat)atXYZ(ax,ny,nz,c,out_value), - Inn = Icnn + 0.5f*(dx*(-Ipnn + Innn) + dx*dx*(2*Ipnn - 5*Icnn + 4*Innn - Iann) + - dx*dx*dx*(-Ipnn + 3*Icnn - 3*Innn + Iann)), - Ipan = (Tfloat)atXYZ(px,ay,nz,c,out_value), Ican = (Tfloat)atXYZ(x,ay,nz,c,out_value), - Inan = (Tfloat)atXYZ(nx,ay,nz,c,out_value), Iaan = (Tfloat)atXYZ(ax,ay,nz,c,out_value), - Ian = Ican + 0.5f*(dx*(-Ipan + Inan) + dx*dx*(2*Ipan - 5*Ican + 4*Inan - Iaan) + - dx*dx*dx*(-Ipan + 3*Ican - 3*Inan + Iaan)), - In = Icn + 0.5f*(dy*(-Ipn + Inn) + dy*dy*(2*Ipn - 5*Icn + 4*Inn - Ian) + - dy*dy*dy*(-Ipn + 3*Icn - 3*Inn + Ian)), - Ippa = (Tfloat)atXYZ(px,py,az,c,out_value), Icpa = (Tfloat)atXYZ(x,py,az,c,out_value), - Inpa = (Tfloat)atXYZ(nx,py,az,c,out_value), Iapa = (Tfloat)atXYZ(ax,py,az,c,out_value), - Ipa = Icpa + 0.5f*(dx*(-Ippa + Inpa) + dx*dx*(2*Ippa - 5*Icpa + 4*Inpa - Iapa) + - dx*dx*dx*(-Ippa + 3*Icpa - 3*Inpa + Iapa)), - Ipca = (Tfloat)atXYZ(px,y,az,c,out_value), Icca = (Tfloat)atXYZ(x, y,az,c,out_value), - Inca = (Tfloat)atXYZ(nx,y,az,c,out_value), Iaca = (Tfloat)atXYZ(ax,y,az,c,out_value), - Ica = Icca + 0.5f*(dx*(-Ipca + Inca) + dx*dx*(2*Ipca - 5*Icca + 4*Inca - Iaca) + - dx*dx*dx*(-Ipca + 3*Icca - 3*Inca + Iaca)), - Ipna = (Tfloat)atXYZ(px,ny,az,c,out_value), Icna = (Tfloat)atXYZ(x,ny,az,c,out_value), - Inna = (Tfloat)atXYZ(nx,ny,az,c,out_value), Iana = (Tfloat)atXYZ(ax,ny,az,c,out_value), - Ina = Icna + 0.5f*(dx*(-Ipna + Inna) + dx*dx*(2*Ipna - 5*Icna + 4*Inna - Iana) + - dx*dx*dx*(-Ipna + 3*Icna - 3*Inna + Iana)), - Ipaa = (Tfloat)atXYZ(px,ay,az,c,out_value), Icaa = (Tfloat)atXYZ(x,ay,az,c,out_value), - Inaa = (Tfloat)atXYZ(nx,ay,az,c,out_value), Iaaa = (Tfloat)atXYZ(ax,ay,az,c,out_value), - Iaa = Icaa + 0.5f*(dx*(-Ipaa + Inaa) + dx*dx*(2*Ipaa - 5*Icaa + 4*Inaa - Iaaa) + - dx*dx*dx*(-Ipaa + 3*Icaa - 3*Inaa + Iaaa)), - Ia = Ica + 0.5f*(dy*(-Ipa + Ina) + dy*dy*(2*Ipa - 5*Ica + 4*Ina - Iaa) + - dy*dy*dy*(-Ipa + 3*Ica - 3*Ina + Iaa)); - return Ic + 0.5f*(dz*(-Ip + In) + dz*dz*(2*Ip - 5*Ic + 4*In - Ia) + dz*dz*dz*(-Ip + 3*Ic - 3*In + Ia)); - } - - //! Return clamped pixel value, using cubic interpolation and Dirichlet boundary conditions for the XYZ-coordinates. - /** - Similar to cubic_atXYZ(float,float,float,int,const T) const, except that the return value is clamped to stay - in the min/max range of the datatype \c T. - **/ - T cubic_atXYZ_c(const float fx, const float fy, const float fz, const int c, const T& out_value) const { - return cimg::type::cut(cubic_atXYZ(fx,fy,fz,c,out_value)); - } - - //! Return pixel value, using cubic interpolation and Neumann boundary conditions for the X,Y and Z-coordinates. - /** - Similar to cubic_atX(float,int,int,int) const, except that the cubic interpolation and boundary checking - are achieved both for X,Y and Z-coordinates. - \note - - If you know your image instance is \e not empty, you may rather use the slightly faster method - \c _cubic_atXYZ(float,float,float,int). - **/ - Tfloat cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "cubic_atXYZ(): Empty instance.", - cimg_instance); - return _cubic_atXYZ(fx,fy,fz,c); - } - - Tfloat _cubic_atXYZ(const float fx, const float fy, const float fz, const int c=0) const { - const float - nfx = cimg::type::is_nan(fx)?0:cimg::cut(fx,0,width() - 1), - nfy = cimg::type::is_nan(fy)?0:cimg::cut(fy,0,height() - 1), - nfz = cimg::type::is_nan(fz)?0:cimg::cut(fz,0,depth() - 1); - const int x = (int)nfx, y = (int)nfy, z = (int)nfz; - const float dx = nfx - x, dy = nfy - y, dz = nfz - z; - const int - px = x - 1<0?0:x - 1, nx = dx>0?x + 1:x, ax = x + 2>=width()?width() - 1:x + 2, - py = y - 1<0?0:y - 1, ny = dy>0?y + 1:y, ay = y + 2>=height()?height() - 1:y + 2, - pz = z - 1<0?0:z - 1, nz = dz>0?z + 1:z, az = z + 2>=depth()?depth() - 1:z + 2; - const Tfloat - Ippp = (Tfloat)(*this)(px,py,pz,c), Icpp = (Tfloat)(*this)(x,py,pz,c), - Inpp = (Tfloat)(*this)(nx,py,pz,c), Iapp = (Tfloat)(*this)(ax,py,pz,c), - Ipp = Icpp + 0.5f*(dx*(-Ippp + Inpp) + dx*dx*(2*Ippp - 5*Icpp + 4*Inpp - Iapp) + - dx*dx*dx*(-Ippp + 3*Icpp - 3*Inpp + Iapp)), - Ipcp = (Tfloat)(*this)(px,y,pz,c), Iccp = (Tfloat)(*this)(x, y,pz,c), - Incp = (Tfloat)(*this)(nx,y,pz,c), Iacp = (Tfloat)(*this)(ax,y,pz,c), - Icp = Iccp + 0.5f*(dx*(-Ipcp + Incp) + dx*dx*(2*Ipcp - 5*Iccp + 4*Incp - Iacp) + - dx*dx*dx*(-Ipcp + 3*Iccp - 3*Incp + Iacp)), - Ipnp = (Tfloat)(*this)(px,ny,pz,c), Icnp = (Tfloat)(*this)(x,ny,pz,c), - Innp = (Tfloat)(*this)(nx,ny,pz,c), Ianp = (Tfloat)(*this)(ax,ny,pz,c), - Inp = Icnp + 0.5f*(dx*(-Ipnp + Innp) + dx*dx*(2*Ipnp - 5*Icnp + 4*Innp - Ianp) + - dx*dx*dx*(-Ipnp + 3*Icnp - 3*Innp + Ianp)), - Ipap = (Tfloat)(*this)(px,ay,pz,c), Icap = (Tfloat)(*this)(x,ay,pz,c), - Inap = (Tfloat)(*this)(nx,ay,pz,c), Iaap = (Tfloat)(*this)(ax,ay,pz,c), - Iap = Icap + 0.5f*(dx*(-Ipap + Inap) + dx*dx*(2*Ipap - 5*Icap + 4*Inap - Iaap) + - dx*dx*dx*(-Ipap + 3*Icap - 3*Inap + Iaap)), - Ip = Icp + 0.5f*(dy*(-Ipp + Inp) + dy*dy*(2*Ipp - 5*Icp + 4*Inp - Iap) + - dy*dy*dy*(-Ipp + 3*Icp - 3*Inp + Iap)), - Ippc = (Tfloat)(*this)(px,py,z,c), Icpc = (Tfloat)(*this)(x,py,z,c), - Inpc = (Tfloat)(*this)(nx,py,z,c), Iapc = (Tfloat)(*this)(ax,py,z,c), - Ipc = Icpc + 0.5f*(dx*(-Ippc + Inpc) + dx*dx*(2*Ippc - 5*Icpc + 4*Inpc - Iapc) + - dx*dx*dx*(-Ippc + 3*Icpc - 3*Inpc + Iapc)), - Ipcc = (Tfloat)(*this)(px,y,z,c), Iccc = (Tfloat)(*this)(x, y,z,c), - Incc = (Tfloat)(*this)(nx,y,z,c), Iacc = (Tfloat)(*this)(ax,y,z,c), - Icc = Iccc + 0.5f*(dx*(-Ipcc + Incc) + dx*dx*(2*Ipcc - 5*Iccc + 4*Incc - Iacc) + - dx*dx*dx*(-Ipcc + 3*Iccc - 3*Incc + Iacc)), - Ipnc = (Tfloat)(*this)(px,ny,z,c), Icnc = (Tfloat)(*this)(x,ny,z,c), - Innc = (Tfloat)(*this)(nx,ny,z,c), Ianc = (Tfloat)(*this)(ax,ny,z,c), - Inc = Icnc + 0.5f*(dx*(-Ipnc + Innc) + dx*dx*(2*Ipnc - 5*Icnc + 4*Innc - Ianc) + - dx*dx*dx*(-Ipnc + 3*Icnc - 3*Innc + Ianc)), - Ipac = (Tfloat)(*this)(px,ay,z,c), Icac = (Tfloat)(*this)(x,ay,z,c), - Inac = (Tfloat)(*this)(nx,ay,z,c), Iaac = (Tfloat)(*this)(ax,ay,z,c), - Iac = Icac + 0.5f*(dx*(-Ipac + Inac) + dx*dx*(2*Ipac - 5*Icac + 4*Inac - Iaac) + - dx*dx*dx*(-Ipac + 3*Icac - 3*Inac + Iaac)), - Ic = Icc + 0.5f*(dy*(-Ipc + Inc) + dy*dy*(2*Ipc - 5*Icc + 4*Inc - Iac) + - dy*dy*dy*(-Ipc + 3*Icc - 3*Inc + Iac)), - Ippn = (Tfloat)(*this)(px,py,nz,c), Icpn = (Tfloat)(*this)(x,py,nz,c), - Inpn = (Tfloat)(*this)(nx,py,nz,c), Iapn = (Tfloat)(*this)(ax,py,nz,c), - Ipn = Icpn + 0.5f*(dx*(-Ippn + Inpn) + dx*dx*(2*Ippn - 5*Icpn + 4*Inpn - Iapn) + - dx*dx*dx*(-Ippn + 3*Icpn - 3*Inpn + Iapn)), - Ipcn = (Tfloat)(*this)(px,y,nz,c), Iccn = (Tfloat)(*this)(x, y,nz,c), - Incn = (Tfloat)(*this)(nx,y,nz,c), Iacn = (Tfloat)(*this)(ax,y,nz,c), - Icn = Iccn + 0.5f*(dx*(-Ipcn + Incn) + dx*dx*(2*Ipcn - 5*Iccn + 4*Incn - Iacn) + - dx*dx*dx*(-Ipcn + 3*Iccn - 3*Incn + Iacn)), - Ipnn = (Tfloat)(*this)(px,ny,nz,c), Icnn = (Tfloat)(*this)(x,ny,nz,c), - Innn = (Tfloat)(*this)(nx,ny,nz,c), Iann = (Tfloat)(*this)(ax,ny,nz,c), - Inn = Icnn + 0.5f*(dx*(-Ipnn + Innn) + dx*dx*(2*Ipnn - 5*Icnn + 4*Innn - Iann) + - dx*dx*dx*(-Ipnn + 3*Icnn - 3*Innn + Iann)), - Ipan = (Tfloat)(*this)(px,ay,nz,c), Ican = (Tfloat)(*this)(x,ay,nz,c), - Inan = (Tfloat)(*this)(nx,ay,nz,c), Iaan = (Tfloat)(*this)(ax,ay,nz,c), - Ian = Ican + 0.5f*(dx*(-Ipan + Inan) + dx*dx*(2*Ipan - 5*Ican + 4*Inan - Iaan) + - dx*dx*dx*(-Ipan + 3*Ican - 3*Inan + Iaan)), - In = Icn + 0.5f*(dy*(-Ipn + Inn) + dy*dy*(2*Ipn - 5*Icn + 4*Inn - Ian) + - dy*dy*dy*(-Ipn + 3*Icn - 3*Inn + Ian)), - Ippa = (Tfloat)(*this)(px,py,az,c), Icpa = (Tfloat)(*this)(x,py,az,c), - Inpa = (Tfloat)(*this)(nx,py,az,c), Iapa = (Tfloat)(*this)(ax,py,az,c), - Ipa = Icpa + 0.5f*(dx*(-Ippa + Inpa) + dx*dx*(2*Ippa - 5*Icpa + 4*Inpa - Iapa) + - dx*dx*dx*(-Ippa + 3*Icpa - 3*Inpa + Iapa)), - Ipca = (Tfloat)(*this)(px,y,az,c), Icca = (Tfloat)(*this)(x, y,az,c), - Inca = (Tfloat)(*this)(nx,y,az,c), Iaca = (Tfloat)(*this)(ax,y,az,c), - Ica = Icca + 0.5f*(dx*(-Ipca + Inca) + dx*dx*(2*Ipca - 5*Icca + 4*Inca - Iaca) + - dx*dx*dx*(-Ipca + 3*Icca - 3*Inca + Iaca)), - Ipna = (Tfloat)(*this)(px,ny,az,c), Icna = (Tfloat)(*this)(x,ny,az,c), - Inna = (Tfloat)(*this)(nx,ny,az,c), Iana = (Tfloat)(*this)(ax,ny,az,c), - Ina = Icna + 0.5f*(dx*(-Ipna + Inna) + dx*dx*(2*Ipna - 5*Icna + 4*Inna - Iana) + - dx*dx*dx*(-Ipna + 3*Icna - 3*Inna + Iana)), - Ipaa = (Tfloat)(*this)(px,ay,az,c), Icaa = (Tfloat)(*this)(x,ay,az,c), - Inaa = (Tfloat)(*this)(nx,ay,az,c), Iaaa = (Tfloat)(*this)(ax,ay,az,c), - Iaa = Icaa + 0.5f*(dx*(-Ipaa + Inaa) + dx*dx*(2*Ipaa - 5*Icaa + 4*Inaa - Iaaa) + - dx*dx*dx*(-Ipaa + 3*Icaa - 3*Inaa + Iaaa)), - Ia = Ica + 0.5f*(dy*(-Ipa + Ina) + dy*dy*(2*Ipa - 5*Ica + 4*Ina - Iaa) + - dy*dy*dy*(-Ipa + 3*Ica - 3*Ina + Iaa)); - return Ic + 0.5f*(dz*(-Ip + In) + dz*dz*(2*Ip - 5*Ic + 4*In - Ia) + dz*dz*dz*(-Ip + 3*Ic - 3*In + Ia)); - } - - //! Return clamped pixel value, using cubic interpolation and Neumann boundary conditions for the XYZ-coordinates. - /** - Similar to cubic_atXYZ(float,float,float,int) const, except that the return value is clamped to stay in the - min/max range of the datatype \c T. - **/ - T cubic_atXYZ_c(const float fx, const float fy, const float fz, const int c) const { - return cimg::type::cut(cubic_atXYZ(fx,fy,fz,c)); - } - - T _cubic_atXYZ_c(const float fx, const float fy, const float fz, const int c) const { - return cimg::type::cut(_cubic_atXYZ(fx,fy,fz,c)); - } - - //! Return pixel value, using cubic interpolation and Neumann boundary conditions for the X,Y and Z-coordinates. - /** - Similar to cubic_atX(float,int,int,int) const, except that the cubic interpolation and boundary checking - are achieved both for X,Y and Z-coordinates. - \note - - If you know your image instance is \e not empty, you may rather use the slightly faster method - \c _cubic_atXYZ(float,float,float,int). - **/ - Tfloat cubic_atXYZ_p(const float fx, const float fy, const float fz, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "cubic_atXYZ_p(): Empty instance.", - cimg_instance); - return _cubic_atXYZ_p(fx,fy,fz,c); - } - - Tfloat _cubic_atXYZ_p(const float fx, const float fy, const float fz, const int c=0) const { - const float - nfx = cimg::type::is_nan(fx)?0:cimg::mod(fx,_width - 0.5f), - nfy = cimg::type::is_nan(fy)?0:cimg::mod(fy,_height - 0.5f), - nfz = cimg::type::is_nan(fz)?0:cimg::mod(fz,_depth - 0.5f); - const int x = (int)nfx, y = (int)nfy, z = (int)nfz; - const float dx = nfx - x, dy = nfy - y, dz = nfz - z; - const int - px = cimg::mod(x - 1,width()), nx = cimg::mod(x + 1,width()), ax = cimg::mod(x + 2,width()), - py = cimg::mod(y - 1,height()), ny = cimg::mod(y + 1,height()), ay = cimg::mod(y + 2,height()), - pz = cimg::mod(z - 1,depth()), nz = cimg::mod(z + 1,depth()), az = cimg::mod(z + 2,depth()); - const Tfloat - Ippp = (Tfloat)(*this)(px,py,pz,c), Icpp = (Tfloat)(*this)(x,py,pz,c), - Inpp = (Tfloat)(*this)(nx,py,pz,c), Iapp = (Tfloat)(*this)(ax,py,pz,c), - Ipp = Icpp + 0.5f*(dx*(-Ippp + Inpp) + dx*dx*(2*Ippp - 5*Icpp + 4*Inpp - Iapp) + - dx*dx*dx*(-Ippp + 3*Icpp - 3*Inpp + Iapp)), - Ipcp = (Tfloat)(*this)(px,y,pz,c), Iccp = (Tfloat)(*this)(x, y,pz,c), - Incp = (Tfloat)(*this)(nx,y,pz,c), Iacp = (Tfloat)(*this)(ax,y,pz,c), - Icp = Iccp + 0.5f*(dx*(-Ipcp + Incp) + dx*dx*(2*Ipcp - 5*Iccp + 4*Incp - Iacp) + - dx*dx*dx*(-Ipcp + 3*Iccp - 3*Incp + Iacp)), - Ipnp = (Tfloat)(*this)(px,ny,pz,c), Icnp = (Tfloat)(*this)(x,ny,pz,c), - Innp = (Tfloat)(*this)(nx,ny,pz,c), Ianp = (Tfloat)(*this)(ax,ny,pz,c), - Inp = Icnp + 0.5f*(dx*(-Ipnp + Innp) + dx*dx*(2*Ipnp - 5*Icnp + 4*Innp - Ianp) + - dx*dx*dx*(-Ipnp + 3*Icnp - 3*Innp + Ianp)), - Ipap = (Tfloat)(*this)(px,ay,pz,c), Icap = (Tfloat)(*this)(x,ay,pz,c), - Inap = (Tfloat)(*this)(nx,ay,pz,c), Iaap = (Tfloat)(*this)(ax,ay,pz,c), - Iap = Icap + 0.5f*(dx*(-Ipap + Inap) + dx*dx*(2*Ipap - 5*Icap + 4*Inap - Iaap) + - dx*dx*dx*(-Ipap + 3*Icap - 3*Inap + Iaap)), - Ip = Icp + 0.5f*(dy*(-Ipp + Inp) + dy*dy*(2*Ipp - 5*Icp + 4*Inp - Iap) + - dy*dy*dy*(-Ipp + 3*Icp - 3*Inp + Iap)), - Ippc = (Tfloat)(*this)(px,py,z,c), Icpc = (Tfloat)(*this)(x,py,z,c), - Inpc = (Tfloat)(*this)(nx,py,z,c), Iapc = (Tfloat)(*this)(ax,py,z,c), - Ipc = Icpc + 0.5f*(dx*(-Ippc + Inpc) + dx*dx*(2*Ippc - 5*Icpc + 4*Inpc - Iapc) + - dx*dx*dx*(-Ippc + 3*Icpc - 3*Inpc + Iapc)), - Ipcc = (Tfloat)(*this)(px,y,z,c), Iccc = (Tfloat)(*this)(x, y,z,c), - Incc = (Tfloat)(*this)(nx,y,z,c), Iacc = (Tfloat)(*this)(ax,y,z,c), - Icc = Iccc + 0.5f*(dx*(-Ipcc + Incc) + dx*dx*(2*Ipcc - 5*Iccc + 4*Incc - Iacc) + - dx*dx*dx*(-Ipcc + 3*Iccc - 3*Incc + Iacc)), - Ipnc = (Tfloat)(*this)(px,ny,z,c), Icnc = (Tfloat)(*this)(x,ny,z,c), - Innc = (Tfloat)(*this)(nx,ny,z,c), Ianc = (Tfloat)(*this)(ax,ny,z,c), - Inc = Icnc + 0.5f*(dx*(-Ipnc + Innc) + dx*dx*(2*Ipnc - 5*Icnc + 4*Innc - Ianc) + - dx*dx*dx*(-Ipnc + 3*Icnc - 3*Innc + Ianc)), - Ipac = (Tfloat)(*this)(px,ay,z,c), Icac = (Tfloat)(*this)(x,ay,z,c), - Inac = (Tfloat)(*this)(nx,ay,z,c), Iaac = (Tfloat)(*this)(ax,ay,z,c), - Iac = Icac + 0.5f*(dx*(-Ipac + Inac) + dx*dx*(2*Ipac - 5*Icac + 4*Inac - Iaac) + - dx*dx*dx*(-Ipac + 3*Icac - 3*Inac + Iaac)), - Ic = Icc + 0.5f*(dy*(-Ipc + Inc) + dy*dy*(2*Ipc - 5*Icc + 4*Inc - Iac) + - dy*dy*dy*(-Ipc + 3*Icc - 3*Inc + Iac)), - Ippn = (Tfloat)(*this)(px,py,nz,c), Icpn = (Tfloat)(*this)(x,py,nz,c), - Inpn = (Tfloat)(*this)(nx,py,nz,c), Iapn = (Tfloat)(*this)(ax,py,nz,c), - Ipn = Icpn + 0.5f*(dx*(-Ippn + Inpn) + dx*dx*(2*Ippn - 5*Icpn + 4*Inpn - Iapn) + - dx*dx*dx*(-Ippn + 3*Icpn - 3*Inpn + Iapn)), - Ipcn = (Tfloat)(*this)(px,y,nz,c), Iccn = (Tfloat)(*this)(x, y,nz,c), - Incn = (Tfloat)(*this)(nx,y,nz,c), Iacn = (Tfloat)(*this)(ax,y,nz,c), - Icn = Iccn + 0.5f*(dx*(-Ipcn + Incn) + dx*dx*(2*Ipcn - 5*Iccn + 4*Incn - Iacn) + - dx*dx*dx*(-Ipcn + 3*Iccn - 3*Incn + Iacn)), - Ipnn = (Tfloat)(*this)(px,ny,nz,c), Icnn = (Tfloat)(*this)(x,ny,nz,c), - Innn = (Tfloat)(*this)(nx,ny,nz,c), Iann = (Tfloat)(*this)(ax,ny,nz,c), - Inn = Icnn + 0.5f*(dx*(-Ipnn + Innn) + dx*dx*(2*Ipnn - 5*Icnn + 4*Innn - Iann) + - dx*dx*dx*(-Ipnn + 3*Icnn - 3*Innn + Iann)), - Ipan = (Tfloat)(*this)(px,ay,nz,c), Ican = (Tfloat)(*this)(x,ay,nz,c), - Inan = (Tfloat)(*this)(nx,ay,nz,c), Iaan = (Tfloat)(*this)(ax,ay,nz,c), - Ian = Ican + 0.5f*(dx*(-Ipan + Inan) + dx*dx*(2*Ipan - 5*Ican + 4*Inan - Iaan) + - dx*dx*dx*(-Ipan + 3*Ican - 3*Inan + Iaan)), - In = Icn + 0.5f*(dy*(-Ipn + Inn) + dy*dy*(2*Ipn - 5*Icn + 4*Inn - Ian) + - dy*dy*dy*(-Ipn + 3*Icn - 3*Inn + Ian)), - Ippa = (Tfloat)(*this)(px,py,az,c), Icpa = (Tfloat)(*this)(x,py,az,c), - Inpa = (Tfloat)(*this)(nx,py,az,c), Iapa = (Tfloat)(*this)(ax,py,az,c), - Ipa = Icpa + 0.5f*(dx*(-Ippa + Inpa) + dx*dx*(2*Ippa - 5*Icpa + 4*Inpa - Iapa) + - dx*dx*dx*(-Ippa + 3*Icpa - 3*Inpa + Iapa)), - Ipca = (Tfloat)(*this)(px,y,az,c), Icca = (Tfloat)(*this)(x, y,az,c), - Inca = (Tfloat)(*this)(nx,y,az,c), Iaca = (Tfloat)(*this)(ax,y,az,c), - Ica = Icca + 0.5f*(dx*(-Ipca + Inca) + dx*dx*(2*Ipca - 5*Icca + 4*Inca - Iaca) + - dx*dx*dx*(-Ipca + 3*Icca - 3*Inca + Iaca)), - Ipna = (Tfloat)(*this)(px,ny,az,c), Icna = (Tfloat)(*this)(x,ny,az,c), - Inna = (Tfloat)(*this)(nx,ny,az,c), Iana = (Tfloat)(*this)(ax,ny,az,c), - Ina = Icna + 0.5f*(dx*(-Ipna + Inna) + dx*dx*(2*Ipna - 5*Icna + 4*Inna - Iana) + - dx*dx*dx*(-Ipna + 3*Icna - 3*Inna + Iana)), - Ipaa = (Tfloat)(*this)(px,ay,az,c), Icaa = (Tfloat)(*this)(x,ay,az,c), - Inaa = (Tfloat)(*this)(nx,ay,az,c), Iaaa = (Tfloat)(*this)(ax,ay,az,c), - Iaa = Icaa + 0.5f*(dx*(-Ipaa + Inaa) + dx*dx*(2*Ipaa - 5*Icaa + 4*Inaa - Iaaa) + - dx*dx*dx*(-Ipaa + 3*Icaa - 3*Inaa + Iaaa)), - Ia = Ica + 0.5f*(dy*(-Ipa + Ina) + dy*dy*(2*Ipa - 5*Ica + 4*Ina - Iaa) + - dy*dy*dy*(-Ipa + 3*Ica - 3*Ina + Iaa)); - return Ic + 0.5f*(dz*(-Ip + In) + dz*dz*(2*Ip - 5*Ic + 4*In - Ia) + dz*dz*dz*(-Ip + 3*Ic - 3*In + Ia)); - } - - T cubic_atXYZ_pc(const float fx, const float fy, const float fz, const int c) const { - return cimg::type::cut(cubic_atXYZ_p(fx,fy,fz,c)); - } - - T _cubic_atXYZ_pc(const float fx, const float fy, const float fz, const int c) const { - return cimg::type::cut(_cubic_atXYZ_p(fx,fy,fz,c)); - } - - //! Set pixel value, using linear interpolation for the X-coordinates. - /** - Set pixel value at specified coordinates (\c fx,\c y,\c z,\c c) in the image instance, in a way that - the value is spread amongst several neighbors if the pixel coordinates are float-valued. - \param value Pixel value to set. - \param fx X-coordinate of the pixel value (float-valued). - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \param is_added Tells if the pixel value is added to (\c true), or simply replace (\c false) the current image - pixel(s). - \return A reference to the current image instance. - \note - - Calling this method with out-of-bounds coordinates does nothing. - **/ - CImg& set_linear_atX(const T& value, const float fx, const int y=0, const int z=0, const int c=0, - const bool is_added=false) { - const int - x = (int)fx - (fx>=0?0:1), nx = x + 1; - const float - dx = fx - x; - if (y>=0 && y=0 && z=0 && c=0 && x=0 && nx& set_linear_atXY(const T& value, const float fx, const float fy=0, const int z=0, const int c=0, - const bool is_added=false) { - const int - x = (int)fx - (fx>=0?0:1), nx = x + 1, - y = (int)fy - (fy>=0?0:1), ny = y + 1; - const float - dx = fx - x, - dy = fy - y; - if (z>=0 && z=0 && c=0 && y=0 && x=0 && nx=0 && ny=0 && x=0 && nx& set_linear_atXYZ(const T& value, const float fx, const float fy=0, const float fz=0, const int c=0, - const bool is_added=false) { - const int - x = (int)fx - (fx>=0?0:1), nx = x + 1, - y = (int)fy - (fy>=0?0:1), ny = y + 1, - z = (int)fz - (fz>=0?0:1), nz = z + 1; - const float - dx = fx - x, - dy = fy - y, - dz = fz - z; - if (c>=0 && c=0 && z=0 && y=0 && x=0 && nx=0 && ny=0 && x=0 && nx=0 && nz=0 && y=0 && x=0 && nx=0 && ny=0 && x=0 && nx image whose buffer data() is a \c char* string describing the list of all pixel values - of the image instance (written in base 10), separated by specified \c separator character. - \param separator A \c char character which specifies the separator between values in the returned C-string. - \param max_size Maximum size of the returned image (or \c 0 if no limits are set). - \param format For float/double-values, tell the printf format used to generate the text representation - of the numbers (or \c 0 for default representation). - \note - - The returned image is never empty. - - For an empty image instance, the returned string is "". - - If \c max_size is equal to \c 0, there are no limits on the size of the returned string. - - Otherwise, if the maximum number of string characters is exceeded, the value string is cut off - and terminated by character \c '\0'. In that case, the returned image size is max_size + 1. - **/ - CImg value_string(const char separator=',', const unsigned int max_size=0, - const char *const format=0) const { - if (is_empty() || max_size==1) return CImg(1,1,1,1,0); - CImgList items; - CImg s_item(256); *s_item = 0; - const T *ptrs = _data; - unsigned int string_size = 0; - const char *const _format = format?format:cimg::type::format(); - for (ulongT off = 0, siz = size(); off::format(*(ptrs++))); - CImg item(s_item._data,printed_size); - item[printed_size - 1] = separator; - item.move_to(items); - if (max_size) string_size+=printed_size; - } - CImg res; - (items>'x').move_to(res); - if (max_size && res._width>=max_size) res.crop(0,max_size - 1); - res.back() = 0; - return res; - } - - //@} - //------------------------------------- - // - //! \name Instance Checking - //@{ - //------------------------------------- - - //! Test shared state of the pixel buffer. - /** - Return \c true if image instance has a shared memory buffer, and \c false otherwise. - \note - - A shared image do not own his pixel buffer data() and will not deallocate it on destruction. - - Most of the time, a \c CImg image instance will \e not be shared. - - A shared image can only be obtained by a limited set of constructors and methods (see list below). - **/ - bool is_shared() const { - return _is_shared; - } - - //! Test if image instance is empty. - /** - Return \c true, if image instance is empty, i.e. does \e not contain any pixel values, has dimensions - \c 0 x \c 0 x \c 0 x \c 0 and a pixel buffer pointer set to \c 0 (null pointer), and \c false otherwise. - **/ - bool is_empty() const { - return !(_data && _width && _height && _depth && _spectrum); - } - - //! Test if image instance contains a 'inf' value. - /** - Return \c true, if image instance contains a 'inf' value, and \c false otherwise. - **/ - bool is_inf() const { - if (cimg::type::is_float()) cimg_for(*this,p,T) if (cimg::type::is_inf((float)*p)) return true; - return false; - } - - //! Test if image instance contains a NaN value. - /** - Return \c true, if image instance contains a NaN value, and \c false otherwise. - **/ - bool is_nan() const { - if (cimg::type::is_float()) cimg_for(*this,p,T) if (cimg::type::is_nan((float)*p)) return true; - return false; - } - - //! Test if image width is equal to specified value. - bool is_sameX(const unsigned int size_x) const { - return _width==size_x; - } - - //! Test if image width is equal to specified value. - template - bool is_sameX(const CImg& img) const { - return is_sameX(img._width); - } - - //! Test if image width is equal to specified value. - bool is_sameX(const CImgDisplay& disp) const { - return is_sameX(disp._width); - } - - //! Test if image height is equal to specified value. - bool is_sameY(const unsigned int size_y) const { - return _height==size_y; - } - - //! Test if image height is equal to specified value. - template - bool is_sameY(const CImg& img) const { - return is_sameY(img._height); - } - - //! Test if image height is equal to specified value. - bool is_sameY(const CImgDisplay& disp) const { - return is_sameY(disp._height); - } - - //! Test if image depth is equal to specified value. - bool is_sameZ(const unsigned int size_z) const { - return _depth==size_z; - } - - //! Test if image depth is equal to specified value. - template - bool is_sameZ(const CImg& img) const { - return is_sameZ(img._depth); - } - - //! Test if image spectrum is equal to specified value. - bool is_sameC(const unsigned int size_c) const { - return _spectrum==size_c; - } - - //! Test if image spectrum is equal to specified value. - template - bool is_sameC(const CImg& img) const { - return is_sameC(img._spectrum); - } - - //! Test if image width and height are equal to specified values. - /** - Test if is_sameX(unsigned int) const and is_sameY(unsigned int) const are both verified. - **/ - bool is_sameXY(const unsigned int size_x, const unsigned int size_y) const { - return _width==size_x && _height==size_y; - } - - //! Test if image width and height are the same as that of another image. - /** - Test if is_sameX(const CImg&) const and is_sameY(const CImg&) const are both verified. - **/ - template - bool is_sameXY(const CImg& img) const { - return is_sameXY(img._width,img._height); - } - - //! Test if image width and height are the same as that of an existing display window. - /** - Test if is_sameX(const CImgDisplay&) const and is_sameY(const CImgDisplay&) const are both verified. - **/ - bool is_sameXY(const CImgDisplay& disp) const { - return is_sameXY(disp._width,disp._height); - } - - //! Test if image width and depth are equal to specified values. - /** - Test if is_sameX(unsigned int) const and is_sameZ(unsigned int) const are both verified. - **/ - bool is_sameXZ(const unsigned int size_x, const unsigned int size_z) const { - return _width==size_x && _depth==size_z; - } - - //! Test if image width and depth are the same as that of another image. - /** - Test if is_sameX(const CImg&) const and is_sameZ(const CImg&) const are both verified. - **/ - template - bool is_sameXZ(const CImg& img) const { - return is_sameXZ(img._width,img._depth); - } - - //! Test if image width and spectrum are equal to specified values. - /** - Test if is_sameX(unsigned int) const and is_sameC(unsigned int) const are both verified. - **/ - bool is_sameXC(const unsigned int size_x, const unsigned int size_c) const { - return _width==size_x && _spectrum==size_c; - } - - //! Test if image width and spectrum are the same as that of another image. - /** - Test if is_sameX(const CImg&) const and is_sameC(const CImg&) const are both verified. - **/ - template - bool is_sameXC(const CImg& img) const { - return is_sameXC(img._width,img._spectrum); - } - - //! Test if image height and depth are equal to specified values. - /** - Test if is_sameY(unsigned int) const and is_sameZ(unsigned int) const are both verified. - **/ - bool is_sameYZ(const unsigned int size_y, const unsigned int size_z) const { - return _height==size_y && _depth==size_z; - } - - //! Test if image height and depth are the same as that of another image. - /** - Test if is_sameY(const CImg&) const and is_sameZ(const CImg&) const are both verified. - **/ - template - bool is_sameYZ(const CImg& img) const { - return is_sameYZ(img._height,img._depth); - } - - //! Test if image height and spectrum are equal to specified values. - /** - Test if is_sameY(unsigned int) const and is_sameC(unsigned int) const are both verified. - **/ - bool is_sameYC(const unsigned int size_y, const unsigned int size_c) const { - return _height==size_y && _spectrum==size_c; - } - - //! Test if image height and spectrum are the same as that of another image. - /** - Test if is_sameY(const CImg&) const and is_sameC(const CImg&) const are both verified. - **/ - template - bool is_sameYC(const CImg& img) const { - return is_sameYC(img._height,img._spectrum); - } - - //! Test if image depth and spectrum are equal to specified values. - /** - Test if is_sameZ(unsigned int) const and is_sameC(unsigned int) const are both verified. - **/ - bool is_sameZC(const unsigned int size_z, const unsigned int size_c) const { - return _depth==size_z && _spectrum==size_c; - } - - //! Test if image depth and spectrum are the same as that of another image. - /** - Test if is_sameZ(const CImg&) const and is_sameC(const CImg&) const are both verified. - **/ - template - bool is_sameZC(const CImg& img) const { - return is_sameZC(img._depth,img._spectrum); - } - - //! Test if image width, height and depth are equal to specified values. - /** - Test if is_sameXY(unsigned int,unsigned int) const and is_sameZ(unsigned int) const are both verified. - **/ - bool is_sameXYZ(const unsigned int size_x, const unsigned int size_y, const unsigned int size_z) const { - return is_sameXY(size_x,size_y) && _depth==size_z; - } - - //! Test if image width, height and depth are the same as that of another image. - /** - Test if is_sameXY(const CImg&) const and is_sameZ(const CImg&) const are both verified. - **/ - template - bool is_sameXYZ(const CImg& img) const { - return is_sameXYZ(img._width,img._height,img._depth); - } - - //! Test if image width, height and spectrum are equal to specified values. - /** - Test if is_sameXY(unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified. - **/ - bool is_sameXYC(const unsigned int size_x, const unsigned int size_y, const unsigned int size_c) const { - return is_sameXY(size_x,size_y) && _spectrum==size_c; - } - - //! Test if image width, height and spectrum are the same as that of another image. - /** - Test if is_sameXY(const CImg&) const and is_sameC(const CImg&) const are both verified. - **/ - template - bool is_sameXYC(const CImg& img) const { - return is_sameXYC(img._width,img._height,img._spectrum); - } - - //! Test if image width, depth and spectrum are equal to specified values. - /** - Test if is_sameXZ(unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified. - **/ - bool is_sameXZC(const unsigned int size_x, const unsigned int size_z, const unsigned int size_c) const { - return is_sameXZ(size_x,size_z) && _spectrum==size_c; - } - - //! Test if image width, depth and spectrum are the same as that of another image. - /** - Test if is_sameXZ(const CImg&) const and is_sameC(const CImg&) const are both verified. - **/ - template - bool is_sameXZC(const CImg& img) const { - return is_sameXZC(img._width,img._depth,img._spectrum); - } - - //! Test if image height, depth and spectrum are equal to specified values. - /** - Test if is_sameYZ(unsigned int,unsigned int) const and is_sameC(unsigned int) const are both verified. - **/ - bool is_sameYZC(const unsigned int size_y, const unsigned int size_z, const unsigned int size_c) const { - return is_sameYZ(size_y,size_z) && _spectrum==size_c; - } - - //! Test if image height, depth and spectrum are the same as that of another image. - /** - Test if is_sameYZ(const CImg&) const and is_sameC(const CImg&) const are both verified. - **/ - template - bool is_sameYZC(const CImg& img) const { - return is_sameYZC(img._height,img._depth,img._spectrum); - } - - //! Test if image width, height, depth and spectrum are equal to specified values. - /** - Test if is_sameXYZ(unsigned int,unsigned int,unsigned int) const and is_sameC(unsigned int) const are both - verified. - **/ - bool is_sameXYZC(const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c) const { - return is_sameXYZ(size_x,size_y,size_z) && _spectrum==size_c; - } - - //! Test if image width, height, depth and spectrum are the same as that of another image. - /** - Test if is_sameXYZ(const CImg&) const and is_sameC(const CImg&) const are both verified. - **/ - template - bool is_sameXYZC(const CImg& img) const { - return is_sameXYZC(img._width,img._height,img._depth,img._spectrum); - } - - //! Test if specified coordinates are inside image bounds. - /** - Return \c true if pixel located at (\c x,\c y,\c z,\c c) is inside bounds of the image instance, - and \c false otherwise. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note - - Return \c true only if all these conditions are verified: - - The image instance is \e not empty. - - 0<=x<=\ref width() - 1. - - 0<=y<=\ref height() - 1. - - 0<=z<=\ref depth() - 1. - - 0<=c<=\ref spectrum() - 1. - **/ - bool containsXYZC(const int x, const int y=0, const int z=0, const int c=0) const { - return !is_empty() && x>=0 && x=0 && y=0 && z=0 && c img(100,100,1,3); // Construct a 100x100 RGB color image - const unsigned long offset = 1249; // Offset to the pixel (49,12,0,0) - unsigned int x,y,z,c; - if (img.contains(img[offset],x,y,z,c)) { // Convert offset to (x,y,z,c) coordinates - std::printf("Offset %u refers to pixel located at (%u,%u,%u,%u).\n", - offset,x,y,z,c); - } - \endcode - **/ - template - bool contains(const T& pixel, t& x, t& y, t& z, t& c) const { - const ulongT wh = (ulongT)_width*_height, whd = wh*_depth, siz = whd*_spectrum; - const T *const ppixel = &pixel; - if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false; - ulongT off = (ulongT)(ppixel - _data); - const ulongT nc = off/whd; - off%=whd; - const ulongT nz = off/wh; - off%=wh; - const ulongT ny = off/_width, nx = off%_width; - x = (t)nx; y = (t)ny; z = (t)nz; c = (t)nc; - return true; - } - - //! Test if pixel value is inside image bounds and get its X,Y and Z-coordinates. - /** - Similar to contains(const T&,t&,t&,t&,t&) const, except that only the X,Y and Z-coordinates are set. - **/ - template - bool contains(const T& pixel, t& x, t& y, t& z) const { - const ulongT wh = (ulongT)_width*_height, whd = wh*_depth, siz = whd*_spectrum; - const T *const ppixel = &pixel; - if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false; - ulongT off = ((ulongT)(ppixel - _data))%whd; - const ulongT nz = off/wh; - off%=wh; - const ulongT ny = off/_width, nx = off%_width; - x = (t)nx; y = (t)ny; z = (t)nz; - return true; - } - - //! Test if pixel value is inside image bounds and get its X and Y-coordinates. - /** - Similar to contains(const T&,t&,t&,t&,t&) const, except that only the X and Y-coordinates are set. - **/ - template - bool contains(const T& pixel, t& x, t& y) const { - const ulongT wh = (ulongT)_width*_height, siz = wh*_depth*_spectrum; - const T *const ppixel = &pixel; - if (is_empty() || ppixel<_data || ppixel>=_data + siz) return false; - ulongT off = ((unsigned int)(ppixel - _data))%wh; - const ulongT ny = off/_width, nx = off%_width; - x = (t)nx; y = (t)ny; - return true; - } - - //! Test if pixel value is inside image bounds and get its X-coordinate. - /** - Similar to contains(const T&,t&,t&,t&,t&) const, except that only the X-coordinate is set. - **/ - template - bool contains(const T& pixel, t& x) const { - const T *const ppixel = &pixel; - if (is_empty() || ppixel<_data || ppixel>=_data + size()) return false; - x = (t)(((ulongT)(ppixel - _data))%_width); - return true; - } - - //! Test if pixel value is inside image bounds. - /** - Similar to contains(const T&,t&,t&,t&,t&) const, except that no pixel coordinates are set. - **/ - bool contains(const T& pixel) const { - const T *const ppixel = &pixel; - return !is_empty() && ppixel>=_data && ppixel<_data + size(); - } - - //! Test if pixel buffers of instance and input images overlap. - /** - Return \c true, if pixel buffers attached to image instance and input image \c img overlap, - and \c false otherwise. - \param img Input image to compare with. - \note - - Buffer overlapping may happen when manipulating \e shared images. - - If two image buffers overlap, operating on one of the image will probably modify the other one. - - Most of the time, \c CImg instances are \e non-shared and do not overlap between each others. - \par Example - \code - const CImg - img1("reference.jpg"), // Load RGB-color image - img2 = img1.get_shared_channel(1); // Get shared version of the green channel - if (img1.is_overlapped(img2)) { // Test succeeds, 'img1' and 'img2' overlaps - std::printf("Buffers overlap!\n"); - } - \endcode - **/ - template - bool is_overlapped(const CImg& img) const { - const ulongT csiz = size(), isiz = img.size(); - return !((void*)(_data + csiz)<=(void*)img._data || (void*)_data>=(void*)(img._data + isiz)); - } - - //! Test if the set {\c *this,\c primitives,\c colors,\c opacities} defines a valid 3D object. - /** - Return \c true is the 3D object represented by the set {\c *this,\c primitives,\c colors,\c opacities} defines a - valid 3D object, and \c false otherwise. The vertex coordinates are defined by the instance image. - \param primitives List of primitives of the 3D object. - \param colors List of colors of the 3D object. - \param opacities List (or image) of opacities of the 3D object. - \param full_check Tells if full checking of the 3D object must be performed. - \param[out] error_message C-string to contain the error message, if the test does not succeed. - \note - - Set \c full_checking to \c false to speed-up the 3D object checking. In this case, only the size of - each 3D object component is checked. - - Size of the string \c error_message should be at least 128-bytes long, to be able to contain the error message. - **/ - template - bool is_object3d(const CImgList& primitives, - const CImgList& colors, - const to& opacities, - const bool full_check=true, - char *const error_message=0) const { - if (error_message) *error_message = 0; - - // Check consistency for the particular case of an empty 3D object. - if (is_empty()) { - if (primitives || colors || opacities) { - if (error_message) cimg_sprintf(error_message, - "3D object (%u,%u) defines no vertices but %u primitives, " - "%u colors and %lu opacities", - _width,primitives._width,primitives._width, - colors._width,(unsigned long)opacities.size()); - return false; - } - return true; - } - - // Check consistency of vertices. - if (_height!=3 || _depth>1 || _spectrum>1) { // Check vertices dimensions - if (error_message) cimg_sprintf(error_message, - "3D object (%u,%u) has invalid vertex dimensions (%u,%u,%u,%u)", - _width,primitives._width,_width,_height,_depth,_spectrum); - return false; - } - if (colors._width>primitives._width + 1) { - if (error_message) cimg_sprintf(error_message, - "3D object (%u,%u) defines %u colors", - _width,primitives._width,colors._width); - return false; - } - if (opacities.size()>primitives._width) { - if (error_message) cimg_sprintf(error_message, - "3D object (%u,%u) defines %lu opacities", - _width,primitives._width,(unsigned long)opacities.size()); - return false; - } - if (!full_check) return true; - - // Check consistency of primitives. - cimglist_for(primitives,l) { - const CImg& primitive = primitives[l]; - const unsigned int psiz = (unsigned int)primitive.size(); - switch (psiz) { - case 1 : { // Point - const unsigned int i0 = (unsigned int)primitive(0); - if (i0>=_width) { - if (error_message) cimg_sprintf(error_message, - "3D object (%u,%u) refers to invalid vertex index %u in " - "point primitive [%u]", - _width,primitives._width,i0,l); - return false; - } - } break; - case 5 : { // Sphere - const unsigned int - i0 = (unsigned int)primitive(0), - i1 = (unsigned int)primitive(1); - if (i0>=_width || i1>=_width) { - if (error_message) cimg_sprintf(error_message, - "3D object (%u,%u) refers to invalid vertex indices (%u,%u) in " - "sphere primitive [%u]", - _width,primitives._width,i0,i1,l); - return false; - } - } break; - case 2 : case 6 : { // Segment - const unsigned int - i0 = (unsigned int)primitive(0), - i1 = (unsigned int)primitive(1); - if (i0>=_width || i1>=_width) { - if (error_message) cimg_sprintf(error_message, - "3D object (%u,%u) refers to invalid vertex indices (%u,%u) in " - "segment primitive [%u]", - _width,primitives._width,i0,i1,l); - return false; - } - } break; - case 3 : case 9 : { // Triangle - const unsigned int - i0 = (unsigned int)primitive(0), - i1 = (unsigned int)primitive(1), - i2 = (unsigned int)primitive(2); - if (i0>=_width || i1>=_width || i2>=_width) { - if (error_message) cimg_sprintf(error_message, - "3D object (%u,%u) refers to invalid vertex indices (%u,%u,%u) in " - "triangle primitive [%u]", - _width,primitives._width,i0,i1,i2,l); - return false; - } - } break; - case 4 : case 12 : { // Quadrangle - const unsigned int - i0 = (unsigned int)primitive(0), - i1 = (unsigned int)primitive(1), - i2 = (unsigned int)primitive(2), - i3 = (unsigned int)primitive(3); - if (i0>=_width || i1>=_width || i2>=_width || i3>=_width) { - if (error_message) cimg_sprintf(error_message, - "3D object (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in " - "quadrangle primitive [%u]", - _width,primitives._width,i0,i1,i2,i3,l); - return false; - } - } break; - default : - if (error_message) cimg_sprintf(error_message, - "3D object (%u,%u) defines an invalid primitive [%u] of size %u", - _width,primitives._width,l,(unsigned int)psiz); - return false; - } - } - - // Check consistency of colors. - cimglist_for(colors,c) { - const CImg& color = colors[c]; - if (!color) { - if (error_message) cimg_sprintf(error_message, - "3D object (%u,%u) defines no color for primitive [%u]", - _width,primitives._width,c); - return false; - } - } - - // Check consistency of light texture. - if (colors._width>primitives._width) { - const CImg &light = colors.back(); - if (!light || light._depth>1) { - if (error_message) cimg_sprintf(error_message, - "3D object (%u,%u) defines an invalid light texture (%u,%u,%u,%u)", - _width,primitives._width,light._width, - light._height,light._depth,light._spectrum); - return false; - } - } - - return true; - } - - //! Test if image instance represents a valid serialization of a 3D object. - /** - Return \c true if the image instance represents a valid serialization of a 3D object, and \c false otherwise. - \param full_check Tells if full checking of the instance must be performed. - \param[out] error_message C-string to contain the error message, if the test does not succeed. - \note - - Set \c full_check to \c false to speed-up the 3D object checking. In this case, only the size of - each 3D object component is checked. - - Size of the string \c error_message should be at least 128-bytes long, to be able to contain the error message. - **/ - bool is_CImg3d(const bool full_check=true, char *const error_message=0) const { - if (error_message) *error_message = 0; - - // Check instance dimension and header. - if (_width!=1 || _height<8 || _depth!=1 || _spectrum!=1) { - if (error_message) cimg_sprintf(error_message, - "CImg3d has invalid dimensions (%u,%u,%u,%u)", - _width,_height,_depth,_spectrum); - return false; - } - const T *ptrs = _data, *const ptre = end(); - if (!_is_CImg3d(*(ptrs++),'C') || !_is_CImg3d(*(ptrs++),'I') || !_is_CImg3d(*(ptrs++),'m') || - !_is_CImg3d(*(ptrs++),'g') || !_is_CImg3d(*(ptrs++),'3') || !_is_CImg3d(*(ptrs++),'d')) { - if (error_message) cimg_sprintf(error_message, - "CImg3d header not found"); - return false; - } - const unsigned int - nb_points = cimg::float2uint((float)*(ptrs++)), - nb_primitives = cimg::float2uint((float)*(ptrs++)); - - // Check consistency of number of vertices / primitives. - if (!full_check) { - const ulongT minimal_size = 8UL + 3*nb_points + 6*nb_primitives; - if (_data + minimal_size>ptre) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) has only %lu values, while at least %lu values were expected", - nb_points,nb_primitives,(unsigned long)size(),(unsigned long)minimal_size); - return false; - } - } - - // Check consistency of vertex data. - if (!nb_points) { - if (nb_primitives) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) defines no vertices but %u primitives", - nb_points,nb_primitives,nb_primitives); - return false; - } - if (ptrs!=ptre) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) is an empty object but contains %u value%s " - "more than expected", - nb_points,nb_primitives,(unsigned int)(ptre - ptrs),(ptre - ptrs)>1?"s":""); - return false; - } - return true; - } - if (ptrs + 3*nb_points>ptre) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) defines only %u vertices data", - nb_points,nb_primitives,(unsigned int)(ptre - ptrs)/3); - return false; - } - ptrs+=3*nb_points; - - // Check consistency of primitive data. - if (ptrs==ptre) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) defines %u vertices but no primitive", - nb_points,nb_primitives,nb_points); - return false; - } - - if (!full_check) return true; - - for (unsigned int p = 0; p=nb_points) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) refers to invalid vertex index %u in point primitive [%u]", - nb_points,nb_primitives,i0,p); - return false; - } - } break; - case 5 : { // Sphere - const unsigned int - i0 = cimg::float2uint((float)*(ptrs++)), - i1 = cimg::float2uint((float)*(ptrs++)); - ptrs+=3; - if (i0>=nb_points || i1>=nb_points) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in " - "sphere primitive [%u]", - nb_points,nb_primitives,i0,i1,p); - return false; - } - } break; - case 2 : case 6 : { // Segment - const unsigned int - i0 = cimg::float2uint((float)*(ptrs++)), - i1 = cimg::float2uint((float)*(ptrs++)); - if (nb_inds==6) ptrs+=4; - if (i0>=nb_points || i1>=nb_points) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u) in " - "segment primitive [%u]", - nb_points,nb_primitives,i0,i1,p); - return false; - } - } break; - case 3 : case 9 : { // Triangle - const unsigned int - i0 = cimg::float2uint((float)*(ptrs++)), - i1 = cimg::float2uint((float)*(ptrs++)), - i2 = cimg::float2uint((float)*(ptrs++)); - if (nb_inds==9) ptrs+=6; - if (i0>=nb_points || i1>=nb_points || i2>=nb_points) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u) in " - "triangle primitive [%u]", - nb_points,nb_primitives,i0,i1,i2,p); - return false; - } - } break; - case 4 : case 12 : { // Quadrangle - const unsigned int - i0 = cimg::float2uint((float)*(ptrs++)), - i1 = cimg::float2uint((float)*(ptrs++)), - i2 = cimg::float2uint((float)*(ptrs++)), - i3 = cimg::float2uint((float)*(ptrs++)); - if (nb_inds==12) ptrs+=8; - if (i0>=nb_points || i1>=nb_points || i2>=nb_points || i3>=nb_points) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) refers to invalid vertex indices (%u,%u,%u,%u) in " - "quadrangle primitive [%u]", - nb_points,nb_primitives,i0,i1,i2,i3,p); - return false; - } - } break; - default : - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) defines an invalid primitive [%u] of size %u", - nb_points,nb_primitives,p,nb_inds); - return false; - } - if (ptrs>ptre) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) has incomplete primitive data for primitive [%u], " - "%u values missing", - nb_points,nb_primitives,p,(unsigned int)(ptrs - ptre)); - return false; - } - } - - // Check consistency of color data. - if (ptrs==ptre) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) defines no color/texture data", - nb_points,nb_primitives); - return false; - } - for (unsigned int c = 0; c=c) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) refers to invalid shared sprite/texture index %u " - "for primitive [%u]", - nb_points,nb_primitives,w,c); - return false; - } - } else ptrs+=w*h*s; - } - if (ptrs>ptre) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) has incomplete color/texture data for primitive [%u], " - "%u values missing", - nb_points,nb_primitives,c,(unsigned int)(ptrs - ptre)); - return false; - } - } - - // Check consistency of opacity data. - if (ptrs==ptre) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) defines no opacity data", - nb_points,nb_primitives); - return false; - } - for (unsigned int o = 0; o=o) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) refers to invalid shared opacity index %u " - "for primitive [%u]", - nb_points,nb_primitives,w,o); - return false; - } - } else ptrs+=w*h*s; - } - if (ptrs>ptre) { - if (error_message) cimg_sprintf(error_message, - "CImg3d (%u,%u) has incomplete opacity data for primitive [%u]", - nb_points,nb_primitives,o); - return false; - } - } - - // Check end of data. - if (ptrs1?"s":""); - return false; - } - return true; - } - - static bool _is_CImg3d(const T val, const char c) { - return val>=(T)c && val<(T)(c + 1); - } - - //@} - //------------------------------------- - // - //! \name Mathematical Functions - //@{ - //------------------------------------- - - // Define the math formula parser/compiler and expression evaluator. - struct _cimg_math_parser { - CImg mem; - CImg memtype, memmerge; - CImgList _code, &code, code_begin, code_end, - _code_begin_t, &code_begin_t, _code_end_t, &code_end_t; - CImg opcode; - const CImg *p_code_end, *p_code; - const CImg *const p_break; - - CImg expr, pexpr; - const CImg& imgin; - CImg &imgout; - CImgList& imglist; - - CImg _img_stats, &img_stats, constcache_vals; - CImgList _list_stats, &list_stats, _list_median, &list_median, _list_norm, &list_norm; - CImg mem_img_stats, constcache_inds; - - CImg level, variable_pos, reserved_label; - CImgList variable_def, macro_def, macro_body; - char *user_macro; - - unsigned int mempos, mem_img_median, mem_img_norm, mem_img_index, debug_indent, result_dim, break_type, - constcache_size; - bool is_parallelizable, is_noncritical_run, is_end_code, is_fill, return_new_comp, need_input_copy; - double *result; - cimg_uint64 rng; - const char *const calling_function, *s_op, *ss_op; - typedef double (*mp_func)(_cimg_math_parser&); - -#define _cimg_mp_is_scalar(arg) (memtype[arg]<2) // Is scalar value? -#define _cimg_mp_is_const_scalar(arg) (memtype[arg]==1) // Is const scalar? -#define _cimg_mp_is_vector(arg) (memtype[arg]>1) // Is vector? -#define _cimg_mp_is_comp(arg) (!memtype[arg]) // Is computation value? -#define _cimg_mp_is_reserved(arg) (memtype[arg]==-1) // Is scalar and reserved (e.g. variable)? -#define _cimg_mp_size(arg) (_cimg_mp_is_scalar(arg)?0U:(unsigned int)memtype[arg] - 1) // Size (0=scalar, N>0=vectorN) -#define _cimg_mp_calling_function s_calling_function()._data -#define _cimg_mp_op(s) s_op = s; ss_op = ss -#define _cimg_mp_check_type(arg,n_arg,mode,N) check_type(arg,n_arg,mode,N,ss,se,saved_char) -#define _cimg_mp_check_const_scalar(arg,n_arg,mode) check_const_scalar(arg,n_arg,mode,ss,se,saved_char) -#define _cimg_mp_check_const_index(arg) check_const_index(arg,ss,se,saved_char) -#define _cimg_mp_check_matrix_square(arg,n_arg) check_matrix_square(arg,n_arg,ss,se,saved_char) -#define _cimg_mp_check_list() check_list(ss,se,saved_char) -#define _cimg_mp_defunc(mp) (*(mp_func)(*(mp).opcode))(mp) -#define _cimg_mp_return(x) { *se = saved_char; s_op = previous_s_op; ss_op = previous_ss_op; return x; } -#define _cimg_mp_return_nan() _cimg_mp_return(_cimg_mp_slot_nan) -#define _cimg_mp_const_scalar(val) _cimg_mp_return(const_scalar((double)(val))) -#define _cimg_mp_scalar0(op) _cimg_mp_return(scalar0(op)) -#define _cimg_mp_scalar1(op,i1) _cimg_mp_return(scalar1(op,i1)) -#define _cimg_mp_scalar2(op,i1,i2) _cimg_mp_return(scalar2(op,i1,i2)) -#define _cimg_mp_scalar3(op,i1,i2,i3) _cimg_mp_return(scalar3(op,i1,i2,i3)) -#define _cimg_mp_scalar4(op,i1,i2,i3,i4) _cimg_mp_return(scalar4(op,i1,i2,i3,i4)) -#define _cimg_mp_scalar5(op,i1,i2,i3,i4,i5) _cimg_mp_return(scalar5(op,i1,i2,i3,i4,i5)) -#define _cimg_mp_scalar6(op,i1,i2,i3,i4,i5,i6) _cimg_mp_return(scalar6(op,i1,i2,i3,i4,i5,i6)) -#define _cimg_mp_scalar7(op,i1,i2,i3,i4,i5,i6,i7) _cimg_mp_return(scalar7(op,i1,i2,i3,i4,i5,i6,i7)) -#define _cimg_mp_vector1_v(op,i1) _cimg_mp_return(vector1_v(op,i1)) -#define _cimg_mp_vector2_sv(op,i1,i2) _cimg_mp_return(vector2_sv(op,i1,i2)) -#define _cimg_mp_vector2_vs(op,i1,i2) _cimg_mp_return(vector2_vs(op,i1,i2)) -#define _cimg_mp_vector2_vv(op,i1,i2) _cimg_mp_return(vector2_vv(op,i1,i2)) -#define _cimg_mp_vector3_vss(op,i1,i2,i3) _cimg_mp_return(vector3_vss(op,i1,i2,i3)) -#define _cimg_mp_strerr \ - *se = saved_char; \ - for (s0 = ss; s0>expr._data && *s0!=';'; --s0) {} \ - if (*s0==';') ++s0; \ - while (cimg::is_blank(*s0)) ++s0; \ - cimg::strellipsize(s0,64) - - // Constructors / Destructors. - ~_cimg_math_parser() { - cimg::srand(rng); - } - - _cimg_math_parser(const char *const expression, const char *const funcname=0, - const CImg& img_input=CImg::const_empty(), CImg *const img_output=0, - CImgList *const list_images=0, const bool _is_fill=false): - code(_code),code_begin_t(_code_begin_t),code_end_t(_code_end_t), - p_break((CImg*)(cimg_ulong)-2),imgin(img_input), - imgout(img_output?*img_output:CImg::empty()),imglist(list_images?*list_images:CImgList::empty()), - img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),list_norm(_list_norm),user_macro(0), - mem_img_median(~0U),mem_img_norm(~0U),mem_img_index(~0U),debug_indent(0),result_dim(0),break_type(0), - constcache_size(0),is_parallelizable(true),is_noncritical_run(false),is_fill(_is_fill),need_input_copy(false), - rng((cimg::_rand(),cimg::rng())),calling_function(funcname?funcname:"cimg_math_parser") { - -#if cimg_use_openmp!=0 - rng+=omp_get_thread_num(); -#endif - if (!expression || !*expression) - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: Empty expression.", - pixel_type(),_cimg_mp_calling_function); - const char *_expression = expression; - while (*_expression && (cimg::is_blank(*_expression) || *_expression==';')) ++_expression; - CImg::string(_expression).move_to(expr); - char *ps = &expr.back() - 1; - while (ps>expr._data && (cimg::is_blank(*ps) || *ps==';')) --ps; - *(++ps) = 0; expr._width = (unsigned int)(ps - expr._data + 1); - - // Ease the retrieval of previous non-space characters afterwards. - pexpr.assign(expr._width); - char c, *pe = pexpr._data; - for (ps = expr._data, c = ' '; *ps; ++ps) { - if (!cimg::is_blank(*ps)) c = *ps; else *ps = ' '; - *(pe++) = c; - } - *pe = 0; - level = get_level(expr); - - // Init constant values. -#define _cimg_mp_interpolation (reserved_label[31]!=~0U?reserved_label[31]:0) -#define _cimg_mp_boundary (reserved_label[32]!=~0U?reserved_label[32]:0) -#define _cimg_mp_slot_t 17 -#define _cimg_mp_slot_nan 29 -#define _cimg_mp_slot_x 30 -#define _cimg_mp_slot_y 31 -#define _cimg_mp_slot_z 32 -#define _cimg_mp_slot_c 33 - - mem.assign(96); - for (unsigned int i = 0; i<=10; ++i) mem[i] = (double)i; // mem[0-10] = 0...10 - for (unsigned int i = 1; i<=5; ++i) mem[i + 10] = -(double)i; // mem[11-15] = -1...-5 - mem[16] = 0.5; - mem[_cimg_mp_slot_t] = 0; // thread_id - mem[18] = (double)imgin._width; // w - mem[19] = (double)imgin._height; // h - mem[20] = (double)imgin._depth; // d - mem[21] = (double)imgin._spectrum; // s - mem[22] = (double)imgin._is_shared; // r - mem[23] = (double)imgin._width*imgin._height; // wh - mem[24] = (double)imgin._width*imgin._height*imgin._depth; // whd - mem[25] = (double)imgin._width*imgin._height*imgin._depth*imgin._spectrum; // whds - mem[26] = (double)imglist._width; // l - mem[27] = std::exp(1.); // e - mem[28] = cimg::PI; // pi - mem[_cimg_mp_slot_nan] = cimg::type::nan(); // nan - - // Set value property : - // { -1 = reserved (e.g. variable) | 0 = computation value | - // 1 = compile-time constant | N>1 = constant ptr to vector[N-1] }. - memtype.assign(mem._width,1,1,1,0); - for (unsigned int i = 0; i<_cimg_mp_slot_x; ++i) memtype[i] = 1; - memtype[_cimg_mp_slot_t] = memtype[_cimg_mp_slot_x] = memtype[_cimg_mp_slot_y] = - memtype[_cimg_mp_slot_z] = memtype[_cimg_mp_slot_c] = -1; - mempos = _cimg_mp_slot_c + 1; - variable_pos.assign(8); - - reserved_label.assign(128,1,1,1,~0U); - // reserved_label[0-32] are used to store the memory index of these variables: - // [0] = wh, [1] = whd, [2] = whds, [3] = pi, [4] = im, [5] = iM, [6] = ia, [7] = iv, [8] = id, - // [9] = is, [10] = ip, [11] = ic, [12] = in, [13] = xm, [14] = ym, [15] = zm, [16] = cm, [17] = xM, - // [18] = yM, [19] = zM, [20] = cM, [21] = i0...[30] = i9, [31] = interpolation, [32] = boundary - - // Compile expression into a sequence of opcodes. - s_op = ""; ss_op = expr._data; - const unsigned int ind_result = compile(expr._data,expr._data + expr._width - 1,0,0,0); - if (!_cimg_mp_is_const_scalar(ind_result)) { - if (_cimg_mp_is_vector(ind_result)) - CImg(&mem[ind_result] + 1,_cimg_mp_size(ind_result),1,1,1,true). - fill(cimg::type::nan()); - else if (ind_result!=_cimg_mp_slot_t) mem[ind_result] = cimg::type::nan(); - } - - // Free resources used for compiling expression and prepare evaluation. - result_dim = _cimg_mp_size(ind_result); - if (mem._width>=256 && mem._width - mempos>=mem._width/2) mem.resize(mempos,1,1,1,-1); - result = mem._data + ind_result; - memtype.assign(); - constcache_vals.assign(); - constcache_inds.assign(); - level.assign(); - variable_pos.assign(); - reserved_label.assign(); - expr.assign(); - pexpr.assign(); - opcode.assign(); - opcode._is_shared = true; - - // Execute begin() block if any specified. - if (code_begin) { - mem[_cimg_mp_slot_x] = mem[_cimg_mp_slot_y] = mem[_cimg_mp_slot_z] = mem[_cimg_mp_slot_c] = 0; - p_code_end = code_begin.end(); - for (p_code = code_begin; p_code_data; - const ulongT target = opcode[1]; - mem[target] = _cimg_mp_defunc(*this); - } - } - p_code_end = code.end(); - } - - _cimg_math_parser(): - code(_code),code_begin_t(_code_begin_t),code_end_t(_code_end_t), - p_code_end(0),p_break((CImg*)(cimg_ulong)-2), - imgin(CImg::const_empty()),imgout(CImg::empty()),imglist(CImgList::empty()), - img_stats(_img_stats),list_stats(_list_stats),list_median(_list_median),list_norm(_list_norm),debug_indent(0), - result_dim(0),break_type(0),constcache_size(0),is_parallelizable(true),is_noncritical_run(false),is_fill(false), - need_input_copy(false),rng(0),calling_function(0) { - mem.assign(1 + _cimg_mp_slot_c,1,1,1,0); // Allow to skip 'is_empty?' test in operator()() - result = mem._data; - } - - _cimg_math_parser(const _cimg_math_parser& mp): - mem(mp.mem),code(mp.code),code_begin_t(mp.code_begin_t),code_end_t(mp.code_end_t), - p_code_end(mp.p_code_end),p_break(mp.p_break), - imgin(mp.imgin),imgout(mp.imgout),imglist(mp.imglist), - img_stats(mp.img_stats),list_stats(mp.list_stats),list_median(mp.list_median),list_norm(mp.list_norm), - debug_indent(0),result_dim(mp.result_dim),break_type(0),constcache_size(0), - is_parallelizable(mp.is_parallelizable),is_noncritical_run(mp.is_noncritical_run),is_fill(mp.is_fill), - need_input_copy(mp.need_input_copy),result(mem._data + (mp.result - mp.mem._data)), - rng((cimg::_rand(),cimg::rng())),calling_function(0) { - -#if cimg_use_openmp!=0 - mem[_cimg_mp_slot_t] = (double)omp_get_thread_num(); - rng+=omp_get_thread_num(); -#endif - opcode.assign(); - opcode._is_shared = true; - } - - // Compilation procedure. - unsigned int compile(char *ss, char *se, const unsigned int depth, unsigned int *const p_ref, - const unsigned char block_flags) { - if (depth>256) { - cimg::strellipsize(expr,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: Call stack overflow (infinite recursion?), " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function, - (ss - 4)>expr._data?ss - 4:expr._data); - } - char c1, c2; - - // Simplify expression when possible. - do { - c2 = 0; - if (ssss && (cimg::is_blank(c1 = *(se - 1)) || c1==';')) --se; // Remove trailing blanks and ';' - } - while (*ss=='(' && *(se - 1)==')' && std::strchr(ss,')')==se - 1) { // Remove useless start/end parentheses - ++ss; --se; c2 = 1; - } - if (*ss=='_' && ss + 1=se) return _cimg_mp_slot_nan; - c2 = 1; - } - } while (c2 && ss::%s: %s%s Missing %s, in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"", - *s_op=='F'?"argument":"item", - ss_op); - } - - static const size_t siz_ref = 7*sizeof(unsigned int); - const char *const previous_s_op = s_op, *const previous_ss_op = ss_op; - const unsigned int depth1 = depth + 1; - unsigned int pos, p1, p2, p3, arg1, arg2, arg3, arg4, arg5, arg6; - char - *const se1 = se - 1, *const se2 = se - 2, *const se3 = se - 3, - *const ss1 = ss + 1, *const ss2 = ss + 2, *const ss3 = ss + 3, *const ss4 = ss + 4, - *const ss5 = ss + 5, *const ss6 = ss + 6, *const ss7 = ss + 7, *const ss8 = ss + 8, - *s, *ps, *ns, *s0, *s1, *s2, *s3, sep = 0, end = 0; - double val = 0, val1, val2; - mp_func op; - return_new_comp = false; - - // Bits of 'block_flags' tell about in which code block we currently are: - // 0: critical(), 1: begin(), 2: begin_t(), 3: end(), 4: end_t(). - const bool is_inside_critical = (bool)(block_flags&1); - - // 'p_ref' is a 'unsigned int[7]' used to return a reference to an image or vector value - // linked to the returned memory slot (reference that cannot be determined at compile time). - // p_ref[0] can be { 0 = scalar (unlinked) | 1 = vector value | 2 = image value (offset) | - // 3 = image value (coordinates) | 4 = image value as a vector (offsets) | - // 5 = image value as a vector (coordinates) }. - // Depending on p_ref[0], the remaining p_ref[k] have the following meaning: - // When p_ref[0]==0, p_ref is actually unlinked. - // When p_ref[0]==1, p_ref = [ 1, vector_ind, offset ]. - // When p_ref[0]==2, p_ref = [ 2, image_ind (or ~0U), is_relative, offset ]. - // When p_ref[0]==3, p_ref = [ 3, image_ind (or ~0U), is_relative, x, y, z, c ]. - // When p_ref[0]==4, p_ref = [ 4, image_ind (or ~0U), is_relative, offset ]. - // When p_ref[0]==5, p_ref = [ 5, image_ind (or ~0U), is_relative, x, y, z ]. - if (p_ref) { *p_ref = 0; p_ref[1] = p_ref[2] = p_ref[3] = p_ref[4] = p_ref[5] = p_ref[6] = ~0U; } - - const char saved_char = *se; *se = 0; - const unsigned int clevel = level[ss - expr._data], clevel1 = clevel + 1; - bool is_sth, is_relative; - CImg ref; - CImg variable_name; - CImgList l_opcode; - - // Look for a single value or a pre-defined variable. - int nb = 0; - s = ss + (*ss=='+' || *ss=='-'?1:0); - if (*s=='i' || *s=='I' || *s=='n' || *s=='N') { // Particular cases : +/-NaN and +/-Inf - is_sth = *ss=='-'; - if (!cimg::strcasecmp(s,"inf")) { val = cimg::type::inf(); nb = 1; } - else if (!cimg::strcasecmp(s,"nan")) { val = cimg::type::nan(); nb = 1; } - if (nb==1 && is_sth) val = -val; - } else if (*s=='0' && (s[1]=='x' || s[1]=='X')) { // Hexadecimal number - is_sth = *ss=='-'; - if (cimg_sscanf(s + 2,"%x%c",&arg1,&sep)==1) { - nb = 1; - val = (double)arg1; - if (is_sth) val = -val; - } - } - if (!nb) nb = cimg_sscanf(ss,"%lf%c%c",&val,&(sep=0),&(end=0)); - if (nb==1) _cimg_mp_const_scalar(val); - if (nb==2 && sep=='%') _cimg_mp_const_scalar(val/100); - - if (ss1==se) switch (*ss) { // One-char reserved variable - case 'c' : _cimg_mp_return(reserved_label[(int)'c']!=~0U?reserved_label[(int)'c']:_cimg_mp_slot_c); - case 'd' : _cimg_mp_return(reserved_label[(int)'d']!=~0U?reserved_label[(int)'d']:20); - case 'e' : _cimg_mp_return(reserved_label[(int)'e']!=~0U?reserved_label[(int)'e']:27); - case 'h' : _cimg_mp_return(reserved_label[(int)'h']!=~0U?reserved_label[(int)'h']:19); - case 'k' : - if (reserved_label[(int)'k']!=~0U) _cimg_mp_return(reserved_label[(int)'k']); - pos = get_mem_img_index(); - if (pos!=~0U) _cimg_mp_return(pos); - _cimg_mp_return_nan(); - case 'l' : _cimg_mp_return(reserved_label[(int)'l']!=~0U?reserved_label[(int)'l']:26); - case 'r' : _cimg_mp_return(reserved_label[(int)'r']!=~0U?reserved_label[(int)'r']:22); - case 's' : _cimg_mp_return(reserved_label[(int)'s']!=~0U?reserved_label[(int)'s']:21); - case 't' : _cimg_mp_return(reserved_label[(int)'t']!=~0U?reserved_label[(int)'t']:_cimg_mp_slot_t); - case 'n' : - if (reserved_label[(int)'n']!=~0U) _cimg_mp_return(reserved_label[(int)'n']); -#if cimg_use_openmp!=0 - _cimg_mp_const_scalar((double)omp_get_max_threads()); -#else - _cimg_mp_return(1); -#endif - case 'w' : _cimg_mp_return(reserved_label[(int)'w']!=~0U?reserved_label[(int)'w']:18); - case 'x' : _cimg_mp_return(reserved_label[(int)'x']!=~0U?reserved_label[(int)'x']:_cimg_mp_slot_x); - case 'y' : _cimg_mp_return(reserved_label[(int)'y']!=~0U?reserved_label[(int)'y']:_cimg_mp_slot_y); - case 'z' : _cimg_mp_return(reserved_label[(int)'z']!=~0U?reserved_label[(int)'z']:_cimg_mp_slot_z); - case 'u' : - if (reserved_label[(int)'u']!=~0U) _cimg_mp_return(reserved_label[(int)'u']); - _cimg_mp_scalar2(mp_u,0,1); - case 'g' : - if (reserved_label[(int)'g']!=~0U) _cimg_mp_return(reserved_label[(int)'g']); - _cimg_mp_scalar0(mp_g); - case 'i' : - if (reserved_label[(int)'i']!=~0U) _cimg_mp_return(reserved_label[(int)'i']); - _cimg_mp_scalar0(mp_i); - case 'I' : - _cimg_mp_op("Variable 'I'"); - if (reserved_label[(int)'I']!=~0U) _cimg_mp_return(reserved_label[(int)'I']); - if (!imgin._spectrum) _cimg_mp_return(0); - need_input_copy = true; - pos = vector(imgin._spectrum); - CImg::vector((ulongT)mp_Joff,pos,0,0,imgin._spectrum).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - case 'R' : - if (reserved_label[(int)'R']!=~0U) _cimg_mp_return(reserved_label[(int)'R']); - need_input_copy = true; - _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,0,0,0); - case 'G' : - if (reserved_label[(int)'G']!=~0U) _cimg_mp_return(reserved_label[(int)'G']); - need_input_copy = true; - _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,1,0,0); - case 'B' : - if (reserved_label[(int)'B']!=~0U) _cimg_mp_return(reserved_label[(int)'B']); - need_input_copy = true; - _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,2,0,0); - case 'A' : - if (reserved_label[(int)'A']!=~0U) _cimg_mp_return(reserved_label[(int)'A']); - need_input_copy = true; - _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,3,0,0); - } - else if (ss2==se) { // Two-chars reserved variable - arg1 = arg2 = ~0U; - if (*ss=='w' && *ss1=='h') // wh - _cimg_mp_return(reserved_label[0]!=~0U?reserved_label[0]:23); - if (*ss=='p' && *ss1=='i') // pi - _cimg_mp_return(reserved_label[3]!=~0U?reserved_label[3]:28); - if (*ss=='i') { - if (*ss1>='0' && *ss1<='9') { // i0...i9 - pos = 21 + *ss1 - '0'; - if (reserved_label[pos]!=~0U) _cimg_mp_return(reserved_label[pos]); - need_input_copy = true; - _cimg_mp_scalar6(mp_ixyzc,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,pos - 21,0,0); - } - switch (*ss1) { - case 'm' : arg1 = 4; arg2 = 0; break; // im - case 'M' : arg1 = 5; arg2 = 1; break; // iM - case 'a' : arg1 = 6; arg2 = 2; break; // ia - case 'v' : arg1 = 7; arg2 = 3; break; // iv - case 'd' : arg1 = 8; arg2 = 3; break; // id - case 's' : arg1 = 9; arg2 = 12; break; // is - case 'p' : arg1 = 10; arg2 = 13; break; // ip - case 'c' : // ic - if (reserved_label[11]!=~0U) _cimg_mp_return(reserved_label[11]); - if (mem_img_median==~0U) mem_img_median = imgin?const_scalar(imgin.median()):0; - _cimg_mp_return(mem_img_median); - break; - case 'n' : // in - if (reserved_label[12]!=~0U) _cimg_mp_return(reserved_label[12]); - if (mem_img_norm==~0U) mem_img_norm = imgin?const_scalar(imgin.magnitude()):0; - _cimg_mp_return(mem_img_norm); - } - } - else if (*ss1=='m') switch (*ss) { - case 'x' : arg1 = 13; arg2 = 4; break; // xm - case 'y' : arg1 = 14; arg2 = 5; break; // ym - case 'z' : arg1 = 15; arg2 = 6; break; // zm - case 'c' : arg1 = 16; arg2 = 7; break; // cm - } - else if (*ss1=='M') switch (*ss) { - case 'x' : arg1 = 17; arg2 = 8; break; // xM - case 'y' : arg1 = 18; arg2 = 9; break; // yM - case 'z' : arg1 = 19; arg2 = 10; break; // zM - case 'c' : arg1 = 20; arg2 = 11; break; // cM - } - if (arg1!=~0U) { - if (reserved_label[arg1]!=~0U) _cimg_mp_return(reserved_label[arg1]); - if (!img_stats) { - img_stats.assign(1,14,1,1,0).fill(imgin.get_stats(),false); - mem_img_stats.assign(1,14,1,1,~0U); - } - if (mem_img_stats[arg2]==~0U) mem_img_stats[arg2] = const_scalar(img_stats[arg2]); - if (arg1==8) _cimg_mp_const_scalar(std::sqrt(img_stats[arg2])); // id: std variation - _cimg_mp_return(mem_img_stats[arg2]); - } - } else if (ss3==se) { // Three-chars reserved variable - if (*ss=='w' && *ss1=='h' && *ss2=='d') // whd - _cimg_mp_return(reserved_label[1]!=~0U?reserved_label[1]:24); - } else if (ss4==se) { // Four-chars reserved variable - if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='s') // whds - _cimg_mp_return(reserved_label[2]!=~0U?reserved_label[2]:25); - } - - pos = ~0U; - is_sth = false; - - for (s0 = ss, s = ss1; s='i'?1:3,0); - if (_cimg_mp_is_vector(arg2)) { - if (p1!=~0U) { - _cimg_mp_check_const_index(p1); - p3 = (unsigned int)cimg::mod((int)mem[p1],imglist.width()); - p2 = imglist[p3]._spectrum; - } else p2 = imgin._spectrum; - if (!p2) _cimg_mp_return(0); - _cimg_mp_check_type(arg2,2,2,p2); - } else p2 = 0; - - if (p_ref) { - *p_ref = _cimg_mp_is_vector(arg2)?4:2; - p_ref[1] = p1; - p_ref[2] = (unsigned int)is_relative; - p_ref[3] = arg1; - if (_cimg_mp_is_vector(arg2)) - set_reserved_vector(arg2); // Prevent from being used in further optimization - else if (_cimg_mp_is_comp(arg2)) memtype[arg2] = -1; - if (_cimg_mp_is_comp(arg1)) memtype[arg1] = -1; - } - - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(arg2); - if (*ss>='i') - CImg::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff), - arg2,p1,arg1).move_to(code); - else if (_cimg_mp_is_scalar(arg2)) - CImg::vector((ulongT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s), - arg2,p1,arg1).move_to(code); - else - CImg::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), - arg2,p1,arg1,_cimg_mp_size(arg2)).move_to(code); - } else { - if (!imgout) _cimg_mp_return(arg2); - if (*ss>='i') - CImg::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff), - arg2,arg1).move_to(code); - else if (_cimg_mp_is_scalar(arg2)) - CImg::vector((ulongT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s), - arg2,arg1).move_to(code); - else - CImg::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), - arg2,arg1,_cimg_mp_size(arg2)).move_to(code); - } - _cimg_mp_return(arg2); - } - - if (*ss1=='(' && *ve1==')') { // i/j/I/J(_#ind,_x,_y,_z,_c) = value - if (!is_inside_critical) is_parallelizable = false; - if (*ss2=='#') { // Index specified - s0 = ss3; while (s0='i'?1:3,0); - if (s01) { - arg2 = arg1 + 1; - if (p2>2) { - arg3 = arg2 + 1; - if (p2>3) arg4 = arg3 + 1; - } - } - } else if (s1='i') - CImg::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), - arg5,p1,arg1,arg2,arg3,arg4).move_to(code); - else if (_cimg_mp_is_scalar(arg5)) - CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s), - arg5,p1,arg1,arg2,arg3).move_to(code); - else - CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), - arg5,p1,arg1,arg2,arg3,_cimg_mp_size(arg5)).move_to(code); - } else { - if (!imgout) _cimg_mp_return(arg5); - if (*ss>='i') - CImg::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), - arg5,arg1,arg2,arg3,arg4).move_to(code); - else if (_cimg_mp_is_scalar(arg5)) - CImg::vector((ulongT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s), - arg5,arg1,arg2,arg3).move_to(code); - else - CImg::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), - arg5,arg1,arg2,arg3,_cimg_mp_size(arg5)).move_to(code); - } - _cimg_mp_return(arg5); - } - } - - // Assign vector value (direct). - if (l_variable_name>3 && *ve1==']' && *ss!='[') { - s0 = ve1; while (s0>ss && (*s0!='[' || level[s0 - expr._data]!=clevel)) --s0; - if (s0>ss && is_varname(ss,s0 - ss)) { - variable_name[s0 - ss] = 0; // Remove brackets in variable name - get_variable_pos(variable_name,arg1,arg2); - arg1 = arg2!=~0U?reserved_label[arg2]:arg1!=~0U?variable_pos[arg1]:~0U; // Vector slot - if (arg1==~0U || _cimg_mp_is_scalar(arg1)) - compile(ss,s0,depth1,0,block_flags); // Variable does not exist or is not a vector -> error - - arg2 = compile(++s0,ve1,depth1,0,block_flags); // Index - arg3 = compile(s + 1,se,depth1,0,block_flags); // Value to assign - _cimg_mp_check_type(arg3,2,1,0); - - if (_cimg_mp_is_const_scalar(arg2)) { // Constant index -> return corresponding variable slot directly - nb = (int)mem[arg2]; - if (nb>=0 && nb<(int)_cimg_mp_size(arg1)) { - arg1+=nb + 1; - CImg::vector((ulongT)mp_copy,arg1,arg3).move_to(code); - _cimg_mp_return(arg1); - } - compile(ss,s,depth1,0,block_flags); // Out-of-bounds reference -> error - } - - // Case of non-constant index -> return assigned value + linked reference - if (p_ref) { - *p_ref = 1; - p_ref[1] = arg1; - p_ref[2] = arg2; - if (_cimg_mp_is_comp(arg3)) memtype[arg3] = -1; // Prevent from being used in further optimization - if (_cimg_mp_is_comp(arg2)) memtype[arg2] = -1; - } - CImg::vector((ulongT)mp_vector_set_off,arg3,arg1,(ulongT)_cimg_mp_size(arg1),arg2). - move_to(code); - _cimg_mp_return(arg3); - } - } - - // Assign user-defined macro. - if (l_variable_name>2 && *ve1==')' && *ss!='(') { - s0 = ve1; while (s0>ss && *s0!='(') --s0; - if (is_varname(ss,s0 - ss) && std::strncmp(variable_name,"debug(",6) && - std::strncmp(variable_name,"print(",6)) { // Valid macro name - s0 = variable_name._data + (s0 - ss); - *s0 = 0; - s1 = variable_name._data + l_variable_name - 1; // Pointer to closing parenthesis - CImg(variable_name._data,(unsigned int)(s0 - variable_name._data + 1)).move_to(macro_def,0); - ++s; while (*s && cimg::is_blank(*s)) ++s; - CImg(s,(unsigned int)(se - s + 1)).move_to(macro_body,0); - - bool is_variadic = false; - p1 = 1; // Index of current parsed argument - for (s = s0 + 1; s<=s1; ++p1, s = ns + 1) { // Parse function arguments - if (is_variadic && p1>1) { - _cimg_mp_strerr; - cimg::strellipsize(variable_name,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Multiple arguments not allowed when first one is " - "variadic, in macro definition '%s()', in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - variable_name._data,s0); - } - if (p1>24) { - _cimg_mp_strerr; - cimg::strellipsize(variable_name,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Too much specified arguments (>24), in macro " - "definition '%s()', in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - variable_name._data,s0); - } - while (*s && cimg::is_blank(*s)) ++s; - if (*s==')' && p1==1) break; // Function has no arguments - s2 = s; // Start of the argument name - is_sth = true; // is_valid_argument_name? - if (*s2>='0' && *s2<='9') is_sth = false; - else for (ns = s2; nss2 && *ns=='.' && ns[1]=='.' && ns[2]=='.') { is_variadic = true; ns+=3; } - else if (*ns=='.') is_sth = false; - while (*ns && cimg::is_blank(*ns)) ++ns; - - if (!is_sth || s2==s3 || (*ns!=',' && ns!=s1)) { - _cimg_mp_strerr; - cimg::strellipsize(variable_name,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: %s name specified for argument %u when defining " - "macro '%s()', in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - is_sth?"Empty":"Invalid",p1, - variable_name._data,s0); - } - - if (ns==s1 || *ns==',' || (is_variadic && *ns=='.')) { // New argument found - *s3 = 0; - p2 = (unsigned int)(s3 - s2); // Argument length - for (ps = std::strstr(macro_body[0],s2); ps; ps = std::strstr(ps,s2)) { // Replace by arg number - if (!((ps>macro_body[0]._data && is_varchar(*(ps - 1))) || - (ps + p2macro_body[0]._data && *(ps - 1)=='#') { // Remove pre-number sign - *(ps - 1) = (char)p1; - if (ps + p26 && !std::strncmp(variable_name,"const ",6); - s0 = variable_name._data; - if (is_const) { - s0+=6; while (cimg::is_blank(*s0)) ++s0; - variable_name.resize(variable_name.end() - s0,1,1,1,0,0,1); - } - if (is_varname(variable_name)) { // Valid variable name - - // Assign variable (direct). - get_variable_pos(variable_name,arg1,arg2); - arg3 = compile(s + 1,se,depth1,0,block_flags); - is_sth = return_new_comp; // is arg3 a new blank object? - if (is_const) _cimg_mp_check_const_scalar(arg3,2,0); - arg1 = arg2!=~0U?reserved_label[arg2]:arg1!=~0U?variable_pos[arg1]:~0U; - - if (arg1==~0U) { // Create new variable - if (_cimg_mp_is_vector(arg3)) { // Vector variable - arg1 = is_sth || is_comp_vector(arg3)?arg3:vector_copy(arg3); - set_reserved_vector(arg1); // Prevent from being used in further optimization - } else { // Scalar variable - if (is_const) arg1 = arg3; - else { - arg1 = is_sth || _cimg_mp_is_comp(arg3)?arg3:scalar1(mp_copy,arg3); - memtype[arg1] = -1; - } - } - - if (arg2!=~0U) reserved_label[arg2] = arg1; - else { - if (variable_def._width>=variable_pos._width) variable_pos.resize(-200,1,1,1,0); - variable_pos[variable_def._width] = arg1; - variable_name.move_to(variable_def); - } - - } else { // Variable already exists -> assign a new value - if (is_const || _cimg_mp_is_const_scalar(arg1)) { - _cimg_mp_strerr; - cimg::strellipsize(variable_name,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Invalid assignment of %sconst variable '%s'%s, " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - _cimg_mp_is_const_scalar(arg1)?"":"non-", - variable_name._data, - !_cimg_mp_is_const_scalar(arg1) && is_const?" as a const variable":"", - s0); - } - _cimg_mp_check_type(arg3,2,_cimg_mp_is_vector(arg1)?3:1,_cimg_mp_size(arg1)); - if (_cimg_mp_is_vector(arg1)) { // Vector - if (_cimg_mp_is_vector(arg3)) // From vector - CImg::vector((ulongT)mp_vector_copy,arg1,arg3,(ulongT)_cimg_mp_size(arg1)). - move_to(code); - else // From scalar - CImg::vector((ulongT)mp_vector_init,arg1,1,(ulongT)_cimg_mp_size(arg1),arg3). - move_to(code); - } else // Scalar - CImg::vector((ulongT)mp_copy,arg1,arg3).move_to(code); - } - return_new_comp = false; - _cimg_mp_return(arg1); - } - - // Assign lvalue (variable name was not valid for a direct assignment). - arg1 = ~0U; - is_sth = (bool)std::strchr(variable_name,'?'); // Contains_ternary_operator? - if (is_sth) break; // Do nothing and make ternary operator priority over assignment - - if (l_variable_name>2 && (std::strchr(variable_name,'(') || std::strchr(variable_name,'['))) { - ref.assign(7); - arg1 = compile(ss,s,depth1,ref,block_flags); // Lvalue slot - arg2 = compile(s + 1,se,depth1,0,block_flags); // Value to assign - - if (*ref==1) { // Vector value (scalar): V[k] = scalar - _cimg_mp_check_type(arg2,2,1,0); - arg3 = ref[1]; // Vector slot - arg4 = ref[2]; // Index - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - CImg::vector((ulongT)mp_vector_set_off,arg2,arg3,(ulongT)_cimg_mp_size(arg3),arg4). - move_to(code); - _cimg_mp_return(arg2); - } - - if (*ref==2) { // Image value (scalar): i/j[_#ind,off] = scalar - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_check_type(arg2,2,1,0); - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // Offset - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(arg2); - CImg::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff), - arg2,p1,arg3).move_to(code); - } else { - if (!imgout) _cimg_mp_return(arg2); - CImg::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff), - arg2,arg3).move_to(code); - } - _cimg_mp_return(arg2); - } - - if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c) = scalar - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_check_type(arg2,2,1,0); - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // X - arg4 = ref[4]; // Y - arg5 = ref[5]; // Z - arg6 = ref[6]; // C - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(arg2); - CImg::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), - arg2,p1,arg3,arg4,arg5,arg6).move_to(code); - } else { - if (!imgout) _cimg_mp_return(arg2); - CImg::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), - arg2,arg3,arg4,arg5,arg6).move_to(code); - } - _cimg_mp_return(arg2); - } - - if (*ref==4) { // Image value (vector): I/J[_#ind,off] = value - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // Offset - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(arg2); - if (_cimg_mp_is_scalar(arg2)) - CImg::vector((ulongT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s), - arg2,p1,arg3).move_to(code); - else { - _cimg_mp_check_const_index(p1); - CImg::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), - arg2,p1,arg3,_cimg_mp_size(arg2)).move_to(code); - } - - } else { - if (!imgout) _cimg_mp_return(arg2); - if (_cimg_mp_is_scalar(arg2)) - CImg::vector((ulongT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s), - arg2,arg3).move_to(code); - else - CImg::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), - arg2,arg3,_cimg_mp_size(arg2)).move_to(code); - } - _cimg_mp_return(arg2); - } - - if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) = value - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // X - arg4 = ref[4]; // Y - arg5 = ref[5]; // Z - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(arg2); - if (_cimg_mp_is_scalar(arg2)) - CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s), - arg2,p1,arg3,arg4,arg5).move_to(code); - else { - _cimg_mp_check_const_index(p1); - CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), - arg2,p1,arg3,arg4,arg5,_cimg_mp_size(arg2)).move_to(code); - } - - } else { - if (!imgout) _cimg_mp_return(arg2); - if (_cimg_mp_is_scalar(arg2)) - CImg::vector((ulongT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s), - arg2,arg3,arg4,arg5).move_to(code); - else - CImg::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), - arg2,arg3,arg4,arg5,_cimg_mp_size(arg2)).move_to(code); - } - _cimg_mp_return(arg2); - } - - if (_cimg_mp_is_vector(arg1)) { // Vector variable: V = value - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (_cimg_mp_is_vector(arg2)) // From vector - CImg::vector((ulongT)mp_vector_copy,arg1,arg2,(ulongT)_cimg_mp_size(arg1)). - move_to(code); - else // From scalar - CImg::vector((ulongT)mp_vector_init,arg1,1,(ulongT)_cimg_mp_size(arg1),arg2). - move_to(code); - _cimg_mp_return(arg1); - } - - if (_cimg_mp_is_reserved(arg1)) { // Scalar variable: s = scalar - _cimg_mp_check_type(arg2,2,1,0); - CImg::vector((ulongT)mp_copy,arg1,arg2).move_to(code); - _cimg_mp_return(arg1); - } - } - - // No assignment expressions match -> error - _cimg_mp_strerr; - cimg::strellipsize(variable_name,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Invalid %slvalue '%s', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - arg1!=~0U && _cimg_mp_is_const_scalar(arg1)?"const ":"", - variable_name._data,s0); - } - - // Apply unary/binary/ternary operators. The operator precedences should be the same as in C++. - for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1 - if (*s=='=' && (*ps=='*' || *ps=='/' || *ps=='^') && *ns==*ps && - level[s - expr._data]==clevel) { // Self-operators for complex numbers only (**=,//=,^^=) - _cimg_mp_op(*ps=='*'?"Operator '**='":*ps=='/'?"Operator '//='":"Operator '^^='"); - - ref.assign(7); - arg1 = compile(ss,ns,depth1,ref,block_flags); // Vector slot - arg2 = compile(s + 1,se,depth1,0,block_flags); // Right operand - _cimg_mp_check_type(arg1,1,2,2); - _cimg_mp_check_type(arg2,2,3,2); - if (_cimg_mp_is_vector(arg2)) { // Complex **= complex - if (*ps=='*') - CImg::vector((ulongT)mp_complex_mul,arg1,arg1,arg2).move_to(code); - else if (*ps=='/') - CImg::vector((ulongT)mp_complex_div_vv,arg1,arg1,arg2).move_to(code); - else - CImg::vector((ulongT)mp_complex_pow_vv,arg1,arg1,arg2).move_to(code); - } else { // Complex **= scalar - if (*ps=='*') { - if (arg2==1) _cimg_mp_return(arg1); - self_vector_s(arg1,mp_self_mul,arg2); - } else if (*ps=='/') { - if (arg2==1) _cimg_mp_return(arg1); - self_vector_s(arg1,mp_self_div,arg2); - } else { - if (arg2==1) _cimg_mp_return(arg1); - CImg::vector((ulongT)mp_complex_pow_vs,arg1,arg1,arg2).move_to(code); - } - } - - if (*ref==4) { // Image value (vector): I/J[_#ind,off] **= value - if (!is_inside_critical) is_parallelizable = false; - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // Offset - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(arg1); - _cimg_mp_check_const_index(p1); - CImg::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), - arg1,p1,arg3,_cimg_mp_size(arg1)).move_to(code); - } else { - if (!imgout) _cimg_mp_return(arg1); - CImg::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), - arg1,arg3,_cimg_mp_size(arg1)).move_to(code); - } - - } else if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) **= value - if (!is_inside_critical) is_parallelizable = false; - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // X - arg4 = ref[4]; // Y - arg5 = ref[5]; // Z - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(arg1); - _cimg_mp_check_const_index(p1); - CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), - arg1,p1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code); - } else { - if (!imgout) _cimg_mp_return(arg1); - CImg::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), - arg1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code); - } - } - - _cimg_mp_return(arg1); - } - - for (s = se2, ps = se3, ns = ps - 1; s>ss1; --s, --ps, --ns) // Here, ns = ps - 1 - if (*s=='=' && (*ps=='+' || *ps=='-' || *ps=='*' || *ps=='/' || (*ps=='%' && s[1]!='=') || - *ps=='&' || *ps=='^' || *ps=='|' || - (*ps=='>' && *ns=='>') || (*ps=='<' && *ns=='<')) && - level[s - expr._data]==clevel) { // Self-operators (+=,-=,*=,/=,%=,>>=,<<=,&=,^=,|=) - switch (*ps) { - case '+' : op = mp_self_add; _cimg_mp_op("Operator '+='"); break; - case '-' : op = mp_self_sub; _cimg_mp_op("Operator '-='"); break; - case '*' : op = mp_self_mul; _cimg_mp_op("Operator '*='"); break; - case '/' : op = mp_self_div; _cimg_mp_op("Operator '/='"); break; - case '%' : op = mp_self_modulo; _cimg_mp_op("Operator '%='"); break; - case '<' : op = mp_self_bitwise_left_shift; _cimg_mp_op("Operator '<<='"); break; - case '>' : op = mp_self_bitwise_right_shift; _cimg_mp_op("Operator '>>='"); break; - case '&' : op = mp_self_bitwise_and; _cimg_mp_op("Operator '&='"); break; - case '|' : op = mp_self_bitwise_or; _cimg_mp_op("Operator '|='"); break; - default : op = mp_self_pow; _cimg_mp_op("Operator '^='"); break; - } - s1 = *ps=='>' || *ps=='<'?ns:ps; - - ref.assign(7); - arg1 = compile(ss,s1,depth1,ref,block_flags); // Variable slot - arg2 = compile(s + 1,se,depth1,0,block_flags); // Value to apply - - // Check for particular case to be simplified. - if ((op==mp_self_add || op==mp_self_sub) && !arg2) _cimg_mp_return(arg1); - if ((op==mp_self_mul || op==mp_self_div) && arg2==1) _cimg_mp_return(arg1); - - // Apply operator on a copy to prevent modifying a constant or a variable. - if (*ref && (_cimg_mp_is_const_scalar(arg1) || _cimg_mp_is_vector(arg1) || _cimg_mp_is_reserved(arg1))) { - if (_cimg_mp_is_vector(arg1)) arg1 = vector_copy(arg1); - else arg1 = scalar1(mp_copy,arg1); - } - - if (*ref==1) { // Vector value (scalar): V[k] += scalar - _cimg_mp_check_type(arg2,2,1,0); - arg3 = ref[1]; // Vector slot - arg4 = ref[2]; // Index - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - CImg::vector((ulongT)op,arg1,arg2).move_to(code); - CImg::vector((ulongT)mp_vector_set_off,arg1,arg3,(ulongT)_cimg_mp_size(arg3),arg4). - move_to(code); - _cimg_mp_return(arg1); - } - - if (*ref==2) { // Image value (scalar): i/j[_#ind,off] += scalar - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_check_type(arg2,2,1,0); - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // Offset - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - CImg::vector((ulongT)op,arg1,arg2).move_to(code); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(arg1); - CImg::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff), - arg1,p1,arg3).move_to(code); - } else { - if (!imgout) _cimg_mp_return(arg1); - CImg::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff), - arg1,arg3).move_to(code); - } - _cimg_mp_return(arg1); - } - - if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c) += scalar - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_check_type(arg2,2,1,0); - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // X - arg4 = ref[4]; // Y - arg5 = ref[5]; // Z - arg6 = ref[6]; // C - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - CImg::vector((ulongT)op,arg1,arg2).move_to(code); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(arg1); - CImg::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), - arg1,p1,arg3,arg4,arg5,arg6).move_to(code); - } else { - if (!imgout) _cimg_mp_return(arg1); - CImg::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), - arg1,arg3,arg4,arg5,arg6).move_to(code); - } - _cimg_mp_return(arg1); - } - - if (*ref==4) { // Image value (vector): I/J[_#ind,off] += value - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // Offset - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - if (_cimg_mp_is_scalar(arg2)) self_vector_s(arg1,op,arg2); else self_vector_v(arg1,op,arg2); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(arg1); - CImg::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), - arg1,p1,arg3,_cimg_mp_size(arg1)).move_to(code); - } else { - if (!imgout) _cimg_mp_return(arg1); - CImg::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), - arg1,arg3,_cimg_mp_size(arg1)).move_to(code); - } - _cimg_mp_return(arg1); - } - - if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c) += value - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // X - arg4 = ref[4]; // Y - arg5 = ref[5]; // Z - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - if (_cimg_mp_is_scalar(arg2)) self_vector_s(arg1,op,arg2); else self_vector_v(arg1,op,arg2); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(arg1); - CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), - arg1,p1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code); - } else { - if (!imgout) _cimg_mp_return(arg1); - CImg::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), - arg1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code); - } - _cimg_mp_return(arg1); - } - - if (_cimg_mp_is_vector(arg1)) { // Vector variable: V += value - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (_cimg_mp_is_vector(arg2)) self_vector_v(arg1,op,arg2); // Vector += vector - else self_vector_s(arg1,op,arg2); // Vector += scalar - _cimg_mp_return(arg1); - } - - if (_cimg_mp_is_reserved(arg1)) { // Scalar variable: s += scalar - _cimg_mp_check_type(arg2,2,1,0); - CImg::vector((ulongT)op,arg1,arg2).move_to(code); - _cimg_mp_return(arg1); - } - - variable_name.assign(ss,(unsigned int)(s - ss)).back() = 0; - cimg::strpare(variable_name,false,true); - _cimg_mp_strerr; - cimg::strellipsize(variable_name,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Invalid %slvalue '%s', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - _cimg_mp_is_const_scalar(arg1)?"const ":"", - variable_name._data,s0); - } - - for (s = ss1; s::vector((ulongT)mp_if,pos,arg1,arg2,arg3, - p3 - p2,code._width - p3,arg4).move_to(code,p2); - return_new_comp = true; - _cimg_mp_return(pos); - } - - for (s = se3, ns = se2; s>ss; --s, --ns) - if (*s=='|' && *ns=='|' && level[s - expr._data]==clevel) { // Logical or ('||') - _cimg_mp_op("Operator '||'"); - arg1 = compile(ss,s,depth1,0,block_flags); - _cimg_mp_check_type(arg1,1,1,0); - if (arg1>0 && arg1<=16) _cimg_mp_return(1); - p2 = code._width; - arg2 = compile(s + 2,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,1,0); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1] || mem[arg2]); - if (!arg1) _cimg_mp_return(arg2); - pos = scalar(); - CImg::vector((ulongT)mp_logical_or,pos,arg1,arg2,code._width - p2). - move_to(code,p2); - return_new_comp = true; - _cimg_mp_return(pos); - } - - for (s = se3, ns = se2; s>ss; --s, --ns) - if (*s=='&' && *ns=='&' && level[s - expr._data]==clevel) { // Logical and ('&&') - _cimg_mp_op("Operator '&&'"); - arg1 = compile(ss,s,depth1,0,block_flags); - _cimg_mp_check_type(arg1,1,1,0); - if (!arg1) _cimg_mp_return(0); - p2 = code._width; - arg2 = compile(s + 2,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,1,0); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1] && mem[arg2]); - if (arg1>0 && arg1<=16) _cimg_mp_return(arg2); - pos = scalar(); - CImg::vector((ulongT)mp_logical_and,pos,arg1,arg2,code._width - p2). - move_to(code,p2); - return_new_comp = true; - _cimg_mp_return(pos); - } - - for (s = se2; s>ss; --s) - if (*s=='|' && level[s - expr._data]==clevel) { // Bitwise or ('|') - _cimg_mp_op("Operator '|'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 1,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_or,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) { - if (!arg2) _cimg_mp_return(arg1); - _cimg_mp_vector2_vs(mp_bitwise_or,arg1,arg2); - } - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) { - if (!arg1) _cimg_mp_return(arg2); - _cimg_mp_vector2_sv(mp_bitwise_or,arg1,arg2); - } - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar((longT)mem[arg1] | (longT)mem[arg2]); - if (!arg2) _cimg_mp_return(arg1); - if (!arg1) _cimg_mp_return(arg2); - _cimg_mp_scalar2(mp_bitwise_or,arg1,arg2); - } - - for (s = se2; s>ss; --s) - if (*s=='&' && level[s - expr._data]==clevel) { // Bitwise and ('&') - _cimg_mp_op("Operator '&'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 1,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_bitwise_and,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_bitwise_and,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_bitwise_and,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar((longT)mem[arg1] & (longT)mem[arg2]); - if (!arg1 || !arg2) _cimg_mp_return(0); - _cimg_mp_scalar2(mp_bitwise_and,arg1,arg2); - } - - for (s = se3, ns = se2; s>ss; --s, --ns) - if (*s=='!' && *ns=='=' && level[s - expr._data]==clevel) { // Not equal to ('!=') - _cimg_mp_op("Operator '!='"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 2,se,depth1,0,block_flags); - if (arg1==arg2) _cimg_mp_return(0); - p1 = _cimg_mp_size(arg1); - p2 = _cimg_mp_size(arg2); - if (p1 || p2) { - if (p1 && p2 && p1!=p2) _cimg_mp_return(1); - pos = scalar(); - CImg::vector((ulongT)mp_vector_neq,pos,arg1,p1,arg2,p2,11,1).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1]!=mem[arg2]); - _cimg_mp_scalar2(mp_neq,arg1,arg2); - } - - for (s = se3, ns = se2; s>ss; --s, --ns) - if (*s=='=' && *ns=='=' && level[s - expr._data]==clevel) { // Equal to ('==') - _cimg_mp_op("Operator '=='"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 2,se,depth1,0,block_flags); - if (arg1==arg2) _cimg_mp_return(1); - p1 = _cimg_mp_size(arg1); - p2 = _cimg_mp_size(arg2); - if (p1 || p2) { - if (p1 && p2 && p1!=p2) _cimg_mp_return(0); - pos = scalar(); - CImg::vector((ulongT)mp_vector_eq,pos,arg1,p1,arg2,p2,11,1).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1]==mem[arg2]); - _cimg_mp_scalar2(mp_eq,arg1,arg2); - } - - for (s = se3, ns = se2; s>ss; --s, --ns) - if (*s=='<' && *ns=='=' && level[s - expr._data]==clevel) { // Less or equal than ('<=') - _cimg_mp_op("Operator '<='"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 2,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lte,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lte,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lte,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1]<=mem[arg2]); - if (arg1==arg2) _cimg_mp_return(1); - _cimg_mp_scalar2(mp_lte,arg1,arg2); - } - - for (s = se3, ns = se2; s>ss; --s, --ns) - if (*s=='>' && *ns=='=' && level[s - expr._data]==clevel) { // Greater or equal than ('>=') - _cimg_mp_op("Operator '>='"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 2,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gte,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gte,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gte,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1]>=mem[arg2]); - if (arg1==arg2) _cimg_mp_return(1); - _cimg_mp_scalar2(mp_gte,arg1,arg2); - } - - for (s = se2, ns = se1, ps = se3; s>ss; --s, --ns, --ps) - if (*s=='<' && *ns!='<' && *ps!='<' && level[s - expr._data]==clevel) { // Less than ('<') - _cimg_mp_op("Operator '<'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 1,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_lt,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_lt,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_lt,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1]ss; --s, --ns, --ps) - if (*s=='>' && *ns!='>' && *ps!='>' && level[s - expr._data]==clevel) { // Greater than ('>') - _cimg_mp_op("Operator '>'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 1,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_gt,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_gt,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_gt,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1]>mem[arg2]); - if (arg1==arg2) _cimg_mp_return(0); - _cimg_mp_scalar2(mp_gt,arg1,arg2); - } - - for (s = se3, ns = se2; s>ss; --s, --ns) - if (*s=='<' && *ns=='<' && level[s - expr._data]==clevel) { // Left bit shift ('<<') - _cimg_mp_op("Operator '<<'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 2,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) - _cimg_mp_vector2_vv(mp_bitwise_left_shift,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) { - if (!arg2) _cimg_mp_return(arg1); - _cimg_mp_vector2_vs(mp_bitwise_left_shift,arg1,arg2); - } - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) - _cimg_mp_vector2_sv(mp_bitwise_left_shift,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar((longT)mem[arg1]<<(unsigned int)mem[arg2]); - if (!arg1) _cimg_mp_return(0); - if (!arg2) _cimg_mp_return(arg1); - _cimg_mp_scalar2(mp_bitwise_left_shift,arg1,arg2); - } - - for (s = se3, ns = se2; s>ss; --s, --ns) - if (*s=='>' && *ns=='>' && level[s - expr._data]==clevel) { // Right bit shift ('>>') - _cimg_mp_op("Operator '>>'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 2,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) - _cimg_mp_vector2_vv(mp_bitwise_right_shift,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) { - if (!arg2) _cimg_mp_return(arg1); - _cimg_mp_vector2_vs(mp_bitwise_right_shift,arg1,arg2); - } - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) - _cimg_mp_vector2_sv(mp_bitwise_right_shift,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar((longT)mem[arg1]>>(unsigned int)mem[arg2]); - if (!arg1) _cimg_mp_return(0); - if (!arg2) _cimg_mp_return(arg1); - _cimg_mp_scalar2(mp_bitwise_right_shift,arg1,arg2); - } - - for (ns = se1, s = se2, ps = pexpr._data + (se3 - expr._data); s>ss; --ns, --s, --ps) - if (*s=='+' && (*ns!='+' || ns!=se1) && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && - *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && *ps!='#' && - (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' && - *(ps - 1)<='9')))) && - level[s - expr._data]==clevel) { // Addition ('+') - _cimg_mp_op("Operator '+'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 1,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (!arg2) _cimg_mp_return(arg1); - if (!arg1) _cimg_mp_return(arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_add,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_add,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_add,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1] + mem[arg2]); - if (code) { // Try to spot linear case 'a*b + c' - CImg &pop = code.back(); - if (pop[0]==(ulongT)mp_mul && _cimg_mp_is_comp(pop[1]) && (pop[1]==arg1 || pop[1]==arg2)) { - arg3 = (unsigned int)pop[1]; - arg4 = (unsigned int)pop[2]; - arg5 = (unsigned int)pop[3]; - code.remove(); - CImg::vector((ulongT)mp_linear_add,arg3,arg4,arg5,arg3==arg2?arg1:arg2).move_to(code); - _cimg_mp_return(arg3); - } - } - if (arg2==1) _cimg_mp_scalar1(mp_increment,arg1); - if (arg1==1) _cimg_mp_scalar1(mp_increment,arg2); - _cimg_mp_scalar2(mp_add,arg1,arg2); - } - - for (ns = se1, s = se2, ps = pexpr._data + (se3 - expr._data); s>ss; --ns, --s, --ps) - if (*s=='-' && (*ns!='-' || ns!=se1) && *ps!='-' && *ps!='+' && *ps!='*' && *ps!='/' && *ps!='%' && - *ps!='&' && *ps!='|' && *ps!='^' && *ps!='!' && *ps!='~' && *ps!='#' && - (*ps!='e' || !(ps - pexpr._data>ss - expr._data && (*(ps - 1)=='.' || (*(ps - 1)>='0' && - *(ps - 1)<='9')))) && - level[s - expr._data]==clevel) { // Subtraction ('-') - _cimg_mp_op("Operator '-'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 1,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (!arg2) _cimg_mp_return(arg1); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_sub,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_sub,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) { - if (!arg1) _cimg_mp_vector1_v(mp_minus,arg2); - _cimg_mp_vector2_sv(mp_sub,arg1,arg2); - } - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1] - mem[arg2]); - if (!arg1) _cimg_mp_scalar1(mp_minus,arg2); - if (code) { // Try to spot linear cases 'a*b - c' and 'c - a*b' - CImg &pop = code.back(); - if (pop[0]==(ulongT)mp_mul && _cimg_mp_is_comp(pop[1]) && (pop[1]==arg1 || pop[1]==arg2)) { - arg3 = (unsigned int)pop[1]; - arg4 = (unsigned int)pop[2]; - arg5 = (unsigned int)pop[3]; - code.remove(); - CImg::vector((ulongT)(arg3==arg1?mp_linear_sub_left:mp_linear_sub_right), - arg3,arg4,arg5,arg3==arg1?arg2:arg1).move_to(code); - _cimg_mp_return(arg3); - } - } - if (arg2==1) _cimg_mp_scalar1(mp_decrement,arg1); - _cimg_mp_scalar2(mp_sub,arg1,arg2); - } - - for (s = se3, ns = se2; s>ss; --s, --ns) - if (*s=='*' && *ns=='*' && level[s - expr._data]==clevel) { // Complex multiplication ('**') - _cimg_mp_op("Operator '**'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 2,se,depth1,0,block_flags); - _cimg_mp_check_type(arg1,1,3,2); - _cimg_mp_check_type(arg2,2,3,2); - if (arg2==1) _cimg_mp_return(arg1); - if (arg1==1) _cimg_mp_return(arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) { - pos = vector(2); - CImg::vector((ulongT)mp_complex_mul,pos,arg1,arg2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1]*mem[arg2]); - if (!arg1 || !arg2) _cimg_mp_return(0); - _cimg_mp_scalar2(mp_mul,arg1,arg2); - } - - for (s = se3, ns = se2; s>ss; --s, --ns) - if (*s=='/' && *ns=='/' && level[s - expr._data]==clevel) { // Complex division ('//') - _cimg_mp_op("Operator '//'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 2,se,depth1,0,block_flags); - _cimg_mp_check_type(arg1,1,3,2); - _cimg_mp_check_type(arg2,2,3,2); - if (arg2==1) _cimg_mp_return(arg1); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) { - pos = vector(2); - CImg::vector((ulongT)mp_complex_div_vv,pos,arg1,arg2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) { - pos = vector(2); - CImg::vector((ulongT)mp_complex_div_sv,pos,arg1,arg2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1]/mem[arg2]); - if (!arg1) _cimg_mp_return(0); - _cimg_mp_scalar2(mp_div,arg1,arg2); - } - - for (s = se2; s>ss; --s) if (*s=='*' && level[s - expr._data]==clevel) { // Multiplication ('*') - _cimg_mp_op("Operator '*'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 1,se,depth1,0,block_flags); - p2 = _cimg_mp_size(arg2); - if (p2>0 && (ulongT)_cimg_mp_size(arg1)==(ulongT)p2*p2) { // Particular case of matrix multiplication - pos = vector(p2); - CImg::vector((ulongT)mp_matrix_mul,pos,arg1,arg2,p2,p2,1).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (arg2==1) _cimg_mp_return(arg1); - if (arg1==1) _cimg_mp_return(arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_mul,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_mul,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_mul,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1]*mem[arg2]); - - if (code) { // Try to spot double multiplication 'a*b*c' - CImg &pop = code.back(); - if (pop[0]==(ulongT)mp_mul && _cimg_mp_is_comp(pop[1]) && (pop[1]==arg1 || pop[1]==arg2)) { - arg3 = (unsigned int)pop[1]; - arg4 = (unsigned int)pop[2]; - arg5 = (unsigned int)pop[3]; - code.remove(); - CImg::vector((ulongT)mp_mul2,arg3,arg4,arg5,arg3==arg2?arg1:arg2).move_to(code); - _cimg_mp_return(arg3); - } - } - if (!arg1 || !arg2) _cimg_mp_return(0); - _cimg_mp_scalar2(mp_mul,arg1,arg2); - } - - for (s = se2; s>ss; --s) if (*s=='/' && level[s - expr._data]==clevel) { // Division ('/') - _cimg_mp_op("Operator '/'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 1,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (arg2==1) _cimg_mp_return(arg1); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_div,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_div,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_div,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(mem[arg1]/mem[arg2]); - if (!arg1) _cimg_mp_return(0); - _cimg_mp_scalar2(mp_div,arg1,arg2); - } - - for (s = se2, ns = se1; s>ss; --s, --ns) - if (*s=='%' && *ns!='^' && level[s - expr._data]==clevel) { // Modulo ('%') - _cimg_mp_op("Operator '%'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 1,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_modulo,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_modulo,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_modulo,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(cimg::mod(mem[arg1],mem[arg2])); - _cimg_mp_scalar2(mp_modulo,arg1,arg2); - } - - if (se1>ss) { - if (*ss=='+' && (*ss1!='+' || (ss2='0' && *ss2<='9'))) { // Unary plus ('+') - _cimg_mp_op("Operator '+'"); - _cimg_mp_return(compile(ss1,se,depth1,0,block_flags)); - } - - if (*ss=='-' && (*ss1!='-' || (ss2='0' && *ss2<='9'))) { // Unary minus ('-') - _cimg_mp_op("Operator '-'"); - arg1 = compile(ss1,se,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_minus,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(-mem[arg1]); - _cimg_mp_scalar1(mp_minus,arg1); - } - - if (*ss=='!') { // Logical not ('!') - _cimg_mp_op("Operator '!'"); - if (*ss1=='!') { // '!!expr' optimized as 'bool(expr)' - arg1 = compile(ss2,se,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_bool,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar((bool)mem[arg1]); - _cimg_mp_scalar1(mp_bool,arg1); - } - arg1 = compile(ss1,se,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_logical_not,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(!mem[arg1]); - _cimg_mp_scalar1(mp_logical_not,arg1); - } - - if (*ss=='~') { // Bitwise not ('~') - _cimg_mp_op("Operator '~'"); - arg1 = compile(ss1,se,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_bitwise_not,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(~(unsigned int)mem[arg1]); - _cimg_mp_scalar1(mp_bitwise_not,arg1); - } - } - - for (s = se3, ns = se2; s>ss; --s, --ns) - if (*s=='^' && *ns=='^' && level[s - expr._data]==clevel) { // Complex power ('^^') - _cimg_mp_op("Operator '^^'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 2,se,depth1,0,block_flags); - _cimg_mp_check_type(arg1,1,3,2); - _cimg_mp_check_type(arg2,2,3,2); - if (arg2==1) _cimg_mp_return(arg1); - pos = vector(2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) - CImg::vector((ulongT)mp_complex_pow_vv,pos,arg1,arg2).move_to(code); - else if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) - CImg::vector((ulongT)mp_complex_pow_vs,pos,arg1,arg2).move_to(code); - else if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) - CImg::vector((ulongT)mp_complex_pow_sv,pos,arg1,arg2).move_to(code); - else - CImg::vector((ulongT)mp_complex_pow_ss,pos,arg1,arg2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - for (s = se2; s>ss; --s) - if (*s=='^' && level[s - expr._data]==clevel) { // Power ('^') - _cimg_mp_op("Operator '^'"); - arg1 = compile(ss,s,depth1,0,block_flags); - arg2 = compile(s + 1,se,depth1,0,block_flags); - _cimg_mp_check_type(arg2,2,3,_cimg_mp_size(arg1)); - if (arg2==1) _cimg_mp_return(arg1); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_vv(mp_pow,arg1,arg2); - if (_cimg_mp_is_vector(arg1) && _cimg_mp_is_scalar(arg2)) _cimg_mp_vector2_vs(mp_pow,arg1,arg2); - if (_cimg_mp_is_scalar(arg1) && _cimg_mp_is_vector(arg2)) _cimg_mp_vector2_sv(mp_pow,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1) && _cimg_mp_is_const_scalar(arg2)) - _cimg_mp_const_scalar(std::pow(mem[arg1],mem[arg2])); - switch (arg2) { - case 0 : _cimg_mp_return(1); - case 2 : _cimg_mp_scalar1(mp_sqr,arg1); - case 3 : _cimg_mp_scalar1(mp_pow3,arg1); - case 4 : _cimg_mp_scalar1(mp_pow4,arg1); - default : - if (_cimg_mp_is_const_scalar(arg2)) { - if (mem[arg2]==0.5) { _cimg_mp_scalar1(mp_sqrt,arg1); } - else if (mem[arg2]==0.25) { _cimg_mp_scalar1(mp_pow0_25,arg1); } - } - _cimg_mp_scalar2(mp_pow,arg1,arg2); - } - } - - // Percentage computation. - if (*se1=='%') { - arg1 = compile(ss,se1,depth1,0,block_flags); - arg2 = _cimg_mp_is_const_scalar(arg1)?0:const_scalar(100); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector2_vs(mp_div,arg1,arg2); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(mem[arg1]/100); - _cimg_mp_scalar2(mp_div,arg1,arg2); - } - - // Degree to radian postfix operator ('°' in UTF-8). - if (se2>ss && (unsigned char)*se2==0xC2 && (unsigned char)*se1==0xB0) { - arg1 = compile(ss,se2,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_deg2rad,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(mem[arg1]*cimg::PI/180); - _cimg_mp_scalar1(mp_deg2rad,arg1); - } - - // Pre/post-decrement and increment. - is_sth = ss1ss && (*se1=='+' || *se1=='-') && *se2==*se1)) { - if ((is_sth && *ss=='+') || (!is_sth && *se1=='+')) { - _cimg_mp_op("Operator '++'"); - op = mp_self_increment; - } else { - _cimg_mp_op("Operator '--'"); - op = mp_self_decrement; - } - ref.assign(7); - arg1 = is_sth?compile(ss2,se,depth1,ref,block_flags): - compile(ss,se2,depth1,ref,block_flags); // Variable slot - - // Apply operator on a copy to prevent modifying a constant or a variable. - if (*ref && (_cimg_mp_is_const_scalar(arg1) || _cimg_mp_is_vector(arg1) || _cimg_mp_is_reserved(arg1))) { - if (_cimg_mp_is_vector(arg1)) arg1 = vector_copy(arg1); - else arg1 = scalar1(mp_copy,arg1); - } - - if (is_sth) pos = arg1; // Determine return index, depending on pre/post action - else { - if (_cimg_mp_is_vector(arg1)) pos = vector_copy(arg1); - else pos = scalar1(mp_copy,arg1); - } - - if (*ref==1) { // Vector value (scalar): V[k]++ - arg3 = ref[1]; // Vector slot - arg4 = ref[2]; // Index - if (is_sth && p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); - CImg::vector((ulongT)op,arg1,1).move_to(code); - CImg::vector((ulongT)mp_vector_set_off,arg1,arg3,(ulongT)_cimg_mp_size(arg3),arg4). - move_to(code); - _cimg_mp_return(pos); - } - - if (*ref==2) { // Image value (scalar): i/j[_#ind,off]++ - if (!is_inside_critical) is_parallelizable = false; - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // Offset - if (is_sth && p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); - CImg::vector((ulongT)op,arg1).move_to(code); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(pos); - CImg::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff), - arg1,p1,arg3).move_to(code); - } else { - if (!imgout) _cimg_mp_return(pos); - CImg::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff), - arg1,arg3).move_to(code); - } - _cimg_mp_return(pos); - } - - if (*ref==3) { // Image value (scalar): i/j(_#ind,_x,_y,_z,_c)++ - if (!is_inside_critical) is_parallelizable = false; - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // X - arg4 = ref[4]; // Y - arg5 = ref[5]; // Z - arg6 = ref[6]; // C - if (is_sth && p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); - CImg::vector((ulongT)op,arg1).move_to(code); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(pos); - CImg::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), - arg1,p1,arg3,arg4,arg5,arg6).move_to(code); - } else { - if (!imgout) _cimg_mp_return(pos); - CImg::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), - arg1,arg3,arg4,arg5,arg6).move_to(code); - } - _cimg_mp_return(pos); - } - - if (*ref==4) { // Image value (vector): I/J[_#ind,off]++ - if (!is_inside_critical) is_parallelizable = false; - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // Offset - if (is_sth && p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); - self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(pos); - CImg::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), - arg1,p1,arg3,_cimg_mp_size(arg1)).move_to(code); - } else { - if (!imgout) _cimg_mp_return(pos); - CImg::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), - arg1,arg3,_cimg_mp_size(arg1)).move_to(code); - } - _cimg_mp_return(pos); - } - - if (*ref==5) { // Image value (vector): I/J(_#ind,_x,_y,_z,_c)++ - if (!is_inside_critical) is_parallelizable = false; - p1 = ref[1]; // Index - is_relative = (bool)ref[2]; - arg3 = ref[3]; // X - arg4 = ref[4]; // Y - arg5 = ref[5]; // Z - if (is_sth && p_ref) std::memcpy(p_ref,ref,ref._width*sizeof(unsigned int)); - self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1); - if (p1!=~0U) { - if (!imglist) _cimg_mp_return(pos); - CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), - arg1,p1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code); - } else { - if (!imgout) _cimg_mp_return(pos); - CImg::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), - arg1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code); - } - _cimg_mp_return(pos); - } - - if (_cimg_mp_is_vector(arg1)) { // Vector variable: V++ - self_vector_s(arg1,op==mp_self_increment?mp_self_add:mp_self_sub,1); - _cimg_mp_return(pos); - } - - if (_cimg_mp_is_reserved(arg1)) { // Scalar variable: s++ - CImg::vector((ulongT)op,arg1).move_to(code); - _cimg_mp_return(pos); - } - - if (is_sth) variable_name.assign(ss2,(unsigned int)(se - ss1)); - else variable_name.assign(ss,(unsigned int)(se1 - ss)); - variable_name.back() = 0; - cimg::strpare(variable_name,false,true); - _cimg_mp_strerr; - cimg::strellipsize(variable_name,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Invalid %slvalue '%s', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - _cimg_mp_is_const_scalar(arg1)?"const ":"", - variable_name._data,s0); - } - - // Array-like access to vectors and image values 'i/j/I/J[_#ind,offset,_boundary]' and 'vector[offset]'. - if (*se1==']') { - _cimg_mp_op("Value accessor '[]'"); - - // Find opening bracket for the offset. - s0 = se1; while (s0>ss && (*s0!='[' || level[s0 - expr._data]!=clevel)) --s0; - if (s0>ss) { s1 = s0; do { --s1; } while (cimg::is_blank(*s1)); cimg::swap(*s0,*++s1); } - is_sth=s0>ss && *(s0-1)==']'; // Particular case s.a. '..[..][..]' ? - is_relative = *ss=='j' || *ss=='J'; - - if (!is_sth && (*ss=='I' || *ss=='J') && *ss1=='[' && - (reserved_label[(int)*ss]==~0U || - !_cimg_mp_is_vector(reserved_label[(int)*ss]))) { // Image value as a vector - if (*ss2=='#') { // Index specified - s0 = ss3; while (s0::vector((ulongT)(is_relative?mp_list_Joff:mp_list_Ioff), - pos,p1,arg1,arg2==~0U?_cimg_mp_boundary:arg2,p2).move_to(code); - } else { - need_input_copy = true; - CImg::vector((ulongT)(is_relative?mp_Joff:mp_Ioff), - pos,arg1,arg2==~0U?_cimg_mp_boundary:arg2,p2).move_to(code); - } - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!is_sth && (*ss=='i' || *ss=='j') && *ss1=='[' && - (reserved_label[(int)*ss]==~0U || - !_cimg_mp_is_vector(reserved_label[(int)*ss]))) { // Image value as a scalar - if (*ss2=='#') { // Index specified - s0 = ss3; while (s0ss && (*s0!='[' || level[s0 - expr._data]!=clevel)) --s0; - if (s0>ss) { // Vector element - arg1 = compile(ss,s0,depth1,0,block_flags); - if (_cimg_mp_is_scalar(arg1)) { - variable_name.assign(ss,(unsigned int)(s0 - ss + 1)).back() = 0; - _cimg_mp_strerr; - cimg::strellipsize(variable_name,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Array brackets used on non-vector variable '%s', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - variable_name._data,s0); - } - s1 = s0 + 1; while (s1 sub-vector extraction - p1 = _cimg_mp_size(arg1); - arg2 = compile(++s0,s1,depth1,0,block_flags); // Starting index - s0 = ++s1; while (s0::vector((ulongT)mp_vector_crop,pos,arg1,p1,arg2,arg3,arg4).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - // One argument -> vector value reference - arg2 = compile(++s0,se1,depth1,0,block_flags); - if (_cimg_mp_is_const_scalar(arg2)) { // Constant index - nb = (int)mem[arg2]; - if (nb>=0 && nb<(int)_cimg_mp_size(arg1)) _cimg_mp_return(arg1 + 1 + nb); - variable_name.assign(ss,(unsigned int)(s0 - ss)).back() = 0; - _cimg_mp_strerr; - cimg::strellipsize(variable_name,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: Out-of-bounds reference '%s[%d]' " - "(vector '%s' has dimension %u), " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function, - variable_name._data,nb, - variable_name._data,_cimg_mp_size(arg1),s0); - } - if (p_ref) { - *p_ref = 1; - p_ref[1] = arg1; - p_ref[2] = arg2; - if (_cimg_mp_is_comp(arg2)) memtype[arg2] = -1; // Prevent from being used in further optimization - } - pos = scalar3(mp_vector_off,arg1,_cimg_mp_size(arg1),arg2); - memtype[pos] = -1; // Prevent from being used in further optimization - _cimg_mp_return(pos); - } - } - - // Look for a function call, an access to image value, or a parenthesis. - if (*se1==')') { - if (*ss=='(') _cimg_mp_return(compile(ss1,se1,depth1,p_ref,block_flags)); // Simple parentheses - _cimg_mp_op("Value accessor '()'"); - is_relative = *ss=='j' || *ss=='J'; - s0 = s1 = std::strchr(ss,'('); if (s0) { do { --s1; } while (cimg::is_blank(*s1)); cimg::swap(*s0,*++s1); } - - // I/J(_#ind,_x,_y,_z,_interpolation,_boundary_conditions) - if ((*ss=='I' || *ss=='J') && *ss1=='(') { // Image value as scalar - if (*ss2=='#') { // Index specified - s0 = ss3; while (s01) { - arg2 = arg1 + 1; - if (p2>2) arg3 = arg2 + 1; - } - if (s1::vector((ulongT)(is_relative?mp_list_Jxyz:mp_list_Ixyz), - pos,p1,arg1,arg2,arg3, - arg4==~0U?_cimg_mp_interpolation:arg4, - arg5==~0U?_cimg_mp_boundary:arg5,p2).move_to(code); - else { - need_input_copy = true; - CImg::vector((ulongT)(is_relative?mp_Jxyz:mp_Ixyz), - pos,arg1,arg2,arg3, - arg4==~0U?_cimg_mp_interpolation:arg4, - arg5==~0U?_cimg_mp_boundary:arg5,p2).move_to(code); - } - return_new_comp = true; - _cimg_mp_return(pos); - } - - // i/j(_#ind,_x,_y,_z,_c,_interpolation,_boundary_conditions) - if ((*ss=='i' || *ss=='j') && *ss1=='(') { // Image value as scalar - if (*ss2=='#') { // Index specified - s0 = ss3; while (s01) { - arg2 = arg1 + 1; - if (p2>2) { - arg3 = arg2 + 1; - if (p2>3) arg4 = arg3 + 1; - } - } - if (s1::vector((ulongT)(*ss3=='0'?mp_arg0:mp_arg),0,0,p2,arg1,arg2).move_to(l_opcode); - for (s = ++s2; s::vector(arg3).move_to(l_opcode); - ++p3; - s = ns; - } - (l_opcode>'y').move_to(opcode); - opcode[2] = opcode._height; - if (_cimg_mp_is_const_scalar(arg1)) { - p3-=1; // Number of args - if (*ss3=='0') arg1 = (unsigned int)(mem[arg1]<0?mem[arg1] + p3:mem[arg1] + 1); - else arg1 = (unsigned int)(mem[arg1]<0?mem[arg1] + p3:mem[arg1]); - if (arg1::vector((ulongT)mp_break,_cimg_mp_slot_nan).move_to(code); - _cimg_mp_return_nan(); - } - } - - if (!std::strncmp(ss,"breakpoint(",11)) { // Break point (for abort test) - _cimg_mp_op("Function 'breakpoint()'"); - if (pexpr[se2 - expr._data]=='(') { // no arguments? - CImg::vector((ulongT)mp_breakpoint,_cimg_mp_slot_nan).move_to(code); - _cimg_mp_return_nan(); - } - } - - if (!std::strncmp(ss,"bool(",5)) { // Boolean cast - _cimg_mp_op("Function 'bool()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_bool,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar((bool)mem[arg1]); - _cimg_mp_scalar1(mp_bool,arg1); - } - - if (!std::strncmp(ss,"begin(",6)) { // Begin - _cimg_mp_op("Function 'begin()'"); - s1 = ss6; while (s1::vector((ulongT)mp_complex_conj,pos,arg1,0).move_to(code); - else CImg::vector((ulongT)mp_complex_conj,pos,arg1 + 1,arg1 + 2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"ceil(",5)) { // Ceil - _cimg_mp_op("Function 'ceil()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_ceil,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::ceil(mem[arg1])); - _cimg_mp_scalar1(mp_ceil,arg1); - } - - if (!std::strncmp(ss,"cexp(",5)) { // Complex exponential - _cimg_mp_op("Function 'cexp()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - _cimg_mp_check_type(arg1,0,3,2); - pos = vector(2); - if (_cimg_mp_is_scalar(arg1)) CImg::vector((ulongT)mp_complex_exp,pos,arg1,0).move_to(code); - else CImg::vector((ulongT)mp_complex_exp,pos,arg1 + 1,arg1 + 2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"clog(",5)) { // Complex logarithm - _cimg_mp_op("Function 'clog()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - _cimg_mp_check_type(arg1,0,3,2); - pos = vector(2); - if (_cimg_mp_is_scalar(arg1)) CImg::vector((ulongT)mp_complex_log,pos,arg1,0).move_to(code); - else CImg::vector((ulongT)mp_complex_log,pos,arg1 + 1,arg1 + 2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"ccos(",5)) { // Complex cosine - _cimg_mp_op("Function 'ccos()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - _cimg_mp_check_type(arg1,0,3,2); - pos = vector(2); - if (_cimg_mp_is_scalar(arg1)) CImg::vector((ulongT)mp_complex_cos,pos,arg1,0).move_to(code); - else CImg::vector((ulongT)mp_complex_cos,pos,arg1 + 1,arg1 + 2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"csin(",5)) { // Complex sine - _cimg_mp_op("Function 'csin()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - _cimg_mp_check_type(arg1,0,3,2); - pos = vector(2); - if (_cimg_mp_is_scalar(arg1)) CImg::vector((ulongT)mp_complex_sin,pos,arg1,0).move_to(code); - else CImg::vector((ulongT)mp_complex_sin,pos,arg1 + 1,arg1 + 2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"ctan(",5)) { // Complex tangent - _cimg_mp_op("Function 'ctan()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - _cimg_mp_check_type(arg1,0,3,2); - pos = vector(2); - if (_cimg_mp_is_scalar(arg1)) CImg::vector((ulongT)mp_complex_tan,pos,arg1,0).move_to(code); - else CImg::vector((ulongT)mp_complex_tan,pos,arg1 + 1,arg1 + 2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"ccosh(",6)) { // Complex hyperbolic cosine - _cimg_mp_op("Function 'ccosh()'"); - arg1 = compile(ss6,se1,depth1,0,block_flags); - _cimg_mp_check_type(arg1,0,3,2); - pos = vector(2); - if (_cimg_mp_is_scalar(arg1)) CImg::vector((ulongT)mp_complex_cosh,pos,arg1,0).move_to(code); - else CImg::vector((ulongT)mp_complex_cosh,pos,arg1 + 1,arg1 + 2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"csinh(",6)) { // Complex hyperbolic sine - _cimg_mp_op("Function 'csinh()'"); - arg1 = compile(ss6,se1,depth1,0,block_flags); - _cimg_mp_check_type(arg1,0,3,2); - pos = vector(2); - if (_cimg_mp_is_scalar(arg1)) CImg::vector((ulongT)mp_complex_sinh,pos,arg1,0).move_to(code); - else CImg::vector((ulongT)mp_complex_sinh,pos,arg1 + 1,arg1 + 2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"ctanh(",6)) { // Complex hyperbolic tangent - _cimg_mp_op("Function 'ctanh()'"); - arg1 = compile(ss6,se1,depth1,0,block_flags); - _cimg_mp_check_type(arg1,0,3,2); - pos = vector(2); - if (_cimg_mp_is_scalar(arg1)) CImg::vector((ulongT)mp_complex_tanh,pos,arg1,0).move_to(code); - else CImg::vector((ulongT)mp_complex_tanh,pos,arg1 + 1,arg1 + 2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"continue(",9)) { // Continue loop - if (pexpr[se2 - expr._data]=='(') { // no arguments? - CImg::vector((ulongT)mp_continue,_cimg_mp_slot_nan).move_to(code); - _cimg_mp_return_nan(); - } - } - - if (!std::strncmp(ss,"copy(",5)) { // Memory copy - _cimg_mp_op("Function 'copy()'"); - ref.assign(14); - s1 = ss5; while (s1=4 && arg4==~0U) arg4 = scalar1(mp_image_whd,ref[1]); - } - if (_cimg_mp_is_vector(arg2)) { - if (arg3==~0U) arg3 = const_scalar(_cimg_mp_size(arg2)); - if (!ref[7]) ++arg2; - if (ref[7]>=4 && arg5==~0U) arg5 = scalar1(mp_image_whd,ref[8]); - } - if (arg3==~0U) arg3 = 1; - if (arg4==~0U) arg4 = 1; - if (arg5==~0U) arg5 = 1; - _cimg_mp_check_type(arg3,3,1,0); - _cimg_mp_check_type(arg4,4,1,0); - _cimg_mp_check_type(arg5,5,1,0); - _cimg_mp_check_type(arg6,5,1,0); - CImg(1,22).move_to(code); - code.back().get_shared_rows(0,7).fill((ulongT)mp_memcopy,p1,arg1,arg2,arg3,arg4,arg5,arg6); - code.back().get_shared_rows(8,21).fill(ref); - _cimg_mp_return_nan(); - } - - if (!std::strncmp(ss,"cos(",4)) { // Cosine - _cimg_mp_op("Function 'cos()'"); - arg1 = compile(ss4,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cos,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::cos(mem[arg1])); - _cimg_mp_scalar1(mp_cos,arg1); - } - - if (!std::strncmp(ss,"cosh(",5)) { // Hyperbolic cosine - _cimg_mp_op("Function 'cosh()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_cosh,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::cosh(mem[arg1])); - _cimg_mp_scalar1(mp_cosh,arg1); - } - - if (!std::strncmp(ss,"cov(",4)) { // Covariance - _cimg_mp_op("Function 'cov()'"); - s1 = ss4; while (s1::vector((ulongT)mp_critical,arg1,code._width - p1).move_to(code,p1); - _cimg_mp_return(arg1); - } - - if (!std::strncmp(ss,"crop(",5)) { // Image crop - _cimg_mp_op("Function 'crop()'"); - if (*ss5=='#') { // Index specified - s0 = ss6; while (s0::sequence(_cimg_mp_size(arg1),arg1 + 1, - arg1 + (ulongT)_cimg_mp_size(arg1)); - opcode.resize(1,std::min(opcode._height,4U),1,1,0).move_to(l_opcode); - is_sth = true; - } else { - _cimg_mp_check_type(arg1,pos + 1,1,0); - CImg::vector(arg1).move_to(l_opcode); - } - s = ns; - } - (l_opcode>'y').move_to(opcode); - - arg1 = 0; arg2 = (p1!=~0U); - switch (opcode._height) { - case 0 : case 1 : - CImg::vector(0,0,0,0,~0U,~0U,~0U,~0U,0).move_to(opcode); - break; - case 2 : - CImg::vector(*opcode,0,0,0,opcode[1],~0U,~0U,~0U,_cimg_mp_boundary).move_to(opcode); - arg1 = arg2 + 2; - break; - case 3 : - CImg::vector(*opcode,0,0,0,opcode[1],~0U,~0U,~0U,opcode[2]).move_to(opcode); - arg1 = arg2 + 2; - break; - case 4 : - CImg::vector(*opcode,opcode[1],0,0,opcode[2],opcode[3],~0U,~0U,_cimg_mp_boundary). - move_to(opcode); - arg1 = arg2 + (is_sth?2:3); - break; - case 5 : - CImg::vector(*opcode,opcode[1],0,0,opcode[2],opcode[3],~0U,~0U,opcode[4]). - move_to(opcode); - arg1 = arg2 + (is_sth?2:3); - break; - case 6 : - CImg::vector(*opcode,opcode[1],opcode[2],0,opcode[3],opcode[4],opcode[5],~0U, - _cimg_mp_boundary).move_to(opcode); - arg1 = arg2 + (is_sth?2:4); - break; - case 7 : - CImg::vector(*opcode,opcode[1],opcode[2],0,opcode[3],opcode[4],opcode[5],~0U, - opcode[6]).move_to(opcode); - arg1 = arg2 + (is_sth?2:4); - break; - case 8 : - CImg::vector(*opcode,opcode[1],opcode[2],opcode[3],opcode[4],opcode[5],opcode[6], - opcode[7],_cimg_mp_boundary).move_to(opcode); - arg1 = arg2 + (is_sth?2:5); - break; - case 9 : - arg1 = arg2 + (is_sth?2:5); - break; - default : // Error -> too much arguments - _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Too much arguments specified, " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op,s0); - } - - _cimg_mp_check_type((unsigned int)*opcode,arg2 + 1,1,0); - _cimg_mp_check_type((unsigned int)opcode[1],arg2 + 1 + (is_sth?0:1),1,0); - _cimg_mp_check_type((unsigned int)opcode[2],arg2 + 1 + (is_sth?0:2),1,0); - _cimg_mp_check_type((unsigned int)opcode[3],arg2 + 1 + (is_sth?0:3),1,0); - if (opcode[4]!=(ulongT)~0U) { - _cimg_mp_check_const_scalar((unsigned int)opcode[4],arg1,3); - opcode[4] = (ulongT)mem[opcode[4]]; - } - if (opcode[5]!=(ulongT)~0U) { - _cimg_mp_check_const_scalar((unsigned int)opcode[5],arg1 + 1,3); - opcode[5] = (ulongT)mem[opcode[5]]; - } - if (opcode[6]!=(ulongT)~0U) { - _cimg_mp_check_const_scalar((unsigned int)opcode[6],arg1 + 2,3); - opcode[6] = (ulongT)mem[opcode[6]]; - } - if (opcode[7]!=(ulongT)~0U) { - _cimg_mp_check_const_scalar((unsigned int)opcode[7],arg1 + 3,3); - opcode[7] = (ulongT)mem[opcode[7]]; - } - _cimg_mp_check_type((unsigned int)opcode[8],arg1 + 4,1,0); - - if (opcode[4]==(ulongT)~0U || opcode[5]==(ulongT)~0U || - opcode[6]==(ulongT)~0U || opcode[7]==(ulongT)~0U) { - p2 = 0; - if (p1!=~0U) { - _cimg_mp_check_const_scalar(p1,1,1); - p2 = (unsigned int)cimg::mod((int)mem[p1],imglist.width()); - } - const CImg &img = p1!=~0U?imglist[p2]:imgin; - if (!img) { - _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Cannot crop empty image when " - "some xyzc-coordinates are unspecified, in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op,s0); - } - if (opcode[4]==(ulongT)~0U) opcode[4] = (ulongT)img._width; - if (opcode[5]==(ulongT)~0U) opcode[5] = (ulongT)img._height; - if (opcode[6]==(ulongT)~0U) opcode[6] = (ulongT)img._depth; - if (opcode[7]==(ulongT)~0U) opcode[7] = (ulongT)img._spectrum; - } - - pos = vector((unsigned int)(opcode[4]*opcode[5]*opcode[6]*opcode[7])); - CImg::vector((ulongT)mp_crop, - pos,p1, - *opcode,opcode[1],opcode[2],opcode[3], - opcode[4],opcode[5],opcode[6],opcode[7], - opcode[8]).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"cross(",6)) { // Cross product - _cimg_mp_op("Function 'cross()'"); - s1 = ss6; while (s1::vector((ulongT)mp_cross,pos,arg1,arg2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"cut(",4)) { // Cut - _cimg_mp_op("Function 'cut()'"); - s1 = ss4; while (s1val2?val2:val); - } - _cimg_mp_scalar3(mp_cut,arg1,arg2,arg3); - } - - if (!std::strncmp(ss,"convolve(",9) || !std::strncmp(ss,"correlate(",10)) { // Convolve & Correlate - is_sth = *ss2=='n'; // is_convolve? - _cimg_mp_op(is_sth?"Function 'convolve()'":"Function 'correlate()'"); - op = is_sth?mp_convolve:mp_correlate; - const ulongT default_params[] = { (ulongT)op,0, // [0]=function, [1]=result vector - 0,0,0,0,0, // [2]=A, [3]=wA, [4]=hA, [5]=dA, [6]=sA - 0,0,0,0,0, // [7]=M, [8]=wM, [9]=hM, [10]=dM, [11]=sM - 1,0,1, // [12]=boundary_conditions, [13]=is_normalized, [14]=chan._mode - ~0U,~0U,~0U, // [15]=xcenter, [16]=ycenter, [17]=zcenter - 0,0,0, // [18]=xstart, [19]=ystart, [20]=zstart - ~0U,~0U,~0U, // [21]=xend, [22]=yend, [23]=zend - 1,1,1, // [24]=xstride, [25]=ystride, [26]=zstride - 1,1,1, // [27]=xdilation, [28]=ydilation, [29]=zdilation, - 0 }; // [30]=interpolation_type - - l_opcode.assign(); // Don't use 'opcode': it could be modified by further calls to 'compile()'! - CImg(default_params,1,sizeof(default_params)/sizeof(ulongT)).move_to(l_opcode); - - arg1 = 2; - for (s = std::strchr(ss,'(') + 1; sopcode._height) { - _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: %s arguments provided, in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - arg1<12?"Not enough":"Too much",s0); - } - _cimg_mp_check_type(opcode[2],1,2,0); // A - _cimg_mp_check_const_scalar(opcode[3],2,3); // wA - _cimg_mp_check_const_scalar(opcode[4],3,3); // hA - _cimg_mp_check_const_scalar(opcode[5],4,3); // dA - _cimg_mp_check_const_scalar(opcode[6],5,3); // sA - _cimg_mp_check_type(opcode[7],6,2,0); // M - _cimg_mp_check_const_scalar(opcode[8],7,3); // wM - _cimg_mp_check_const_scalar(opcode[9],8,3); // hM - _cimg_mp_check_const_scalar(opcode[10],9,3); // dM - _cimg_mp_check_const_scalar(opcode[11],10,3); // sM - _cimg_mp_check_type(opcode[12],11,1,0); // boundary_conditions - _cimg_mp_check_type(opcode[13],12,1,0); // is_normalized - _cimg_mp_check_const_scalar(opcode[14],13,1); // channel_mode - if (opcode[15]!=~0U) _cimg_mp_check_type(opcode[15],14,1,0); // xcenter - if (opcode[16]!=~0U) _cimg_mp_check_type(opcode[16],15,1,0); // ycenter - if (opcode[17]!=~0U) _cimg_mp_check_type(opcode[17],16,1,0); // zcenter - _cimg_mp_check_const_scalar(opcode[18],17,1); // xstart - _cimg_mp_check_const_scalar(opcode[19],18,1); // ystart - _cimg_mp_check_const_scalar(opcode[20],19,1); // zstart - if (opcode[21]!=~0U) _cimg_mp_check_const_scalar(opcode[21],20,1); // xend - if (opcode[22]!=~0U) _cimg_mp_check_const_scalar(opcode[22],21,1); // yend - if (opcode[23]!=~0U) _cimg_mp_check_const_scalar(opcode[23],22,1); // zend - _cimg_mp_check_const_scalar(opcode[24],23,0); // xstride - _cimg_mp_check_const_scalar(opcode[25],24,0); // ystride - _cimg_mp_check_const_scalar(opcode[26],25,0); // zstride - _cimg_mp_check_type(opcode[27],26,1,0); // xdilation - _cimg_mp_check_type(opcode[28],27,1,0); // ydilation - _cimg_mp_check_type(opcode[29],28,1,0); // zdilation - _cimg_mp_check_type(opcode[30],29,1,0); // interpolation_type - - const unsigned int - wA = (unsigned int)mem[opcode[3]], - hA = (unsigned int)mem[opcode[4]], - dA = (unsigned int)mem[opcode[5]], - sA = (unsigned int)mem[opcode[6]], - wM = (unsigned int)mem[opcode[8]], - hM = (unsigned int)mem[opcode[9]], - dM = (unsigned int)mem[opcode[10]], - sM = (unsigned int)mem[opcode[11]], - channel_mode = (unsigned int)mem[opcode[14]]; - const int - xstart = (int)mem[opcode[18]], - ystart = (int)mem[opcode[19]], - zstart = (int)mem[opcode[20]], - xend = opcode[21]!=~0U?(int)mem[opcode[21]]:wA - 1, - yend = opcode[22]!=~0U?(int)mem[opcode[22]]:hA - 1, - zend = opcode[23]!=~0U?(int)mem[opcode[23]]:dA - 1; - - if (xstart>xend || ystart>yend || zstart>zend) { - _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Invalid xyz-start/end arguments " - "(start = (%d,%d,%d), end = (%d,%d,%d)), in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - xstart,ystart,zstart,xend,yend,zend,s0); - } - - const float - xstride = (float)mem[opcode[24]], - ystride = (float)mem[opcode[25]], - zstride = (float)mem[opcode[26]]; - - if (xstride<=0 || ystride<=0 || zstride<=0) { - _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Invalid stride arguments (%g,%g,%g), " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - xstride,ystride,zstride,s0); - } - - arg2 = xend - xstart + 1; - arg3 = yend - ystart + 1; - arg4 = zend + zstart + 1; - arg5 = !channel_mode?sA*sM:channel_mode==1?std::max(sA,sM): - channel_mode==2?std::max(sA,sM)/std::min(sA,sM):1U; - - opcode[1] = pos = vector(arg2*arg3*arg4*arg5); - opcode[3] = (ulongT)wA; - opcode[4] = (ulongT)hA; - opcode[5] = (ulongT)dA; - opcode[6] = (ulongT)sA; - opcode[8] = (ulongT)wM; - opcode[9] = (ulongT)hM; - opcode[10] = (ulongT)dM; - opcode[11] = (ulongT)sM; - opcode[14] = (ulongT)channel_mode; - opcode[18] = (ulongT)xstart; - opcode[19] = (ulongT)ystart; - opcode[20] = (ulongT)zstart; - opcode[21] = (ulongT)xend; - opcode[22] = (ulongT)yend; - opcode[23] = (ulongT)zend; - opcode.move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - break; - - case 'd' : - if (*ss1=='(') { // Image depth - _cimg_mp_op("Function 'd()'"); - if (*ss2=='#') { // Index specified - p1 = compile(ss3,se1,depth1,0,block_flags); - _cimg_mp_check_list(); - } else { if (ss2!=se1) break; p1 = ~0U; } - _cimg_mp_scalar1(mp_image_d,p1); - } - - if (!std::strncmp(ss,"da_back(",8) || - !std::strncmp(ss,"da_pop(",7)) { // Get latest element in a dynamic array - if (!is_inside_critical) is_parallelizable = false; - const bool is_pop = *ss3=='p'; - _cimg_mp_op(is_pop?"Function 'da_pop()'":"Function 'da_back()'"); - s0 = ss + (is_pop?7:8); - if (*s0=='#') { // Index specified - s1 = ++s0; while (s11) pos = vector(p2); else pos = scalar(); // Return vector or scalar result - CImg::vector((ulongT)mp_da_back_or_pop,pos,p2,p1,is_pop).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"da_insert(",10) || - !std::strncmp(ss,"da_push(",8)) { // Insert element(s) in a dynamic array - if (!is_inside_critical) is_parallelizable = false; - const bool is_push = *ss3=='p'; - _cimg_mp_op(is_push?"Function 'da_push()'":"Function 'da_insert()'"); - s0 = ss + (is_push?8:10); - if (*s0=='#') { // Index specified - s1 = ++s0; while (s1::vector((ulongT)mp_da_insert_or_push,_cimg_mp_slot_nan,p1,arg1,0,0).move_to(l_opcode); - p3 = p1==~0U?2:3; - p1 = ~0U; - for (s = s1; s::vector(arg2).move_to(l_opcode); - s = ns; - ++p3; - } - if (p1==~0U) compile(++s1,se1,depth1,0,block_flags); // Missing element -> error - (l_opcode>'y').move_to(opcode); - opcode[4] = p1; - opcode[5] = opcode._height; - opcode.move_to(code); - _cimg_mp_return_nan(); - } - - if (!std::strncmp(ss,"da_freeze(",10)) { // Freeze dynamic array - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_op("Function 'da_freeze()'"); - s0 = ss + 10; - if (*s0=='#') { // Index specified - s1 = ++s0; while (s1::vector((ulongT)mp_da_freeze,_cimg_mp_slot_nan,p1).move_to(code); - _cimg_mp_return_nan(); - } - - if (!std::strncmp(ss,"da_remove(",10)) { // Remove element(s) in a dynamic array - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_op("Function 'da_remove()'"); - if (ss[10]=='#') { // Index specified - s0 = ss + 11; while (s0::vector((ulongT)mp_da_remove,_cimg_mp_slot_nan,p1,arg1,arg2).move_to(code); - _cimg_mp_return_nan(); - } - - if (!std::strncmp(ss,"da_size(",8)) { // Size of a dynamic array - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_op("Function 'da_size()'"); - if (ss[8]=='#') { // Index specified - s0 = ss + 9; while (s0::vector((ulongT)mp_date,pos,_cimg_mp_size(pos), - arg1,arg1==~0U?~0U:_cimg_mp_size(arg1), - arg2,arg2==~0U?~0U:_cimg_mp_size(arg2)).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"debug(",6)) { // Print debug info - _cimg_mp_op("Function 'debug()'"); - p1 = code._width; - arg1 = compile(ss6,se1,depth1,p_ref,block_flags); - *se1 = 0; - variable_name.assign(CImg::string(ss6,true,true).unroll('y'),true); - cimg::strpare(variable_name,false,true); - ((CImg::vector((ulongT)mp_debug,arg1,0,code._width - p1), - variable_name)>'y').move_to(opcode); - opcode[2] = opcode._height; - opcode.move_to(code,p1); - *se1 = ')'; - _cimg_mp_return(arg1); - } - - if (!std::strncmp(ss,"deg2rad(",8)) { // Degrees to radians - _cimg_mp_op("Function 'deg2rad()'"); - arg1 = compile(ss8,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_deg2rad,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(mem[arg1]*cimg::PI/180); - _cimg_mp_scalar1(mp_deg2rad,arg1); - } - - if (!std::strncmp(ss,"display(",8)) { // Display memory, vector or image - _cimg_mp_op("Function 'display()'"); - if (pexpr[se2 - expr._data]=='(') { // no arguments? - CImg::vector((ulongT)mp_display_memory,_cimg_mp_slot_nan).move_to(code); - _cimg_mp_return_nan(); - } - if (*ss8!='#') { // Vector - s1 = ss8; while (s1::string(ss8,true,true).unroll('y'),true); - cimg::strpare(variable_name,false,true); - if (_cimg_mp_is_vector(arg1)) - ((CImg::vector((ulongT)mp_vector_print,arg1,0,(ulongT)_cimg_mp_size(arg1),0), - variable_name)>'y').move_to(opcode); - else - ((CImg::vector((ulongT)mp_print,arg1,0,0), - variable_name)>'y').move_to(opcode); - opcode[2] = opcode._height; - opcode.move_to(code); - - ((CImg::vector((ulongT)mp_display,arg1,0,(ulongT)_cimg_mp_size(arg1), - arg2,arg3,arg4,arg5), - variable_name)>'y').move_to(opcode); - opcode[2] = opcode._height; - opcode.move_to(code); - *s1 = c1; - _cimg_mp_return(arg1); - - } else { // Image - p1 = compile(ss8 + 1,se1,depth1,0,block_flags); - _cimg_mp_check_list(); - CImg::vector((ulongT)mp_image_display,_cimg_mp_slot_nan,p1).move_to(code); - _cimg_mp_return_nan(); - } - } - - if (!std::strncmp(ss,"det(",4)) { // Matrix determinant - _cimg_mp_op("Function 'det()'"); - arg1 = compile(ss4,se1,depth1,0,block_flags); - _cimg_mp_check_matrix_square(arg1,1); - p1 = (unsigned int)cimg::round(std::sqrt((float)_cimg_mp_size(arg1))); - _cimg_mp_scalar2(mp_det,arg1,p1); - } - - if (!std::strncmp(ss,"diag(",5)) { // Diagonal matrix - _cimg_mp_op("Function 'diag()'"); - CImg::vector((ulongT)mp_diag,0,0).move_to(l_opcode); - for (s = ss5; s::sequence(_cimg_mp_size(arg2),arg2 + 1, - arg2 + (ulongT)_cimg_mp_size(arg2)). - move_to(l_opcode); - else CImg::vector(arg2).move_to(l_opcode); - s = ns; - } - (l_opcode>'y').move_to(opcode); - arg1 = opcode._height - 3; - pos = vector(arg1*arg1); - opcode[1] = pos; - opcode[2] = opcode._height; - opcode.move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"dot(",4)) { // Dot product - _cimg_mp_op("Function 'dot()'"); - s1 = ss4; while (s1::vector((ulongT)mp_do,p1,p2,arg2 - arg1,code._width - arg2,_cimg_mp_size(p1), - p1>=arg6 && !_cimg_mp_is_const_scalar(p1), - p2>=arg6 && !_cimg_mp_is_const_scalar(p2)).move_to(code,arg1); - _cimg_mp_return(p1); - } - - if (!std::strncmp(ss,"draw(",5)) { // Draw image - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_op("Function 'draw()'"); - if (*ss5=='#') { // Index specified - s0 = ss6; while (s01) { - arg3 = arg2 + 1; - if (p2>2) { - arg4 = arg3 + 1; - if (p2>3) arg5 = arg4 + 1; - } - } - ++s0; - is_sth = true; - } else { - if (s0::vector((ulongT)mp_draw,arg1,(ulongT)_cimg_mp_size(arg1),p1,arg2,arg3,arg4,arg5, - 0,0,0,0,1,(ulongT)~0U,0,1).move_to(l_opcode); - - arg2 = arg3 = arg4 = arg5 = ~0U; - p2 = p1!=~0U?0:1; - if (s0::vector((ulongT)mp_echo,_cimg_mp_slot_nan,0).move_to(l_opcode); - for (s = ss5; s::vector(arg1,_cimg_mp_size(arg1)).move_to(l_opcode); - s = ns; - } - (l_opcode>'y').move_to(opcode); - opcode[2] = opcode._height; - opcode.move_to(code); - _cimg_mp_return_nan(); - } - - if (!std::strncmp(ss,"eig(",4)) { // Matrix eigenvalues/eigenvector - _cimg_mp_op("Function 'eig()'"); - arg1 = compile(ss4,se1,depth1,0,block_flags); - _cimg_mp_check_matrix_square(arg1,1); - p1 = (unsigned int)cimg::round(std::sqrt((float)_cimg_mp_size(arg1))); - pos = vector((p1 + 1)*p1); - CImg::vector((ulongT)mp_matrix_eig,pos,arg1,p1).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"ellipse(",8)) { // Ellipse/circle drawing - if (!is_inside_critical) is_parallelizable = false; - _cimg_mp_op("Function 'ellipse()'"); - if (*ss8=='#') { // Index specified - s0 = ss + 9; while (s0::vector((ulongT)mp_ellipse,_cimg_mp_slot_nan,0,p1).move_to(l_opcode); - for (s = s0; s::sequence(_cimg_mp_size(arg2),arg2 + 1, - arg2 + (ulongT)_cimg_mp_size(arg2)). - move_to(l_opcode); - else CImg::vector(arg2).move_to(l_opcode); - s = ns; - } - (l_opcode>'y').move_to(opcode); - opcode[2] = opcode._height; - opcode.move_to(code); - _cimg_mp_return_nan(); - } - - if (!std::strncmp(ss,"erf(",4)) { // Error function - _cimg_mp_op("Function 'erf()'"); - arg1 = compile(ss4,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_erf,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::erf(mem[arg1])); - _cimg_mp_scalar1(mp_erf,arg1); - } - - if (!std::strncmp(ss,"erfinv(",7)) { // Inverse of error function - _cimg_mp_op("Function 'erfinv()'"); - arg1 = compile(ss7,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_erfinv,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(cimg::erfinv(mem[arg1])); - _cimg_mp_scalar1(mp_erfinv,arg1); - } - - if (!std::strncmp(ss,"exp(",4)) { // Exponential - _cimg_mp_op("Function 'exp()'"); - arg1 = compile(ss4,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_exp,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::exp(mem[arg1])); - _cimg_mp_scalar1(mp_exp,arg1); - } - - if (!std::strncmp(ss,"expr(",5)) { // Vector from expression - _cimg_mp_op("Function 'expr()'"); - s1 = ss5; while (s1::vector((ulongT)mp_expr,pos,arg1,p1,arg2,arg3,arg4,arg5).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"eye(",4)) { // Identity matrix - _cimg_mp_op("Function 'eye()'"); - arg1 = compile(ss4,se1,depth1,0,block_flags); - _cimg_mp_check_const_scalar(arg1,1,3); - p1 = (unsigned int)mem[arg1]; - pos = vector(p1*p1); - CImg::vector((ulongT)mp_eye,pos,p1).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"end(",4)) { // End - _cimg_mp_op("Function 'end()'"); - s1 = ss4; while (s1uint conversion - _cimg_mp_op("Function 'f2ui()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_f2ui,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar((double)cimg::float2uint((float)mem[arg1])); - _cimg_mp_scalar1(mp_f2ui,arg1); - } - - if (!std::strncmp(ss,"fact(",5)) { // Factorial - _cimg_mp_op("Function 'fact()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_factorial,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(cimg::factorial((int)mem[arg1])); - _cimg_mp_scalar1(mp_factorial,arg1); - } - - if (!std::strncmp(ss,"fibo(",5)) { // Fibonacci - _cimg_mp_op("Function 'fibo()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_fibonacci,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(cimg::fibonacci((int)mem[arg1])); - _cimg_mp_scalar1(mp_fibonacci,arg1); - } - - if (!std::strncmp(ss,"fill(",5)) { // Fill - _cimg_mp_op("Function 'fill()'"); - s0 = ss5; while (s0::%s: %s: Target scalar is constant, " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op,ss); - s1 = ++s0; while (s1::%s: %s: Invalid loop variable name '%s', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - variable_name._data,s0); - } - get_variable_pos(variable_name,arg2,arg3); - arg2 = arg3!=~0U?reserved_label[arg3]:arg2!=~0U?variable_pos[arg2]:~0U; // Variable slot - if (arg2!=~0U && (!_cimg_mp_is_scalar(arg2) || - _cimg_mp_is_const_scalar(arg2))) { // Variable is not a vector or is a constant->error - cimg::strellipsize(variable_name,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Invalid type '%s' for variable '%s' " - "(expected 'scalar'), in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - s_type(arg2)._data,variable_name._data,s0); - } else if (arg2==~0U) { // Variable does not exist -> create it - arg2 = scalar(); - if (arg3!=~0U) reserved_label[arg3] = arg2; - else { - if (variable_def._width>=variable_pos._width) variable_pos.resize(-200,1,1,1,0); - variable_pos[variable_def._width] = arg2; - variable_name.move_to(variable_def); - } - memtype[arg2] = -1; - } - arg3 = compile(++s1,se1,depth1,0,block_flags); - _cimg_mp_check_type(arg3,3,1,0); - } else { // Version with 2 arguments - arg2 = ~0U; - arg3 = compile(s0,se1,depth1,0,block_flags); - } - // arg2 = variable slot, arg3 = fill expression. - _cimg_mp_check_type(arg3,3,1,0); - CImg::vector((ulongT)mp_fill,arg1,_cimg_mp_size(arg1),arg2,arg3,code._width - p1). - move_to(code,p1); - _cimg_mp_return_nan(); - } - - if (!std::strncmp(ss,"find(",5)) { // Find - _cimg_mp_op("Function 'find()'"); - - // First argument: data to look at. - s0 = ss5; while (s01) - _cimg_mp_scalar5(mp_list_find_seq,p1,arg2,_cimg_mp_size(arg2),arg3,arg4); - _cimg_mp_scalar4(mp_list_find,p1,arg2 + (_cimg_mp_size(arg2)?1:0),arg3,arg4); - } - if (_cimg_mp_size(arg2)>1) - _cimg_mp_scalar6(mp_find_seq,arg1,_cimg_mp_size(arg1),arg2,_cimg_mp_size(arg2),arg3,arg4); - _cimg_mp_scalar5(mp_find,arg1,_cimg_mp_size(arg1),arg2 + (_cimg_mp_size(arg2)?1:0),arg3,arg4); - } - - if (*ss1=='o' && *ss2=='r' && *ss3=='(') { // For loop - _cimg_mp_op("Function 'for()'"); - s1 = ss4; while (s1::vector((ulongT)mp_for,p3,(ulongT)_cimg_mp_size(p3),p2,arg2 - arg1,arg3 - arg2, - arg4 - arg3,code._width - arg4, - p3>=arg6 && !_cimg_mp_is_const_scalar(p3), - p2>=arg6 && !_cimg_mp_is_const_scalar(p2)).move_to(code,arg1); - _cimg_mp_return(p3); - } - - if (!std::strncmp(ss,"floor(",6)) { // Floor - _cimg_mp_op("Function 'floor()'"); - arg1 = compile(ss6,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_floor,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::floor(mem[arg1])); - _cimg_mp_scalar1(mp_floor,arg1); - } - - if (!std::strncmp(ss,"fsize(",6)) { // File size - _cimg_mp_op("Function 'fsize()'"); - arg1 = compile(ss6,se1,depth1,0,block_flags); - _cimg_mp_check_type(arg1,1,2,0); - pos = scalar(); - CImg::vector((ulongT)mp_fsize,pos,arg1,(ulongT)_cimg_mp_size(arg1)).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - break; - - case 'g' : - if (!std::strncmp(ss,"gauss(",6)) { // Gaussian function - _cimg_mp_op("Function 'gauss()'"); - s1 = ss6; while (s1::max(); - if (mem[arg2]>=siz_max) { - _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Specified variable size %g is larger than %d.", - pixel_type(),_cimg_mp_calling_function,s_op, - mem[arg2],siz_max); - } - arg2 = (unsigned int)mem[arg2]; - if (arg2) pos = vector(arg2); else pos = scalar(); - CImg::vector((ulongT)mp_get,pos,arg1,p1,arg2,arg3).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } -#endif - break; - - case 'h' : - if (*ss1=='(') { // Image height - _cimg_mp_op("Function 'h()'"); - if (*ss2=='#') { // Index specified - p1 = compile(ss3,se1,depth1,0,block_flags); - _cimg_mp_check_list(); - } else { if (ss2!=se1) break; p1 = ~0U; } - _cimg_mp_scalar1(mp_image_h,p1); - } - break; - - case 'i' : - if (*ss1=='c' && *ss2=='(') { // Image median - _cimg_mp_op("Function 'ic()'"); - if (*ss3=='#') { // Index specified - p1 = compile(ss4,se1,depth1,0,block_flags); - _cimg_mp_check_list(); - } else { if (ss3!=se1) break; p1 = ~0U; } - pos = scalar(); - CImg::vector((ulongT)mp_image_median,pos,p1).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (*ss1=='n' && *ss2=='(') { // Image norm - _cimg_mp_op("Function 'in()'"); - if (*ss3=='#') { // Index specified - p1 = compile(ss4,se1,depth1,0,block_flags); - _cimg_mp_check_list(); - } else { if (ss3!=se1) break; p1 = ~0U; } - pos = scalar(); - CImg::vector((ulongT)mp_image_norm,pos,p1).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (*ss1=='f' && *ss2=='(') { // If..then[..else.] - _cimg_mp_op("Function 'if()'"); - s1 = ss3; while (s1::vector((ulongT)mp_if,pos,arg1,arg2,arg3, - p3 - p2,code._width - p3,arg4).move_to(code,p2); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"inrange(",8)) { // Check value range - _cimg_mp_op("Function 'inrange()'"); - s1 = ss8; while (s1=val1) - is_sth = (mem[arg4]?(val>=val1):(val>val1)) && (mem[arg5]?(val<=val2):(val=val2):(val>val2)) && (mem[arg4]?(val<=val1):(val::vector((ulongT)mp_inrange,pos,arg6,arg1,p1,arg2,p2,arg3,p3,arg4,arg5).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"int(",4)) { // Integer cast - _cimg_mp_op("Function 'int()'"); - arg1 = compile(ss4,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_int,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar((longT)mem[arg1]); - _cimg_mp_scalar1(mp_int,arg1); - } - - if (!std::strncmp(ss,"invert(",7)) { // Matrix/scalar inverse (or pseudoinverse) - _cimg_mp_op("Function 'invert()'"); - s1 = ss7; while (s1::%s: %s: Type of first argument ('%s') " - "does not match with second argument 'nb_colsA=%u', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - s_type(arg1)._data,p2,s0); - } - } - pos = vector(p1); - CImg::vector((ulongT)mp_matrix_invert,pos,arg1,p2,p3,arg3,arg4).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(1/mem[arg1]); - _cimg_mp_scalar2(mp_div,1,arg1); - } - - if (*ss1=='s') { // Family of 'is_?()' functions - - if (!std::strncmp(ss,"isbool(",7)) { // Is boolean? - _cimg_mp_op("Function 'isbool()'"); - if (ss7==se1) _cimg_mp_return(0); - try { arg1 = compile(ss7,se1,depth1,0,block_flags); } - catch(CImgException&) { _cimg_mp_return(0); } - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isbool,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_return(mem[arg1]==0. || mem[arg1]==1.); - _cimg_mp_scalar1(mp_isbool,arg1); - } - - if (!std::strncmp(ss,"isdir(",6)) { // Is directory? - _cimg_mp_op("Function 'isdir()'"); - arg1 = compile(ss6,se1,depth1,0,block_flags); - pos = scalar(); - CImg::vector((ulongT)mp_isdir,pos,arg1,(ulongT)_cimg_mp_size(arg1)).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"isfile(",7)) { // Is file? - _cimg_mp_op("Function 'isfile()'"); - arg1 = compile(ss7,se1,depth1,0,block_flags); - pos = scalar(); - CImg::vector((ulongT)mp_isfile,pos,arg1,(ulongT)_cimg_mp_size(arg1)).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"isin(",5)) { // Is in sequence/vector? - if (ss5>=se1) _cimg_mp_return(0); - _cimg_mp_op("Function 'isin()'"); - pos = scalar(); - CImg::vector((ulongT)mp_isin,pos,0).move_to(l_opcode); - for (s = ss5; s::vector(arg1,_cimg_mp_size(arg1)).move_to(l_opcode); - s = ns; - } - (l_opcode>'y').move_to(opcode); - opcode[2] = opcode._height; - opcode.move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"isinf(",6)) { // Is infinite? - _cimg_mp_op("Function 'isinf()'"); - if (ss6==se1) _cimg_mp_return(0); - arg1 = compile(ss6,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isinf,arg1); - if (_cimg_mp_is_const_scalar(arg1)) - _cimg_mp_return((unsigned int)cimg::type::is_inf(mem[arg1])); - _cimg_mp_scalar1(mp_isinf,arg1); - } - - if (!std::strncmp(ss,"isint(",6)) { // Is integer? - _cimg_mp_op("Function 'isint()'"); - if (ss6==se1) _cimg_mp_return(0); - try { arg1 = compile(ss6,se1,depth1,0,block_flags); } - catch(CImgException&) { _cimg_mp_return(0); } - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isint,arg1); - if (_cimg_mp_is_const_scalar(arg1)) - _cimg_mp_return((unsigned int)((double)(longT)mem[arg1]==mem[arg1])); - _cimg_mp_scalar1(mp_isint,arg1); - } - - if (!std::strncmp(ss,"isnan(",6)) { // Is NaN? - _cimg_mp_op("Function 'isnan()'"); - if (ss6==se1) _cimg_mp_return(0); - arg1 = compile(ss6,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_isnan,arg1); - if (_cimg_mp_is_const_scalar(arg1)) - _cimg_mp_return((unsigned int)cimg::type::is_nan(mem[arg1])); - _cimg_mp_scalar1(mp_isnan,arg1); - } - - if (!std::strncmp(ss,"isnum(",6)) { // Is number? - _cimg_mp_op("Function 'isnum()'"); - val = 0; - if (cimg_sscanf(ss6,"%lf%c%c",&val,&sep,&end)==2 && sep==')') _cimg_mp_return(1); - _cimg_mp_return(0); - } - - if (!std::strncmp(ss,"isexpr(",7)) { // Is valid expression? - _cimg_mp_op("Function 'isexpr()'"); - if (ss7==se1) _cimg_mp_return(0); - try { arg1 = compile(ss7,se1,depth1,0,block_flags); } - catch (CImgException&) { _cimg_mp_return(0); } - _cimg_mp_return(1); - } - - if (!std::strncmp(ss,"isvarname(",10)) { // Is variable name? - _cimg_mp_op("Function 'isvarname()'"); - arg1 = compile(ss + 10,se1,depth1,0,block_flags); - pos = scalar(); - CImg::vector((ulongT)mp_isvarname,pos,arg1,(ulongT)_cimg_mp_size(arg1)).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - } - break; - - case 'l' : - if (*ss1=='(') { // Size of image list - _cimg_mp_op("Function 'l()'"); - if (ss2!=se1) break; - _cimg_mp_scalar0(mp_list_l); - } - - if (!std::strncmp(ss,"lerp(",5)) { // Linear interpolation - _cimg_mp_op("Function 'lerp()'"); - s1 = ss5; while (s1::vector((ulongT)mp_vector_lerp,pos,p1,arg1,arg2,arg3).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"log(",4)) { // Natural logarithm - _cimg_mp_op("Function 'log()'"); - arg1 = compile(ss4,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::log(mem[arg1])); - _cimg_mp_scalar1(mp_log,arg1); - } - - if (!std::strncmp(ss,"log2(",5)) { // Base-2 logarithm - _cimg_mp_op("Function 'log2()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log2,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(cimg::log2(mem[arg1])); - _cimg_mp_scalar1(mp_log2,arg1); - } - - if (!std::strncmp(ss,"log10(",6)) { // Base-10 logarithm - _cimg_mp_op("Function 'log10()'"); - arg1 = compile(ss6,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_log10,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::log10(mem[arg1])); - _cimg_mp_scalar1(mp_log10,arg1); - } - - if (!std::strncmp(ss,"lowercase(",10)) { // Lower case - _cimg_mp_op("Function 'lowercase()'"); - arg1 = compile(ss + 10,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_lowercase,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(cimg::lowercase(mem[arg1])); - _cimg_mp_scalar1(mp_lowercase,arg1); - } - break; - - case 'm' : - if (!std::strncmp(ss,"mul(",4)) { // Matrix multiplication - _cimg_mp_op("Function 'mul()'"); - s1 = ss4; while (s1::%s: %s: Types of first and second arguments ('%s' and '%s') " - "do not match with third argument 'nb_colsB=%u', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - s_type(arg1)._data,s_type(arg2)._data,p3,s0); - } - pos = vector(arg4*p3); - CImg::vector((ulongT)mp_matrix_mul,pos,arg1,arg2,arg4,arg5,p3).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"mproj(",6)) { // Project matrix onto dictionary - _cimg_mp_op("Function 'mproj()'"); - s1 = ss6; while (s1::%s: %s: Type of first argument ('%s') " - "do not match with second argument 'nb_colsS=%u', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - s_type(arg1)._data,wS,s0); - } - if (wD*hD!=p2) { - _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Type of third argument ('%s') " - "do not match with fourth argument 'nb_colsD=%u', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - s_type(arg3)._data,wD,s0); - } - if (hS!=hD) { - _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Type of first argument ('%s') " - "do not match with third argument ('%s'), " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - s_type(arg1)._data,s_type(arg3)._data,s0); - } - pos = vector(wS*wD); - CImg::vector((ulongT)mp_mproj,pos,arg1,wS,hS,arg3,wD,arg5,arg6,p3).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"mse(",4)) { // Mean-squared error - _cimg_mp_op("Function 'mse()'"); - s1 = ss4; while (s1::%s: %s: First argument cannot be a linked reference, " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - s0); - } - - arg1 = ~0U; // Merge operator - // (0='=',1='+',2='-',3='*',4='/',5='&',6='|',7='xor',8='&&',9=='||',10='min',11='max') - if (s1::%s: %s: Merge has already been requested before " - "for specified variable " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op,s0); - } - if (arg1==~0U) { - _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Invalid specified operator " - "(should be one of '=,+,-,*,/,&,|,xor,&&,||,min,max'), " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op,s0); - } - memmerge.resize(3,memmerge._height + 1,1,1,0,0); - memmerge(0,memmerge._height - 1) = (int)pos; - memmerge(1,memmerge._height - 1) = (int)_cimg_mp_size(pos); - memmerge(2,memmerge._height - 1) = (int)arg1; - _cimg_mp_return_nan(); - } - break; - - case 'n' : -#ifdef cimg_mp_func_name - if (!std::strncmp(ss,"name(",5)) { // Get image name as a string vector - _cimg_mp_op("Function 'name()'"); - if (*ss5=='#') { // Index specified - s0 = ss6; while (s0::vector((ulongT)mp_name,pos,p1,arg1).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } -#endif - - if (!std::strncmp(ss,"narg(",5)) { // Number of arguments - _cimg_mp_op("Function 'narg()'"); - if (ss5>=se1) _cimg_mp_return(0); - arg1 = 0; - for (s = ss5; s::vector((ulongT)mp_norm0,pos,0).move_to(l_opcode); break; - case 1 : - CImg::vector((ulongT)mp_norm1,pos,0).move_to(l_opcode); break; - case 2 : - CImg::vector((ulongT)mp_norm2,pos,0).move_to(l_opcode); break; - case ~0U : - CImg::vector((ulongT)mp_norminf,pos,0).move_to(l_opcode); break; - default : - CImg::vector((ulongT)mp_normp,pos,0,(ulongT)(arg1==~0U?-1:(int)arg1)). - move_to(l_opcode); - } - for ( ; s::sequence(_cimg_mp_size(arg2),arg2 + 1, - arg2 + (ulongT)_cimg_mp_size(arg2)). - move_to(l_opcode); - else CImg::vector(arg2).move_to(l_opcode); - s = ns; - } - - (l_opcode>'y').move_to(opcode); - if (arg1>0 && opcode._height==4) // Special case with one argument and p>=1 - _cimg_mp_scalar1(mp_abs,opcode[3]); - opcode[2] = opcode._height; - opcode.move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - break; - - case 'p' : - if (!std::strncmp(ss,"permut(",7)) { // Number of permutations - _cimg_mp_op("Function 'permut()'"); - s1 = ss7; while (s1::vector((ulongT)mp_polygon,_cimg_mp_slot_nan,0,p1).move_to(l_opcode); - for (s = s0; s::sequence(_cimg_mp_size(arg2),arg2 + 1, - arg2 + (ulongT)_cimg_mp_size(arg2)). - move_to(l_opcode); - else CImg::vector(arg2).move_to(l_opcode); - s = ns; - } - (l_opcode>'y').move_to(opcode); - opcode[2] = opcode._height; - opcode.move_to(code); - _cimg_mp_return_nan(); - } - - if (!std::strncmp(ss,"print(",6) || - !std::strncmp(ss,"prints(",7)) { // Print expressions - s0 = ss6 + (*ss5=='('?0:1); - is_sth = *ss5=='s'; // string must be printed? - _cimg_mp_op(is_sth?"Function 'prints()'":"Function 'print()'"); - if (!is_sth && *s0=='#') { // Image - p1 = compile(ss7,se1,depth1,0,block_flags); - _cimg_mp_check_list(); - CImg::vector((ulongT)mp_image_print,_cimg_mp_slot_nan,p1).move_to(code); - _cimg_mp_return_nan(); - } - - // Regular expression - for (s = s0; s::string(s,true,true).unroll('y'),true); - cimg::strpare(variable_name,false,true); - - if (_cimg_mp_is_const_scalar(pos)) // Const scalar - std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = %.17g " - "(compiled as '%s', memslot = %u)", - variable_name._data,mem[pos],s_type(pos)._data,pos); - else // Vector or non-const scalar - std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = (uninitialized) " - "(compiled as '%s', memslot = %u)", - variable_name._data,s_type(pos)._data,pos); - - if (_cimg_mp_is_vector(pos)) // Vector - ((CImg::vector((ulongT)mp_vector_print,pos,0,(ulongT)_cimg_mp_size(pos),is_sth?1:0), - variable_name)>'y').move_to(opcode); - else // Scalar - ((CImg::vector((ulongT)mp_print,pos,0,is_sth?1:0), - variable_name)>'y').move_to(opcode); - - opcode[2] = opcode._height; - opcode.move_to(code); - *ns = c1; s = ns; - } - _cimg_mp_return(pos); - } - break; - - case 'r' : - if (!std::strncmp(ss,"rad2deg(",8)) { // Degrees to radians - _cimg_mp_op("Function 'rad2deg()'"); - arg1 = compile(ss8,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_rad2deg,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(mem[arg1]*180/cimg::PI); - _cimg_mp_scalar1(mp_rad2deg,arg1); - } - - if (!std::strncmp(ss,"ref(",4)) { // Variable declaration - _cimg_mp_op("Function 'ref()'"); - s1 = ss4; while (s1=se1 || !*s1) compile(s1,s1,depth1,0,block_flags); // Will throw missing argument error - arg3 = compile(ss4,s1++,depth1,p_ref,block_flags); - *se1 = 0; - - if (!is_varname(s1)) { // Invalid variable name - variable_name.assign(s1,(unsigned int)(se1 + 1 - s1)).back() = 0; - cimg::strellipsize(variable_name,64); - *se1 = ')'; - _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Invalid specified variable name '%s', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - variable_name._data,s0); - } - get_variable_pos(s1,arg1,arg2); - if (arg2!=~0U) reserved_label[arg2] = arg3; - else if (arg1!=~0U) variable_pos[arg1] = arg3; - else { // New variable - if (variable_def._width>=variable_pos._width) variable_pos.resize(-200,1,1,1,0); - variable_pos[variable_def._width] = arg3; - CImg::string(s1).move_to(variable_def); - } - if (_cimg_mp_is_vector(arg3)) - set_reserved_vector(arg3); // Prevent from being used in further optimization - else if (_cimg_mp_is_comp(arg3)) memtype[arg3] = -1; - *se1 = ')'; - _cimg_mp_return(arg3); - } - - if (!std::strncmp(ss,"repeat(",7)) { // Repeat - _cimg_mp_op("Function 'repeat()'"); - s0 = ss7; while (s0::%s: %s: Invalid loop variable name '%s', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - variable_name._data,s0); - } - get_variable_pos(variable_name,arg2,arg3); - arg2 = arg3!=~0U?reserved_label[arg3]:arg2!=~0U?variable_pos[arg2]:~0U; // Variable slot - if (arg2!=~0U && (!_cimg_mp_is_scalar(arg2) || - _cimg_mp_is_const_scalar(arg2))) { // Variable is not a vector or is a constant->error - cimg::strellipsize(variable_name,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Invalid type '%s' for variable '%s' " - "(expected 'scalar'), in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - s_type(arg2)._data,variable_name._data,s0); - } else if (arg2==~0U) { // Variable does not exist -> create it - arg2 = scalar(); - if (arg3!=~0U) reserved_label[arg3] = arg2; - else { - if (variable_def._width>=variable_pos._width) variable_pos.resize(-200,1,1,1,0); - variable_pos[variable_def._width] = arg2; - variable_name.move_to(variable_def); - } - memtype[arg2] = -1; - } - arg3 = compile(++s1,se1,depth1,0,block_flags); - } else { // Version with 2 arguments - arg2 = ~0U; - arg3 = compile(s0,se1,depth1,0,block_flags); - } - // arg2 = variable slot, arg3 = fill expression. - CImg::vector((ulongT)mp_repeat,arg3,arg1,arg2,code._width - p1).move_to(code,p1); - _cimg_mp_return_nan(); - } - - if (!std::strncmp(ss,"resize(",7)) { // Vector or image resize - _cimg_mp_op("Function 'resize()'"); - if (*ss7!='#') { // Vector - for (s = ss7; s::sequence(_cimg_mp_size(arg2),arg2 + 1, - arg2 + (ulongT)_cimg_mp_size(arg2)). - move_to(l_opcode); - else CImg::vector(arg2).move_to(l_opcode); - s = ns; - } - (l_opcode>'y').move_to(opcode); - if (opcode.height()<2) compile(s,se1,depth1,0,block_flags); // Not enough arguments -> throw exception - arg1 = (unsigned int)opcode[0]; // Vector to resize - p1 = _cimg_mp_size(arg1); - - if (opcode.height()<=4) { // Simple vector resize - arg2 = (unsigned int)opcode[1]; - _cimg_mp_check_const_scalar(arg2,2,3); - arg2 = (unsigned int)mem[arg2]; - arg3 = opcode.height()<3?1U:(unsigned int)opcode[2]; - _cimg_mp_check_type(arg3,3,1,0); - arg4 = opcode.height()<4?0U:(unsigned int)opcode[3]; - _cimg_mp_check_type(arg4,4,1,0); - pos = vector(arg2); - CImg::vector((ulongT)mp_vector_resize,pos,arg2,arg1,p1,arg3,arg4).move_to(code); - } else { // Advanced vector resize (vector viewed as an image) - // opcode = [ A, ow,oh,od,os, nw,nh,nd,ns, interp, boundary_cond, ax,ay,az,ac ] - // [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ] - - if (opcode.height()<6) compile(s,se1,depth1,0,block_flags); // Not enough arguments -> throw exception - p2 = opcode.height(); - opcode.resize(1,15,1,1,0); - if (p2<7) opcode[6] = opcode[2]; - if (p2<8) opcode[7] = opcode[3]; - if (p2<9) opcode[8] = opcode[4]; - if (p2<10) opcode[9] = 1; - _cimg_mp_check_const_scalar(opcode[1],2,3); - _cimg_mp_check_const_scalar(opcode[2],3,3); - _cimg_mp_check_const_scalar(opcode[3],4,3); - _cimg_mp_check_const_scalar(opcode[4],5,3); - _cimg_mp_check_const_scalar(opcode[5],6,3); - _cimg_mp_check_const_scalar(opcode[6],7,3); - _cimg_mp_check_const_scalar(opcode[7],8,3); - _cimg_mp_check_const_scalar(opcode[8],9,3); - arg2 = (unsigned int)mem[opcode[1]]; opcode[1] = arg2; - arg3 = (unsigned int)mem[opcode[2]]; opcode[2] = arg3; - arg4 = (unsigned int)mem[opcode[3]]; opcode[3] = arg4; - arg5 = (unsigned int)mem[opcode[4]]; opcode[4] = arg5; - if (arg2*arg3*arg4*arg5!=std::max(1U,p1)) - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Input size (%lu values) and specified input vector " - "geometry (%u,%u,%u,%u) (%lu values) do not match.", - pixel_type(),_cimg_mp_calling_function,s_op, - std::max(p1,1U),arg2,arg3,arg4,arg5,(ulongT)arg2*arg3*arg4*arg5); - arg2 = (unsigned int)mem[opcode[5]]; opcode[5] = arg2; - arg3 = (unsigned int)mem[opcode[6]]; opcode[6] = arg3; - arg4 = (unsigned int)mem[opcode[7]]; opcode[7] = arg4; - arg5 = (unsigned int)mem[opcode[8]]; opcode[8] = arg5; - pos = vector(arg2*arg3*arg4*arg5); - opcode.resize(1,18,1,1,0,0,0,1); - opcode[0] = (ulongT)mp_vector_resize_ext; - opcode[1] = (ulongT)pos; - opcode[2] = (ulongT)p1; - opcode.move_to(code); - } - return_new_comp = true; - _cimg_mp_return(pos); - - } else { // Image - if (!is_inside_critical) is_parallelizable = false; - s0 = ss8; while (s0::vector((ulongT)mp_image_resize,_cimg_mp_slot_nan,p1,~0U,~0U,~0U,~0U,1,0,0,0,0,0). - move_to(l_opcode); - pos = 0; - for (s = s0; s10) { - _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: %s arguments, in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - pos<1?"Missing":"Too much",s0); - } - l_opcode[0].move_to(code); - _cimg_mp_return_nan(); - } - } - - if (!std::strncmp(ss,"reverse(",8)) { // Vector reverse - _cimg_mp_op("Function 'reverse()'"); - arg1 = compile(ss8,se1,depth1,0,block_flags); - if (!_cimg_mp_is_vector(arg1)) _cimg_mp_return(arg1); - p1 = _cimg_mp_size(arg1); - pos = vector(p1); - CImg::vector((ulongT)mp_vector_reverse,pos,arg1,p1).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"rol(",4) || !std::strncmp(ss,"ror(",4)) { // Bitwise rotation - _cimg_mp_op(ss[2]=='l'?"Function 'rol()'":"Function 'ror()'"); - s1 = ss4; while (s11) { - arg2 = arg1 + 1; - if (p2>2) arg3 = arg2 + 1; - } - arg4 = compile(++s1,se1,depth1,0,block_flags); - } else { - s2 = ++s1; while (s2::vector((ulongT)mp_rot3d,pos,arg1,arg2,arg3,arg4).move_to(code); - } else { // 2D rotation - _cimg_mp_check_type(arg1,1,1,0); - pos = vector(4); - CImg::vector((ulongT)mp_rot2d,pos,arg1).move_to(code); - } - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"round(",6)) { // Value rounding - _cimg_mp_op("Function 'round()'"); - s1 = ss6; while (s1::vector((ulongT)mp_run,0,0).move_to(l_opcode); - pos = 1; - for (s = ss4; s::vector(arg1,_cimg_mp_size(arg1)).move_to(l_opcode); - s = ns; - } - (l_opcode>'y').move_to(opcode); - pos = scalar(); - opcode[1] = pos; - opcode[2] = opcode._height; - opcode.move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } -#endif - break; - - case 's' : - if (*ss1=='(') { // Image spectrum - _cimg_mp_op("Function 's()'"); - if (*ss2=='#') { // Index specified - p1 = compile(ss3,se1,depth1,0,block_flags); - _cimg_mp_check_list(); - } else { if (ss2!=se1) break; p1 = ~0U; } - _cimg_mp_scalar1(mp_image_s,p1); - } - - if (!std::strncmp(ss,"same(",5)) { // Test if operands have the same values - _cimg_mp_op("Function 'same()'"); - s1 = ss5; while (s1::vector((ulongT)mp_set,arg2,p2,arg1,p1).move_to(code); - _cimg_mp_return_nan(); - } -#endif - - if (!std::strncmp(ss,"shift(",6)) { // Shift vector - _cimg_mp_op("Function 'shift()'"); - s1 = ss6; while (s1::vector((ulongT)mp_shift,pos,arg1,p1,arg2,arg3).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"sign(",5)) { // Sign - _cimg_mp_op("Function 'sign()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sign,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(cimg::sign(mem[arg1])); - _cimg_mp_scalar1(mp_sign,arg1); - } - - if (!std::strncmp(ss,"sin(",4)) { // Sine - _cimg_mp_op("Function 'sin()'"); - arg1 = compile(ss4,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sin,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::sin(mem[arg1])); - _cimg_mp_scalar1(mp_sin,arg1); - } - - if (!std::strncmp(ss,"sinc(",5)) { // Sine cardinal - _cimg_mp_op("Function 'sinc()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinc,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(cimg::sinc(mem[arg1])); - _cimg_mp_scalar1(mp_sinc,arg1); - } - - if (!std::strncmp(ss,"sinh(",5)) { // Hyperbolic sine - _cimg_mp_op("Function 'sinh()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sinh,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::sinh(mem[arg1])); - _cimg_mp_scalar1(mp_sinh,arg1); - } - - if (!std::strncmp(ss,"size(",5)) { // Vector size - _cimg_mp_op("Function 'size()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - _cimg_mp_const_scalar(_cimg_mp_is_scalar(arg1)?0:_cimg_mp_size(arg1)); - } - - if (!std::strncmp(ss,"solve(",6)) { // Solve square linear system - _cimg_mp_op("Function 'solve()'"); - s1 = ss6; while (s1::%s: %s: Types of first and second arguments ('%s' and '%s') " - "do not match with third argument 'nb_colsB=%u', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - s_type(arg1)._data,s_type(arg2)._data,p3,s0); - } - pos = vector(arg6*p3); - CImg::vector((ulongT)mp_solve,pos,arg1,arg2,arg6,arg5,p3,arg4).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"sort(",5)) { // Sort vector - _cimg_mp_op("Function 'sort()'"); - s1 = ss5; while (s1::vector((ulongT)mp_sort,pos,arg1,p1,arg2,arg3,arg4).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"sqr(",4)) { // Square - _cimg_mp_op("Function 'sqr()'"); - arg1 = compile(ss4,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqr,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(cimg::sqr(mem[arg1])); - _cimg_mp_scalar1(mp_sqr,arg1); - } - - if (!std::strncmp(ss,"sqrt(",5)) { // Square root - _cimg_mp_op("Function 'sqrt()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_sqrt,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::sqrt(mem[arg1])); - _cimg_mp_scalar1(mp_sqrt,arg1); - } - - if (!std::strncmp(ss,"srand(",6)) { // Set RNG seed - _cimg_mp_op("Function 'srand()'"); - arg1 = ss6::vector((ulongT)mp_image_stats,pos,p1).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - -#ifdef cimg_mp_func_store - if (!std::strncmp(ss,"store(",6)) { // Store vector to variable - _cimg_mp_op("Function 'store()'"); - s1 = ss6; while (s1::vector((ulongT)mp_store,_cimg_mp_slot_nan,arg2,p2,arg1,p1, - arg3,arg4,arg5,arg6,pos).move_to(code); - _cimg_mp_return_nan(); - } -#endif - - if (!std::strncmp(ss,"s2v(",4)) { // String to double - _cimg_mp_op("Function 's2v()'"); - s1 = ss4; while (s1::vector((ulongT)mp_s2v,pos,arg1,p1,arg2,arg3).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"string(",7)) { // Construct string from list of arguments - _cimg_mp_op("Function 'string()'"); - CImg::vector((ulongT)mp_string,0,0,0).move_to(l_opcode); - - if (*ss7=='#') { // Output vector size specified, with '#' - s0 = ss8; while (s0::vector(arg2,p2).move_to(l_opcode); - s = ns; - } - if (arg1==~0U) arg1 = p1; - pos = vector(arg1,0); - (l_opcode>'y').move_to(opcode); - opcode[1] = pos; - opcode[2] = arg1; - opcode[3] = opcode._height; - opcode.move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"svd(",4)) { // Matrix SVD - _cimg_mp_op("Function 'svd()'"); - s1 = ss4; while (s1::%s: %s: Type of first argument ('%s') " - "does not match with second argument 'nb_colsA=%u', " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - s_type(arg1)._data,p2,s0); - } - pos = vector(p1 + p2 + p2*p2); - CImg::vector((ulongT)mp_matrix_svd,pos,arg1,p2,p3).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"swap(",5)) { // Swap values - _cimg_mp_op("Function 'swap()'"); - s1 = ss5; while (s1::%s: %s: %s argument cannot be a constant, " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - _cimg_mp_is_const_scalar(arg1)?"First":"Second",s0); - } - CImg::vector((ulongT)mp_swap,arg1,arg2,p1).move_to(code); - - // Write back values of linked arg1 and arg2. - const unsigned int *_ref = ref; - is_sth = true; // Is first argument? - do { - switch (*_ref) { - case 1 : // arg1: V[k] - arg3 = _ref[1]; // Vector slot - arg4 = _ref[2]; // Index - CImg::vector((ulongT)mp_vector_set_off,arg1,arg3,(ulongT)_cimg_mp_size(arg3),arg4). - move_to(code); - break; - case 2 : // arg1: i/j[_#ind,off] - if (!is_inside_critical) is_parallelizable = false; - p1 = _ref[1]; // Index - is_relative = (bool)_ref[2]; - arg3 = _ref[3]; // Offset - if (p1!=~0U) { - if (imglist) - CImg::vector((ulongT)(is_relative?mp_list_set_joff:mp_list_set_ioff), - arg1,p1,arg3).move_to(code); - } else { - if (imgout) - CImg::vector((ulongT)(is_relative?mp_set_joff:mp_set_ioff), - arg1,arg3).move_to(code); - } - break; - case 3 : // arg1: i/j(_#ind,_x,_y,_z,_c) - if (!is_inside_critical) is_parallelizable = false; - p1 = _ref[1]; // Index - is_relative = (bool)_ref[2]; - arg3 = _ref[3]; // X - arg4 = _ref[4]; // Y - arg5 = _ref[5]; // Z - arg6 = _ref[6]; // C - if (p1!=~0U) { - if (imglist) - CImg::vector((ulongT)(is_relative?mp_list_set_jxyzc:mp_list_set_ixyzc), - arg1,p1,arg3,arg4,arg5,arg6).move_to(code); - } else { - if (imgout) - CImg::vector((ulongT)(is_relative?mp_set_jxyzc:mp_set_ixyzc), - arg1,arg3,arg4,arg5,arg6).move_to(code); - } - break; - case 4: // arg1: I/J[_#ind,off] - if (!is_inside_critical) is_parallelizable = false; - p1 = _ref[1]; // Index - is_relative = (bool)_ref[2]; - arg3 = _ref[3]; // Offset - if (p1!=~0U) { - if (imglist) { - if (_cimg_mp_is_scalar(arg1)) - CImg::vector((ulongT)(is_relative?mp_list_set_Joff_s:mp_list_set_Ioff_s), - arg1,p1,arg3).move_to(code); - else { - _cimg_mp_check_const_index(p1); - CImg::vector((ulongT)(is_relative?mp_list_set_Joff_v:mp_list_set_Ioff_v), - arg1,p1,arg3,_cimg_mp_size(arg1)).move_to(code); - } - } - } else { - if (imgout) { - if (_cimg_mp_is_scalar(arg1)) - CImg::vector((ulongT)(is_relative?mp_set_Joff_s:mp_set_Ioff_s), - arg1,arg3).move_to(code); - else - CImg::vector((ulongT)(is_relative?mp_set_Joff_v:mp_set_Ioff_v), - arg1,arg3,_cimg_mp_size(arg1)).move_to(code); - } - } - break; - case 5 : // arg1: I/J(_#ind,_x,_y,_z,_c) - if (!is_inside_critical) is_parallelizable = false; - p1 = _ref[1]; // Index - is_relative = (bool)_ref[2]; - arg3 = _ref[3]; // X - arg4 = _ref[4]; // Y - arg5 = _ref[5]; // Z - if (p1!=~0U) { - if (imglist) { - if (_cimg_mp_is_scalar(arg1)) - CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_s:mp_list_set_Ixyz_s), - arg1,p1,arg3,arg4,arg5).move_to(code); - else { - _cimg_mp_check_const_index(p1); - CImg::vector((ulongT)(is_relative?mp_list_set_Jxyz_v:mp_list_set_Ixyz_v), - arg1,p1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code); - } - } - } else { - if (imgout) { - if (_cimg_mp_is_scalar(arg1)) - CImg::vector((ulongT)(is_relative?mp_set_Jxyz_s:mp_set_Ixyz_s), - arg1,arg3,arg4,arg5).move_to(code); - else - CImg::vector((ulongT)(is_relative?mp_set_Jxyz_v:mp_set_Ixyz_v), - arg1,arg3,arg4,arg5,_cimg_mp_size(arg1)).move_to(code); - } - } - break; - } - - _ref+=7; - arg1 = arg2; - is_sth = !is_sth; - } while (!is_sth); - - if (p_ref) std::memcpy(p_ref,ref,siz_ref); - _cimg_mp_return_nan(); - } - break; - - case 't' : - if (!std::strncmp(ss,"tan(",4)) { // Tangent - _cimg_mp_op("Function 'tan()'"); - arg1 = compile(ss4,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tan,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::tan(mem[arg1])); - _cimg_mp_scalar1(mp_tan,arg1); - } - - if (!std::strncmp(ss,"tanh(",5)) { // Hyperbolic tangent - _cimg_mp_op("Function 'tanh()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_tanh,arg1); - if (_cimg_mp_is_const_scalar(arg1)) _cimg_mp_const_scalar(std::tanh(mem[arg1])); - _cimg_mp_scalar1(mp_tanh,arg1); - } - - if (!std::strncmp(ss,"trace(",6)) { // Matrix trace - _cimg_mp_op("Function 'trace()'"); - arg1 = compile(ss6,se1,depth1,0,block_flags); - _cimg_mp_check_matrix_square(arg1,1); - p1 = (unsigned int)cimg::round(std::sqrt((float)_cimg_mp_size(arg1))); - _cimg_mp_scalar2(mp_trace,arg1,p1); - } - - if (!std::strncmp(ss,"transpose(",10)) { // Matrix transpose - _cimg_mp_op("Function 'transpose()'"); - s1 = ss + 10; while (s1::%s: %s: Size of first argument ('%s') does not match " - "second argument 'nb_cols=%u', in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - s_type(arg1)._data,p2,s0); - } - pos = vector(p3*p2); - CImg::vector((ulongT)mp_transpose,pos,arg1,p2,p3).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - break; - - case 'u' : - if (*ss1=='(') { // Random value with uniform distribution - _cimg_mp_op("Function 'u()'"); - if (*ss2==')') _cimg_mp_scalar2(mp_u,0,1); - s1 = ss2; while (s1float conversion - _cimg_mp_op("Function 'ui2f()'"); - arg1 = compile(ss5,se1,depth1,0,block_flags); - if (_cimg_mp_is_vector(arg1)) _cimg_mp_vector1_v(mp_ui2f,arg1); - if (_cimg_mp_is_const_scalar(arg1)) - _cimg_mp_const_scalar((double)cimg::uint2float((unsigned int)mem[arg1])); - _cimg_mp_scalar1(mp_ui2f,arg1); - } - - if (!std::strncmp(ss,"unref(",6)) { // Un-reference variable - _cimg_mp_op("Function 'unref()'"); - arg1=~0U; - for (s0 = ss6; s0ss6 && *s0==',') ++s0; - s1 = s0; while (s1s0) { - *s1 = 0; - get_variable_pos(s0,arg1,arg2); - if (arg2!=~0U) reserved_label[arg2] = ~0U; - else if (arg1!=~0U) { - variable_def.remove(arg1); - if (arg10) || - !std::strncmp(ss,"vector(",7) || - (!std::strncmp(ss,"vector",6) && ss7::sequence(arg4,arg3 + 1,arg3 + arg4).move_to(l_opcode); - arg2+=arg4; - } else { CImg::vector(arg3).move_to(l_opcode); ++arg2; } - s = ns; - } - if (arg1==~0U) arg1 = arg2; - if (!arg1) _cimg_mp_return(0); - pos = vector(arg1); - l_opcode.insert(CImg::vector((ulongT)mp_vector_init,pos,0,arg1),0); - (l_opcode>'y').move_to(opcode); - opcode[2] = opcode._height; - opcode.move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"vmax(",5) || !std::strncmp(ss,"vmin(",5) || - !std::strncmp(ss,"vmaxabs(",8) || !std::strncmp(ss,"vminabs(",8) || - !std::strncmp(ss,"vmed(",5) || !std::strncmp(ss,"vkth(",5) || - !std::strncmp(ss,"vsum(",5) || !std::strncmp(ss,"vavg(",5) || - !std::strncmp(ss,"vstd(",5) || !std::strncmp(ss,"vvar(",5) || - !std::strncmp(ss,"vprod(",6) || - !std::strncmp(ss,"vargmin(",8) || !std::strncmp(ss,"vargmax(",8) || - !std::strncmp(ss,"vargminabs(",11) || !std::strncmp(ss,"vargmaxabs(",11) || - !std::strncmp(ss,"vargkth(",8)) { // Multi-argument vector functions - _cimg_mp_op(ss[1]=='a'?(ss[2]=='v'?"Function 'vavg()'": - ss[4]=='k'?"Function 'vargkth()'": - ss[5]=='i' && ss[7]=='('?"Function 'vargmin()'": - ss[5]=='i'?"Function vargminabs()'": - ss[7]=='('?"Function 'vargmax()'": - "Function 'vargmaxabs()'"): - ss[1]=='s'?(ss[2]=='u'?"Function 'vsum()'":"Function 'vstd()'"): - ss[1]=='k'?"Function 'vkth()'": - ss[1]=='p'?"Function 'vprod()'": - ss[1]=='v'?"Function 'vvar()'": - ss[2]=='i'?(ss[4]=='('?"Function 'vmin()'": - "Function 'vminabs()'"): - ss[2]=='a'?(ss[4]=='('?"Function 'vmax()'": - "Function 'vmaxabs()'"): - "Function 'vmed()'"); - op = ss[1]=='a'?(ss[2]=='v'?mp_vavg: - ss[4]=='k'?mp_vargkth: - ss[5]=='i' && ss[7]=='('?mp_vargmin: - ss[5]=='i'?mp_vargminabs: - ss[7]=='('?mp_vargmax:mp_vargmaxabs): - ss[1]=='s'?(ss[2]=='u'?mp_vsum:mp_vstd): - ss[1]=='k'?mp_vkth: - ss[1]=='p'?mp_vprod: - ss[1]=='v'?mp_vvar: - ss[2]=='i'?(ss[4]=='('?mp_vmin:mp_vminabs): - ss[2]=='a'?(ss[4]=='('?mp_vmax:mp_vmaxabs): - mp_vmedian; - CImg::vector((ulongT)op,0,0,0).move_to(l_opcode); - p1 = ~0U; - p3 = 1; - for (s = std::strchr(ss,'(') + 1; s::vector(arg2,p2).move_to(l_opcode); - s = ns; - ++p3; - } - (l_opcode>'y').move_to(opcode); - if (p1==~0U) { pos = scalar(); p1 = 0; } else pos = vector(p1); - opcode[1] = pos; - opcode[2] = p1; - opcode[3] = opcode._height; - opcode.move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - if (!std::strncmp(ss,"v2s(",4)) { // Double(s) to string - _cimg_mp_op("Function 'v2s()'"); - s1 = ss4; while (s1::vector((ulongT)mp_v2s,pos,p1,arg1,_cimg_mp_size(arg1),arg2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - break; - - case 'w' : - if (*ss1=='(') { // Image width - _cimg_mp_op("Function 'w()'"); - if (*ss2=='#') { // Index specified - p1 = compile(ss3,se1,depth1,0,block_flags); - _cimg_mp_check_list(); - } else { if (ss2!=se1) break; p1 = ~0U; } - _cimg_mp_scalar1(mp_image_w,p1); - } - - if (*ss1=='h' && *ss2=='(') { // Image width*height - _cimg_mp_op("Function 'wh()'"); - if (*ss3=='#') { // Index specified - p1 = compile(ss4,se1,depth1,0,block_flags); - _cimg_mp_check_list(); - } else { if (ss3!=se1) break; p1 = ~0U; } - _cimg_mp_scalar1(mp_image_wh,p1); - } - - if (*ss1=='h' && *ss2=='d' && *ss3=='(') { // Image width*height*depth - _cimg_mp_op("Function 'whd()'"); - if (*ss4=='#') { // Index specified - p1 = compile(ss5,se1,depth1,0,block_flags); - _cimg_mp_check_list(); - } else { if (ss4!=se1) break; p1 = ~0U; } - _cimg_mp_scalar1(mp_image_whd,p1); - } - - if (*ss1=='h' && *ss2=='d' && *ss3=='s' && *ss4=='(') { // Image width*height*depth*spectrum - _cimg_mp_op("Function 'whds()'"); - if (*ss5=='#') { // Index specified - p1 = compile(ss6,se1,depth1,0,block_flags); - _cimg_mp_check_list(); - } else { if (ss5!=se1) break; p1 = ~0U; } - _cimg_mp_scalar1(mp_image_whds,p1); - } - - if (!std::strncmp(ss,"while(",6)) { // While...do - _cimg_mp_op("Function 'while()'"); - s0 = *ss5=='('?ss6:ss8; - s1 = s0; while (s1::vector((ulongT)mp_while,pos,arg1,p2 - p1,code._width - p2,arg2, - pos>=arg6 && !_cimg_mp_is_const_scalar(pos), - arg1>=arg6 && !_cimg_mp_is_const_scalar(arg1)).move_to(code,p1); - _cimg_mp_return(pos); - } - break; - - case 'x' : - if (!std::strncmp(ss,"xor(",4)) { // Xor - _cimg_mp_op("Function 'xor()'"); - s1 = ss4; while (s1::vector((ulongT)op,pos,0).move_to(l_opcode); - for (s = std::strchr(ss,'(') + 1; s::sequence(_cimg_mp_size(arg2),arg2 + 1, - arg2 + (ulongT)_cimg_mp_size(arg2)). - move_to(l_opcode); - else CImg::vector(arg2).move_to(l_opcode); - is_sth&=_cimg_mp_is_const_scalar(arg2); - s = ns; - } - (l_opcode>'y').move_to(opcode); - opcode[2] = opcode._height; - if (is_sth) _cimg_mp_const_scalar(op(*this)); - opcode.move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - // No corresponding built-in function -> Look for a user-defined macro call. - s0 = strchr(ss,'('); - if (s0) { - variable_name.assign(ss,(unsigned int)(s0 - ss + 1)).back() = 0; - - // Count number of specified arguments. - p1 = 0; - for (s = s0 + 1; s<=se1; ++p1, s = ns + 1) { - while (*s && cimg::is_blank(*s)) ++s; - if (*s==')' && !p1) break; - ns = s; while (ns _expr = macro_body[l]; // Expression to be substituted - - p1 = 1; // Index of current parsed argument - for (s = s0 + 1; s<=se1; ++p1, s = ns + 1) { // Parse function arguments - while (*s && cimg::is_blank(*s)) ++s; - if (!is_variadic && *s==')' && p1==1) break; // Function has no arguments - if (p1>p2) { ++p1; break; } - - if (is_variadic) ns = se1; - else { - ns = s; while (ns1) { - _expr.resize(arg1 + variable_name._width - 2,1,1,1,0); - std::memmove(_expr._data + k + variable_name._width - 1,_expr._data + k + 1,arg1 - k - 1); - std::memcpy(_expr._data + k,variable_name,variable_name._width - 1); - k+=variable_name._width - 2; - } else { - std::memmove(_expr._data + k,_expr._data + k + 1,arg1 - k - 1); - --k; - } - } - ++arg2; - } - } - - // Recompute 'pexpr' and 'level' for evaluating substituted expression. - CImg _pexpr(_expr._width); - ns = _pexpr._data; - for (ps = _expr._data, c1 = ' '; *ps; ++ps) { - if (!cimg::is_blank(*ps)) c1 = *ps; - *(ns++) = c1; - } - *ns = 0; - - CImg _level = get_level(_expr); - expr.swap(_expr); - pexpr.swap(_pexpr); - level.swap(_level); - s0 = user_macro; - user_macro = macro_def[l]; - pos = compile(expr._data,expr._data + expr._width - 1,depth1,p_ref,block_flags); - user_macro = s0; - level.swap(_level); - pexpr.swap(_pexpr); - expr.swap(_expr); - _cimg_mp_return(pos); - } - - if (arg3) { // Macro name matched but number of arguments does not - CImg sig_nargs(arg3); - arg1 = 0; - cimglist_for(macro_def,l) if (!std::strcmp(macro_def[l],variable_name)) - sig_nargs[arg1++] = (unsigned int)macro_def[l].back(); - _cimg_mp_strerr; - cimg::strellipsize(variable_name,64); - if (sig_nargs._width>1) { - sig_nargs.sort(); - arg1 = sig_nargs.back(); - --sig_nargs._width; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: Function '%s()': Number of specified arguments (%u) " - "does not match macro declaration (defined for %s or %u arguments), " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,variable_name._data, - p1,sig_nargs.value_string()._data,arg1,s0); - } else - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: Function '%s()': Number of specified arguments (%u) " - "does not match macro declaration (defined for %u argument%s), " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,variable_name._data, - p1,*sig_nargs,*sig_nargs!=1?"s":"",s0); - } - } - } // if (se1==')') - - // Char / string initializer. - if (*se1=='\'' && - ((se1>ss && *ss=='\'') || - (se1>ss1 && *ss=='_' && *ss1=='\''))) { - if (*ss=='_') { _cimg_mp_op("Char initializer"); s1 = ss2; } - else { _cimg_mp_op("String initializer"); s1 = ss1; } - arg1 = (unsigned int)(se1 - s1); // Original string length - if (arg1) { - CImg(s1,arg1 + 1).move_to(variable_name).back() = 0; - cimg::strunescape(variable_name); - arg1 = (unsigned int)std::strlen(variable_name); - } - if (!arg1) _cimg_mp_return(0); // Empty string -> 0 - if (*ss=='_') { - if (arg1==1) _cimg_mp_const_scalar((unsigned char)*variable_name); - _cimg_mp_strerr; - cimg::strellipsize(variable_name,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s: Literal %s contains more than one byte, " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op, - ss1,s0); - } - pos = vector(arg1); - CImg::vector((ulongT)mp_string_init,pos,arg1).move_to(l_opcode); - CImg(1,arg1/sizeof(ulongT) + (arg1%sizeof(ulongT)?1:0)).move_to(l_opcode); - std::memcpy((char*)l_opcode[1]._data,variable_name,arg1); - (l_opcode>'y').move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - } - - // Vector initializer [ ... ]. - if (*ss=='[' && *se1==']') { - _cimg_mp_op("Vector initializer"); - s1 = ss1; while (s1s1 && cimg::is_blank(*s2)) --s2; - if (s2>s1 && *s1=='\'' && *s2=='\'') { // Vector values provided as a string - arg1 = (unsigned int)(s2 - s1 - 1); // Original string length - if (arg1) { - CImg(s1 + 1,arg1 + 1).move_to(variable_name).back() = 0; - cimg::strunescape(variable_name); - arg1 = (unsigned int)std::strlen(variable_name); - } - if (!arg1) _cimg_mp_return(0); // Empty string -> 0 - pos = vector(arg1); - CImg::vector((ulongT)mp_string_init,pos,arg1).move_to(l_opcode); - CImg(1,arg1/sizeof(ulongT) + (arg1%sizeof(ulongT)?1:0)).move_to(l_opcode); - std::memcpy((char*)l_opcode[1]._data,variable_name,arg1); - (l_opcode>'y').move_to(code); - } else { // Vector values provided as list of items - arg1 = 0; // Number of specified values - if (*ss1!=']') for (s = ss1; s::sequence(arg3,arg2 + 1,arg2 + arg3).move_to(l_opcode); - arg1+=arg3; - } else { CImg::vector(arg2).move_to(l_opcode); ++arg1; } - s = ns; - } - if (!arg1) _cimg_mp_return(0); - pos = vector(arg1); - l_opcode.insert(CImg::vector((ulongT)mp_vector_init,pos,0,arg1),0); - (l_opcode>'y').move_to(opcode); - opcode[2] = opcode._height; - opcode.move_to(code); - } - return_new_comp = true; - _cimg_mp_return(pos); - } - - // Variables related to the input list of images. - if (*ss1=='#' && ss2::vector((ulongT)mp_list_Joff,pos,p1,0,0,p2).move_to(code); - return_new_comp = true; - _cimg_mp_return(pos); - case 'R' : // R#ind - if (!imglist) _cimg_mp_return(0); - _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,0, - 0,_cimg_mp_boundary); - case 'G' : // G#ind - if (!imglist) _cimg_mp_return(0); - _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,1, - 0,_cimg_mp_boundary); - case 'B' : // B#ind - if (!imglist) _cimg_mp_return(0); - _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,2, - 0,_cimg_mp_boundary); - case 'A' : // A#ind - if (!imglist) _cimg_mp_return(0); - _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,3, - 0,_cimg_mp_boundary); - } - } - - if (*ss1 && *ss2=='#' && ss3='0' && *ss1<='9') { // i0#ind...i9#ind - if (!imglist) _cimg_mp_return(0); - _cimg_mp_scalar7(mp_list_ixyzc,arg1,_cimg_mp_slot_x,_cimg_mp_slot_y,_cimg_mp_slot_z,*ss1 - '0', - 0,_cimg_mp_boundary); - } - - if (*ss1=='c') { // ic#ind - if (!imglist) _cimg_mp_return(0); - if (_cimg_mp_is_const_scalar(arg1)) { - if (!list_median) list_median.assign(imglist._width); - if (!list_median[p1]) CImg::vector(imglist[p1].median()).move_to(list_median[p1]); - _cimg_mp_const_scalar(*list_median[p1]); - } - _cimg_mp_scalar1(mp_list_median,arg1); - } - - if (*ss1=='n') { // in#ind - if (!imglist) _cimg_mp_return(0); - if (_cimg_mp_is_const_scalar(arg1)) { - if (!list_norm) list_norm.assign(imglist._width); - if (!list_norm[p1]) CImg::vector(imglist[p1].magnitude()).move_to(list_norm[p1]); - _cimg_mp_const_scalar(*list_norm[p1]); - } - _cimg_mp_scalar1(mp_list_norm,arg1); - } - - switch (*ss1) { - case 'm' : arg2 = 0; break; // im#ind - case 'M' : arg2 = 1; break; // iM#ind - case 'a' : arg2 = 2; break; // ia#ind - case 'v' : arg2 = 3; break; // iv#ind - case 's' : arg2 = 12; break; // is#ind - case 'p' : arg2 = 13; break; // ip#ind - } - } else if (*ss1=='m') switch (*ss) { - case 'x' : arg2 = 4; break; // xm#ind - case 'y' : arg2 = 5; break; // ym#ind - case 'z' : arg2 = 6; break; // zm#ind - case 'c' : arg2 = 7; break; // cm#ind - } else if (*ss1=='M') switch (*ss) { - case 'x' : arg2 = 8; break; // xM#ind - case 'y' : arg2 = 9; break; // yM#ind - case 'z' : arg2 = 10; break; // zM#ind - case 'c' : arg2 = 11; break; // cM#ind - } - if (arg2!=~0U) { - if (!imglist) _cimg_mp_return(0); - if (_cimg_mp_is_const_scalar(arg1)) { - if (!list_stats) list_stats.assign(imglist._width); - if (!list_stats[p1]) list_stats[p1].assign(1,14,1,1,0).fill(imglist[p1].get_stats(),false); - _cimg_mp_const_scalar(list_stats(p1,arg2)); - } - _cimg_mp_scalar2(mp_list_stats,arg1,arg2); - } - } - - if (*ss=='w' && *ss1=='h' && *ss2=='d' && *ss3=='#' && ss4 error. - c1 = *se1; - _cimg_mp_strerr; - cimg::strellipsize(variable_name,64); - if (is_sth) - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: Undefined variable '%s' in expression '%s'.", - pixel_type(),_cimg_mp_calling_function, - variable_name._data,s0); - s1 = std::strchr(ss,'('); - s_op = s1 && c1==')'?"function call":"item"; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: Unrecognized %s '%s' in expression '%s'.", - pixel_type(),_cimg_mp_calling_function, - s_op,variable_name._data,s0); - } - - // Evaluation procedure. - double operator()(const double x, const double y, const double z, const double c) { - mem[_cimg_mp_slot_x] = x; mem[_cimg_mp_slot_y] = y; mem[_cimg_mp_slot_z] = z; mem[_cimg_mp_slot_c] = c; - for (p_code = code; p_code_data; - const ulongT target = opcode[1]; - mem[target] = _cimg_mp_defunc(*this); - } - return *result; - } - - // Evaluation procedure (return output values in vector 'output'). - template - void operator()(const double x, const double y, const double z, const double c, t *const output) { - mem[_cimg_mp_slot_x] = x; mem[_cimg_mp_slot_y] = y; mem[_cimg_mp_slot_z] = z; mem[_cimg_mp_slot_c] = c; - for (p_code = code; p_code_data; - const ulongT target = opcode[1]; - mem[target] = _cimg_mp_defunc(*this); - } - if (result_dim) { - const double *ptrs = result + 1; - t *ptrd = output; - for (unsigned int k = 0; k_data; - const ulongT target = opcode[1]; - mem[target] = _cimg_mp_defunc(*this); - } - p_code_end = code.end(); - } - - // Evaluation procedure for end_t() bloc. - void end_t() { - if (!code_end_t) return; - if (imgin) { - mem[_cimg_mp_slot_x] = imgin._width - 1.; - mem[_cimg_mp_slot_y] = imgin._height - 1.; - mem[_cimg_mp_slot_z] = imgin._depth - 1.; - mem[_cimg_mp_slot_c] = imgin._spectrum - 1.; - } else mem[_cimg_mp_slot_x] = mem[_cimg_mp_slot_y] = mem[_cimg_mp_slot_z] = mem[_cimg_mp_slot_c] = 0; - p_code_end = code_end_t.end(); - for (p_code = code_end_t; p_code_data; - const ulongT target = opcode[1]; - mem[target] = _cimg_mp_defunc(*this); - } - } - - // Evaluation procedure the end() bloc. - void end() { - if (!code_end) return; - if (imgin) { - mem[_cimg_mp_slot_x] = imgin._width - 1.; - mem[_cimg_mp_slot_y] = imgin._height - 1.; - mem[_cimg_mp_slot_z] = imgin._depth - 1.; - mem[_cimg_mp_slot_c] = imgin._spectrum - 1.; - } else mem[_cimg_mp_slot_x] = mem[_cimg_mp_slot_y] = mem[_cimg_mp_slot_z] = mem[_cimg_mp_slot_c] = 0; - p_code_end = code_end.end(); - for (p_code = code_end; p_code_data; - const ulongT target = opcode[1]; - mem[target] = _cimg_mp_defunc(*this); - } - } - - // Merge inter-thread variables. - // (argument 'mp' is the master instance). - void merge(_cimg_math_parser& mp) { - if (&mp==this) return; - cimg_rofY(mp.memmerge,k) { - const unsigned int - pos = (unsigned int)mp.memmerge(0,k), - siz = (unsigned int)mp.memmerge(1,k), - iop = (unsigned int)mp.memmerge(2,k); - if (!siz) switch (iop) { // Scalar value - case 0 : mp.mem[pos] = mem[pos]; break; // Assignment - case 1 : mp.mem[pos]+=mem[pos]; break; // Operator+ - case 2 : mp.mem[pos]-=mem[pos]; break; // Operator- - case 3 : mp.mem[pos]*=mem[pos]; break; // Operator* - case 4 : mp.mem[pos]/=mem[pos]; break; // Operator/ - case 5 : mp.mem[pos] = (double)((longT)mp.mem[pos] & (longT)mem[pos]); break; // Operator& - case 6 : mp.mem[pos] = (double)((longT)mp.mem[pos] | (longT)mem[pos]); break; // Operator| - case 7 : mp.mem[pos] = (double)((longT)mp.mem[pos] ^ (longT)mem[pos]); break; // Operator 'xor' - case 8 : mp.mem[pos] = mp.mem[pos] && mem[pos]; break; // Operator&& - case 9 : mp.mem[pos] = mp.mem[pos] || mem[pos]; break; // Operator|| - case 10 : mp.mem[pos] = std::min(mp.mem[pos],mem[pos]); break; // Operator 'min' - case 11 : mp.mem[pos] = std::max(mp.mem[pos],mem[pos]); break; // Operator 'max' - } else switch (iop) { // Vector value - case 0 : // Assignment - CImg(&mp.mem[pos + 1],siz,1,1,1,true) = CImg(&mem[pos + 1],siz,1,1,1,true); - break; - case 1 : // Operator+ - CImg(&mp.mem[pos + 1],siz,1,1,1,true)+=CImg(&mem[pos + 1],siz,1,1,1,true); - break; - case 2 : // Operator- - CImg(&mp.mem[pos + 1],siz,1,1,1,true)-=CImg(&mem[pos + 1],siz,1,1,1,true); - break; - case 3 : // Operator* - CImg(&mp.mem[pos + 1],siz,1,1,1,true)*=CImg(&mem[pos + 1],siz,1,1,1,true); - break; - case 4 : // Operator/ - CImg(&mp.mem[pos + 1],siz,1,1,1,true)/=CImg(&mem[pos + 1],siz,1,1,1,true); - break; - case 5 : // Operator& - CImg(&mp.mem[pos + 1],siz,1,1,1,true)&=CImg(&mem[pos + 1],siz,1,1,1,true); - break; - case 6 : // Operator| - CImg(&mp.mem[pos + 1],siz,1,1,1,true)|=CImg(&mem[pos + 1],siz,1,1,1,true); - break; - case 7 : // Operator 'xor' - CImg(&mp.mem[pos + 1],siz,1,1,1,true)^=CImg(&mem[pos + 1],siz,1,1,1,true); - break; - case 8 : { // Operator&& - CImg - arg1(&mp.mem[pos + 1],siz,1,1,1,true), - arg2(&mem[pos + 1],siz,1,1,1,true); - cimg_foroff(arg1,off) arg1[off] = arg1[off] && arg2[off]; - } break; - case 9 : { // Operator|| - CImg - arg1(&mp.mem[pos + 1],siz,1,1,1,true), - arg2(&mem[pos + 1],siz,1,1,1,true); - cimg_foroff(arg1,off) arg1[off] = arg1[off] || arg2[off]; - } break; - case 10 : // Operator 'min' - CImg(&mp.mem[pos + 1],siz,1,1,1,true).min(CImg(&mem[pos + 1],siz,1,1,1,true)); - break; - case 11 : // Operator 'max' - CImg(&mp.mem[pos + 1],siz,1,1,1,true).max(CImg(&mem[pos + 1],siz,1,1,1,true)); - break; - } - } - } - - // Return specified argument number as a string. - static const char *s_argth(const unsigned int n_arg) { - const char - *_s_arg[] = { "", "First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh", "Eighth","Ninth", - "10th", "11th", "12th", "13th", "14th", "15th", "16th", "17th", "18th", "19th", - "20th", "21st", "22nd", "23rd", "24th", "25th", "26th", "27th", "28th", "One of the" }; - return _s_arg[n_arg s_calling_function() const { - CImg res; - const unsigned int - l1 = calling_function?(unsigned int)std::strlen(calling_function):0U, - l2 = user_macro?(unsigned int)std::strlen(user_macro):0U; - if (l2) { - res.assign(l1 + l2 + 48); - cimg_snprintf(res,res._width,"%s(): When substituting function '%s()'",calling_function,user_macro); - } else { - res.assign(l1 + l2 + 4); - cimg_snprintf(res,res._width,"%s()",calling_function); - } - return res; - } - - // Return type of a memory element as a string. - CImg s_type(const unsigned int arg) const { - CImg res; - if (_cimg_mp_is_vector(arg)) { // Vector - CImg::string("vectorXXXXXXXXXXXXXXXX").move_to(res); - cimg_sprintf(res._data + 6,"%u",_cimg_mp_size(arg)); - } else if (_cimg_mp_is_const_scalar(arg)) CImg::string("const scalar").move_to(res); // Const scalar - else CImg::string("scalar").move_to(res); // Scalar - return res; - } - - // Count parentheses/brackets level of each character of the expression. - CImg get_level(CImg& _expr) const { - bool is_escaped = false, next_is_escaped = false; - unsigned int mode = 0, next_mode = 0; // { 0=normal | 1=char-string | 2=vector-string - CImg res(_expr._width - 1); - unsigned int *pd = res._data; - int _level = 0; - for (const char *ps = _expr._data; *ps && _level>=0; ++ps) { - if (!is_escaped && !next_is_escaped && *ps=='\\') next_is_escaped = true; - if (!is_escaped && *ps=='\'') { // Non-escaped character - if (!mode && ps>_expr._data && *(ps - 1)=='[') next_mode = mode = 2; // Start vector-string - else if (mode==2 && *(ps + 1)==']') next_mode = !mode; // End vector-string - else if (mode<2) next_mode = mode?(mode = 0):1; // Start/end char-string - } - *(pd++) = (unsigned int)(mode>=1 || is_escaped?_level + (mode==1): - *ps=='(' || *ps=='['?_level++: - *ps==')' || *ps==']'?--_level: - _level); - mode = next_mode; - is_escaped = next_is_escaped; - next_is_escaped = false; - } - if (mode) { - cimg::strellipsize(_expr,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: Unterminated string literal, in expression '%s'.", - pixel_type(),_cimg_mp_calling_function, - _expr._data); - } - if (_level) { - cimg::strellipsize(_expr,64); - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: Unbalanced parentheses/brackets, in expression '%s'.", - pixel_type(),_cimg_mp_calling_function, - _expr._data); - } - return res; - } - - // Find and return index of current image 'imgin' within image list 'imglist'. - unsigned int get_mem_img_index() { - if (mem_img_index==~0U) { - if (&imgout>imglist.data() && &imgout='0' && c2<='9') rp = 21 + c2 - '0'; // i0...i9 - else if (c2=='m') rp = 4; // im - else if (c2=='M') rp = 5; // iM - else if (c2=='a') rp = 6; // ia - else if (c2=='v') rp = 7; // iv - else if (c2=='d') rp = 8; // id - else if (c2=='s') rp = 9; // is - else if (c2=='p') rp = 10; // ip - else if (c2=='c') rp = 11; // ic - else if (c2=='n') rp = 12; // in - } else if (c2=='m') { - if (c1=='x') rp = 13; // xm - else if (c1=='y') rp = 14; // ym - else if (c1=='z') rp = 15; // zm - else if (c1=='c') rp = 16; // cm - } else if (c2=='M') { - if (c1=='x') rp = 17; // xM - else if (c1=='y') rp = 18; // yM - else if (c1=='z') rp = 19; // zM - else if (c1=='c') rp = 20; // cM - } - } else if (variable_name[1] && variable_name[2] && !variable_name[3]) { // Three-chars variable - c1 = variable_name[0]; - c2 = variable_name[1]; - c3 = variable_name[2]; - if (c1=='w' && c2=='h' && c3=='d') rp = 1; // whd - } else if (variable_name[1] && variable_name[2] && variable_name[3] && - !variable_name[4]) { // Four-chars variable - c1 = variable_name[0]; - c2 = variable_name[1]; - c3 = variable_name[2]; - c4 = variable_name[3]; - if (c1=='w' && c2=='h' && c3=='d' && c4=='s') rp = 2; // whds - } else if (!std::strcmp(variable_name,"interpolation")) rp = 31; // interpolation - else if (!std::strcmp(variable_name,"boundary")) rp = 32; // boundary - - if (rp!=~0U) { rpos = rp; return; } // One of the reserved labels - - // Multi-char variable name : check for existing variable with same name - cimglist_for(variable_def,i) - if (!std::strcmp(variable_name,variable_def[i])) { pos = i; break; } - } - - // Return true if specified argument can be a part of an allowed variable name. - static bool is_varchar(const char c) { - return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_'; - } - - // Return true if specified argument can be considered as a variable name. - static bool is_varname(const char *const str, const unsigned int length=~0U) { - if (*str>='0' && *str<='9') return false; - for (unsigned int l = 0; l128) return false; - const int *ptr = memtype.data(arg + 1); - bool is_tmp = true; - while (siz-->0) if (*(ptr++)) { is_tmp = false; break; } - return is_tmp; - } - - // Check if a memory slot is a positive integer constant scalar value. - // 'mode' can be: - // { 0=constant | 1=integer constant | 2=positive integer constant | 3=strictly-positive integer constant } - void check_const_scalar(const unsigned int arg, const unsigned int n_arg, - const unsigned int mode, - char *const ss, char *const se, const char saved_char) { - _cimg_mp_check_type(arg,n_arg,1,0); - if (!_cimg_mp_is_const_scalar(arg)) { - const char *const s_arg = s_argth(n_arg); - char *s0; _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s%s %s%s (of type '%s') is not a constant, " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"", - s_arg,*s_arg?" argument":" Argument",s_type(arg)._data,s0); - } - const double val = mem[arg]; - - if (!((!mode || (double)(int)mem[arg]==mem[arg]) && - (mode<2 || mem[arg]>=(mode==3)))) { - const char *const s_arg = s_argth(n_arg); - char *s0; _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s%s %s%s (of type '%s' and value %g) is not a%s constant, " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"", - s_arg,*s_arg?" argument":" Argument",s_type(arg)._data,val, - !mode?"":mode==1?"n integer": - mode==2?" positive integer":" strictly positive integer",s0); - } - } - - // Check if an image index is a constant value. - void check_const_index(const unsigned int arg, - char *const ss, char *const se, const char saved_char) { - if (arg!=~0U && !_cimg_mp_is_const_scalar(arg)) { - char *s0; _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s%s Specified image index is not a constant, " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",s0); - } - } - - // Check a matrix is square. - void check_matrix_square(const unsigned int arg, const unsigned int n_arg, - char *const ss, char *const se, const char saved_char) { - _cimg_mp_check_type(arg,n_arg,2,0); - const unsigned int - siz = _cimg_mp_size(arg), - n = (unsigned int)cimg::round(std::sqrt((float)siz)); - if (n*n!=siz) { - const char *s_arg; - if (*s_op!='F') s_arg = !n_arg?"":n_arg==1?"Left-hand":"Right-hand"; - else s_arg = !n_arg?"":n_arg==1?"First":n_arg==2?"Second":n_arg==3?"Third":"One"; - char *s0; _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s%s %s%s (of type '%s') " - "cannot be considered as a square matrix, in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"", - s_arg,*s_op=='F'?(*s_arg?" argument":" Argument"):(*s_arg?" operand":" Operand"), - s_type(arg)._data,s0); - } - } - - // Check type compatibility for one argument. - // Bits of 'mode' tells what types are allowed: - // { 1 = scalar | 2 = vectorN }. - // If 'N' is not zero, it also restricts the vectors to be of size N only. - void check_type(const unsigned int arg, const unsigned int n_arg, - const unsigned int mode, const unsigned int N, - char *const ss, char *const se, const char saved_char) { - const bool - is_scalar = _cimg_mp_is_scalar(arg), - is_vector = _cimg_mp_is_vector(arg) && (!N || _cimg_mp_size(arg)==N); - bool cond = false; - if (mode&1) cond|=is_scalar; - if (mode&2) cond|=is_vector; - if (!cond) { - const char *s_arg; - if (*s_op!='F') s_arg = !n_arg?"":n_arg==1?"Left-hand":"Right-hand"; - else s_arg = s_argth(n_arg); - CImg sb_type(32); - if (mode==1) cimg_snprintf(sb_type,sb_type._width,"'scalar'"); - else if (mode==2) { - if (N) cimg_snprintf(sb_type,sb_type._width,"'vector%u'",N); - else cimg_snprintf(sb_type,sb_type._width,"'vector'"); - } else { - if (N) cimg_snprintf(sb_type,sb_type._width,"'scalar' or 'vector%u'",N); - else cimg_snprintf(sb_type,sb_type._width,"'scalar' or 'vector'"); - } - char *s0; _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s%s %s%s has invalid type '%s' (should be %s), " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"", - s_arg,*s_op=='F'?(*s_arg?" argument":" Argument"):(*s_arg?" operand":" Operand"), - s_type(arg)._data,sb_type._data,s0); - } - } - - // Check that imglist are not empty. - void check_list(char *const ss, char *const se, const char saved_char) { - if (!imglist) { - char *s0; _cimg_mp_strerr; - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>::%s: %s%s Invalid call with an empty image list, " - "in expression '%s'.", - pixel_type(),_cimg_mp_calling_function,s_op,*s_op?":":"",s0); - } - } - - static void mp_check_list(_cimg_math_parser& mp, const char *const funcname) { - if (!mp.imglist) - throw CImgArgumentException("[" cimg_appname "_math_parser] " - "CImg<%s>: Function '%s()': Invalid call with an empty image list.", - pixel_type(),funcname); - } - - // Insert constant value in memory. - unsigned int const_scalar(const double val) { - - // Search for built-in constant. - if (cimg::type::is_nan(val)) return _cimg_mp_slot_nan; - if (val==(double)(int)val) { - if (val>=0 && val<=10) return (unsigned int)val; - if (val<0 && val>=-5) return (unsigned int)(10 - val); - } - if (val==0.5) return 16; - - // Search for constant already requested before (in const cache). - unsigned int ind = ~0U; - if (constcache_size<1024) { - if (!constcache_size) { - constcache_vals.assign(16,1,1,1,0); - constcache_inds.assign(16,1,1,1,0); - *constcache_vals = val; - constcache_size = 1; - ind = 0; - } else { // Dichotomic search - const double val_beg = *constcache_vals, val_end = constcache_vals[constcache_size - 1]; - if (val_beg>=val) ind = 0; - else if (val_end==val) ind = constcache_size - 1; - else if (val_end=constcache_size || constcache_vals[ind]!=val) { - ++constcache_size; - if (constcache_size>constcache_vals._width) { - constcache_vals.resize(-200,1,1,1,0); - constcache_inds.resize(-200,1,1,1,0); - } - const int l = constcache_size - (int)ind - 1; - if (l>0) { - std::memmove(&constcache_vals[ind + 1],&constcache_vals[ind],l*sizeof(double)); - std::memmove(&constcache_inds[ind + 1],&constcache_inds[ind],l*sizeof(unsigned int)); - } - constcache_vals[ind] = val; - constcache_inds[ind] = 0; - } - } - if (constcache_inds[ind]) return constcache_inds[ind]; - } - - // Insert new constant in memory if necessary. - if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(-200,1,1,1,0); } - const unsigned int pos = mempos++; - mem[pos] = val; - memtype[pos] = 1; // Set constant property - if (ind!=~0U) constcache_inds[ind] = pos; - return pos; - } - - // Insert new scalar in memory. - unsigned int scalar() { - if (mempos>=mem._width) { mem.resize(-200,1,1,1,0); memtype.resize(mem._width,1,1,1,0); } - return mempos++; - } - - // Insert new vector of specified size in memory. - unsigned int vector(const unsigned int siz) { - if (mempos + siz>=mem._width) { - mem.resize(2*mem._width + siz,1,1,1,0); - memtype.resize(mem._width,1,1,1,0); - } - const unsigned int pos = mempos++; - mem[pos] = cimg::type::nan(); - memtype[pos] = siz + 1; - mempos+=siz; - return pos; - } - - // Insert new initialized vector. - unsigned int vector(const unsigned int siz, const double value) { - const unsigned int pos = vector(siz); - double *ptr = &mem[pos] + 1; - for (unsigned int i = 0; i::vector((ulongT)mp_vector_copy,pos,arg,siz).move_to(code); - return pos; - } - - // Set reserved status to all values of a vector. - void set_reserved_vector(const unsigned int arg) { - unsigned int siz = _cimg_mp_size(arg); - int *ptr = memtype.data(arg + 1); - while (siz-->0) *(ptr++) = -1; - } - - unsigned int scalar0(const mp_func op) { - const unsigned int pos = scalar(); - CImg::vector((ulongT)op,pos).move_to(code); - return_new_comp = true; - return pos; - } - - unsigned int scalar1(const mp_func op, const unsigned int arg1) { - const unsigned int pos = - arg1!=~0U && arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1) && op!=mp_copy?arg1: - ((return_new_comp = true), scalar()); - CImg::vector((ulongT)op,pos,arg1).move_to(code); - return pos; - } - - unsigned int scalar2(const mp_func op, const unsigned int arg1, const unsigned int arg2) { - const unsigned int pos = - arg1!=~0U && arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1: - arg2!=~0U && arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2: - ((return_new_comp = true), scalar()); - CImg::vector((ulongT)op,pos,arg1,arg2).move_to(code); - return pos; - } - - unsigned int scalar3(const mp_func op, - const unsigned int arg1, const unsigned int arg2, const unsigned int arg3) { - const unsigned int pos = - arg1!=~0U && arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1: - arg2!=~0U && arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2: - arg3!=~0U && arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3: - ((return_new_comp = true), scalar()); - CImg::vector((ulongT)op,pos,arg1,arg2,arg3).move_to(code); - return pos; - } - - unsigned int scalar4(const mp_func op, - const unsigned int arg1, const unsigned int arg2, const unsigned int arg3, - const unsigned int arg4) { - const unsigned int pos = - arg1!=~0U && arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1: - arg2!=~0U && arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2: - arg3!=~0U && arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3: - arg4!=~0U && arg4>_cimg_mp_slot_c && _cimg_mp_is_comp(arg4)?arg4: - ((return_new_comp = true), scalar()); - CImg::vector((ulongT)op,pos,arg1,arg2,arg3,arg4).move_to(code); - return pos; - } - - unsigned int scalar5(const mp_func op, - const unsigned int arg1, const unsigned int arg2, const unsigned int arg3, - const unsigned int arg4, const unsigned int arg5) { - const unsigned int pos = - arg1!=~0U && arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1: - arg2!=~0U && arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2: - arg3!=~0U && arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3: - arg4!=~0U && arg4>_cimg_mp_slot_c && _cimg_mp_is_comp(arg4)?arg4: - arg5!=~0U && arg5>_cimg_mp_slot_c && _cimg_mp_is_comp(arg5)?arg5: - ((return_new_comp = true), scalar()); - CImg::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5).move_to(code); - return pos; - } - - unsigned int scalar6(const mp_func op, - const unsigned int arg1, const unsigned int arg2, const unsigned int arg3, - const unsigned int arg4, const unsigned int arg5, const unsigned int arg6) { - const unsigned int pos = - arg1!=~0U && arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1: - arg2!=~0U && arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2: - arg3!=~0U && arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3: - arg4!=~0U && arg4>_cimg_mp_slot_c && _cimg_mp_is_comp(arg4)?arg4: - arg5!=~0U && arg5>_cimg_mp_slot_c && _cimg_mp_is_comp(arg5)?arg5: - arg6!=~0U && arg6>_cimg_mp_slot_c && _cimg_mp_is_comp(arg6)?arg6: - ((return_new_comp = true), scalar()); - CImg::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6).move_to(code); - return pos; - } - - unsigned int scalar7(const mp_func op, - const unsigned int arg1, const unsigned int arg2, const unsigned int arg3, - const unsigned int arg4, const unsigned int arg5, const unsigned int arg6, - const unsigned int arg7) { - const unsigned int pos = - arg1!=~0U && arg1>_cimg_mp_slot_c && _cimg_mp_is_comp(arg1)?arg1: - arg2!=~0U && arg2>_cimg_mp_slot_c && _cimg_mp_is_comp(arg2)?arg2: - arg3!=~0U && arg3>_cimg_mp_slot_c && _cimg_mp_is_comp(arg3)?arg3: - arg4!=~0U && arg4>_cimg_mp_slot_c && _cimg_mp_is_comp(arg4)?arg4: - arg5!=~0U && arg5>_cimg_mp_slot_c && _cimg_mp_is_comp(arg5)?arg5: - arg6!=~0U && arg6>_cimg_mp_slot_c && _cimg_mp_is_comp(arg6)?arg6: - arg7!=~0U && arg7>_cimg_mp_slot_c && _cimg_mp_is_comp(arg7)?arg7: - ((return_new_comp = true), scalar()); - CImg::vector((ulongT)op,pos,arg1,arg2,arg3,arg4,arg5,arg6,arg7).move_to(code); - return pos; - } - - void self_vector_s(const unsigned int pos, const mp_func op, const unsigned int arg1) { - const unsigned int siz = _cimg_mp_size(pos); - if (siz>24) CImg::vector((ulongT)mp_self_map_vector_s,pos,siz,(ulongT)op,arg1).move_to(code); - else { - code.insert(siz); - for (unsigned int k = 1; k<=siz; ++k) - CImg::vector((ulongT)op,pos + k,arg1).move_to(code[code._width - 1 - siz + k]); - } - } - - void self_vector_v(const unsigned int pos, const mp_func op, const unsigned int arg1) { - const unsigned int siz = _cimg_mp_size(pos); - if (siz>24) CImg::vector((ulongT)mp_self_map_vector_v,pos,siz,(ulongT)op,arg1).move_to(code); - else { - code.insert(siz); - for (unsigned int k = 1; k<=siz; ++k) - CImg::vector((ulongT)op,pos + k,arg1 + k).move_to(code[code._width - 1 - siz + k]); - } - } - - unsigned int vector1_v(const mp_func op, const unsigned int arg1) { - const unsigned int - siz = _cimg_mp_size(arg1), - pos = is_comp_vector(arg1)?arg1: - ((return_new_comp = true), vector(siz)); - if (siz>24) CImg::vector((ulongT)mp_vector_map_v,pos,siz,(ulongT)op,arg1).move_to(code); - else { - code.insert(siz); - for (unsigned int k = 1; k<=siz; ++k) - CImg::vector((ulongT)op,pos + k,arg1 + k).move_to(code[code._width - 1 - siz + k]); - } - return pos; - } - - unsigned int vector2_vv(const mp_func op, const unsigned int arg1, const unsigned int arg2) { - const unsigned int - siz = _cimg_mp_size(arg1), - pos = is_comp_vector(arg1)?arg1:is_comp_vector(arg2)?arg2: - ((return_new_comp = true), vector(siz)); - if (siz>24) CImg::vector((ulongT)mp_vector_map_vv,pos,siz,(ulongT)op,arg1,arg2).move_to(code); - else { - code.insert(siz); - for (unsigned int k = 1; k<=siz; ++k) - CImg::vector((ulongT)op,pos + k,arg1 + k,arg2 + k).move_to(code[code._width - 1 - siz + k]); - } - return pos; - } - - unsigned int vector2_vs(const mp_func op, const unsigned int arg1, const unsigned int arg2) { - const unsigned int - siz = _cimg_mp_size(arg1), - pos = is_comp_vector(arg1)?arg1: - ((return_new_comp = true), vector(siz)); - if (siz>24) CImg::vector((ulongT)mp_vector_map_vs,pos,siz,(ulongT)op,arg1,arg2).move_to(code); - else { - code.insert(siz); - for (unsigned int k = 1; k<=siz; ++k) - CImg::vector((ulongT)op,pos + k,arg1 + k,arg2).move_to(code[code._width - 1 - siz + k]); - } - return pos; - } - - unsigned int vector2_sv(const mp_func op, const unsigned int arg1, const unsigned int arg2) { - const unsigned int - siz = _cimg_mp_size(arg2), - pos = is_comp_vector(arg2)?arg2: - ((return_new_comp = true), vector(siz)); - if (siz>24) CImg::vector((ulongT)mp_vector_map_sv,pos,siz,(ulongT)op,arg1,arg2).move_to(code); - else { - code.insert(siz); - for (unsigned int k = 1; k<=siz; ++k) - CImg::vector((ulongT)op,pos + k,arg1,arg2 + k).move_to(code[code._width - 1 - siz + k]); - } - return pos; - } - - unsigned int vector3_vss(const mp_func op, const unsigned int arg1, const unsigned int arg2, - const unsigned int arg3) { - const unsigned int - siz = _cimg_mp_size(arg1), - pos = is_comp_vector(arg1)?arg1: - ((return_new_comp = true), vector(siz)); - if (siz>24) CImg::vector((ulongT)mp_vector_map_vss,pos,siz,(ulongT)op,arg1,arg2,arg3).move_to(code); - else { - code.insert(siz); - for (unsigned int k = 1; k<=siz; ++k) - CImg::vector((ulongT)op,pos + k,arg1 + k,arg2,arg3).move_to(code[code._width - 1 - siz + k]); - } - return pos; - } - - // Evaluation functions, known by the parser. - // Defining these functions 'static' ensures that sizeof(mp_func)==sizeof(ulongT), - // so we can store pointers to them directly in the opcode vectors. -#ifdef _mp_arg -#undef _mp_arg -#endif -#define _mp_arg(x) mp.mem[mp.opcode[x]] - - static double mp_abs(_cimg_math_parser& mp) { - return cimg::abs(_mp_arg(2)); - } - - static double mp_add(_cimg_math_parser& mp) { - return _mp_arg(2) + _mp_arg(3); - } - - static double mp_acos(_cimg_math_parser& mp) { - return std::acos(_mp_arg(2)); - } - - static double mp_acosh(_cimg_math_parser& mp) { - return cimg::acosh(_mp_arg(2)); - } - - static double mp_asinh(_cimg_math_parser& mp) { - return cimg::asinh(_mp_arg(2)); - } - - static double mp_atanh(_cimg_math_parser& mp) { - return cimg::atanh(_mp_arg(2)); - } - - static double mp_arg(_cimg_math_parser& mp) { - const int _ind = (int)_mp_arg(4); - const unsigned int - nb_args = (unsigned int)mp.opcode[2] - 4, - ind = _ind<0?_ind + nb_args:(unsigned int)_ind, - siz = (unsigned int)mp.opcode[3]; - if (siz>0) { - if (ind>=nb_args) std::memset(&_mp_arg(1) + 1,0,siz*sizeof(double)); - else std::memcpy(&_mp_arg(1) + 1,&_mp_arg(ind + 4) + 1,siz*sizeof(double)); - return cimg::type::nan(); - } - if (ind>=nb_args) return 0; - return _mp_arg(ind + 4); - } - - static double mp_arg0(_cimg_math_parser& mp) { - const int _ind = (int)_mp_arg(4); - const unsigned int - nb_args = (unsigned int)mp.opcode[2] - 4, - ind = _ind<0?_ind + nb_args:_ind + 1U, - siz = (unsigned int)mp.opcode[3]; - if (siz>0) { - if (ind>=nb_args) std::memset(&_mp_arg(1) + 1,0,siz*sizeof(double)); - else std::memcpy(&_mp_arg(1) + 1,&_mp_arg(ind + 4) + 1,siz*sizeof(double)); - return cimg::type::nan(); - } - if (ind>=nb_args) return 0; - return _mp_arg(ind + 4); - } - - static double mp_argkth(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2]; - const double val = mp_kth(mp); - for (unsigned int i = 4; ival) { val = _val; argval = i - 3; } - } - return (double)argval; - } - - static double mp_argmaxabs(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2]; - double val = _mp_arg(3), absval = cimg::abs(val); - unsigned int argval = 0; - for (unsigned int i = 4; iabsval) { val = _val; absval = _absval; argval = i - 3; } - } - return (double)argval; - } - - static double mp_asin(_cimg_math_parser& mp) { - return std::asin(_mp_arg(2)); - } - - static double mp_atan(_cimg_math_parser& mp) { - return std::atan(_mp_arg(2)); - } - - static double mp_atan2(_cimg_math_parser& mp) { - return std::atan2(_mp_arg(2),_mp_arg(3)); - } - - static double mp_avg(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2]; - double val = _mp_arg(3); - for (unsigned int i = 4; i>(unsigned int)_mp_arg(3)); - } - - static double mp_bitwise_xor(_cimg_math_parser& mp) { - return (double)((longT)_mp_arg(2) ^ (longT)_mp_arg(3)); - } - - static double mp_bool(_cimg_math_parser& mp) { - return (double)(bool)_mp_arg(2); - } - - static double mp_break(_cimg_math_parser& mp) { - mp.break_type = 1; - mp.p_code = mp.p_break - 1; - return cimg::type::nan(); - } - - static double mp_breakpoint(_cimg_math_parser& mp) { - cimg_abort_init; - cimg_abort_test; - cimg::unused(mp); - return cimg::type::nan(); - } - -#ifdef cimg_mp_func_run - static double mp_run(_cimg_math_parser& mp) { - const unsigned int nb_args = (unsigned int)(mp.opcode[2] - 3)/2; - CImgList _str; - CImg it; - for (unsigned int n = 0; n string - const double *ptr = &_mp_arg(3 + 2*n) + 1; - unsigned int l = 0; - while (l(ptr,l,1,1,1,true).move_to(_str); - } else { // Scalar argument -> number - it.assign(24); - cimg_snprintf(it,it._width,"%.17g",_mp_arg(3 + 2*n)); - CImg::string(it,false,true).move_to(_str); - } - } - CImg(1,1,1,1,0).move_to(_str); - CImg str = _str>'x'; - cimg_mp_func_run(str._data); - return cimg::type::nan(); - } -#endif - - static double mp_cbrt(_cimg_math_parser& mp) { - return cimg::cbrt(_mp_arg(2)); - } - - static double mp_ceil(_cimg_math_parser& mp) { - return std::ceil(_mp_arg(2)); - } - - static double mp_complex_abs(_cimg_math_parser& mp) { - return cimg::_hypot(_mp_arg(2),_mp_arg(3)); - } - - static double mp_complex_conj(_cimg_math_parser& mp) { - const double real = _mp_arg(2), imag = _mp_arg(3); - double *ptrd = &_mp_arg(1) + 1; - ptrd[0] = real; - ptrd[1] = -imag; - return cimg::type::nan(); - } - - static double mp_complex_div_sv(_cimg_math_parser& mp) { - const double - *ptr2 = &_mp_arg(3) + 1, - r1 = _mp_arg(2), - r2 = *(ptr2++), i2 = *ptr2; - double *ptrd = &_mp_arg(1) + 1; - const double denom = r2*r2 + i2*i2; - *(ptrd++) = r1*r2/denom; - *ptrd = -r1*i2/denom; - return cimg::type::nan(); - } - - static double mp_complex_div_vv(_cimg_math_parser& mp) { - const double - *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1, - r1 = *(ptr1++), i1 = *ptr1, - r2 = *(ptr2++), i2 = *ptr2; - double *ptrd = &_mp_arg(1) + 1; - const double denom = r2*r2 + i2*i2; - *(ptrd++) = (r1*r2 + i1*i2)/denom; - *ptrd = (r2*i1 - r1*i2)/denom; - return cimg::type::nan(); - } - - static double mp_complex_exp(_cimg_math_parser& mp) { - const double real = _mp_arg(2), imag = _mp_arg(3), exp_real = std::exp(real); - double *ptrd = &_mp_arg(1) + 1; - ptrd[0] = exp_real*std::cos(imag); - ptrd[1] = exp_real*std::sin(imag); - return cimg::type::nan(); - } - - static double mp_complex_log(_cimg_math_parser& mp) { - const double real = _mp_arg(2), imag = _mp_arg(3); - double *ptrd = &_mp_arg(1) + 1; - ptrd[0] = 0.5*std::log(real*real + imag*imag); - ptrd[1] = std::atan2(imag,real); - return cimg::type::nan(); - } - - static double mp_complex_mul(_cimg_math_parser& mp) { - const double - *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1, - r1 = *(ptr1++), i1 = *ptr1, - r2 = *(ptr2++), i2 = *ptr2; - double *ptrd = &_mp_arg(1) + 1; - *(ptrd++) = r1*r2 - i1*i2; - *(ptrd++) = r1*i2 + r2*i1; - return cimg::type::nan(); - } - - static void _mp_complex_pow(const double r1, const double i1, - const double r2, const double i2, - double *ptrd) { - double ro, io; - if (cimg::abs(i2)<1e-15) { // Exponent is real - if (cimg::abs(r1)<1e-15 && cimg::abs(i1)<1e-15) { - if (cimg::abs(r2)<1e-15) { ro = 1; io = 0; } - else ro = io = 0; - } else { - const double - mod1_2 = r1*r1 + i1*i1, - phi1 = std::atan2(i1,r1), - modo = std::pow(mod1_2,0.5*r2), - phio = r2*phi1; - ro = modo*std::cos(phio); - io = modo*std::sin(phio); - } - } else { // Exponent is complex - if (cimg::abs(r1)<1e-15 && cimg::abs(i1)<1e-15) ro = io = 0; - const double - mod1_2 = r1*r1 + i1*i1, - phi1 = std::atan2(i1,r1), - modo = std::pow(mod1_2,0.5*r2)*std::exp(-i2*phi1), - phio = r2*phi1 + 0.5*i2*std::log(mod1_2); - ro = modo*std::cos(phio); - io = modo*std::sin(phio); - } - *(ptrd++) = ro; - *ptrd = io; - } - - static double mp_complex_pow_ss(_cimg_math_parser& mp) { - const double val1 = _mp_arg(2), val2 = _mp_arg(3); - double *ptrd = &_mp_arg(1) + 1; - _mp_complex_pow(val1,0,val2,0,ptrd); - return cimg::type::nan(); - } - - static double mp_complex_pow_sv(_cimg_math_parser& mp) { - const double val1 = _mp_arg(2), *ptr2 = &_mp_arg(3) + 1; - double *ptrd = &_mp_arg(1) + 1; - _mp_complex_pow(val1,0,ptr2[0],ptr2[1],ptrd); - return cimg::type::nan(); - } - - static double mp_complex_pow_vs(_cimg_math_parser& mp) { - const double *ptr1 = &_mp_arg(2) + 1, val2 = _mp_arg(3); - double *ptrd = &_mp_arg(1) + 1; - _mp_complex_pow(ptr1[0],ptr1[1],val2,0,ptrd); - return cimg::type::nan(); - } - - static double mp_complex_pow_vv(_cimg_math_parser& mp) { - const double *ptr1 = &_mp_arg(2) + 1, *ptr2 = &_mp_arg(3) + 1; - double *ptrd = &_mp_arg(1) + 1; - _mp_complex_pow(ptr1[0],ptr1[1],ptr2[0],ptr2[1],ptrd); - return cimg::type::nan(); - } - - static double mp_complex_cos(_cimg_math_parser& mp) { - const double real = _mp_arg(2), imag = _mp_arg(3); - double *ptrd = &_mp_arg(1) + 1; - ptrd[0] = std::cos(real)*std::cosh(imag); - ptrd[1] = -std::sin(real)*std::sinh(imag); - return cimg::type::nan(); - } - - static double mp_complex_sin(_cimg_math_parser& mp) { - const double real = _mp_arg(2), imag = _mp_arg(3); - double *ptrd = &_mp_arg(1) + 1; - ptrd[0] = std::sin(real)*std::cosh(imag); - ptrd[1] = std::cos(real)*std::sinh(imag); - return cimg::type::nan(); - } - - static double mp_complex_tan(_cimg_math_parser& mp) { - const double real = _mp_arg(2), imag = _mp_arg(3), denom = std::cos(2*real) + std::cosh(2*imag); - double *ptrd = &_mp_arg(1) + 1; - ptrd[0] = std::sin(2*real)/denom; - ptrd[1] = std::sinh(2*imag)/denom; - return cimg::type::nan(); - } - - static double mp_complex_cosh(_cimg_math_parser& mp) { - const double real = _mp_arg(2), imag = _mp_arg(3); - double *ptrd = &_mp_arg(1) + 1; - ptrd[0] = std::cosh(real)*std::cos(imag); - ptrd[1] = std::sinh(real)*std::sin(imag); - return cimg::type::nan(); - } - - static double mp_complex_sinh(_cimg_math_parser& mp) { - const double real = _mp_arg(2), imag = _mp_arg(3); - double *ptrd = &_mp_arg(1) + 1; - ptrd[0] = std::sinh(real)*std::cos(imag); - ptrd[1] = std::cosh(real)*std::sin(imag); - return cimg::type::nan(); - } - - static double mp_complex_tanh(_cimg_math_parser& mp) { - const double real = _mp_arg(2), imag = _mp_arg(3), denom = std::cosh(2*real) + std::cos(2*imag); - double *ptrd = &_mp_arg(1) + 1; - ptrd[0] = std::sinh(2*real)/denom; - ptrd[1] = std::sin(2*imag)/denom; - return cimg::type::nan(); - } - - static double mp_continue(_cimg_math_parser& mp) { - mp.break_type = 2; - mp.p_code = mp.p_break - 1; - return cimg::type::nan(); - } - - static double mp_convolve(_cimg_math_parser &mp) { - return _mp_correlate(mp,true); - } - - static double mp_copy(_cimg_math_parser& mp) { - return _mp_arg(2); - } - - static double mp_correlate(_cimg_math_parser &mp) { - return _mp_correlate(mp,false); - } - - static double _mp_correlate(_cimg_math_parser &mp, bool is_convolve) { - double *ptrd = &_mp_arg(1) + 1; - const double *const ptrA = &_mp_arg(2) + 1, *const ptrM = &_mp_arg(7) + 1; - const unsigned int - wA = (unsigned int)mp.opcode[3], - hA = (unsigned int)mp.opcode[4], - dA = (unsigned int)mp.opcode[5], - sA = (unsigned int)mp.opcode[6], - wM = (unsigned int)mp.opcode[8], - hM = (unsigned int)mp.opcode[9], - dM = (unsigned int)mp.opcode[10], - sM = (unsigned int)mp.opcode[11], - boundary_conditions = (unsigned int)_mp_arg(12), - channel_mode = (unsigned int)mp.opcode[14]; - const bool - is_normalized = (bool)_mp_arg(13), - interpolation_type = (bool)_mp_arg(30); - const int - xcenter = mp.opcode[15]!=~0U?(int)_mp_arg(15):(int)(~0U>>1), - ycenter = mp.opcode[16]!=~0U?(int)_mp_arg(16):(int)(~0U>>1), - zcenter = mp.opcode[17]!=~0U?(int)_mp_arg(17):(int)(~0U>>1), - xstart = (int)mp.opcode[18], - ystart = (int)mp.opcode[19], - zstart = (int)mp.opcode[20], - xend = (int)mp.opcode[21], - yend = (int)mp.opcode[22], - zend = (int)mp.opcode[23]; - const float - xstride = (float)_mp_arg(24), - ystride = (float)_mp_arg(25), - zstride = (float)_mp_arg(26), - xdilation = (float)_mp_arg(27), - ydilation = (float)_mp_arg(28), - zdilation = (float)_mp_arg(29); - CImg res; - if (is_convolve) res = CImg(ptrA,wA,hA,dA,sA,true). - get_convolve(CImg(ptrM,wM,hM,dM,sM,true), - boundary_conditions,is_normalized,channel_mode, - xcenter,ycenter,zcenter, - xstart,ystart,zstart, - xend,yend,zend, - xstride,ystride,zstride, - xdilation,ydilation,zdilation, - interpolation_type); - else res = CImg(ptrA,wA,hA,dA,sA,true). - get_correlate(CImg(ptrM,wM,hM,dM,sM,true), - boundary_conditions,is_normalized,channel_mode, - xcenter,ycenter,zcenter, - xstart,ystart,zstart, - xend,yend,zend, - xstride,ystride,zstride, - xdilation,ydilation,zdilation, - interpolation_type); - CImg(ptrd,res._width,res._height,res._depth,res._spectrum,true) = res; - return cimg::type::nan(); - } - - static double mp_cos(_cimg_math_parser& mp) { - return std::cos(_mp_arg(2)); - } - - static double mp_cosh(_cimg_math_parser& mp) { - return std::cosh(_mp_arg(2)); - } - - static double mp_cov(_cimg_math_parser& mp) { - const unsigned int - _siz = (unsigned int)mp.opcode[4], - siz = std::max(_siz,1U), - off = _siz?1:0, - sizm1 = siz>1?siz - 1:1; - const CImg - A(&_mp_arg(2) + off,1,siz,1,1,true), - B(&_mp_arg(3) + off,1,siz,1,1,true); - const double - avgA = (unsigned int)mp.opcode[5]==~0U?A.mean():_mp_arg(5), - avgB = (unsigned int)mp.opcode[6]==~0U?B.mean():_mp_arg(6); - double res = 0; - cimg_forY(A,k) res+=(A[k] - avgA)*(B[k] - avgB); - return res/sizm1; - } - - static double mp_critical(_cimg_math_parser& mp) { - const ulongT g_target = mp.opcode[1]; - cimg_pragma_openmp(critical(mp_critical)) - { - for (const CImg *const p_end = ++mp.p_code + mp.opcode[2]; - mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - } - --mp.p_code; - return mp.mem[g_target]; - } - - static double mp_crop(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const int x = (int)_mp_arg(3), y = (int)_mp_arg(4), z = (int)_mp_arg(5), c = (int)_mp_arg(6); - const unsigned int - dx = (unsigned int)mp.opcode[7], - dy = (unsigned int)mp.opcode[8], - dz = (unsigned int)mp.opcode[9], - dc = (unsigned int)mp.opcode[10]; - const unsigned int boundary_conditions = (unsigned int)_mp_arg(11); - unsigned int ind = (unsigned int)mp.opcode[2]; - if (ind!=~0U) ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - const CImg &img = ind==~0U?mp.imgin:mp.imglist[ind]; - if (!img) std::memset(ptrd,0,dx*dy*dz*dc*sizeof(double)); - else CImg(ptrd,dx,dy,dz,dc,true) = img.get_crop(x,y,z,c, - x + dx - 1,y + dy - 1, - z + dz - 1,c + dc - 1, - boundary_conditions); - return cimg::type::nan(); - } - - static double mp_cross(_cimg_math_parser& mp) { - CImg - vout(&_mp_arg(1) + 1,1,3,1,1,true), - v1(&_mp_arg(2) + 1,1,3,1,1,true), - v2(&_mp_arg(3) + 1,1,3,1,1,true); - (vout = v1).cross(v2); - return cimg::type::nan(); - } - - static double mp_cut(_cimg_math_parser& mp) { - double val = _mp_arg(2), cmin = _mp_arg(3), cmax = _mp_arg(4); - return valcmax?cmax:val; - } - - static double mp_da_back_or_pop(_cimg_math_parser& mp) { - const bool is_pop = (bool)mp.opcode[4]; - const char *const s_op = is_pop?"da_pop":"da_back"; - mp_check_list(mp,s_op); - const unsigned int - dim = (unsigned int)mp.opcode[2], - ind = (unsigned int)cimg::mod((int)_mp_arg(3),mp.imglist.width()); - double *const ptrd = &_mp_arg(1) + (dim>1?1:0); - CImg &img = mp.imglist[ind]; - int siz = img?(int)img[img._height - 1]:0; - if (img && (img._width!=1 || img._depth!=1 || siz<0 || siz>img.height() - 1)) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function '%s()': " - "Specified image #%u of size (%d,%d,%d,%d) cannot be used as dynamic array%s.", - mp.imgout.pixel_type(),s_op,ind, - img.width(),img.height(),img.depth(),img.spectrum(), - img._width==1 && img._depth==1?"":" (contains invalid element counter)"); - if (!siz) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function '%s()': " - "Specified dynamic array #%u contains no elements.", - mp.imgout.pixel_type(),s_op,ind); - - double ret = cimg::type::nan(); - if (dim<1) ret = img[siz - 1]; // Scalar element - else cimg_forC(img,c) ptrd[c] = img(0,siz - 1,0,c); // Vector element - if (is_pop) { // Remove element from array - --siz; - if (img.height()>32 && siz<2*img.height()/3) // Reduce size of dynamic array - img.resize(1,std::max(2*siz + 1,32),1,-100,0); - img[img._height - 1] = (T)siz; - } - return ret; - } - - static double mp_da_freeze(_cimg_math_parser& mp) { - const char *const s_op = "da_freeze"; - mp_check_list(mp,s_op); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - int siz = img?(int)img[img._height - 1]:0; - if (img && (img._width!=1 || img._depth!=1 || siz<0 || siz>img.height() - 1)) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function '%s()': " - "Specified image #%u of size (%d,%d,%d,%d) cannot be used as dynamic array%s.", - mp.imgout.pixel_type(),s_op,ind, - img.width(),img.height(),img.depth(),img.spectrum(), - img._width==1 && img._depth==1?"":" (contains invalid element counter)"); - if (siz) img.resize(1,siz,1,-100,0,0); else img.assign(); - return cimg::type::nan(); - } - - static double mp_da_insert_or_push(_cimg_math_parser& mp) { - const char *const s_op = mp.opcode[3]==~0U?"da_push":"da_insert"; - mp_check_list(mp,s_op); - const unsigned int - dim = (unsigned int)mp.opcode[4], - _dim = std::max(1U,dim), - nb_elts = (unsigned int)mp.opcode[5] - 6, - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const int - siz = img?(int)img[img._height - 1]:0, - pos0 = mp.opcode[3]==~0U?siz:(int)_mp_arg(3), - pos = pos0<0?pos0 + siz:pos0; - - if (img && _dim!=img._spectrum) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function '%s()': " - "Element to insert has invalid size %u (should be %u).", - mp.imgout.pixel_type(),s_op,_dim,img._spectrum); - if (img && (img._width!=1 || img._depth!=1 || siz<0 || siz>img.height() - 1)) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function '%s()': " - "Specified image #%u of size (%d,%d,%d,%d) cannot be used as dynamic array%s.", - mp.imgout.pixel_type(),s_op,ind, - img.width(),img.height(),img.depth(),img.spectrum(), - img._width==1 && img._depth==1?"":" (contains invalid element counter)"); - if (pos<0 || pos>siz) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function '%s()': " - "Invalid position %d (not in range -%d...%d).", - mp.imgout.pixel_type(),s_op,pos0,siz,siz); - - if (siz + nb_elts + 1>=img._height) // Increase size of dynamic array, if necessary - img.resize(1,2*siz + nb_elts + 1,1,_dim,0); - - if (pos!=siz) // Move existing data in dynamic array - cimg_forC(img,c) std::memmove(img.data(0,pos + nb_elts,0,c),img.data(0,pos,0,c),(siz - pos)*sizeof(T)); - - if (!dim) // Scalar or vector1() elements - for (unsigned int k = 0; k1 - for (unsigned int k = 0; k::nan(); - } - - static double mp_da_remove(_cimg_math_parser& mp) { - mp_check_list(mp,"da_remove"); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - int siz = img?(int)img[img._height - 1]:0; - if (img && (img._width!=1 || img._depth!=1 || siz<0 || siz>img.height() - 1)) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'da_remove()': " - "Specified image #%u of size (%d,%d,%d,%d) cannot be used as dynamic array%s.", - mp.imgout.pixel_type(),ind, - img.width(),img.height(),img.depth(),img.spectrum(), - img._width==1 && img._depth==1?"":" (contains invalid element counter)"); - if (img._height<2) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'da_remove()': " - "Dynamic array is empty.", - mp.imgout.pixel_type()); - int - start0 = mp.opcode[3]==~0U?siz - 1:_mp_arg(3), - end0 = mp.opcode[4]==~0U?start0:_mp_arg(4), - start = start0<0?start0 + siz:start0, - end = end0<0?end0 + siz:end0; - if (start<0 || start>=siz || end<0 || end>=siz || start>end) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'da_remove()': " - "Invalid starting (%d) and ending (%d) positions " - "(not ordered, in range -%d...%d).", - mp.imgout.pixel_type(),start0,end0,siz,siz - 1); - if (end32 && siz<2*img.height()/3) // Reduce size of dynamic array - img.resize(1,std::max(2*siz + 1,32),1,-100,0); - img[img._height - 1] = (T)siz; - return cimg::type::nan(); - } - - static double mp_da_size(_cimg_math_parser& mp) { - mp_check_list(mp,"da_size"); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const int siz = img?(int)img[img._height - 1]:0; - if (img && (img._width!=1 || img._depth!=1 || siz<0 || siz>img.height() - 1)) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'da_size()': " - "Specified image #%u of size (%d,%d,%d,%d) cannot be used as dynamic array%s.", - mp.imgout.pixel_type(),ind, - img.width(),img.height(),img.depth(),img.spectrum(), - img._width==1 && img._depth==1?"":" (contains invalid element counter)"); - return siz; - } - - static double mp_date(_cimg_math_parser& mp) { - const unsigned int - siz_out = (unsigned int)mp.opcode[2], - siz_arg1 = (unsigned int)mp.opcode[4], - siz_arg2 = (unsigned int)mp.opcode[6]; - double *ptr_out = &_mp_arg(1) + (siz_out?1:0); - const double - *ptr_arg1 = siz_arg1==~0U?0:&_mp_arg(3) + (siz_arg1?1:0), - *ptr_arg2 = siz_arg2==~0U?0:&_mp_arg(5) + 1; - - if (!ptr_arg2) { // No filename specified - if (!siz_arg1) return cimg::date((unsigned int)*ptr_arg1); - if (siz_arg1==~0U) for (unsigned int k = 0; k::nan(); - } - - // Filename specified. - CImg ss(siz_arg2 + 1); - cimg_forX(ss,i) ss[i] = (char)ptr_arg2[i]; - ss.back() = 0; - if (!siz_arg1) return cimg::fdate(ss,(unsigned int)*ptr_arg1); - for (unsigned int k = 0; k::nan(); - } - - static double mp_debug(_cimg_math_parser& mp) { - CImg expr(mp.opcode[2] - 4); - { - const ulongT *ptrs = mp.opcode._data + 4; - cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++); - } - cimg::strellipsize(expr); - const ulongT g_target = mp.opcode[1]; - -#if cimg_use_openmp==0 - const unsigned int n_thread = 0; -#else - const unsigned int n_thread = omp_get_thread_num(); -#endif - cimg_pragma_openmp(critical(mp_debug)) - { - std::fprintf(cimg::output(), - "\n[" cimg_appname "_math_parser] %p[thread #%u]:%*c" - "Start debugging expression '%s', code length %u -> mem[%u] (memsize: %u)", - (void*)&mp,n_thread,mp.debug_indent,' ', - expr._data,(unsigned int)mp.opcode[3],(unsigned int)g_target,mp.mem._width); - std::fflush(cimg::output()); - mp.debug_indent+=3; - } - const CImg *const p_end = ++mp.p_code + mp.opcode[3]; - CImg _op; - for ( ; mp.p_code &op = *mp.p_code; - mp.opcode._data = op._data; - - _op.assign(1,op._height - 1); - const ulongT *ptrs = op._data + 1; - for (ulongT *ptrd = _op._data, *const ptrde = _op._data + _op._height; ptrd mem[%u] = %.17g", - (void*)&mp,n_thread,mp.debug_indent,' ', - (void*)mp.opcode._data,(void*)*mp.opcode,_op.value_string().data(), - (unsigned int)target,mp.mem[target]); - std::fflush(cimg::output()); - } - } - cimg_pragma_openmp(critical(mp_debug)) - { - mp.debug_indent-=3; - std::fprintf(cimg::output(), - "\n[" cimg_appname "_math_parser] %p[thread #%u]:%*c" - "End debugging expression '%s' -> mem[%u] = %.17g (memsize: %u)", - (void*)&mp,n_thread,mp.debug_indent,' ', - expr._data,(unsigned int)g_target,mp.mem[g_target],mp.mem._width); - std::fflush(cimg::output()); - } - --mp.p_code; - return mp.mem[g_target]; - } - - static double mp_decrement(_cimg_math_parser& mp) { - return _mp_arg(2) - 1; - } - - static double mp_deg2rad(_cimg_math_parser& mp) { - return _mp_arg(2)*cimg::PI/180; - } - - static double mp_det(_cimg_math_parser& mp) { - const double *ptrs = &_mp_arg(2) + 1; - const unsigned int k = (unsigned int)mp.opcode[3]; - return CImg(ptrs,k,k,1,1,true).det(); - } - - static double mp_diag(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2], siz = mp.opcode[2] - 3; - double *ptrd = &_mp_arg(1) + 1; - std::memset(ptrd,0,siz*siz*sizeof(double)); - for (unsigned int i = 3; i::nan(); - } - - static double mp_display_memory(_cimg_math_parser& mp) { - cimg::unused(mp); - std::fputc('\n',cimg::output()); - CImg title(128); - cimg_snprintf(title,title._width,"%s (%u)","[" cimg_appname "_math_parser] Memory snapshot",mp.mem._width); - mp.mem.display(title); - return cimg::type::nan(); - } - - static double mp_display(_cimg_math_parser& mp) { - const unsigned int - _siz = (unsigned int)mp.opcode[3], - siz = _siz?_siz:1; - const double *const ptr = &_mp_arg(1) + (_siz?1:0); - const int - w = (int)_mp_arg(4), - h = (int)_mp_arg(5), - d = (int)_mp_arg(6), - s = (int)_mp_arg(7); - CImg img; - if (w>0 && h>0 && d>0 && s>0) { - if ((unsigned int)w*h*d*s<=siz) img.assign(ptr,w,h,d,s,true); - else img.assign(ptr,siz).resize(w,h,d,s,-1); - } else img.assign(ptr,1,siz,1,1,true); - - CImg expr(mp.opcode[2] - 8); - const ulongT *ptrs = mp.opcode._data + 8; - cimg_for(expr,ptrd,char) *ptrd = (char)*(ptrs++); - ((CImg::string("[" cimg_appname "_math_parser] ",false,true),expr)>'x').move_to(expr); - cimg::strellipsize(expr); - std::fputc('\n',cimg::output()); - img.display(expr._data); - return cimg::type::nan(); - } - - static double mp_div(_cimg_math_parser& mp) { - return _mp_arg(2)/_mp_arg(3); - } - - static double mp_dot(_cimg_math_parser& mp) { - const unsigned int siz = (unsigned int)mp.opcode[4]; - return CImg(&_mp_arg(2) + 1,1,siz,1,1,true). - dot(CImg(&_mp_arg(3) + 1,1,siz,1,1,true)); - } - - static double mp_do(_cimg_math_parser& mp) { - const ulongT - mem_body = mp.opcode[1], - mem_cond = mp.opcode[2]; - const CImg - *const p_body = ++mp.p_code, - *const p_cond = p_body + mp.opcode[3], - *const p_end = p_cond + mp.opcode[4]; - const unsigned int vsiz = (unsigned int)mp.opcode[5]; - if (mp.opcode[6]) { // Set default value for result and condition if necessary - if (vsiz) CImg(&mp.mem[mem_body] + 1,vsiz,1,1,1,true).fill(cimg::type::nan()); - else mp.mem[mem_body] = cimg::type::nan(); - } - if (mp.opcode[7]) mp.mem[mem_cond] = 0; - - const unsigned int _break_type = mp.break_type; - mp.break_type = 0; - do { - for (mp.p_code = p_body; mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0; - for (mp.p_code = p_cond; mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0; - } while (mp.mem[mem_cond]); - mp.break_type = _break_type; - mp.p_code = p_end - 1; - return mp.mem[mem_body]; - } - - static double mp_draw(_cimg_math_parser& mp) { - const int x = (int)_mp_arg(4), y = (int)_mp_arg(5), z = (int)_mp_arg(6), c = (int)_mp_arg(7); - unsigned int ind = (unsigned int)mp.opcode[3]; - if (ind!=~0U) { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(3),mp.imglist.width()); - } - CImg &img = ind==~0U?mp.imgout:mp.imglist[ind]; - unsigned int - dx = (unsigned int)mp.opcode[8], - dy = (unsigned int)mp.opcode[9], - dz = (unsigned int)mp.opcode[10], - dc = (unsigned int)mp.opcode[11]; - dx = dx==~0U?img._width:(unsigned int)_mp_arg(8); - dy = dy==~0U?img._height:(unsigned int)_mp_arg(9); - dz = dz==~0U?img._depth:(unsigned int)_mp_arg(10); - dc = dc==~0U?img._spectrum:(unsigned int)_mp_arg(11); - - const ulongT sizS = mp.opcode[2]; - if (sizS<(ulongT)dx*dy*dz*dc) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'draw()': " - "Sprite dimension (%lu values) and specified sprite geometry (%u,%u,%u,%u) " - "(%lu values) do not match.", - mp.imgin.pixel_type(),sizS,dx,dy,dz,dc,(ulongT)dx*dy*dz*dc); - CImg S(&_mp_arg(1) + 1,dx,dy,dz,dc,true); - const float opacity = (float)_mp_arg(12); - - if (img._data) { - if (mp.opcode[13]!=~0U) { // Opacity mask specified - const ulongT sizM = mp.opcode[14]; - if (sizM<(ulongT)dx*dy*dz) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'draw()': " - "Mask dimension (%lu values) and specified sprite geometry (%u,%u,%u,%u) " - "(%lu values) do not match.", - mp.imgin.pixel_type(),sizS,dx,dy,dz,dc,(ulongT)dx*dy*dz*dc); - const CImg M(&_mp_arg(13) + 1,dx,dy,dz,(unsigned int)(sizM/(dx*dy*dz)),true); - img.draw_image(x,y,z,c,S,M,opacity,(float)_mp_arg(15)); - } else img.draw_image(x,y,z,c,S,opacity); - } - return cimg::type::nan(); - } - - static double mp_echo(_cimg_math_parser& mp) { - const unsigned int nb_args = (unsigned int)(mp.opcode[2] - 3)/2; - if (!nb_args) { std::fputc('\n',cimg::output()); return cimg::type::nan(); } // No arguments - CImgList _str; - CImg it; - for (unsigned int n = 0; n string - const double *ptr = &_mp_arg(3 + 2*n) + 1; - unsigned int l = 0; - while (l(ptr,l,1,1,1,true).move_to(_str); - } else { // Scalar argument -> number - it.assign(24); - cimg_snprintf(it,it._width,"%.17g",_mp_arg(3 + 2*n)); - CImg::string(it,false,true).move_to(_str); - } - } - CImg(1,1,1,1,0).move_to(_str); - const CImg str = _str>'x'; - std::fprintf(cimg::output(),"\n%s",str._data); - return cimg::type::nan(); - } - - static double mp_ellipse(_cimg_math_parser& mp) { - mp_check_list(mp,"ellipse"); - const unsigned int i_end = (unsigned int)mp.opcode[2]; - unsigned int ind = (unsigned int)mp.opcode[3]; - if (ind!=~0U) { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(3),mp.imglist.width()); - } - CImg &img = ind==~0U?mp.imgout:mp.imglist[ind]; - CImg color(img._spectrum,1,1,1,0); - bool is_invalid_arguments = false, is_outlined = false; - float r1 = 0, r2 = 0, angle = 0, opacity = 1; - unsigned int i = 4, pattern = ~0U; - int x0 = 0, y0 = 0; - if (i>=i_end) is_invalid_arguments = true; - else { - x0 = (int)cimg::round(_mp_arg(i++)); - if (i>=i_end) is_invalid_arguments = true; - else { - y0 = (int)cimg::round(_mp_arg(i++)); - if (i>=i_end) is_invalid_arguments = true; - else { - r1 = (float)_mp_arg(i++); - if (i>=i_end) r2 = r1; - else { - r2 = (float)_mp_arg(i++); - if (i args(i_end - 4); - cimg_forX(args,k) args[k] = _mp_arg(4 + k); - if (ind==~0U) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'ellipse()': " - "Invalid arguments '%s'. ", - mp.imgin.pixel_type(),args.value_string()._data); - else - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'ellipse()': " - "Invalid arguments '#%u%s%s'. ", - mp.imgin.pixel_type(),ind,args._width?",":"",args.value_string()._data); - } - return cimg::type::nan(); - } - - static double mp_eq(_cimg_math_parser& mp) { - return (double)(_mp_arg(2)==_mp_arg(3)); - } - - static double mp_erf(_cimg_math_parser& mp) { - return std::erf(_mp_arg(2)); - } - - static double mp_erfinv(_cimg_math_parser& mp) { - return cimg::erfinv(_mp_arg(2)); - } - - static double mp_exp(_cimg_math_parser& mp) { - return std::exp(_mp_arg(2)); - } - - static double mp_expr(_cimg_math_parser& mp) { - const unsigned int - sizs = (unsigned int)mp.opcode[3], - w = (unsigned int)mp.opcode[4], - h = (unsigned int)mp.opcode[5], - d = (unsigned int)mp.opcode[6], - s = (unsigned int)mp.opcode[7], - sizd = w*h*d*s; - const double *ptrs = &_mp_arg(2) + 1; - double *ptrd = &_mp_arg(1); - CImg ss(sizs + 1); - cimg_for_inX(ss,0,ss.width() - 1,i) ss[i] = (char)ptrs[i]; - ss.back() = 0; - if (!sizd) return CImg(w,h,d,s,0).eval(ss,0,0,0,0,&mp.imglist); // Scalar result - CImg(++ptrd,w,h,d,s,true) = CImg(w,h,d,s,0).fill(ss,true,true,&mp.imglist); - return cimg::type::nan(); - } - - static double mp_eye(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const unsigned int k = (unsigned int)mp.opcode[2]; - CImg(ptrd,k,k,1,1,true).identity_matrix(); - return cimg::type::nan(); - } - - static double mp_f2ui(_cimg_math_parser& mp) { - return (double)cimg::float2uint((float)_mp_arg(2)); - } - - static double mp_factorial(_cimg_math_parser& mp) { - return cimg::factorial((int)_mp_arg(2)); - } - - static double mp_fibonacci(_cimg_math_parser& mp) { - return cimg::fibonacci((int)_mp_arg(2)); - } - - static double mp_fill(_cimg_math_parser& mp) { - unsigned int siz = (unsigned int)mp.opcode[2]; - double - *ptrd = &_mp_arg(1), - *const ptrc = mp.opcode[3]!=~0U?&_mp_arg(3):0, - *const ptrs = &_mp_arg(4); - if (siz) ++ptrd; else ++siz; // Fill vector-valued slot - const CImg - *const p_body = ++mp.p_code, - *const p_end = p_body + mp.opcode[5]; - const unsigned int _break_type = mp.break_type; - mp.break_type = 0; - - unsigned int it = 0; - if (ptrc) { // Version with loop variable (3 arguments) - while (it_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0; - else ptrd[it] = *ptrs; - ++it; - } - *ptrc = (double)it; - } else // Version without loop variable (2 arguments) - while (it_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0; - else ptrd[it] = *ptrs; - ++it; - } - - mp.break_type = _break_type; - mp.p_code = p_end - 1; - return *ptrd; - } - - static double mp_find(_cimg_math_parser& mp) { - const int _step = (int)_mp_arg(6), step = _step?_step:-1; - const ulongT siz = (ulongT)mp.opcode[3]; - longT ind = (longT)(mp.opcode[5]!=_cimg_mp_slot_nan?_mp_arg(5):step>0?0:siz - 1); - if (ind<0 || ind>=(longT)siz) return -1.; - const double - *const ptrb = &_mp_arg(2) + 1, - *const ptre = ptrb + siz, - val = _mp_arg(4), - *ptr = ptrb + ind; - - // Forward search - if (step>0) { - while (ptr=ptre?-1.:(double)(ptr - ptrb); - } - - // Backward search. - while (ptr>=ptrb && *ptr!=val) ptr+=step; - return ptr0?0:siz1 - 1); - if (ind<0 || ind>=(longT)siz1) return -1.; - const double - *const ptr1b = &_mp_arg(2) + 1, - *const ptr1e = ptr1b + siz1, - *const ptr2b = &_mp_arg(4) + 1, - *const ptr2e = ptr2b + siz2, - *ptr1 = ptr1b + ind, - *p1 = 0, - *p2 = 0; - - // Forward search. - if (step>0) { - do { - while (ptr1=ptr1e) return -1.; - p1 = ptr1 + 1; - p2 = ptr2b + 1; - while (p1=ptr1b && *ptr1!=*ptr2b) ptr1+=step; - if (ptr1=ptr1b); - return p2 - *const p_init = ++mp.p_code, - *const p_cond = p_init + mp.opcode[4], - *const p_body = p_cond + mp.opcode[5], - *const p_post = p_body + mp.opcode[6], - *const p_end = p_post + mp.opcode[7]; - const unsigned int vsiz = (unsigned int)mp.opcode[2]; - bool is_cond = false; - if (mp.opcode[8]) { // Set default value for result and condition if necessary - if (vsiz) CImg(&mp.mem[mem_body] + 1,vsiz,1,1,1,true).fill(cimg::type::nan()); - else mp.mem[mem_body] = cimg::type::nan(); - } - if (mp.opcode[9]) mp.mem[mem_cond] = 0; - const unsigned int _break_type = mp.break_type; - mp.break_type = 0; - - for (mp.p_code = p_init; mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - - if (!mp.break_type) do { - for (mp.p_code = p_cond; mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - if (mp.break_type==1) break; - - is_cond = (bool)mp.mem[mem_cond]; - if (is_cond && !mp.break_type) { - for (mp.p_code = p_body; mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0; - - for (mp.p_code = p_post; mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0; - } - } while (is_cond); - - mp.break_type = _break_type; - mp.p_code = p_end - 1; - return mp.mem[mem_body]; - } - - static double mp_fsize(_cimg_math_parser& mp) { - const double *ptrs = &_mp_arg(2) + 1; - const ulongT siz = (ulongT)mp.opcode[3]; - CImg ss(siz + 1); - cimg_forX(ss,i) ss[i] = (char)ptrs[i]; - ss.back() = 0; - return (double)cimg::fsize(ss); - } - - static double mp_g(_cimg_math_parser& mp) { - cimg::unused(mp); - return cimg::grand(&mp.rng); - } - - static double mp_gauss(_cimg_math_parser& mp) { - const double x = _mp_arg(2), s = _mp_arg(3); - return std::exp(-x*x/(2*s*s))/(_mp_arg(4)?std::sqrt(2*s*s*cimg::PI):1); - } - -#ifdef cimg_mp_func_get - static double mp_get(_cimg_math_parser& mp) { - const double *ptrs = &_mp_arg(2) + 1; - double *ptrd = &_mp_arg(1); - const unsigned int - sizs = (unsigned int)mp.opcode[3], - sizd = (unsigned int)mp.opcode[4]; - const bool to_string = (bool)mp.opcode[5]; - CImg ss(sizs + 1); - cimg_for_inX(ss,0,ss.width() - 1,i) ss[i] = (char)ptrs[i]; - ss.back() = 0; - if (sizd) cimg_mp_func_get(ptrd + 1,sizd,to_string,ss._data); - else cimg_mp_func_get(ptrd,0,to_string,ss._data); - return cimg::type::nan(); - } -#endif - - static double mp_gcd(_cimg_math_parser& mp) { - return cimg::gcd((long)_mp_arg(2),(long)_mp_arg(3)); - } - -#ifdef cimg_mp_func_name - static double mp_name(_cimg_math_parser& mp) { - double *const ptr = &_mp_arg(1) + 1; - const unsigned int siz = (unsigned int)mp.opcode[3]; - unsigned int ind = (unsigned int)mp.opcode[2]; - if (ind==~0U) std::memset(ptr,0,siz*sizeof(double)); - else { - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - cimg_mp_func_name(ind,ptr,siz); - } - return cimg::type::nan(); - } -#endif - - static double mp_gt(_cimg_math_parser& mp) { - return (double)(_mp_arg(2)>_mp_arg(3)); - } - - static double mp_gte(_cimg_math_parser& mp) { - return (double)(_mp_arg(2)>=_mp_arg(3)); - } - - static double mp_i(_cimg_math_parser& mp) { - return (double)mp.imgin.atXYZC((int)mp.mem[_cimg_mp_slot_x],(int)mp.mem[_cimg_mp_slot_y], - (int)mp.mem[_cimg_mp_slot_z],(int)mp.mem[_cimg_mp_slot_c],(T)0); - } - - static double mp_if(_cimg_math_parser& mp) { - const bool is_cond = (bool)_mp_arg(2); - const ulongT - mem_left = mp.opcode[3], - mem_right = mp.opcode[4]; - const CImg - *const p_right = ++mp.p_code + mp.opcode[5], - *const p_end = p_right + mp.opcode[6]; - const unsigned int vtarget = (unsigned int)mp.opcode[1], vsiz = (unsigned int)mp.opcode[7]; - if (is_cond) for ( ; mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - else for (mp.p_code = p_right; mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - if (mp.p_code==mp.p_break) --mp.p_code; - else mp.p_code = p_end - 1; - if (vsiz) std::memcpy(&mp.mem[vtarget] + 1,&mp.mem[is_cond?mem_left:mem_right] + 1,sizeof(double)*vsiz); - return mp.mem[is_cond?mem_left:mem_right]; - } - - static double mp_image_d(_cimg_math_parser& mp) { - unsigned int ind = (unsigned int)mp.opcode[2]; - if (ind!=~0U) { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - } - const CImg &img = ind==~0U?mp.imgout:mp.imglist[ind]; - return (double)img.depth(); - } - - static double mp_image_display(_cimg_math_parser& mp) { - mp_check_list(mp,"display"); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - cimg::mutex(6); - CImg &img = mp.imglist[ind]; - CImg title(256); - std::fputc('\n',cimg::output()); - cimg_snprintf(title,title._width,"[ Image #%u ]",ind); - img.display(title); - cimg::mutex(6,0); - return cimg::type::nan(); - } - - static double mp_image_h(_cimg_math_parser& mp) { - unsigned int ind = (unsigned int)mp.opcode[2]; - if (ind!=~0U) { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - } - const CImg &img = ind==~0U?mp.imgout:mp.imglist[ind]; - return (double)img.height(); - } - - static double mp_image_median(_cimg_math_parser& mp) { - unsigned int ind = (unsigned int)mp.opcode[2]; - if (ind!=~0U) { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - } - const CImg &img = ind==~0U?mp.imgout:mp.imglist[ind]; - return (double)img.median(); - } - - static double mp_image_norm(_cimg_math_parser& mp) { - unsigned int ind = (unsigned int)mp.opcode[2]; - if (ind!=~0U) { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - } - const CImg &img = ind==~0U?mp.imgout:mp.imglist[ind]; - return (double)img.magnitude(); - } - - static double mp_image_print(_cimg_math_parser& mp) { - mp_check_list(mp,"print"); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - cimg::mutex(6); - CImg &img = mp.imglist[ind]; - CImg title(256); - std::fputc('\n',cimg::output()); - cimg_snprintf(title,title._width,"[ Image #%u ]",ind); - img.print(title); - cimg::mutex(6,0); - return cimg::type::nan(); - } - - static double mp_image_resize(_cimg_math_parser& mp) { - mp_check_list(mp,"resize"); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - cimg::mutex(6); - CImg &img = mp.imglist[ind]; - const double - _w = mp.opcode[3]==~0U?-100:_mp_arg(3), - _h = mp.opcode[4]==~0U?-100:_mp_arg(4), - _d = mp.opcode[5]==~0U?-100:_mp_arg(5), - _s = mp.opcode[6]==~0U?-100:_mp_arg(6); - const unsigned int - w = (unsigned int)(_w>=0?_w:-_w*img.width()/100), - h = (unsigned int)(_h>=0?_h:-_h*img.height()/100), - d = (unsigned int)(_d>=0?_d:-_d*img.depth()/100), - s = (unsigned int)(_s>=0?_s:-_s*img.spectrum()/100), - interp = (int)_mp_arg(7); - if (mp.is_fill && img._data==mp.imgout._data) { - cimg::mutex(6,0); - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'resize()': " - "Cannot both fill and resize image (%u,%u,%u,%u) " - "to new dimensions (%u,%u,%u,%u).", - img.pixel_type(),img._width,img._height,img._depth,img._spectrum,w,h,d,s); - } - const unsigned int - boundary = (int)_mp_arg(8); - const float - cx = (float)_mp_arg(9), - cy = (float)_mp_arg(10), - cz = (float)_mp_arg(11), - cc = (float)_mp_arg(12); - img.resize(w,h,d,s,interp,boundary,cx,cy,cz,cc); - cimg::mutex(6,0); - return cimg::type::nan(); - } - - static double mp_image_s(_cimg_math_parser& mp) { - unsigned int ind = (unsigned int)mp.opcode[2]; - if (ind!=~0U) { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - } - const CImg &img = ind==~0U?mp.imgout:mp.imglist[ind]; - return (double)img.spectrum(); - } - - static double mp_image_sort(_cimg_math_parser& mp) { - mp_check_list(mp,"sort"); - const bool is_increasing = (bool)_mp_arg(3); - const unsigned int - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()), - axis = (unsigned int)_mp_arg(4); - cimg::mutex(6); - CImg &img = mp.imglist[ind]; - img.sort(is_increasing, - axis==0 || axis=='x'?'x': - axis==1 || axis=='y'?'y': - axis==2 || axis=='z'?'z': - axis==3 || axis=='c'?'c':0); - cimg::mutex(6,0); - return cimg::type::nan(); - } - - static double mp_image_stats(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - unsigned int ind = (unsigned int)mp.opcode[2]; - if (ind==~0U) - CImg(ptrd,14,1,1,1,true) = mp.imgout.get_stats(); - else { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg(ptrd,14,1,1,1,true) = mp.imglist[ind].get_stats(); - } - return cimg::type::nan(); - } - - static double mp_image_w(_cimg_math_parser& mp) { - unsigned int ind = (unsigned int)mp.opcode[2]; - if (ind!=~0U) { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - } - const CImg &img = ind==~0U?mp.imgout:mp.imglist[ind]; - return (double)img.width(); - } - - static double mp_image_wh(_cimg_math_parser& mp) { - unsigned int ind = (unsigned int)mp.opcode[2]; - if (ind!=~0U) { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - } - const CImg &img = ind==~0U?mp.imgout:mp.imglist[ind]; - return (double)img.width()*img.height(); - } - - static double mp_image_whd(_cimg_math_parser& mp) { - unsigned int ind = (unsigned int)mp.opcode[2]; - if (ind!=~0U) { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - } - const CImg &img = ind==~0U?mp.imgout:mp.imglist[ind]; - return (double)img.width()*img.height()*img.depth(); - } - - static double mp_image_whds(_cimg_math_parser& mp) { - unsigned int ind = (unsigned int)mp.opcode[2]; - if (ind!=~0U) { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - } - const CImg &img = ind==~0U?mp.imgout:mp.imglist[ind]; - return (double)img.width()*img.height()*img.depth()*img.spectrum(); - } - - static double mp_increment(_cimg_math_parser& mp) { - return _mp_arg(2) + 1; - } - - static double mp_inrange(_cimg_math_parser& mp) { - const unsigned int sizd = (unsigned int)mp.opcode[2]; - const bool - include_m = (bool)_mp_arg(9), - include_M = (bool)_mp_arg(10); - if (!sizd) { // Scalar result - const double val = _mp_arg(3); - const double m = _mp_arg(5), M = _mp_arg(7); - if (M>=m) return (double)((include_m?(val>=m):(val>m)) && (include_M?(val<=M):(val=M):(val>M)) && (include_m?(val<=m):(val=m) - ptrd[k] = (double)((include_m?(val>=m):(val>m)) && (include_M?(val<=M):(val=M):(val>M)) && (include_m?(val<=m):(val::nan(); - } - - static double mp_int(_cimg_math_parser& mp) { - return (double)(longT)_mp_arg(2); - } - - static double mp_ioff(_cimg_math_parser& mp) { - const unsigned int - boundary_conditions = (unsigned int)_mp_arg(3); - const CImg &img = mp.imgin; - const longT - off = (longT)_mp_arg(2), - whds = (longT)img.size(); - if (off>=0 && off ss(siz + 1); - cimg_forX(ss,i) ss[i] = (char)ptrs[i]; - ss.back() = 0; - return (double)cimg::is_directory(ss); - } - - static double mp_isin(_cimg_math_parser& mp) { - const unsigned int - i_end = (unsigned int)mp.opcode[2], - siz_ref = (unsigned int)mp.opcode[4]; - bool res = false; - if (siz_ref) { // Reference value is a vector - const CImg ref(&_mp_arg(3) + 1,siz_ref,1,1,1,true); - for (unsigned int i = 5; i(&_mp_arg(i) + 1,siz,1,1,1,true)==ref) { res = true; break; } - } - } else { // Reference value is a scalar - const double ref = _mp_arg(3); - for (unsigned i = 5; i::is_inf(_mp_arg(2)); - } - - static double mp_isint(_cimg_math_parser& mp) { - return (double)((double)(longT)_mp_arg(2)==_mp_arg(2)); - } - - static double mp_isfile(_cimg_math_parser& mp) { - const unsigned int siz = (unsigned int)mp.opcode[3]; - const double *const ptrs = &_mp_arg(2) + (siz?1:0); - if (!siz) { char str[2] = { 0 }; *str = *ptrs; return (double)cimg::is_file(str); } - CImg ss(siz + 1); - cimg_forX(ss,i) ss[i] = (char)ptrs[i]; - ss.back() = 0; - return (double)cimg::is_file(ss); - } - - static double mp_isnan(_cimg_math_parser& mp) { - return (double)cimg::type::is_nan(_mp_arg(2)); - } - - static double mp_isvarname(_cimg_math_parser& mp) { - const unsigned int siz = (unsigned int)mp.opcode[3]; - const double *ptrs = &_mp_arg(2) + (siz?1:0); - if (!siz) { - const char c = (char)*ptrs; - return (c>='a' && c<='z') || (c>='A' && c<='Z') || c=='_'; - } - if (*ptrs>='0' && *ptrs<='9') return 0; - for (unsigned int k = 0; k &img = mp.imgin; - const double - x = _mp_arg(2), y = _mp_arg(3), - z = _mp_arg(4), c = _mp_arg(5); - switch (interpolation) { - case 2 : // Cubic interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const float - w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), s2 = 2.f*img.spectrum(), - mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), - mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2); - return (double)img._cubic_atXYZ(mx=img._spectrum?img._spectrum - 1:c)); - default : // Dirichlet - if (c<0 || c>=img._spectrum) return (T)0; - return (double)img.cubic_atXYZ((float)x,(float)y,(float)z,(int)c,(T)0); - } - case 1 : // Linear interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const float - w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), s2 = 2.f*img.spectrum(), - mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), - mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2); - return (double)img._linear_atXYZ(mx=img._spectrum?img._spectrum - 1:c)); - default : // Dirichlet - if (c<0 || c>=img._spectrum) return (T)0; - return (double)img.linear_atXYZ((float)x,(float)y,(float)z,(int)c,(T)0); - } - default : // Nearest neighbor interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const int - w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), s2 = 2*img.spectrum(), - mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2), - mz = cimg::mod((int)z,d2), mc = cimg::mod((int)c,s2); - return (double)img(mx &img = mp.imgin; - const longT - off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2), - whds = (longT)img.size(); - if (off>=0 && off &img = mp.imgin; - const double - ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], - oz = mp.mem[_cimg_mp_slot_z], oc = mp.mem[_cimg_mp_slot_c], - x = ox + _mp_arg(2), y = oy + _mp_arg(3), - z = oz + _mp_arg(4), c = oc + _mp_arg(5); - switch (interpolation) { - case 2 : // Cubic interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const float - w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), s2 = 2.f*img.spectrum(), - mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), - mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2); - return (double)img._cubic_atXYZ(mx=img._spectrum?img._spectrum - 1:c)); - default : // Dirichlet - if (c<0 || c>=img._spectrum) return (T)0; - return (double)img.cubic_atXYZ((float)x,(float)y,(float)z,(int)c,(T)0); - } - case 1 : // Linear interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const float - w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), s2 = 2.f*img.spectrum(), - mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), - mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2); - return (double)img._linear_atXYZ(mx=img._spectrum?img._spectrum - 1:c)); - default : // Dirichlet - if (c<0 || c>=img._spectrum) return (T)0; - return (double)img.linear_atXYZ((float)x,(float)y,(float)z,(int)c,(T)0); - } - default : // Nearest neighbor interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const int - w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), s2 = 2*img.spectrum(), - mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2), - mz = cimg::mod((int)z,d2), mc = cimg::mod((int)c,s2); - return (double)img(mx vals(i_end - 4); - double *p = vals.data(); - for (unsigned int i = 4; i &img = mp.imglist[indi]; - const int _step = (int)_mp_arg(5), step = _step?_step:-1; - const ulongT siz = (ulongT)img.size(); - longT ind = (longT)(mp.opcode[4]!=_cimg_mp_slot_nan?_mp_arg(4):step>0?0:siz - 1); - if (ind<0 || ind>=(longT)siz) return -1.; - const T - *const ptrb = img.data(), - *const ptre = img.end(), - *ptr = ptrb + ind; - const double val = _mp_arg(3); - - // Forward search - if (step>0) { - while (ptr=ptre?-1.:(double)(ptr - ptrb); - } - - // Backward search. - while (ptr>=ptrb && (double)*ptr!=val) ptr+=step; - return ptr &img = mp.imglist[indi]; - const int _step = (bool)_mp_arg(6), step = _step?_step:-1; - const ulongT - siz1 = (ulongT)img.size(), - siz2 = (ulongT)mp.opcode[4]; - longT ind = (longT)(mp.opcode[5]!=_cimg_mp_slot_nan?_mp_arg(5):step>0?0:siz1 - 1); - if (ind<0 || ind>=(longT)siz1) return -1.; - const T - *const ptr1b = img.data(), - *const ptr1e = ptr1b + siz1, - *ptr1 = ptr1b + ind, - *p1 = 0; - const double - *const ptr2b = &_mp_arg(3) + 1, - *const ptr2e = ptr2b + siz2, - *p2 = 0; - - // Forward search. - if (step>0) { - do { - while (ptr1=ptr1e) return -1.; - p1 = ptr1 + 1; - p2 = ptr2b + 1; - while (p1=ptr1b && *ptr1!=*ptr2b) ptr1+=step; - if (ptr1=ptr1b); - return p2 &img = mp.imglist[ind]; - const longT - off = (longT)_mp_arg(3), - whds = (longT)img.size(); - if (off>=0 && off &img = mp.imglist[ind]; - const double - x = _mp_arg(3), y = _mp_arg(4), - z = _mp_arg(5), c = _mp_arg(6); - switch (interpolation) { - case 2 : // Cubic interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const float - w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), s2 = 2.f*img.spectrum(), - mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), - mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2); - return (double)img._cubic_atXYZ(mx=img._spectrum?img._spectrum - 1:c)); - default : // Dirichlet - if (c<0 || c>=img._spectrum) return (T)0; - return (double)img.cubic_atXYZ((float)x,(float)y,(float)z,(int)c,(T)0); - } - case 1 : // Linear interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const float - w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), s2 = 2.f*img.spectrum(), - mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), - mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2); - return (double)img._linear_atXYZ(mx=img._spectrum?img._spectrum - 1:c)); - default : // Dirichlet - if (c<0 || c>=img._spectrum) return (T)0; - return (double)img.linear_atXYZ((float)x,(float)y,(float)z,(int)c,(T)0); - } - default : // Nearest neighbor interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const int - w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), s2 = 2*img.spectrum(), - mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2), - mz = cimg::mod((int)z,d2), mc = cimg::mod((int)c,s2); - return (double)img(mx &img = mp.imglist[ind]; - const longT - off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3), - whds = (longT)img.size(); - if (off>=0 && off &img = mp.imglist[ind]; - const double - ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], - oz = mp.mem[_cimg_mp_slot_z], oc = mp.mem[_cimg_mp_slot_c], - x = ox + _mp_arg(3), y = oy + _mp_arg(4), - z = oz + _mp_arg(5), c = oc + _mp_arg(6); - switch (interpolation) { - case 2 : // Cubic interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const float - w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), s2 = 2.f*img.spectrum(), - mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), - mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2); - return (double)img._cubic_atXYZ(mx=img._spectrum?img._spectrum - 1:c)); - default : // Dirichlet - if (c<0 || c>=img._spectrum) return (T)0; - return (double)img.cubic_atXYZ((float)x,(float)y,(float)z,(int)c,(T)0); - } - case 1 : // Linear interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const float - w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), s2 = 2.f*img.spectrum(), - mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), - mz = cimg::mod((float)z,d2), mc = cimg::mod((float)c,s2); - return (double)img._linear_atXYZ(mx=img._spectrum?img._spectrum - 1:c)); - default : // Dirichlet - if (c<0 || c>=img._spectrum) return (T)0; - return (double)img.linear_atXYZ((float)x,(float)y,(float)z,(int)c,(T)0); - } - default : // Nearest neighbor interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const int - w2 = 2*img.width(), h2 = 2*img.height(), d2 = 2*img.depth(), s2 = 2*img.spectrum(), - mx = cimg::mod((int)x,w2), my = cimg::mod((int)y,h2), - mz = cimg::mod((int)z,d2), mc = cimg::mod((int)c,s2); - return (double)img(mx::vector(mp.imglist[ind].median()).move_to(mp.list_median[ind]); - return *mp.list_median[ind]; - } - - static double mp_list_norm(_cimg_math_parser& mp) { - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - if (!mp.list_norm) mp.list_norm.assign(mp.imglist._width); - if (!mp.list_norm[ind]) CImg::vector(mp.imglist[ind].magnitude()).move_to(mp.list_norm[ind]); - return *mp.list_norm[ind]; - } - - static double mp_list_set_ioff(_cimg_math_parser& mp) { - if (!mp.imglist.width()) return cimg::type::nan(); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const longT - off = (longT)_mp_arg(3), - whds = (longT)img.size(); - const double val = _mp_arg(1); - if (off>=0 && off::nan(); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const int - x = (int)_mp_arg(3), y = (int)_mp_arg(4), - z = (int)_mp_arg(5), c = (int)_mp_arg(6); - const double val = _mp_arg(1); - if (x>=0 && x=0 && y=0 && z=0 && c::nan(); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const int - ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y], - oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c]; - const longT - off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3), - whds = (longT)img.size(); - const double val = _mp_arg(1); - if (off>=0 && off::nan(); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const double - ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], - oz = mp.mem[_cimg_mp_slot_z], oc = mp.mem[_cimg_mp_slot_c]; - const int - x = (int)(ox + _mp_arg(3)), y = (int)(oy + _mp_arg(4)), - z = (int)(oz + _mp_arg(5)), c = (int)(oc + _mp_arg(6)); - const double val = _mp_arg(1); - if (x>=0 && x=0 && y=0 && z=0 && c::nan(); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const longT - off = (longT)_mp_arg(3), - whd = (longT)img.width()*img.height()*img.depth(); - const T val = (T)_mp_arg(1); - if (off>=0 && off::nan(); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const longT - off = (longT)_mp_arg(3), - whd = (longT)img.width()*img.height()*img.depth(); - const double *ptrs = &_mp_arg(1) + 1; - if (off>=0 && off::nan(); - } - - static double mp_list_set_Ixyz_s(_cimg_math_parser& mp) { - if (!mp.imglist.width()) return cimg::type::nan(); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const int - x = (int)_mp_arg(3), - y = (int)_mp_arg(4), - z = (int)_mp_arg(5); - const T val = (T)_mp_arg(1); - if (x>=0 && x=0 && y=0 && z::nan(); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const int - x = (int)_mp_arg(3), - y = (int)_mp_arg(4), - z = (int)_mp_arg(5); - const double *ptrs = &_mp_arg(1) + 1; - if (x>=0 && x=0 && y=0 && z::nan(); - } - - static double mp_list_set_Joff_s(_cimg_math_parser& mp) { - if (!mp.imglist.width()) return cimg::type::nan(); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const int - ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y], - oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c]; - const longT - off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3), - whd = (longT)img.width()*img.height()*img.depth(); - const T val = (T)_mp_arg(1); - if (off>=0 && off::nan(); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const int - ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y], - oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c]; - const longT - off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(3), - whd = (longT)img.width()*img.height()*img.depth(); - const double *ptrs = &_mp_arg(1) + 1; - if (off>=0 && off::nan(); - } - - static double mp_list_set_Jxyz_s(_cimg_math_parser& mp) { - if (!mp.imglist.width()) return cimg::type::nan(); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const double ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z]; - const int - x = (int)(ox + _mp_arg(3)), - y = (int)(oy + _mp_arg(4)), - z = (int)(oz + _mp_arg(5)); - const T val = (T)_mp_arg(1); - if (x>=0 && x=0 && y=0 && z::nan(); - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - CImg &img = mp.imglist[ind]; - const double ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z]; - const int - x = (int)(ox + _mp_arg(3)), - y = (int)(oy + _mp_arg(4)), - z = (int)(oz + _mp_arg(5)); - const double *ptrs = &_mp_arg(1) + 1; - if (x>=0 && x=0 && y=0 && z::nan(); - } - - static double mp_list_spectrum(_cimg_math_parser& mp) { - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - return (double)mp.imglist[ind]._spectrum; - } - - static double mp_list_stats(_cimg_math_parser& mp) { - const unsigned int - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()), - k = (unsigned int)mp.opcode[3]; - if (!mp.list_stats) mp.list_stats.assign(mp.imglist._width); - if (!mp.list_stats[ind]) mp.list_stats[ind].assign(1,14,1,1,0).fill(mp.imglist[ind].get_stats(),false); - return mp.list_stats(ind,k); - } - - static double mp_list_wh(_cimg_math_parser& mp) { - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - return (double)mp.imglist[ind]._width*mp.imglist[ind]._height; - } - - static double mp_list_whd(_cimg_math_parser& mp) { - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - return (double)mp.imglist[ind]._width*mp.imglist[ind]._height*mp.imglist[ind]._depth; - } - - static double mp_list_whds(_cimg_math_parser& mp) { - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - return (double)mp.imglist[ind]._width*mp.imglist[ind]._height*mp.imglist[ind]._depth*mp.imglist[ind]._spectrum; - } - - static double mp_list_width(_cimg_math_parser& mp) { - const unsigned int ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()); - return (double)mp.imglist[ind]._width; - } - - static double mp_list_Ioff(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const unsigned int - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()), - boundary_conditions = (unsigned int)_mp_arg(4), - vsiz = (unsigned int)mp.opcode[5]; - const CImg &img = mp.imglist[ind]; - const longT - off = (longT)_mp_arg(3), - whd = (longT)img.width()*img.height()*img.depth(); - const T *ptrs; - if (off>=0 && off::nan(); - } - if (img._data) switch (boundary_conditions) { - case 3 : { // Mirror - const longT whd2 = 2*whd, moff = cimg::mod(off,whd2); - ptrs = &img[moff::nan(); - } - case 2 : // Periodic - ptrs = &img[cimg::mod(off,whd)]; - cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; } - return cimg::type::nan(); - case 1 : // Neumann - ptrs = off<0?&img[0]:&img[whd - 1]; - cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; } - return cimg::type::nan(); - default : // Dirichlet - std::memset(ptrd,0,vsiz*sizeof(double)); - return cimg::type::nan(); - } - std::memset(ptrd,0,vsiz*sizeof(double)); - return cimg::type::nan(); - } - - static double mp_list_Ixyz(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const unsigned int - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()), - interpolation = (unsigned int)_mp_arg(6), - boundary_conditions = (unsigned int)_mp_arg(7), - vsiz = (unsigned int)mp.opcode[8]; - const CImg &img = mp.imglist[ind]; - const double x = _mp_arg(3), y = _mp_arg(4), z = _mp_arg(5); - const ulongT whd = (ulongT)img._width*img._height*img._depth; - const T *ptrs; - switch (interpolation) { - case 2 : // Cubic interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const float - w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), - mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2), - cx = mx::nan(); - } - - static double mp_list_Joff(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const unsigned int - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()), - boundary_conditions = (unsigned int)_mp_arg(4), - vsiz = (unsigned int)mp.opcode[5]; - const int - ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y], oz = (int)mp.mem[_cimg_mp_slot_z]; - const CImg &img = mp.imglist[ind]; - const longT - off = img.offset(ox,oy,oz) + (longT)_mp_arg(3), - whd = (longT)img.width()*img.height()*img.depth(); - const T *ptrs; - if (off>=0 && off::nan(); - } - if (img._data) switch (boundary_conditions) { - case 3 : { // Mirror - const longT whd2 = 2*whd, moff = cimg::mod(off,whd2); - ptrs = &img[moff::nan(); - } - case 2 : // Periodic - ptrs = &img[cimg::mod(off,whd)]; - cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; } - return cimg::type::nan(); - case 1 : // Neumann - ptrs = off<0?&img[0]:&img[whd - 1]; - cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; } - return cimg::type::nan(); - default : // Dirichlet - std::memset(ptrd,0,vsiz*sizeof(double)); - return cimg::type::nan(); - } - std::memset(ptrd,0,vsiz*sizeof(double)); - return cimg::type::nan(); - } - - static double mp_list_Jxyz(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const unsigned int - ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width()), - interpolation = (unsigned int)_mp_arg(6), - boundary_conditions = (unsigned int)_mp_arg(7), - vsiz = (unsigned int)mp.opcode[8]; - const CImg &img = mp.imglist[ind]; - const double - ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z], - x = ox + _mp_arg(3), y = oy + _mp_arg(4), z = oz + _mp_arg(5); - const ulongT whd = (ulongT)img._width*img._height*img._depth; - const T *ptrs; - switch (interpolation) { - case 2 : // Cubic interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const float - w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), - mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2), - cx = mx::nan(); - } - - static double mp_log(_cimg_math_parser& mp) { - return std::log(_mp_arg(2)); - } - - static double mp_log10(_cimg_math_parser& mp) { - return std::log10(_mp_arg(2)); - } - - static double mp_log2(_cimg_math_parser& mp) { - return cimg::log2(_mp_arg(2)); - } - - static double mp_logical_and(_cimg_math_parser& mp) { - const bool val_left = (bool)_mp_arg(2); - const CImg *const p_end = ++mp.p_code + mp.opcode[4]; - if (!val_left) { mp.p_code = p_end - 1; return 0; } - const ulongT mem_right = mp.opcode[3]; - for ( ; mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - --mp.p_code; - return (double)(bool)mp.mem[mem_right]; - } - - static double mp_logical_not(_cimg_math_parser& mp) { - return (double)!_mp_arg(2); - } - - static double mp_logical_or(_cimg_math_parser& mp) { - const bool val_left = (bool)_mp_arg(2); - const CImg *const p_end = ++mp.p_code + mp.opcode[4]; - if (val_left) { mp.p_code = p_end - 1; return 1; } - const ulongT mem_right = mp.opcode[3]; - for ( ; mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - --mp.p_code; - return (double)(bool)mp.mem[mem_right]; - } - - static double mp_lowercase(_cimg_math_parser& mp) { - return cimg::lowercase(_mp_arg(2)); - } - - static double mp_lt(_cimg_math_parser& mp) { - return (double)(_mp_arg(2)<_mp_arg(3)); - } - - static double mp_lte(_cimg_math_parser& mp) { - return (double)(_mp_arg(2)<=_mp_arg(3)); - } - - static double mp_matrix_eig(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const double *ptr1 = &_mp_arg(2) + 1; - const unsigned int k = (unsigned int)mp.opcode[3]; - CImg val, vec; - CImg(ptr1,k,k,1,1,true).symmetric_eigen(val,vec); - CImg(ptrd,1,k,1,1,true) = val; - CImg(ptrd + k,k,k,1,1,true) = vec.get_transpose(); - return cimg::type::nan(); - } - - static double mp_matrix_invert(_cimg_math_parser& mp) { - double *const ptrd = &_mp_arg(1) + 1; - const double *const ptr1 = &_mp_arg(2) + 1; - const unsigned int - w = (unsigned int)mp.opcode[3], - h = (unsigned int)mp.opcode[4]; - const bool use_LU = (bool)_mp_arg(5); - const float lambda = (float)_mp_arg(6); - CImg(ptrd,h,w,1,1,true) = CImg(ptr1,w,h,1,1,true).get_invert(use_LU,lambda); - return cimg::type::nan(); - } - - static double mp_matrix_mul(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const double - *ptr1 = &_mp_arg(2) + 1, - *ptr2 = &_mp_arg(3) + 1; - const unsigned int - k = (unsigned int)mp.opcode[4], - l = (unsigned int)mp.opcode[5], - m = (unsigned int)mp.opcode[6]; - CImg(ptrd,m,k,1,1,true) = CImg(ptr1,l,k,1,1,true)*CImg(ptr2,m,l,1,1,true); - return cimg::type::nan(); - } - - static double mp_matrix_svd(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const double *ptr1 = &_mp_arg(2) + 1; - const unsigned int - k = (unsigned int)mp.opcode[3], - l = (unsigned int)mp.opcode[4]; - CImg U, S, V; - CImg(ptr1,k,l,1,1,true).SVD(U,S,V); - CImg(ptrd,k,l,1,1,true) = U; - CImg(ptrd + k*l,1,k,1,1,true) = S; - CImg(ptrd + k*l + k,k,k,1,1,true) = V; - return cimg::type::nan(); - } - - static double mp_max(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2]; - double val = _mp_arg(3); - for (unsigned int i = 4; iabsval) { val = _val; absval = _absval; } - } - return val; - } - - static double* _mp_memcopy_double(_cimg_math_parser& mp, const unsigned int ind, const ulongT *const p_ref, - const longT siz, const long inc) { - const longT - off = *p_ref?p_ref[1] + (longT)mp.mem[(longT)p_ref[2]] + 1:ind, - eoff = off + (siz - 1)*inc; - if (off<0 || eoff>=mp.mem.width()) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'copy()': " - "Out-of-bounds variable pointer " - "(length: %ld, increment: %ld, offset start: %ld, " - "offset end: %ld, offset max: %u).", - mp.imgin.pixel_type(),siz,inc,off,eoff,mp.mem._width - 1); - return &mp.mem[off]; - } - - static float* _mp_memcopy_float(_cimg_math_parser& mp, const ulongT *const p_ref, - const longT siz, const long inc, const bool is_out) { - const unsigned ind = (unsigned int)p_ref[1]; - const CImg &img = is_out? - (ind==~0U?mp.imgout:mp.imglist[cimg::mod((int)mp.mem[ind],mp.imglist.width())]): - (ind==~0U?mp.imgin:mp.imglist[cimg::mod((int)mp.mem[ind],mp.imglist.width())]); - const bool is_relative = (bool)p_ref[2]; - int ox, oy, oz, oc; - longT off = 0; - if (is_relative) { - ox = (int)mp.mem[_cimg_mp_slot_x]; - oy = (int)mp.mem[_cimg_mp_slot_y]; - oz = (int)mp.mem[_cimg_mp_slot_z]; - oc = (int)mp.mem[_cimg_mp_slot_c]; - off = img.offset(ox,oy,oz,oc); - } - if ((*p_ref)%2) { - const int - x = (int)mp.mem[p_ref[3]], - y = (int)mp.mem[p_ref[4]], - z = (int)mp.mem[p_ref[5]], - c = *p_ref==5?0:(int)mp.mem[p_ref[6]]; - off+=img.offset(x,y,z,c); - } else off+=(longT)mp.mem[p_ref[3]]; - const longT eoff = off + (siz - 1)*inc; - if (off<0 || eoff>=(longT)img.size()) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'copy()': " - "Out-of-bounds image pointer " - "(length: %ld, increment: %ld, offset start: %ld, " - "offset end: %ld, offset max: %lu).", - mp.imgin.pixel_type(),siz,inc,off,eoff,img.size() - 1); - return (float*)&img[off]; - } - - static double mp_memcopy(_cimg_math_parser& mp) { - longT siz = (longT)_mp_arg(4); - const longT inc_d = (longT)_mp_arg(5), inc_s = (longT)_mp_arg(6); - const float - _opacity = (float)_mp_arg(7), - opacity = (float)cimg::abs(_opacity), - omopacity = 1 - std::max(_opacity,0.f); - if (siz>0) { - const bool - is_doubled = mp.opcode[8]<=1, - is_doubles = mp.opcode[15]<=1; - if (is_doubled && is_doubles) { // (double*) <- (double*) - double *ptrd = _mp_memcopy_double(mp,(unsigned int)mp.opcode[2],&mp.opcode[8],siz,inc_d); - const double *ptrs = _mp_memcopy_double(mp,(unsigned int)mp.opcode[3],&mp.opcode[15],siz,inc_s); - if (inc_d==1 && inc_s==1 && _opacity>=1) { - if (ptrs + siz - 1ptrd + siz - 1) std::memcpy(ptrd,ptrs,siz*sizeof(double)); - else std::memmove(ptrd,ptrs,siz*sizeof(double)); - } else { - if (ptrs + (siz - 1)*inc_sptrd + (siz - 1)*inc_d) { - if (_opacity>=1) while (siz-->0) { *ptrd = *ptrs; ptrd+=inc_d; ptrs+=inc_s; } - else while (siz-->0) { *ptrd = omopacity**ptrd + opacity**ptrs; ptrd+=inc_d; ptrs+=inc_s; } - } else { // Overlapping buffers - CImg buf((unsigned int)siz); - cimg_for(buf,ptr,double) { *ptr = *ptrs; ptrs+=inc_s; } - ptrs = buf; - if (_opacity>=1) while (siz-->0) { *ptrd = *(ptrs++); ptrd+=inc_d; } - else while (siz-->0) { *ptrd = omopacity**ptrd + opacity**(ptrs++); ptrd+=inc_d; } - } - } - } else if (is_doubled && !is_doubles) { // (double*) <- (float*) - double *ptrd = _mp_memcopy_double(mp,(unsigned int)mp.opcode[2],&mp.opcode[8],siz,inc_d); - const float *ptrs = _mp_memcopy_float(mp,&mp.opcode[15],siz,inc_s,false); - if (_opacity>=1) while (siz-->0) { *ptrd = *ptrs; ptrd+=inc_d; ptrs+=inc_s; } - else while (siz-->0) { *ptrd = omopacity**ptrd + _opacity**ptrs; ptrd+=inc_d; ptrs+=inc_s; } - } else if (!is_doubled && is_doubles) { // (float*) <- (double*) - float *ptrd = _mp_memcopy_float(mp,&mp.opcode[8],siz,inc_d,true); - const double *ptrs = _mp_memcopy_double(mp,(unsigned int)mp.opcode[3],&mp.opcode[15],siz,inc_s); - if (_opacity>=1) while (siz-->0) { *ptrd = (float)*ptrs; ptrd+=inc_d; ptrs+=inc_s; } - else while (siz-->0) { *ptrd = (float)(omopacity**ptrd + opacity**ptrs); ptrd+=inc_d; ptrs+=inc_s; } - } else { // (float*) <- (float*) - float *ptrd = _mp_memcopy_float(mp,&mp.opcode[8],siz,inc_d,true); - const float *ptrs = _mp_memcopy_float(mp,&mp.opcode[15],siz,inc_s,false); - if (inc_d==1 && inc_s==1 && _opacity>=1) { - if (ptrs + siz - 1ptrd + siz - 1) std::memcpy(ptrd,ptrs,siz*sizeof(float)); - else std::memmove(ptrd,ptrs,siz*sizeof(float)); - } else { - if (ptrs + (siz - 1)*inc_sptrd + (siz - 1)*inc_d) { - if (_opacity>=1) while (siz-->0) { *ptrd = *ptrs; ptrd+=inc_d; ptrs+=inc_s; } - else while (siz-->0) { *ptrd = omopacity**ptrd + opacity**ptrs; ptrd+=inc_d; ptrs+=inc_s; } - } else { // Overlapping buffers - CImg buf((unsigned int)siz); - cimg_for(buf,ptr,float) { *ptr = *ptrs; ptrs+=inc_s; } - ptrs = buf; - if (_opacity>=1) while (siz-->0) { *ptrd = *(ptrs++); ptrd+=inc_d; } - else while (siz-->0) { *ptrd = omopacity**ptrd + opacity**(ptrs++); ptrd+=inc_d; } - } - } - } - } - return _mp_arg(1); - } - - static double mp_min(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2]; - double val = _mp_arg(3); - for (unsigned int i = 4; i vals(i_end - 3); - double *p = vals.data(); - for (unsigned int i = 3; i(ptrd,wS,wD,1,1,true) = CImg(ptrS,wS,hS,1,1,false). - project_matrix(CImg(ptrD,wD,hS,1,1,true),method,max_iter,max_residual); - return cimg::type::nan(); - } - - static double mp_mse(_cimg_math_parser& mp) { - const unsigned int - _siz = (unsigned int)mp.opcode[4], - siz = std::max(_siz,1U), - off = _siz?1:0; - return CImg(&_mp_arg(2) + off,1,siz,1,1,true). - MSE(CImg(&_mp_arg(3) + off,1,siz,1,1,true)); - } - - static double mp_mul(_cimg_math_parser& mp) { - return _mp_arg(2)*_mp_arg(3); - } - - static double mp_mul2(_cimg_math_parser& mp) { - return _mp_arg(2)*_mp_arg(3)*_mp_arg(4); - } - - static double mp_neq(_cimg_math_parser& mp) { - return (double)(_mp_arg(2)!=_mp_arg(3)); - } - - static double mp_norm0(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2]; - switch (i_end - 3) { - case 1 : return _mp_arg(3)!=0; - case 2 : return (_mp_arg(3)!=0) + (_mp_arg(4)!=0); - } - double res = 0; - for (unsigned int i = 3; ires) res = val; - } - return res; - } - - static double mp_normp(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2]; - if (i_end==4) return cimg::abs(_mp_arg(3)); - const double p = (double)mp.opcode[3]; - double res = 0; - for (unsigned int i = 4; i0?res:0.; - } - - static double mp_permutations(_cimg_math_parser& mp) { - return cimg::permutations((int)_mp_arg(2),(int)_mp_arg(3),(bool)_mp_arg(4)); - } - - static double mp_polygon(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2]; - unsigned int ind = (unsigned int)mp.opcode[3]; - if (ind!=~0U) { - if (!mp.imglist.width()) return cimg::type::nan(); - ind = (unsigned int)cimg::mod((int)_mp_arg(3),mp.imglist.width()); - } - CImg &img = ind==~0U?mp.imgout:mp.imglist[ind]; - bool is_invalid_arguments = i_end<=4, is_outlined = false; - if (!is_invalid_arguments) { - int nbv = (int)_mp_arg(4); - if (!nbv) is_invalid_arguments = true; - else { - if (nbv<0) { nbv = -nbv; is_outlined = true; } - CImg points(nbv,2,1,1,0); - CImg color(img._spectrum,1,1,1,0); - float opacity = 1; - unsigned int i = 5, pattern=~0U; - cimg_foroff(points,k) if (i args(i_end - 4); - cimg_forX(args,k) args[k] = _mp_arg(4 + k); - if (ind==~0U) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'polygon()': " - "Invalid arguments '%s'. ", - mp.imgin.pixel_type(),args.value_string()._data); - else - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'polygon()': " - "Invalid arguments '#%u%s%s'. ", - mp.imgin.pixel_type(),ind,args._width?",":"",args.value_string()._data); - } - return cimg::type::nan(); - } - - static double mp_pow(_cimg_math_parser& mp) { - const double v = _mp_arg(2), p = _mp_arg(3); - return std::pow(v,p); - } - - static double mp_pow0_25(_cimg_math_parser& mp) { - const double val = _mp_arg(2); - return std::sqrt(std::sqrt(val)); - } - - static double mp_pow3(_cimg_math_parser& mp) { - const double val = _mp_arg(2); - return val*val*val; - } - - static double mp_pow4(_cimg_math_parser& mp) { - const double val = _mp_arg(2); - return val*val*val*val; - } - - static double mp_print(_cimg_math_parser& mp) { - const double val = _mp_arg(1); - const bool print_char = (bool)mp.opcode[3]; - cimg_pragma_openmp(critical(mp_print)) - { - CImg _expr(mp.opcode[2] - 4); - const ulongT *ptrs = mp.opcode._data + 4; - cimg_for(_expr,ptrd,char) *ptrd = (char)*(ptrs++); - cimg::strellipsize(_expr); - cimg::mutex(6); - if (print_char) - std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = %.17g = '%c'", - _expr._data,val,(int)val); - else - std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = %.17g", - _expr._data,val); - std::fflush(cimg::output()); - cimg::mutex(6,0); - } - return val; - } - - static double mp_prod(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2]; - double val = _mp_arg(3); - for (unsigned int i = 4; i - *const p_body = ++mp.p_code, - *const p_end = p_body + mp.opcode[4]; - - if (nb_it>0) { - const unsigned int _break_type = mp.break_type; - mp.break_type = 0; - - double it = 0; - if (ptrc) { // Version with loop variable (3 arguments) - while (it_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0; - ++it; - } - *ptrc = it; - } else // Version without loop variable (2 arguments) - while (it_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0; - ++it; - } - mp.break_type = _break_type; - } - - mp.p_code = p_end - 1; - return *ptrs; - } - - static double mp_rol(_cimg_math_parser& mp) { - return cimg::rol(_mp_arg(2),(unsigned int)_mp_arg(3)); - } - - static double mp_ror(_cimg_math_parser& mp) { - return cimg::ror(_mp_arg(2),(unsigned int)_mp_arg(3)); - } - - static double mp_rot2d(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const float - theta = (float)_mp_arg(2), - ca = std::cos(theta), - sa = std::sin(theta); - *(ptrd++) = ca; - *(ptrd++) = -sa; - *(ptrd++) = sa; - *ptrd = ca; - return cimg::type::nan(); - } - - static double mp_rot3d(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const float - x = (float)_mp_arg(2), - y = (float)_mp_arg(3), - z = (float)_mp_arg(4), - theta = (float)_mp_arg(5); - CImg(ptrd,3,3,1,1,true) = CImg::rotation_matrix(x,y,z,theta*180/cimg::PI); - return cimg::type::nan(); - } - - static double mp_round(_cimg_math_parser& mp) { - return cimg::round(_mp_arg(2),_mp_arg(3),(int)_mp_arg(4)); - } - - static double mp_self_add(_cimg_math_parser& mp) { - return _mp_arg(1)+=_mp_arg(2); - } - - static double mp_self_bitwise_and(_cimg_math_parser& mp) { - double &val = _mp_arg(1); - return val = (double)((longT)val & (longT)_mp_arg(2)); - } - - static double mp_self_bitwise_left_shift(_cimg_math_parser& mp) { - double &val = _mp_arg(1); - return val = (double)((longT)val<<(unsigned int)_mp_arg(2)); - } - - static double mp_self_bitwise_or(_cimg_math_parser& mp) { - double &val = _mp_arg(1); - return val = (double)((longT)val | (longT)_mp_arg(2)); - } - - static double mp_self_bitwise_right_shift(_cimg_math_parser& mp) { - double &val = _mp_arg(1); - return val = (double)((longT)val>>(unsigned int)_mp_arg(2)); - } - - static double mp_self_decrement(_cimg_math_parser& mp) { - return --_mp_arg(1); - } - - static double mp_self_increment(_cimg_math_parser& mp) { - return ++_mp_arg(1); - } - - static double mp_self_map_vector_s(_cimg_math_parser& mp) { // Vector += scalar - unsigned int - ptrd = (unsigned int)mp.opcode[1] + 1, - siz = (unsigned int)mp.opcode[2]; - mp_func op = (mp_func)mp.opcode[3]; - CImg l_opcode(1,3); - l_opcode[2] = mp.opcode[4]; // Scalar argument - l_opcode.swap(mp.opcode); - ulongT &target = mp.opcode[1]; - while (siz-->0) { target = ptrd++; (*op)(mp); } - l_opcode.swap(mp.opcode); - return cimg::type::nan(); - } - - static double mp_self_map_vector_v(_cimg_math_parser& mp) { // Vector += vector - unsigned int - ptrd = (unsigned int)mp.opcode[1] + 1, - siz = (unsigned int)mp.opcode[2], - ptrs = (unsigned int)mp.opcode[4] + 1; - mp_func op = (mp_func)mp.opcode[3]; - CImg l_opcode(1,4); - l_opcode.swap(mp.opcode); - ulongT &target = mp.opcode[1], &argument = mp.opcode[2]; - while (siz-->0) { target = ptrd++; argument = ptrs++; (*op)(mp); } - l_opcode.swap(mp.opcode); - return cimg::type::nan(); - } - - static double mp_self_mul(_cimg_math_parser& mp) { - return _mp_arg(1)*=_mp_arg(2); - } - - static double mp_self_div(_cimg_math_parser& mp) { - return _mp_arg(1)/=_mp_arg(2); - } - - static double mp_self_modulo(_cimg_math_parser& mp) { - double &val = _mp_arg(1); - return val = cimg::mod(val,_mp_arg(2)); - } - - static double mp_self_pow(_cimg_math_parser& mp) { - double &val = _mp_arg(1); - return val = std::pow(val,_mp_arg(2)); - } - - static double mp_self_sub(_cimg_math_parser& mp) { - return _mp_arg(1)-=_mp_arg(2); - } - -#ifdef cimg_mp_func_set - static double mp_set(_cimg_math_parser& mp) { - const double *ptrs = &_mp_arg(1); - double *ptrd = &_mp_arg(3) + 1; - const unsigned int - sizs = (unsigned int)mp.opcode[2], - sizd = (unsigned int)mp.opcode[4]; - CImg sd(sizd + 1); - cimg_for_inX(sd,0,sd.width() - 1,i) sd[i] = (char)ptrd[i]; - sd.back() = 0; - if (sizs) cimg_mp_func_set(ptrs + 1,sizs,sd._data); - else cimg_mp_func_set(ptrs,0,sd._data); - return *ptrs; - } -#endif - - static double mp_set_ioff(_cimg_math_parser& mp) { - CImg &img = mp.imgout; - const longT - off = (longT)_mp_arg(2), - whds = (longT)img.size(); - const double val = _mp_arg(1); - if (off>=0 && off &img = mp.imgout; - const int - x = (int)_mp_arg(2), y = (int)_mp_arg(3), - z = (int)_mp_arg(4), c = (int)_mp_arg(5); - const double val = _mp_arg(1); - if (x>=0 && x=0 && y=0 && z=0 && c &img = mp.imgout; - const int - ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y], - oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c]; - const longT - off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2), - whds = (longT)img.size(); - const double val = _mp_arg(1); - if (off>=0 && off &img = mp.imgout; - const double - ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], - oz = mp.mem[_cimg_mp_slot_z], oc = mp.mem[_cimg_mp_slot_c]; - const int - x = (int)(ox + _mp_arg(2)), y = (int)(oy + _mp_arg(3)), - z = (int)(oz + _mp_arg(4)), c = (int)(oc + _mp_arg(5)); - const double val = _mp_arg(1); - if (x>=0 && x=0 && y=0 && z=0 && c &img = mp.imgout; - const longT - off = (longT)_mp_arg(2), - whd = (longT)img.width()*img.height()*img.depth(); - const T val = (T)_mp_arg(1); - if (off>=0 && off &img = mp.imgout; - const longT - off = (longT)_mp_arg(2), - whd = (longT)img.width()*img.height()*img.depth(); - const double *ptrs = &_mp_arg(1) + 1; - if (off>=0 && off::nan(); - } - - static double mp_set_Ixyz_s(_cimg_math_parser& mp) { - CImg &img = mp.imgout; - const int - x = (int)_mp_arg(2), - y = (int)_mp_arg(3), - z = (int)_mp_arg(4); - const T val = (T)_mp_arg(1); - if (x>=0 && x=0 && y=0 && z &img = mp.imgout; - const int - x = (int)_mp_arg(2), - y = (int)_mp_arg(3), - z = (int)_mp_arg(4); - const double *ptrs = &_mp_arg(1) + 1; - if (x>=0 && x=0 && y=0 && z::nan(); - } - - static double mp_set_Joff_s(_cimg_math_parser& mp) { - CImg &img = mp.imgout; - const int - ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y], - oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c]; - const longT - off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2), - whd = (longT)img.width()*img.height()*img.depth(); - const T val = (T)_mp_arg(1); - if (off>=0 && off &img = mp.imgout; - const int - ox = (int)mp.mem[_cimg_mp_slot_x], oy = (int)mp.mem[_cimg_mp_slot_y], - oz = (int)mp.mem[_cimg_mp_slot_z], oc = (int)mp.mem[_cimg_mp_slot_c]; - const longT - off = img.offset(ox,oy,oz,oc) + (longT)_mp_arg(2), - whd = (longT)img.width()*img.height()*img.depth(); - const double *ptrs = &_mp_arg(1) + 1; - if (off>=0 && off::nan(); - } - - static double mp_set_Jxyz_s(_cimg_math_parser& mp) { - CImg &img = mp.imgout; - const double ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z]; - const int - x = (int)(ox + _mp_arg(2)), - y = (int)(oy + _mp_arg(3)), - z = (int)(oz + _mp_arg(4)); - const T val = (T)_mp_arg(1); - if (x>=0 && x=0 && y=0 && z &img = mp.imgout; - const double ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z]; - const int - x = (int)(ox + _mp_arg(2)), - y = (int)(oy + _mp_arg(3)), - z = (int)(oz + _mp_arg(4)); - const double *ptrs = &_mp_arg(1) + 1; - if (x>=0 && x=0 && y=0 && z::nan(); - } - - static double mp_shift(_cimg_math_parser& mp) { - double *const ptrd = &_mp_arg(1) + 1; - const double *const ptrs = &_mp_arg(2) + 1; - const unsigned int siz = (unsigned int)mp.opcode[3]; - const int - shift = (int)_mp_arg(4), - boundary_conditions = (int)_mp_arg(5); - CImg(ptrd,siz,1,1,1,true) = CImg(ptrs,siz,1,1,1,true).shift(shift,0,0,0,boundary_conditions); - return cimg::type::nan(); - } - - static double mp_sign(_cimg_math_parser& mp) { - return cimg::sign(_mp_arg(2)); - } - - static double mp_sin(_cimg_math_parser& mp) { - return std::sin(_mp_arg(2)); - } - - static double mp_sinc(_cimg_math_parser& mp) { - return cimg::sinc(_mp_arg(2)); - } - - static double mp_sinh(_cimg_math_parser& mp) { - return std::sinh(_mp_arg(2)); - } - - static double mp_solve(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const double - *ptr1 = &_mp_arg(2) + 1, - *ptr2 = &_mp_arg(3) + 1; - const unsigned int - k = (unsigned int)mp.opcode[4], - l = (unsigned int)mp.opcode[5], - m = (unsigned int)mp.opcode[6]; - const bool use_LU = (bool)_mp_arg(7); - CImg(ptrd,m,k,1,1,true) = CImg(ptr2,m,l,1,1,false). - solve(CImg(ptr1,k,l,1,1,true),use_LU); - return cimg::type::nan(); - } - - static double mp_sort(_cimg_math_parser& mp) { - double *const ptrd = &_mp_arg(1) + 1; - const double *const ptrs = &_mp_arg(2) + 1; - const bool is_increasing = (bool)_mp_arg(4); - const unsigned int - siz = (unsigned int)mp.opcode[3], - nb_elts = mp.opcode[5]==~0U?siz:(unsigned int)_mp_arg(5), - siz_elt = (unsigned int)_mp_arg(6); - const ulongT sn = siz_elt*nb_elts; - if (sn>siz || siz_elt<1) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'sort()': " - "Arguments 'nb_elts=%g' and 'siz_elt=%g' are invalid " - "for sorting a vector of size %u.", - mp.imgin.pixel_type(),_mp_arg(5),_mp_arg(6),siz); - CImg(ptrd,siz_elt,nb_elts,1,1,true) = CImg(ptrs,siz_elt,nb_elts,1,1,true). - get_sort(is_increasing,siz_elt>1?'y':0); - if (sn(ptrd + sn,siz - sn,1,1,1,true) = CImg(ptrs + sn,siz - sn,1,1,1,true); - return cimg::type::nan(); - } - - static double mp_sqr(_cimg_math_parser& mp) { - return cimg::sqr(_mp_arg(2)); - } - - static double mp_sqrt(_cimg_math_parser& mp) { - return std::sqrt(_mp_arg(2)); - } - - static double mp_srand(_cimg_math_parser& mp) { - mp.rng = (cimg_uint64)_mp_arg(2); - return cimg::type::nan(); - } - - static double mp_srand0(_cimg_math_parser& mp) { - cimg::srand(&mp.rng); - -#if cimg_use_openmp!=0 - mp.rng+=omp_get_thread_num(); -#endif - return cimg::type::nan(); - } - - static double mp_std(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2]; - CImg vals(i_end - 3); - double *p = vals.data(); - for (unsigned int i = 3; i0) mp.mem[ptrd++] = (double)*(ptrs++); - return cimg::type::nan(); - } - -#ifdef cimg_mp_func_store - static double mp_store(_cimg_math_parser& mp) { - const double - *ptr1 = &_mp_arg(2), - *ptr2 = &_mp_arg(4) + 1; - const unsigned int - siz1 = (unsigned int)mp.opcode[3], - siz2 = (unsigned int)mp.opcode[5]; - const int - w = (int)_mp_arg(6), - h = (int)_mp_arg(7), - d = (int)_mp_arg(8), - s = (int)_mp_arg(9); - - const bool is_compressed = (bool)_mp_arg(10); - if (w<0 || h<0 || d<0 || s<0) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Function 'store()': " - "Specified image dimensions (%d,%d,%d,%d) are invalid.", - pixel_type(),w,h,d,s); - CImg ss(siz2 + 1); - cimg_for_inX(ss,0,ss.width() - 1,i) ss[i] = (char)ptr2[i]; - ss.back() = 0; - if (siz1) cimg_mp_func_store(ptr1 + 1,siz1, - (unsigned int)w,(unsigned int)h,(unsigned int)d,(unsigned int)s, - is_compressed,ss._data); - else cimg_mp_func_store(ptr1,1,(unsigned int)w,(unsigned int)h,(unsigned int)d,(unsigned int)s, - is_compressed,ss._data); - return cimg::type::nan(); - } -#endif - - static double mp_s2v(_cimg_math_parser& mp) { - const double *ptrs = &_mp_arg(2); - const ulongT siz = (ulongT)mp.opcode[3]; - longT ind = (longT)_mp_arg(4); - const bool is_strict = (bool)_mp_arg(5); - double val = cimg::type::nan(); - if (ind<0 || ind>=(longT)siz) return val; - if (!siz) return *ptrs>='0' && *ptrs<='9'?*ptrs - '0':val; - - CImg ss(siz + 1 - ind); - ptrs+=1 + ind; - cimg_forX(ss,i) ss[i] = (char)ptrs[i]; - ss.back() = 0; - - const char *s = ss._data; - while (*s && *s<=32) ++s; - const bool is_negative = *s=='-'; - if (is_negative || *s=='+') ++s; - int err = 0; - char sep; - - if (*s=='0' && (s[1]=='x' || s[1]=='X') && s[2]>32) { // Hexadecimal number - unsigned int ival; - err = cimg_sscanf(s + 2,"%x%c",&ival,&sep); - if (err>0) val = (double)ival; - } else if (*s>32) { // Decimal number - err = cimg_sscanf(s,"%lf%c",&val,&sep); -#if cimg_OS==2 - // Check for +/-NaN and +/-inf as Microsoft's sscanf() version is not able - // to read those particular values. - if (!err && (*s=='i' || *s=='I' || *s=='n' || *s=='N')) { - if (!cimg::strncasecmp(s,"inf",3)) { val = cimg::type::inf(); err = 1 + (s[3]!=0); } - else if (!cimg::strncasecmp(s,"nan",3)) { val = cimg::type::nan(); err = 1 + (s[3]!=0); } - } -#endif - } - if (err<=0 || (is_strict && err!=1)) return cimg::type::nan(); - if (is_negative) val = -val; - return val; - } - - static double mp_string(_cimg_math_parser& mp) { - double *const ptrd = &_mp_arg(1) + 1; - const unsigned int nb_args = (unsigned int)(mp.opcode[3] - 3)/2; - CImgList _str; - CImg it; - for (unsigned int n = 0; n string - const double *ptr = &_mp_arg(4 + 2*n) + 1; - unsigned int l = 0; - while (l(ptr,l,1,1,1,true).move_to(_str); - } else { // Scalar argument -> number - it.assign(24); - cimg_snprintf(it,it._width,"%.17g",_mp_arg(4 + 2*n)); - CImg::string(it,false,true).move_to(_str); - } - } - const CImg str = _str>'x'; - const unsigned int sizd = std::min(str._width,(unsigned int)mp.opcode[2]); - std::memset(ptrd,0,mp.opcode[2]*sizeof(double)); - for (unsigned int k = 0; k::nan(); - } - - static double mp_sub(_cimg_math_parser& mp) { - return _mp_arg(2) - _mp_arg(3); - } - - static double mp_sum(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2]; - double val = _mp_arg(3); - for (unsigned int i = 4; i(ptrs,k,k,1,1,true).trace(); - } - - static double mp_transpose(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const double *ptrs = &_mp_arg(2) + 1; - const unsigned int - k = (unsigned int)mp.opcode[3], - l = (unsigned int)mp.opcode[4]; - CImg(ptrd,l,k,1,1,true) = CImg(ptrs,k,l,1,1,true).get_transpose(); - return cimg::type::nan(); - } - - static double mp_u(_cimg_math_parser& mp) { - return cimg::rand(_mp_arg(2),_mp_arg(3),&mp.rng); - } - - static double mp_ui2f(_cimg_math_parser& mp) { - return (double)cimg::uint2float((unsigned int)_mp_arg(2)); - } - - static double mp_uppercase(_cimg_math_parser& mp) { - return cimg::uppercase(_mp_arg(2)); - } - - static double mp_var(_cimg_math_parser& mp) { - const unsigned int i_end = (unsigned int)mp.opcode[2]; - CImg vals(i_end - 3); - double *p = vals.data(); - for (unsigned int i = 3; i::nan(); - } - - static double mp_vector_crop(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const double *ptrs = &_mp_arg(2) + 1; - const longT - length = (longT)mp.opcode[3], - start = (longT)_mp_arg(4), - sublength = (longT)mp.opcode[5], - step = (longT)_mp_arg(6); - if (start<0 || start + step*(sublength-1)>=length) - throw CImgArgumentException("[" cimg_appname "_math_parser] CImg<%s>: Value accessor '[]': " - "Out-of-bounds sub-vector request " - "(length: %ld, start: %ld, sub-length: %ld, step: %ld).", - mp.imgin.pixel_type(),length,start,sublength,step); - ptrs+=start; - if (step==1) std::memcpy(ptrd,ptrs,sublength*sizeof(double)); - else for (longT k = 0; k::nan(); - } - - static double mp_vector_init(_cimg_math_parser& mp) { - unsigned int - ptrs = 4U, - ptrd = (unsigned int)mp.opcode[1] + 1, - siz = (unsigned int)mp.opcode[3]; - switch (mp.opcode[2] - 4) { - case 0 : std::memset(mp.mem._data + ptrd,0,siz*sizeof(double)); break; // 0 values given - case 1 : { const double val = _mp_arg(ptrs); while (siz-->0) mp.mem[ptrd++] = val; } break; - default : while (siz-->0) { mp.mem[ptrd++] = _mp_arg(ptrs++); if (ptrs>=mp.opcode[2]) ptrs = 4U; } - } - return cimg::type::nan(); - } - - static double mp_vector_eq(_cimg_math_parser& mp) { - const double - *ptr1 = &_mp_arg(2) + 1, - *ptr2 = &_mp_arg(4) + 1; - unsigned int p1 = (unsigned int)mp.opcode[3], p2 = (unsigned int)mp.opcode[5], n; - const int N = (int)_mp_arg(6); - const bool case_sensitive = (bool)_mp_arg(7); - bool still_equal = true; - double value; - if (!N) return true; - - // Compare all values. - if (N<0) { - if (p1>0 && p2>0) { // Vector == vector - if (p1!=p2) return false; - if (case_sensitive) - while (still_equal && p1--) still_equal = *(ptr1++)==*(ptr2++); - else - while (still_equal && p1--) - still_equal = cimg::lowercase(*(ptr1++))==cimg::lowercase(*(ptr2++)); - return still_equal; - } else if (p1>0 && !p2) { // Vector == scalar - value = _mp_arg(4); - if (!case_sensitive) value = cimg::lowercase(value); - while (still_equal && p1--) still_equal = *(ptr1++)==value; - return still_equal; - } else if (!p1 && p2>0) { // Scalar == vector - value = _mp_arg(2); - if (!case_sensitive) value = cimg::lowercase(value); - while (still_equal && p2--) still_equal = *(ptr2++)==value; - return still_equal; - } else { // Scalar == scalar - if (case_sensitive) return _mp_arg(2)==_mp_arg(4); - else return cimg::lowercase(_mp_arg(2))==cimg::lowercase(_mp_arg(4)); - } - } - - // Compare only first N values. - if (p1>0 && p2>0) { // Vector == vector - n = cimg::min((unsigned int)N,p1,p2); - if (case_sensitive) - while (still_equal && n--) still_equal = *(ptr1++)==(*ptr2++); - else - while (still_equal && n--) still_equal = cimg::lowercase(*(ptr1++))==cimg::lowercase(*(ptr2++)); - return still_equal; - } else if (p1>0 && !p2) { // Vector == scalar - n = std::min((unsigned int)N,p1); - value = _mp_arg(4); - if (!case_sensitive) value = cimg::lowercase(value); - while (still_equal && n--) still_equal = *(ptr1++)==value; - return still_equal; - } else if (!p1 && p2>0) { // Scalar == vector - n = std::min((unsigned int)N,p2); - value = _mp_arg(2); - if (!case_sensitive) value = cimg::lowercase(value); - while (still_equal && n--) still_equal = *(ptr2++)==value; - return still_equal; - } // Scalar == scalar - if (case_sensitive) return _mp_arg(2)==_mp_arg(4); - return cimg::lowercase(_mp_arg(2))==cimg::lowercase(_mp_arg(4)); - } - - static double mp_vector_lerp(_cimg_math_parser& mp) { - unsigned int siz = (unsigned int)mp.opcode[2]; - double *ptrd = &_mp_arg(1) + 1; - const double - *ptrs1 = &_mp_arg(3) + 1, - *ptrs2 = &_mp_arg(4) + 1, - t = _mp_arg(5); - for (unsigned int k = 0; k::nan(); - } - - static double mp_vector_off(_cimg_math_parser& mp) { - const unsigned int - ptr = (unsigned int)mp.opcode[2] + 1, - siz = (unsigned int)mp.opcode[3]; - const int off = (int)_mp_arg(4); - return off>=0 && off<(int)siz?mp.mem[ptr + off]:cimg::type::nan(); - } - - static double mp_vector_map_sv(_cimg_math_parser& mp) { // Operator(scalar,vector) - unsigned int - siz = (unsigned int)mp.opcode[2], - ptrs = (unsigned int)mp.opcode[5] + 1; - double *ptrd = &_mp_arg(1) + 1; - mp_func op = (mp_func)mp.opcode[3]; - CImg l_opcode(4); - l_opcode[2] = mp.opcode[4]; // Scalar argument1 - l_opcode.swap(mp.opcode); - ulongT &argument2 = mp.opcode[3]; - while (siz-->0) { argument2 = ptrs++; *(ptrd++) = (*op)(mp); } - l_opcode.swap(mp.opcode); - return cimg::type::nan(); - } - - static double mp_vector_map_v(_cimg_math_parser& mp) { // Operator(vector) - unsigned int - siz = (unsigned int)mp.opcode[2], - ptrs = (unsigned int)mp.opcode[4] + 1; - double *ptrd = &_mp_arg(1) + 1; - mp_func op = (mp_func)mp.opcode[3]; - CImg l_opcode(1,3); - l_opcode.swap(mp.opcode); - ulongT &argument = mp.opcode[2]; - while (siz-->0) { argument = ptrs++; *(ptrd++) = (*op)(mp); } - l_opcode.swap(mp.opcode); - return cimg::type::nan(); - } - - static double mp_vector_map_vs(_cimg_math_parser& mp) { // Operator(vector,scalar) - unsigned int - siz = (unsigned int)mp.opcode[2], - ptrs = (unsigned int)mp.opcode[4] + 1; - double *ptrd = &_mp_arg(1) + 1; - mp_func op = (mp_func)mp.opcode[3]; - CImg l_opcode(1,4); - l_opcode[3] = mp.opcode[5]; // Scalar argument2 - l_opcode.swap(mp.opcode); - ulongT &argument1 = mp.opcode[2]; - while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); } - l_opcode.swap(mp.opcode); - return cimg::type::nan(); - } - - static double mp_vector_map_vss(_cimg_math_parser& mp) { // Operator(vector,scalar,scalar) - unsigned int - siz = (unsigned int)mp.opcode[2], - ptrs = (unsigned int)mp.opcode[4] + 1; - double *ptrd = &_mp_arg(1) + 1; - mp_func op = (mp_func)mp.opcode[3]; - CImg l_opcode(1,5); - l_opcode[3] = mp.opcode[5]; // Scalar argument2 - l_opcode[4] = mp.opcode[6]; // Scalar argument3 - l_opcode.swap(mp.opcode); - ulongT &argument1 = mp.opcode[2]; - while (siz-->0) { argument1 = ptrs++; *(ptrd++) = (*op)(mp); } - l_opcode.swap(mp.opcode); - return cimg::type::nan(); - } - - static double mp_vector_map_vv(_cimg_math_parser& mp) { // Operator(vector,vector) - unsigned int - siz = (unsigned int)mp.opcode[2], - ptrs1 = (unsigned int)mp.opcode[4] + 1, - ptrs2 = (unsigned int)mp.opcode[5] + 1; - double *ptrd = &_mp_arg(1) + 1; - mp_func op = (mp_func)mp.opcode[3]; - CImg l_opcode(1,4); - l_opcode.swap(mp.opcode); - ulongT &argument1 = mp.opcode[2], &argument2 = mp.opcode[3]; - while (siz-->0) { argument1 = ptrs1++; argument2 = ptrs2++; *(ptrd++) = (*op)(mp); } - l_opcode.swap(mp.opcode); - return cimg::type::nan(); - } - - static double mp_vector_neq(_cimg_math_parser& mp) { - return !mp_vector_eq(mp); - } - - static double mp_vector_print(_cimg_math_parser& mp) { - const bool print_string = (bool)mp.opcode[4]; - cimg_pragma_openmp(critical(mp_vector_print)) - { - CImg _expr(mp.opcode[2] - 5); - const ulongT *ptrs = mp.opcode._data + 5; - cimg_for(_expr,ptrd,char) *ptrd = (char)*(ptrs++); - cimg::strellipsize(_expr); - unsigned int - ptr = (unsigned int)mp.opcode[1] + 1, - siz0 = (unsigned int)mp.opcode[3], - siz = siz0; - cimg::mutex(6); - std::fprintf(cimg::output(),"\n[" cimg_appname "_math_parser] %s = [ ",_expr._data); - unsigned int count = 0; - while (siz-->0) { - if (count>=64 && siz>=64) { - std::fprintf(cimg::output(),"...,"); - ptr = (unsigned int)mp.opcode[1] + 1 + siz0 - 64; - siz = 64; - } else std::fprintf(cimg::output(),"%.17g%s",mp.mem[ptr++],siz?",":""); - ++count; - } - if (print_string) { - CImg str(siz0 + 1); - ptr = (unsigned int)mp.opcode[1] + 1; - for (unsigned int k = 0; k::nan(); - } - - static double mp_vector_resize(_cimg_math_parser& mp) { - double *const ptrd = &_mp_arg(1) + 1; - const unsigned int p1 = (unsigned int)mp.opcode[2], p2 = (unsigned int)mp.opcode[4]; - const int - interpolation = (int)_mp_arg(5), - boundary_conditions = (int)_mp_arg(6); - if (p2) { // Resize vector - const double *const ptrs = &_mp_arg(3) + 1; - CImg(ptrd,p1,1,1,1,true) = CImg(ptrs,p2,1,1,1,true). - get_resize(p1,1,1,1,interpolation,boundary_conditions); - } else { // Resize scalar - const double value = _mp_arg(3); - CImg(ptrd,p1,1,1,1,true) = CImg(1,1,1,1,value).resize(p1,1,1,1,interpolation, - boundary_conditions); - } - return cimg::type::nan(); - } - - static double mp_vector_resize_ext(_cimg_math_parser& mp) { - double *const ptrd = &_mp_arg(1) + 1; - const unsigned int - siz = (unsigned int)mp.opcode[2], - ow = (unsigned int)mp.opcode[4], - oh = (unsigned int)mp.opcode[5], - od = (unsigned int)mp.opcode[6], - os = (unsigned int)mp.opcode[7], - nw = (unsigned int)mp.opcode[8], - nh = (unsigned int)mp.opcode[9], - nd = (unsigned int)mp.opcode[10], - ns = (unsigned int)mp.opcode[11]; - const int - interpolation = (int)_mp_arg(12), - boundary_conditions = (int)_mp_arg(13); - const float - ax = (float)_mp_arg(14), - ay = (float)_mp_arg(15), - az = (float)_mp_arg(16), - ac = (float)_mp_arg(17); - if (siz) { // Resize vector - const double *const ptrs = &_mp_arg(3) + 1; - CImg(ptrd,nw,nh,nd,ns,true) = CImg(ptrs,ow,oh,od,os,true). - get_resize(nw,nh,nd,ns,interpolation,boundary_conditions,ax,ay,az,ac); - } else { // Resize scalar - const double value = _mp_arg(3); - CImg(ptrd,nw,nh,nd,ns,true) = CImg(1,1,1,1,value). - resize(nw,nh,nd,ns,interpolation,boundary_conditions,ax,ay,az,ac); - } - return cimg::type::nan(); - } - - static double mp_vector_reverse(_cimg_math_parser& mp) { - double *const ptrd = &_mp_arg(1) + 1; - const double *const ptrs = &_mp_arg(2) + 1; - const unsigned int p1 = (unsigned int)mp.opcode[3]; - CImg(ptrd,p1,1,1,1,true) = CImg(ptrs,p1,1,1,1,true).get_mirror('x'); - return cimg::type::nan(); - } - - static double mp_vector_set_off(_cimg_math_parser& mp) { - const unsigned int - ptr = (unsigned int)mp.opcode[2] + 1, - siz = (unsigned int)mp.opcode[3]; - const int off = (int)_mp_arg(4); - if (off>=0 && off<(int)siz) mp.mem[ptr + off] = _mp_arg(1); - return _mp_arg(1); - } - -#define _cimg_mp_vfunc(func) \ - const longT sizd = (longT)mp.opcode[2];\ - const unsigned int nbargs = (unsigned int)(mp.opcode[3] - 4)/2; \ - double *const ptrd = &_mp_arg(1) + (sizd?1:0); \ - cimg_pragma_openmp(parallel cimg_openmp_if_size(sizd,256)) \ - { CImg vec(nbargs); double res; \ - cimg_pragma_openmp(for) for (longT k = sizd?sizd - 1:0; k>=0; --k) { \ - cimg_forX(vec,n) vec[n] = *(&_mp_arg(4 + 2*n) + (k+1)*(mp.opcode[4 + 2*n + 1]?1:0)); \ - func; ptrd[k] = res; \ - }} \ - return sizd?cimg::type::nan():*ptrd; - - static double _mp_vargkth(CImg& vec) { - const double val = (+vec).get_shared_points(1,vec.width() - 1). - kth_smallest((ulongT)cimg::cut((longT)*vec - 1,(longT)0,(longT)vec.width() - 2)); - cimg_for_inX(vec,1,vec.width()-1,ind) if (vec[ind]==val) return ind - 1.; - return 1.; - } - - static double mp_vargkth(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = _mp_vargkth(vec)); - } - - static double mp_vargmax(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = (double)(&vec.max() - vec.data())); - } - - static double mp_vargmaxabs(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = (double)(&vec.maxabs() - vec.data())); - } - - static double mp_vargmin(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = (double)(&vec.min() - vec.data())); - } - - static double mp_vargminabs(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = (double)(&vec.minabs() - vec.data())); - } - - static double mp_vavg(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = vec.mean()); - } - - static double mp_vkth(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = vec.get_shared_points(1,vec.width() - 1). - kth_smallest((ulongT)cimg::cut((longT)*vec - 1,(longT)0,(longT)vec.width() - 2))); - } - - static double mp_vmax(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = vec.max()); - } - - static double mp_vmaxabs(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = vec.maxabs()); - } - - static double mp_vmedian(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = vec.median()); - } - - static double mp_vmin(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = vec.min()); - } - - static double mp_vminabs(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = vec.minabs()); - } - - static double mp_vprod(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = vec.product()); - } - - static double mp_vstd(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = std::sqrt(vec.get_stats()[3])); - } - - static double mp_vsum(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = vec.sum()); - } - - static double mp_vvar(_cimg_math_parser& mp) { - _cimg_mp_vfunc(res = vec.get_stats()[3]); - } - - static double mp_v2s(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const unsigned int - sizd = (unsigned int)mp.opcode[2], - sizs = (unsigned int)mp.opcode[4]; - std::memset(ptrd,0,sizd*sizeof(double)); - const int nb_digits = (int)_mp_arg(5); - CImg format(8); - switch (nb_digits) { - case -1 : std::strcpy(format,"%g"); break; - case 0 : std::strcpy(format,"%.17g"); break; - default : cimg_snprintf(format,format._width,"%%.%dg",nb_digits); - } - CImg str; - if (sizs) { // Vector expression - const double *ptrs = &_mp_arg(3) + 1; - CImg(ptrs,sizs,1,1,1,true).value_string(',',sizd + 1,format).move_to(str); - } else { // Scalar expression - str.assign(sizd + 1); - cimg_snprintf(str,sizd + 1,format,_mp_arg(3)); - } - const unsigned int l = std::min(sizd,(unsigned int)std::strlen(str) + 1); - CImg(ptrd,l,1,1,1,true) = str.get_shared_points(0,l - 1); - return cimg::type::nan(); - } - - static double mp_while(_cimg_math_parser& mp) { - const ulongT - mem_body = mp.opcode[1], - mem_cond = mp.opcode[2]; - const CImg - *const p_cond = ++mp.p_code, - *const p_body = p_cond + mp.opcode[3], - *const p_end = p_body + mp.opcode[4]; - const unsigned int vsiz = (unsigned int)mp.opcode[5]; - bool is_cond = false; - if (mp.opcode[6]) { // Set default value for result and condition if necessary - if (vsiz) CImg(&mp.mem[mem_body] + 1,vsiz,1,1,1,true).fill(cimg::type::nan()); - else mp.mem[mem_body] = cimg::type::nan(); - } - if (mp.opcode[7]) mp.mem[mem_cond] = 0; - const unsigned int _break_type = mp.break_type; - mp.break_type = 0; - do { - for (mp.p_code = p_cond; mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - if (mp.break_type==1) break; - is_cond = (bool)mp.mem[mem_cond]; - if (is_cond && !mp.break_type) // Evaluate body - for (mp.p_code = p_body; mp.p_code_data; - const ulongT target = mp.opcode[1]; - mp.mem[target] = _cimg_mp_defunc(mp); - } - if (mp.break_type==1) break; else if (mp.break_type==2) mp.break_type = 0; - } while (is_cond); - - mp.break_type = _break_type; - mp.p_code = p_end - 1; - return mp.mem[mem_body]; - } - - static double mp_Ioff(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const unsigned int - boundary_conditions = (unsigned int)_mp_arg(3), - vsiz = (unsigned int)mp.opcode[4]; - const CImg &img = mp.imgin; - const longT - off = (longT)_mp_arg(2), - whd = (longT)img.width()*img.height()*img.depth(); - const T *ptrs; - if (off>=0 && off::nan(); - } - if (img._data) switch (boundary_conditions) { - case 3 : { // Mirror - const longT whd2 = 2*whd, moff = cimg::mod(off,whd2); - ptrs = &img[moff::nan(); - } - case 2 : // Periodic - ptrs = &img[cimg::mod(off,whd)]; - cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; } - return cimg::type::nan(); - case 1 : // Neumann - ptrs = off<0?&img[0]:&img[whd - 1]; - cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; } - return cimg::type::nan(); - default : // Dirichlet - std::memset(ptrd,0,vsiz*sizeof(double)); - return cimg::type::nan(); - } - std::memset(ptrd,0,vsiz*sizeof(double)); - return cimg::type::nan(); - } - - static double mp_Ixyz(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const unsigned int - interpolation = (unsigned int)_mp_arg(5), - boundary_conditions = (unsigned int)_mp_arg(6), - vsiz = (unsigned int)mp.opcode[7]; - const CImg &img = mp.imgin; - const double x = _mp_arg(2), y = _mp_arg(3), z = _mp_arg(4); - const ulongT whd = (ulongT)img._width*img._height*img._depth; - const T *ptrs; - switch (interpolation) { - case 2 : // Cubic interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const float - w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), - mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2), - cx = mx::nan(); - } - - static double mp_Joff(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const unsigned int - boundary_conditions = (unsigned int)_mp_arg(3), - vsiz = (unsigned int)mp.opcode[4]; - const CImg &img = mp.imgin; - const int - ox = (int)mp.mem[_cimg_mp_slot_x], - oy = (int)mp.mem[_cimg_mp_slot_y], - oz = (int)mp.mem[_cimg_mp_slot_z]; - const longT - off = img.offset(ox,oy,oz) + (longT)_mp_arg(2), - whd = (longT)img.width()*img.height()*img.depth(); - const T *ptrs; - if (off>=0 && off::nan(); - } - if (img._data) switch (boundary_conditions) { - case 3 : { // Mirror - const longT whd2 = 2*whd, moff = cimg::mod(off,whd2); - ptrs = &img[moff::nan(); - } - case 2 : // Periodic - ptrs = &img[cimg::mod(off,whd)]; - cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; } - return cimg::type::nan(); - case 1 : // Neumann - ptrs = off<0?&img[0]:&img[whd - 1]; - cimg_for_inC(img,0,vsiz - 1,c) { *(ptrd++) = *ptrs; ptrs+=whd; } - return cimg::type::nan(); - default : // Dirichlet - std::memset(ptrd,0,vsiz*sizeof(double)); - return cimg::type::nan(); - } - std::memset(ptrd,0,vsiz*sizeof(double)); - return cimg::type::nan(); - } - - static double mp_Jxyz(_cimg_math_parser& mp) { - double *ptrd = &_mp_arg(1) + 1; - const unsigned int - interpolation = (unsigned int)_mp_arg(5), - boundary_conditions = (unsigned int)_mp_arg(6), - vsiz = (unsigned int)mp.opcode[7]; - const CImg &img = mp.imgin; - const double - ox = mp.mem[_cimg_mp_slot_x], oy = mp.mem[_cimg_mp_slot_y], oz = mp.mem[_cimg_mp_slot_z], - x = ox + _mp_arg(2), y = oy + _mp_arg(3), z = oz + _mp_arg(4); - const ulongT whd = (ulongT)img._width*img._height*img._depth; - const T *ptrs; - switch (interpolation) { - case 2 : // Cubic interpolation - switch (boundary_conditions) { - case 3 : { // Mirror - const float - w2 = 2.f*img.width(), h2 = 2.f*img.height(), d2 = 2.f*img.depth(), - mx = cimg::mod((float)x,w2), my = cimg::mod((float)y,h2), mz = cimg::mod((float)z,d2), - cx = mx::nan(); - } - -#undef _mp_arg - - }; // struct _cimg_math_parser {} - -#define _cimg_create_pointwise_functions(name,func,min_size) \ - CImg& name() { \ - if (is_empty()) return *this; \ - cimg_openmp_for(*this,func((typename cimg::superset::type)*ptr),min_size); \ - return *this; \ - } \ - CImg get_##name() const { \ - return CImg(*this,false).name(); \ - } - - //! Compute the square value of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its square value \f$I_{(x,y,z,c)}^2\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - \par Example - \code - const CImg img("reference.jpg"); - (img,img.get_sqr().normalize(0,255)).display(); - \endcode - \image html ref_sqr.jpg - **/ - _cimg_create_pointwise_functions(sqr,cimg::sqr,524288) - - //! Compute the square root of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its square root \f$\sqrt{I_{(x,y,z,c)}}\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - \par Example - \code - const CImg img("reference.jpg"); - (img,img.get_sqrt().normalize(0,255)).display(); - \endcode - \image html ref_sqrt.jpg - **/ - _cimg_create_pointwise_functions(sqrt,std::sqrt,8192) - - //! Compute the exponential of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its exponential \f$e^{I_{(x,y,z,c)}}\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(exp,std::exp,4096) - - //! Compute the error function of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its error function. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(erf,std::erf,4096) - - //! Compute the logarithm of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its logarithm - \f$\mathrm{log}_{e}(I_{(x,y,z,c)})\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(log,std::log,262144) - - //! Compute the base-2 logarithm of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its base-2 logarithm - \f$\mathrm{log}_{2}(I_{(x,y,z,c)})\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(log2,cimg::log2,4096) - - //! Compute the base-10 logarithm of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its base-10 logarithm - \f$\mathrm{log}_{10}(I_{(x,y,z,c)})\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(log10,std::log10,4096) - - //! Compute the absolute value of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its absolute value \f$|I_{(x,y,z,c)}|\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(abs,cimg::abs,524288) - - //! Compute the sign of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its sign - \f$\mathrm{sign}(I_{(x,y,z,c)})\f$. - \note - - The sign is set to: - - \c 1 if pixel value is strictly positive. - - \c -1 if pixel value is strictly negative. - - \c 0 if pixel value is equal to \c 0. - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(sign,cimg::sign,32768) - - //! Compute the cosine of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its cosine \f$\cos(I_{(x,y,z,c)})\f$. - \note - - Pixel values are regarded as being in \e radian. - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(cos,std::cos,8192) - - //! Compute the sine of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its sine \f$\sin(I_{(x,y,z,c)})\f$. - \note - - Pixel values are regarded as being in \e radian. - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(sin,std::sin,8192) - - //! Compute the sinc of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its sinc - \f$\mathrm{sinc}(I_{(x,y,z,c)})\f$. - \note - - Pixel values are regarded as being exin \e radian. - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(sinc,cimg::sinc,2048) - - //! Compute the tangent of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its tangent \f$\tan(I_{(x,y,z,c)})\f$. - \note - - Pixel values are regarded as being exin \e radian. - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(tan,std::tan,2048) - - //! Compute the hyperbolic cosine of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its hyperbolic cosine - \f$\mathrm{cosh}(I_{(x,y,z,c)})\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(cosh,std::cosh,2048) - - //! Compute the hyperbolic sine of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its hyperbolic sine - \f$\mathrm{sinh}(I_{(x,y,z,c)})\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(sinh,std::sinh,2048) - - //! Compute the hyperbolic tangent of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its hyperbolic tangent - \f$\mathrm{tanh}(I_{(x,y,z,c)})\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(tanh,std::tanh,2048) - - //! Compute the arccosine of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arccosine - \f$\mathrm{acos}(I_{(x,y,z,c)})\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(acos,std::acos,8192) - - //! Compute the arcsine of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arcsine - \f$\mathrm{asin}(I_{(x,y,z,c)})\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(asin,std::asin,8192) - - //! Compute the arctangent of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arctangent - \f$\mathrm{atan}(I_{(x,y,z,c)})\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(atan,std::atan,8192) - - //! Compute the arctangent2 of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arctangent2 - \f$\mathrm{atan2}(I_{(x,y,z,c)})\f$. - \param img Image whose pixel values specify the second argument of the \c atan2() function. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - \par Example - \code - const CImg - img_x(100,100,1,1,"x-w/2",false), // Define an horizontal centered gradient, from '-width/2' to 'width/2' - img_y(100,100,1,1,"y-h/2",false), // Define a vertical centered gradient, from '-height/2' to 'height/2' - img_atan2 = img_y.get_atan2(img_x); // Compute atan2(y,x) for each pixel value - (img_x,img_y,img_atan2).display(); - \endcode - **/ - template - CImg& atan2(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return atan2(+img); - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg get_atan2(const CImg& img) const { - return CImg(*this,false).atan2(img); - } - - //! Compute the hyperbolic arccosine of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its arccosineh - \f$\mathrm{acosh}(I_{(x,y,z,c)})\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(acosh,cimg::acosh,8192) - - //! Compute the hyperbolic arcsine of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its hyperbolic arcsine - \f$\mathrm{asinh}(I_{(x,y,z,c)})\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(asinh,cimg::asinh,8192) - - //! Compute the hyperbolic arctangent of each pixel value. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its hyperbolic arctangent - \f$\mathrm{atanh}(I_{(x,y,z,c)})\f$. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - **/ - _cimg_create_pointwise_functions(atanh,cimg::atanh,8192) - - //! In-place pointwise multiplication. - /** - Compute the pointwise multiplication between the image instance and the specified input image \c img. - \param img Input image, as the second operand of the multiplication. - \note - - Similar to operator+=(const CImg&), except that it performs a pointwise multiplication - instead of an addition. - - It does \e not perform a \e matrix multiplication. For this purpose, use operator*=(const CImg&) instead. - \par Example - \code - CImg - img("reference.jpg"), - shade(img.width,img.height(),1,1,"-(x-w/2)^2-(y-h/2)^2",false); - shade.normalize(0,1); - (img,shade,img.get_mul(shade)).display(); - \endcode - **/ - template - CImg& mul(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return mul(+img); - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg<_cimg_Tt> get_mul(const CImg& img) const { - return CImg<_cimg_Tt>(*this,false).mul(img); - } - - //! In-place pointwise division. - /** - Similar to mul(const CImg&), except that it performs a pointwise division instead of a multiplication. - **/ - template - CImg& div(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return div(+img); - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg<_cimg_Tt> get_div(const CImg& img) const { - return CImg<_cimg_Tt>(*this,false).div(img); - } - - //! Raise each pixel value to a specified power. - /** - Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by its power \f$I_{(x,y,z,c)}^p\f$. - \param p Exponent value. - \note - - The \inplace of this method statically casts the computed values to the pixel type \c T. - - The \newinstance returns a \c CImg image, if the pixel type \c T is \e not float-valued. - \par Example - \code - const CImg - img0("reference.jpg"), // Load reference color image - img1 = (img0/255).pow(1.8)*=255, // Compute gamma correction, with gamma = 1.8 - img2 = (img0/255).pow(0.5)*=255; // Compute gamma correction, with gamma = 0.5 - (img0,img1,img2).display(); - \endcode - **/ - CImg& pow(const double p) { - if (is_empty()) return *this; - if (p==-4) { cimg_openmp_for(*this,1/(Tfloat)cimg::pow4(*ptr),32768); return *this; } - if (p==-3) { cimg_openmp_for(*this,1/(Tfloat)cimg::pow3(*ptr),32768); return *this; } - if (p==-2) { cimg_openmp_for(*this,1/(Tfloat)cimg::sqr(*ptr),32768); return *this; } - if (p==-1) { cimg_openmp_for(*this,1/(Tfloat)*ptr,32768); return *this; } - if (p==-0.5) { cimg_openmp_for(*this,1/std::sqrt((Tfloat)*ptr),8192); return *this; } - if (p==0) return fill((T)1); - if (p==0.5) return sqrt(); - if (p==1) return *this; - if (p==2) return sqr(); - if (p==3) { cimg_openmp_for(*this,cimg::pow3(*ptr),262144); return *this; } - if (p==4) { cimg_openmp_for(*this,cimg::pow4(*ptr),131072); return *this; } - cimg_openmp_for(*this,std::pow((Tfloat)*ptr,(Tfloat)p),1024); - return *this; - } - - //! Raise each pixel value to a specified power \newinstance. - CImg get_pow(const double p) const { - return CImg(*this,false).pow(p); - } - - //! Raise each pixel value to a power, specified from an expression. - /** - Similar to operator+=(const char*), except it performs a pointwise exponentiation instead of an addition. - **/ - CImg& pow(const char *const expression) { - return pow((+*this)._fill(expression,true,1,0,0,"pow",this)); - } - - //! Raise each pixel value to a power, specified from an expression \newinstance. - CImg get_pow(const char *const expression) const { - return CImg(*this,false).pow(expression); - } - - //! Raise each pixel value to a power, pointwisely specified from another image. - /** - Similar to operator+=(const CImg& img), except that it performs an exponentiation instead of an addition. - **/ - template - CImg& pow(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return pow(+img); - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg get_pow(const CImg& img) const { - return CImg(*this,false).pow(img); - } - - //! Compute the bitwise left rotation of each pixel value. - /** - Similar to operator<<=(unsigned int), except that it performs a left rotation instead of a left shift. - **/ - CImg& rol(const unsigned int n=1) { - if (is_empty()) return *this; - cimg_openmp_for(*this,cimg::rol(*ptr,n),32768); - return *this; - } - - //! Compute the bitwise left rotation of each pixel value \newinstance. - CImg get_rol(const unsigned int n=1) const { - return (+*this).rol(n); - } - - //! Compute the bitwise left rotation of each pixel value. - /** - Similar to operator<<=(const char*), except that it performs a left rotation instead of a left shift. - **/ - CImg& rol(const char *const expression) { - return rol((+*this)._fill(expression,true,1,0,0,"rol",this)); - } - - //! Compute the bitwise left rotation of each pixel value \newinstance. - CImg get_rol(const char *const expression) const { - return (+*this).rol(expression); - } - - //! Compute the bitwise left rotation of each pixel value. - /** - Similar to operator<<=(const CImg&), except that it performs a left rotation instead of a left shift. - **/ - template - CImg& rol(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return rol(+img); - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg get_rol(const CImg& img) const { - return (+*this).rol(img); - } - - //! Compute the bitwise right rotation of each pixel value. - /** - Similar to operator>>=(unsigned int), except that it performs a right rotation instead of a right shift. - **/ - CImg& ror(const unsigned int n=1) { - if (is_empty()) return *this; - cimg_openmp_for(*this,cimg::ror(*ptr,n),32768); - return *this; - } - - //! Compute the bitwise right rotation of each pixel value \newinstance. - CImg get_ror(const unsigned int n=1) const { - return (+*this).ror(n); - } - - //! Compute the bitwise right rotation of each pixel value. - /** - Similar to operator>>=(const char*), except that it performs a right rotation instead of a right shift. - **/ - CImg& ror(const char *const expression) { - return ror((+*this)._fill(expression,true,1,0,0,"ror",this)); - } - - //! Compute the bitwise right rotation of each pixel value \newinstance. - CImg get_ror(const char *const expression) const { - return (+*this).ror(expression); - } - - //! Compute the bitwise right rotation of each pixel value. - /** - Similar to operator>>=(const CImg&), except that it performs a right rotation instead of a right shift. - **/ - template - CImg& ror(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return ror(+img); - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg get_ror(const CImg& img) const { - return (+*this).ror(img); - } - - //! Pointwise min operator between instance image and a value. - /** - \param val Value used as the reference argument of the min operator. - \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by - \f$\mathrm{min}(I_{(x,y,z,c)},\mathrm{val})\f$. - **/ - CImg& min(const T& value) { - if (is_empty()) return *this; - cimg_openmp_for(*this,std::min(*ptr,value),65536); - return *this; - } - - //! Pointwise min operator between instance image and a value \newinstance. - CImg get_min(const T& value) const { - return (+*this).min(value); - } - - //! Pointwise min operator between two images. - /** - \param img Image used as the reference argument of the min operator. - \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by - \f$\mathrm{min}(I_{(x,y,z,c)},\mathrm{img}_{(x,y,z,c)})\f$. - **/ - template - CImg& min(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return min(+img); - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg<_cimg_Tt> get_min(const CImg& img) const { - return CImg<_cimg_Tt>(*this,false).min(img); - } - - //! Pointwise min operator between an image and an expression. - /** - \param expression Math formula as a C-string. - \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by - \f$\mathrm{min}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$. - **/ - CImg& min(const char *const expression) { - return min((+*this)._fill(expression,true,1,0,0,"min",this)); - } - - //! Pointwise min operator between an image and an expression \newinstance. - CImg get_min(const char *const expression) const { - return CImg(*this,false).min(expression); - } - - //! Pointwise max operator between instance image and a value. - /** - \param val Value used as the reference argument of the max operator. - \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by - \f$\mathrm{max}(I_{(x,y,z,c)},\mathrm{val})\f$. - **/ - CImg& max(const T& value) { - if (is_empty()) return *this; - cimg_openmp_for(*this,std::max(*ptr,value),65536); - return *this; - } - - //! Pointwise max operator between instance image and a value \newinstance. - CImg get_max(const T& value) const { - return (+*this).max(value); - } - - //! Pointwise max operator between two images. - /** - \param img Image used as the reference argument of the max operator. - \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by - \f$\mathrm{max}(I_{(x,y,z,c)},\mathrm{img}_{(x,y,z,c)})\f$. - **/ - template - CImg& max(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return max(+img); - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg<_cimg_Tt> get_max(const CImg& img) const { - return CImg<_cimg_Tt>(*this,false).max(img); - } - - //! Pointwise max operator between an image and an expression. - /** - \param expression Math formula as a C-string. - \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by - \f$\mathrm{max}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$. - **/ - CImg& max(const char *const expression) { - return max((+*this)._fill(expression,true,1,0,0,"max",this)); - } - - //! Pointwise max operator between an image and an expression \newinstance. - CImg get_max(const char *const expression) const { - return CImg(*this,false).max(expression); - } - - //! Pointwise minabs operator between instance image and a value. - /** - \param val Value used as the reference argument of the minabs operator. - \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by - \f$\mathrm{minabs}(I_{(x,y,z,c)},\mathrm{val})\f$. - **/ - CImg& minabs(const T& value) { - if (is_empty()) return *this; - const T absvalue = cimg::abs(value); - cimg_openmp_for(*this,cimg::minabs(*ptr,value,absvalue),65536); - return *this; - } - - //! Pointwise minabs operator between instance image and a value \newinstance. - CImg get_minabs(const T& value) const { - return (+*this).minabs(value); - } - - //! Pointwise minabs operator between two images. - /** - \param img Image used as the reference argument of the minabs operator. - \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by - \f$\mathrm{minabs}(I_{(x,y,z,c)},\mathrm{img}_{(x,y,z,c)})\f$. - **/ - template - CImg& minabs(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return minabs(+img); - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg<_cimg_Tt> get_minabs(const CImg& img) const { - return CImg<_cimg_Tt>(*this,false).minabs(img); - } - - //! Pointwise minabs operator between an image and an expression. - /** - \param expression Math formula as a C-string. - \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by - \f$\mathrm{minabs}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$. - **/ - CImg& minabs(const char *const expression) { - return minabs((+*this)._fill(expression,true,1,0,0,"minabs",this)); - } - - //! Pointwise minabs operator between an image and an expression \newinstance. - CImg get_minabs(const char *const expression) const { - return CImg(*this,false).minabs(expression); - } - - //! Pointwise maxabs operator between instance image and a value. - /** - \param val Value used as the reference argument of the maxabs operator. - \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by - \f$\mathrm{maxabs}(I_{(x,y,z,c)},\mathrm{val})\f$. - **/ - CImg& maxabs(const T& value) { - if (is_empty()) return *this; - const T absvalue = cimg::abs(value); - cimg_openmp_for(*this,cimg::maxabs(*ptr,value,absvalue),65536); - return *this; - } - - //! Pointwise maxabs operator between instance image and a value \newinstance. - CImg get_maxabs(const T& value) const { - return (+*this).maxabs(value); - } - - //! Pointwise maxabs operator between two images. - /** - \param img Image used as the reference argument of the maxabs operator. - \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by - \f$\mathrm{maxabs}(I_{(x,y,z,c)},\mathrm{img}_{(x,y,z,c)})\f$. - **/ - template - CImg& maxabs(const CImg& img) { - const ulongT siz = size(), isiz = img.size(); - if (siz && isiz) { - if (is_overlapped(img)) return maxabs(+img); - T *ptrd = _data, *const ptre = _data + siz; - if (siz>isiz) for (ulongT n = siz/isiz; n; --n) - for (const t *ptrs = img._data, *ptrs_end = ptrs + isiz; ptrs - CImg<_cimg_Tt> get_maxabs(const CImg& img) const { - return CImg<_cimg_Tt>(*this,false).maxabs(img); - } - - //! Pointwise maxabs operator between an image and an expression. - /** - \param expression Math formula as a C-string. - \note Replace each pixel value \f$I_{(x,y,z,c)}\f$ of the image instance by - \f$\mathrm{maxabs}(I_{(x,y,z,c)},\mathrm{expr}_{(x,y,z,c)})\f$. - **/ - CImg& maxabs(const char *const expression) { - return maxabs((+*this)._fill(expression,true,1,0,0,"maxabs",this)); - } - - //! Pointwise maxabs operator between an image and an expression \newinstance. - CImg get_maxabs(const char *const expression) const { - return CImg(*this,false).maxabs(expression); - } - - //! Return a reference to the minimum pixel value. - /** - **/ - T& min() { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "min(): Empty instance.", - cimg_instance); - T *ptr_min = _data; - T min_value = *ptr_min; - cimg_for(*this,ptrs,T) if (*ptrsmax_value) max_value = *(ptr_max=ptrs); - return *ptr_max; - } - - //! Return a reference to the maximum pixel value \const. - const T& max() const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "max(): Empty instance.", - cimg_instance); - const T *ptr_max = _data; - T max_value = *ptr_max; - cimg_for(*this,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs); - return *ptr_max; - } - - //! Return a reference to the maximum pixel value in absolute value. - /** - **/ - T& maxabs() { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "maxabs(): Empty instance.", - cimg_instance); - T *ptr_maxabs = _data; - T maxabs_value = *ptr_maxabs; - cimg_for(*this,ptrs,T) { - const T ma = cimg::abs(*ptrs); - if (ma>maxabs_value) { maxabs_value = ma; ptr_maxabs = ptrs; } - } - return *ptr_maxabs; - } - - //! Return a reference to the maximum pixel value in absolute value \const. - const T& maxabs() const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "maxabs(): Empty instance.", - cimg_instance); - const T *ptr_maxabs = _data; - T maxabs_value = *ptr_maxabs; - cimg_for(*this,ptrs,T) { - const T ma = cimg::abs(*ptrs); - if (ma>maxabs_value) { maxabs_value = ma; ptr_maxabs = ptrs; } - } - return *ptr_maxabs; - } - - //! Return a reference to the minimum pixel value as well as the maximum pixel value. - /** - \param[out] max_val Maximum pixel value. - **/ - template - T& min_max(t& max_val) { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "min_max(): Empty instance.", - cimg_instance); - T *ptr_min = _data; - T min_value = *ptr_min, max_value = min_value; - cimg_for(*this,ptrs,T) { - const T val = *ptrs; - if (valmax_value) max_value = val; - } - max_val = (t)max_value; - return *ptr_min; - } - - //! Return a reference to the minimum pixel value as well as the maximum pixel value \const. - template - const T& min_max(t& max_val) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "min_max(): Empty instance.", - cimg_instance); - const T *ptr_min = _data; - T min_value = *ptr_min, max_value = min_value; - cimg_for(*this,ptrs,T) { - const T val = *ptrs; - if (valmax_value) max_value = val; - } - max_val = (t)max_value; - return *ptr_min; - } - - //! Return a reference to the maximum pixel value as well as the minimum pixel value. - /** - \param[out] min_val Minimum pixel value. - **/ - template - T& max_min(t& min_val) { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "max_min(): Empty instance.", - cimg_instance); - T *ptr_max = _data; - T max_value = *ptr_max, min_value = max_value; - cimg_for(*this,ptrs,T) { - const T val = *ptrs; - if (val>max_value) { max_value = val; ptr_max = ptrs; } - if (val - const T& max_min(t& min_val) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "max_min(): Empty instance.", - cimg_instance); - const T *ptr_max = _data; - T max_value = *ptr_max, min_value = max_value; - cimg_for(*this,ptrs,T) { - const T val = *ptrs; - if (val>max_value) { max_value = val; ptr_max = ptrs; } - if (val=size()) return max(); - CImg arr(*this,false); - ulongT l = 0, ir = size() - 1; - for ( ; ; ) { - if (ir<=l + 1) { - if (ir==l + 1 && arr[ir]>1; - cimg::swap(arr[mid],arr[l + 1]); - if (arr[l]>arr[ir]) cimg::swap(arr[l],arr[ir]); - if (arr[l + 1]>arr[ir]) cimg::swap(arr[l + 1],arr[ir]); - if (arr[l]>arr[l + 1]) cimg::swap(arr[l],arr[l + 1]); - ulongT i = l + 1, j = ir; - const T pivot = arr[l + 1]; - for ( ; ; ) { - do ++i; while (arr[i]pivot); - if (j=k) ir = j - 1; - if (j<=k) l = i; - } - } - } - - //! Return the median pixel value. - /** - **/ - T median() const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "median(): Empty instance.", - cimg_instance); - const ulongT s = size(); - switch (s) { - case 1 : return _data[0]; - case 2 : return cimg::median(_data[0],_data[1]); - case 3 : return cimg::median(_data[0],_data[1],_data[2]); - case 5 : return cimg::median(_data[0],_data[1],_data[2],_data[3],_data[4]); - case 7 : return cimg::median(_data[0],_data[1],_data[2],_data[3],_data[4],_data[5],_data[6]); - case 9 : return cimg::median(_data[0],_data[1],_data[2],_data[3],_data[4],_data[5],_data[6],_data[7],_data[8]); - case 13 : return cimg::median(_data[0],_data[1],_data[2],_data[3],_data[4],_data[5],_data[6],_data[7],_data[8], - _data[9],_data[10],_data[11],_data[12]); - } - const T res = kth_smallest(s>>1); - return (s%2)?res:(T)((res + kth_smallest((s>>1) - 1))/2); - } - - //! Return the product of all the pixel values. - /** - **/ - double product() const { - if (is_empty()) return 0; - double res = 1; - cimg_for(*this,ptrs,T) res*=(double)*ptrs; - return res; - } - - //! Return the sum of all the pixel values. - /** - **/ - double sum() const { - double res = 0; - cimg_for(*this,ptrs,T) res+=(double)*ptrs; - return res; - } - - //! Return the average pixel value. - /** - **/ - double mean() const { - double res = 0; - cimg_for(*this,ptrs,T) res+=(double)*ptrs; - return res/size(); - } - - //! Return the variance of the pixel values. - /** - \param variance_method Method used to estimate the variance. Can be: - - \c 0: Second moment, computed as - \f$1/N \sum\limits_{k=1}^{N} (x_k - \bar x)^2 = - 1/N \left( \sum\limits_{k=1}^N x_k^2 - \left( \sum\limits_{k=1}^N x_k \right)^2 / N \right)\f$ - with \f$ \bar x = 1/N \sum\limits_{k=1}^N x_k \f$. - - \c 1: Best unbiased estimator, computed as \f$\frac{1}{N - 1} \sum\limits_{k=1}^{N} (x_k - \bar x)^2 \f$. - - \c 2: Least median of squares. - - \c 3: Least trimmed of squares. - **/ - double variance(const unsigned int variance_method=1) const { - double foo; - return variance_mean(variance_method,foo); - } - - //! Return the variance as well as the average of the pixel values. - /** - \param variance_method Method used to estimate the variance (see variance(const unsigned int) const). - \param[out] mean Average pixel value. - **/ - template - double variance_mean(const unsigned int variance_method, t& mean) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "variance_mean(): Empty instance.", - cimg_instance); - - double variance = 0, average = 0; - const ulongT siz = size(); - switch (variance_method) { - case 0 : { // Least mean square (standard definition) - double S = 0, S2 = 0; - cimg_for(*this,ptrs,T) { const double val = (double)*ptrs; S+=val; S2+=val*val; } - variance = (S2 - S*S/siz)/siz; - average = S; - } break; - case 1 : { // Least mean square (robust definition) - double S = 0, S2 = 0; - cimg_for(*this,ptrs,T) { const double val = (double)*ptrs; S+=val; S2+=val*val; } - variance = siz>1?(S2 - S*S/siz)/(siz - 1):0; - average = S; - } break; - case 2 : { // Least Median of Squares (MAD) - CImg buf(*this,false); - buf.sort(); - const ulongT siz2 = siz>>1; - const double med_i = (double)buf[siz2]; - cimg_for(buf,ptrs,Tfloat) { - const double val = (double)*ptrs; *ptrs = (Tfloat)cimg::abs(val - med_i); average+=val; - } - buf.sort(); - const double sig = (double)(1.4828*buf[siz2]); - variance = sig*sig; - } break; - default : { // Least trimmed of Squares - CImg buf(*this,false); - const ulongT siz2 = siz>>1; - cimg_for(buf,ptrs,Tfloat) { - const double val = (double)*ptrs; (*ptrs)=(Tfloat)((*ptrs)*val); average+=val; - } - buf.sort(); - double a = 0; - const Tfloat *ptrs = buf._data; - for (ulongT j = 0; j0?variance:0; - } - - //! Return estimated variance of the noise. - /** - \param variance_method Method used to compute the variance (see variance(const unsigned int) const). - \note Because of structures such as edges in images it is - recommended to use a robust variance estimation. The variance of the - noise is estimated by computing the variance of the Laplacian \f$(\Delta - I)^2 \f$ scaled by a factor \f$c\f$ insuring \f$ c E[(\Delta I)^2]= - \sigma^2\f$ where \f$\sigma\f$ is the noise variance. - **/ - double variance_noise(const unsigned int variance_method=2) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "variance_noise(): Empty instance.", - cimg_instance); - - const ulongT siz = size(); - if (!siz || !_data) return 0; - if (variance_method>1) { // Compute a scaled version of the Laplacian - CImg tmp(*this,false); - if (_depth==1) { - const double cste = 1./std::sqrt(20.); // Depends on how the Laplacian is computed - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*262144 && - _spectrum>=2)) - cimg_forC(*this,c) { - CImg_3x3(I,T); - cimg_for3x3(*this,x,y,0,c,I,T) { - tmp(x,y,c) = cste*((double)Inc + (double)Ipc + (double)Icn + - (double)Icp - 4*(double)Icc); - } - } - } else { - const double cste = 1./std::sqrt(42.); // Depends on how the Laplacian is computed - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*262144 && - _spectrum>=2)) - cimg_forC(*this,c) { - CImg_3x3x3(I,T); - cimg_for3x3x3(*this,x,y,z,c,I,T) { - tmp(x,y,z,c) = cste*( - (double)Incc + (double)Ipcc + (double)Icnc + (double)Icpc + - (double)Iccn + (double)Iccp - 6*(double)Iccc); - } - } - } - return tmp.variance(variance_method); - } - - // Version that doesn't need intermediate images. - double variance = 0, S = 0, S2 = 0; - if (_depth==1) { - const double cste = 1./std::sqrt(20.); - CImg_3x3(I,T); - cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,T) { - const double val = cste*((double)Inc + (double)Ipc + - (double)Icn + (double)Icp - 4*(double)Icc); - S+=val; S2+=val*val; - } - } else { - const double cste = 1./std::sqrt(42.); - CImg_3x3x3(I,T); - cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,T) { - const double val = cste * - ((double)Incc + (double)Ipcc + (double)Icnc + - (double)Icpc + - (double)Iccn + (double)Iccp - 6*(double)Iccc); - S+=val; S2+=val*val; - } - } - if (variance_method) variance = siz>1?(S2 - S*S/siz)/(siz - 1):0; - else variance = (S2 - S*S/siz)/siz; - return variance>0?variance:0; - } - - //! Compute the MSE (Mean-Squared Error) between two images. - /** - \param img Image used as the second argument of the MSE operator. - **/ - template - double MSE(const CImg& img) const { - if (img.size()!=size()) - throw CImgArgumentException(_cimg_instance - "MSE(): Instance and specified image (%u,%u,%u,%u,%p) have different dimensions.", - cimg_instance, - img._width,img._height,img._depth,img._spectrum,img._data); - double vMSE = 0; - const t* ptr2 = img._data; - cimg_for(*this,ptr1,T) { - const double diff = (double)*ptr1 - (double)*(ptr2++); - vMSE+=diff*diff; - } - const ulongT siz = img.size(); - if (siz) vMSE/=siz; - return vMSE; - } - - //! Compute the PSNR (Peak Signal-to-Noise Ratio) between two images. - /** - \param img Image used as the second argument of the PSNR operator. - \param max_value Maximum theoretical value of the signal. - **/ - template - double PSNR(const CImg& img, const double max_value=255) const { - const double vMSE = (double)std::sqrt(MSE(img)); - return (vMSE!=0)?(double)(20*std::log10(max_value/vMSE)):(double)(cimg::type::max()); - } - - //! Evaluate math formula. - /** - \param expression Math formula, as a C-string. - \param x Value of the pre-defined variable \c x. - \param y Value of the pre-defined variable \c y. - \param z Value of the pre-defined variable \c z. - \param c Value of the pre-defined variable \c c. - \param list_images A list of images attached to the specified math formula. - **/ - double eval(const char *const expression, - const double x=0, const double y=0, const double z=0, const double c=0, - CImgList *const list_images=0) { - return _eval(this,expression,x,y,z,c,list_images); - } - - //! Evaluate math formula \const. - double eval(const char *const expression, - const double x=0, const double y=0, const double z=0, const double c=0, - CImgList *const list_images=0) const { - return _eval(0,expression,x,y,z,c,list_images); - } - - // Fast function to pre-evaluate common expressions. - // (return 'true' in case of success, and set value of 'res'). - template - bool __eval(const char *const expression, t &res) const { - if (!expression || !*expression) { res = (t)0; return true; } - const char c = *expression; - bool is_success = false; - char sep, end; - double val,val2; - int err; - if ((c>='0' && c<='9') || c=='.') { // Possible value - if (!expression[1]) { // Single digit - res = (t)(c - '0'); - is_success = true; - } else if ((err = std::sscanf(expression,"%lf %c%lf %c",&val,&sep,&val2,&end))==1) { // Single value - res = (t)val; - is_success = true; - } else if (err==3) { // Value1 Operator Value2 - switch (sep) { - case '+' : res = (t)(val + val2); is_success = true; break; - case '-' : res = (t)(val - val2); is_success = true; break; - case '*' : res = (t)(val*val2); is_success = true; break; - case '/' : res = (t)(val/val2); is_success = true; break; - case '%' : res = (t)cimg::mod(val,val2); is_success = true; break; - case '&' : res = (t)((long)val & (long)val2); is_success = true; break; - case '|' : res = (t)((long)val | (long)val2); is_success = true; break; - case '>' : res = (t)(val>val2); is_success = true; break; - case '<' : res = (t)(val='0' && sep<='9') || sep=='.')) { - if (!expression[2]) { // [+-!] + Single digit - const int ival = sep - '0'; - res = (t)(c=='+'?ival:c=='-'?-ival:!ival); - is_success = true; - } else if ((err = std::sscanf(expression + 1,"%lf %c%lf %c",&val,&sep,&val2,&end))==1) { // [+-!] Single value - res = (t)(c=='+'?val:c=='-'?-val:(double)!val); - is_success = true; - } else if (err==3) { // [+-!] Value1 Operator Value2 - const double val1 = c=='+'?val:c=='-'?-val:(double)!val; - switch (sep) { - case '+' : res = (t)(val1 + val2); is_success = true; break; - case '-' : res = (t)(val1 - val2); is_success = true; break; - case '*' : res = (t)(val1*val2); is_success = true; break; - case '/' : res = (t)(val1/val2); is_success = true; break; - case '%' : res = (t)cimg::mod(val1,val2); is_success = true; break; - case '&' : res = (t)((long)val1 & (long)val2); is_success = true; break; - case '|' : res = (t)((long)val1 | (long)val2); is_success = true; break; - case '>' : res = (t)(val1>val2); is_success = true; break; - case '<' : res = (t)(val1 *const img_output, const char *const expression, - const double x, const double y, const double z, const double c, - CImgList *const list_images) const { - if (!expression || !*expression) return 0; - double _val = 0; - if (__eval(expression,_val)) return _val; - _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || - *expression=='*' || *expression==':'),"eval", - *this,img_output,list_images,false); - mp.begin_t(); - const double val = mp(x,y,z,c); - mp.end_t(); - mp.end(); - return val; - } - - //! Evaluate math formula. - /** - \param[out] output Contains values of output vector returned by the evaluated expression - (or is empty if the returned type is scalar). - \param expression Math formula, as a C-string. - \param x Value of the pre-defined variable \c x. - \param y Value of the pre-defined variable \c y. - \param z Value of the pre-defined variable \c z. - \param c Value of the pre-defined variable \c c. - \param list_images A list of input images attached to the specified math formula. - **/ - template - void eval(CImg &output, const char *const expression, - const double x=0, const double y=0, const double z=0, const double c=0, - CImgList *const list_images=0) { - _eval(output,this,expression,x,y,z,c,list_images); - } - - //! Evaluate math formula \const. - template - void eval(CImg& output, const char *const expression, - const double x=0, const double y=0, const double z=0, const double c=0, - CImgList *const list_images=0) const { - _eval(output,0,expression,x,y,z,c,list_images); - } - - template - void _eval(CImg& output, CImg *const img_output, const char *const expression, - const double x, const double y, const double z, const double c, - CImgList *const list_images) const { - if (!expression || !*expression) { output.assign(1); *output = 0; return; } - double _val = 0; - if (__eval(expression,_val)) { output.assign(1); *output = _val; return; } - _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || - *expression=='*' || *expression==':'),"eval", - *this,img_output,list_images,false); - output.assign(1,std::max(1U,mp.result_dim)); - mp.begin_t(); - mp(x,y,z,c,output._data); - mp.end_t(); - mp.end(); - } - - //! Evaluate math formula on a set of variables. - /** - \param expression Math formula, as a C-string. - \param xyzc Set of values (x,y,z,c) used for the evaluation. - \param list_images A list of input images attached to the specified math formula. - **/ - template - CImg eval(const char *const expression, const CImg& xyzc, - CImgList *const list_images=0) { - return _eval(this,expression,xyzc,list_images); - } - - //! Evaluate math formula on a set of variables \const. - template - CImg eval(const char *const expression, const CImg& xyzc, - CImgList *const list_images=0) const { - return _eval(0,expression,xyzc,list_images); - } - - template - CImg _eval(CImg *const output, const char *const expression, const CImg& xyzc, - CImgList *const list_images=0) const { - CImg res(1,xyzc.size()/4); - if (!expression || !*expression) return res.fill(0); - _cimg_math_parser mp(expression,"eval",*this,output,list_images,false); - -#if cimg_use_openmp!=0 - cimg_pragma_openmp(parallel if (res._height>=512)) - { - _cimg_math_parser - *const _mp = omp_get_thread_num()?new _cimg_math_parser(mp):&mp, - &lmp = *_mp; - cimg_pragma_openmp(barrier) - lmp.begin_t(); - cimg_pragma_openmp(for) - for (int i = 0; i[min, max, mean, variance, xmin, ymin, zmin, cmin, xmax, ymax, zmax, cmax, sum, product]. - **/ - CImg get_stats(const unsigned int variance_method=1) const { - if (is_empty()) return CImg(); - const ulongT siz = size(); - const longT off_end = (longT)siz; - double S = 0, S2 = 0, P = 1; - longT offm = 0, offM = 0; - T m = *_data, M = m; - - cimg_pragma_openmp(parallel reduction(+:S,S2) reduction(*:P) cimg_openmp_if_size(siz,131072)) { - longT loffm = 0, loffM = 0; - T lm = *_data, lM = lm; - cimg_pragma_openmp(for) - for (longT off = 0; offlM) { lM = val; loffM = off; } - S+=_val; - S2+=_val*_val; - P*=_val; - } - cimg_pragma_openmp(critical(get_stats)) { - if (lmM || (lM==M && loffM1?(S2 - S*S/siz)/(siz - 1):0): - variance(variance_method)), - variance_value = _variance_value>0?_variance_value:0; - int - xm = 0, ym = 0, zm = 0, cm = 0, - xM = 0, yM = 0, zM = 0, cM = 0; - contains(_data[offm],xm,ym,zm,cm); - contains(_data[offM],xM,yM,zM,cM); - return CImg(1,14).fill((double)m,(double)M,mean_value,variance_value, - (double)xm,(double)ym,(double)zm,(double)cm, - (double)xM,(double)yM,(double)zM,(double)cM, - S,P); - } - - //! Compute statistics vector from the pixel values \inplace. - CImg& stats(const unsigned int variance_method=1) { - return get_stats(variance_method).move_to(*this); - } - - //@} - //------------------------------------- - // - //! \name Vector / Matrix Operations - //@{ - //------------------------------------- - - //! Compute norm of the image, viewed as a matrix. - /** - \param magnitude_type Norm type. Can be: - - \c -1: Linf-norm - - \c 0: L0-norm - - \c 1: L1-norm - - \c 2: L2-norm - **/ - double magnitude(const int magnitude_type=2) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "magnitude(): Empty instance.", - cimg_instance); - const ulongT siz = size(); - double res = 0; - switch (magnitude_type) { - case -1 : { - cimg_for(*this,ptrs,T) { const double val = (double)cimg::abs(*ptrs); if (val>res) res = val; } - } break; - case 1 : { - cimg_pragma_openmp(parallel for reduction(+:res) cimg_openmp_if_size(size(),8192)) - for (longT off = 0; off<(longT)siz; ++off) res+=(double)cimg::abs(_data[off]); - } break; - default : { - cimg_pragma_openmp(parallel for reduction(+:res) cimg_openmp_if_size(size(),8192)) - for (longT off = 0; off<(longT)siz; ++off) res+=(double)cimg::sqr(_data[off]); - res = (double)std::sqrt(res); - } - } - return res; - } - - //! Compute the trace of the image, viewed as a matrix. - /** - **/ - double trace() const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "trace(): Empty instance.", - cimg_instance); - double res = 0; - cimg_forX(*this,k) res+=(double)(*this)(k,k); - return res; - } - - //! Compute the determinant of the image, viewed as a matrix. - /** - **/ - double det() const { - if (is_empty() || _width!=_height || _depth!=1 || _spectrum!=1) - throw CImgInstanceException(_cimg_instance - "det(): Instance is not a square matrix.", - cimg_instance); - - switch (_width) { - case 1 : return (double)((*this)(0,0)); - case 2 : return (double)((*this)(0,0))*(double)((*this)(1,1)) - (double)((*this)(0,1))*(double)((*this)(1,0)); - case 3 : { - const double - a = (double)_data[0], d = (double)_data[1], g = (double)_data[2], - b = (double)_data[3], e = (double)_data[4], h = (double)_data[5], - c = (double)_data[6], f = (double)_data[7], i = (double)_data[8]; - return i*a*e - a*h*f - i*b*d + b*g*f + c*d*h - c*g*e; - } - default : { - CImg lu(*this,false); - CImg indx; - bool d; - lu._LU(indx,d); - double res = d?(double)1:(double)-1; - cimg_forX(lu,i) res*=lu(i,i); - return res; - } - } - } - - //! Compute the dot product between instance and argument, viewed as matrices. - /** - \param img Image used as a second argument of the dot product. - **/ - template - double dot(const CImg& img) const { - const ulongT nb = std::min(size(),img.size()); - double res = 0; - cimg_pragma_openmp(parallel for reduction(+:res) cimg_openmp_if_size(nb,8192)) - for (longT off = 0; off<(longT)nb; ++off) res+=(double)_data[off]*(double)img[off]; - return res; - } - - //! Get vector-valued pixel located at specified position. - /** - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - **/ - CImg get_vector_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const { - CImg res; - if (res._height!=_spectrum) res.assign(1,_spectrum); - const ulongT whd = (ulongT)_width*_height*_depth; - const T *ptrs = data(x,y,z); - T *ptrd = res._data; - cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; } - return res; - } - - //! Get (square) matrix-valued pixel located at specified position. - /** - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \note - The spectrum() of the image must be a square. - **/ - CImg get_matrix_at(const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) const { - const int n = (int)cimg::round(std::sqrt((double)_spectrum)); - const T *ptrs = data(x,y,z,0); - const ulongT whd = (ulongT)_width*_height*_depth; - CImg res(n,n); - T *ptrd = res._data; - cimg_forC(*this,c) { *(ptrd++) = *ptrs; ptrs+=whd; } - return res; - } - - //! Get tensor-valued pixel located at specified position. - /** - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - **/ - CImg get_tensor_at(const unsigned int x, const unsigned int y=0, const unsigned int z=0) const { - const T *ptrs = data(x,y,z,0); - const ulongT whd = (ulongT)_width*_height*_depth; - if (_spectrum==6) - return tensor(*ptrs,*(ptrs + whd),*(ptrs + 2*whd),*(ptrs + 3*whd),*(ptrs + 4*whd),*(ptrs + 5*whd)); - if (_spectrum==3) - return tensor(*ptrs,*(ptrs + whd),*(ptrs + 2*whd)); - return tensor(*ptrs); - } - - //! Set vector-valued pixel at specified position. - /** - \param vec Vector to put on the instance image. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - **/ - template - CImg& set_vector_at(const CImg& vec, const unsigned int x, const unsigned int y=0, const unsigned int z=0) { - if (x<_width && y<_height && z<_depth) { - const t *ptrs = vec._data; - const ulongT whd = (ulongT)_width*_height*_depth; - T *ptrd = data(x,y,z); - for (unsigned int k = std::min((unsigned int)vec.size(),_spectrum); k; --k) { - *ptrd = (T)*(ptrs++); ptrd+=whd; - } - } - return *this; - } - - //! Set (square) matrix-valued pixel at specified position. - /** - \param mat Matrix to put on the instance image. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - **/ - template - CImg& set_matrix_at(const CImg& mat, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) { - return set_vector_at(mat,x,y,z); - } - - //! Set tensor-valued pixel at specified position. - /** - \param ten Tensor to put on the instance image. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - **/ - template - CImg& set_tensor_at(const CImg& ten, const unsigned int x=0, const unsigned int y=0, const unsigned int z=0) { - T *ptrd = data(x,y,z,0); - const ulongT siz = (ulongT)_width*_height*_depth; - if (ten._height==2) { - *ptrd = (T)ten[0]; ptrd+=siz; - *ptrd = (T)ten[1]; ptrd+=siz; - *ptrd = (T)ten[3]; - } - else { - *ptrd = (T)ten[0]; ptrd+=siz; - *ptrd = (T)ten[1]; ptrd+=siz; - *ptrd = (T)ten[2]; ptrd+=siz; - *ptrd = (T)ten[4]; ptrd+=siz; - *ptrd = (T)ten[5]; ptrd+=siz; - *ptrd = (T)ten[8]; - } - return *this; - } - - //! Resize image to become a diagonal matrix. - /** - \note Transform the image as a diagonal matrix so that each of its initial value becomes a diagonal coefficient. - **/ - CImg& diagonal() { - return get_diagonal().move_to(*this); - } - - //! Resize image to become a diagonal matrix \newinstance. - CImg get_diagonal() const { - if (is_empty()) return *this; - const unsigned int siz = (unsigned int)size(); - CImg res(siz,siz,1,1,0); - cimg_foroff(*this,off) res((unsigned int)off,(unsigned int)off) = (*this)[off]; - return res; - } - - //! Replace the image by an identity matrix. - /** - \note If the instance image is not square, it is resized to a square matrix using its maximum - dimension as a reference. - **/ - CImg& identity_matrix() { - return identity_matrix(std::max(_width,_height)).move_to(*this); - } - - //! Replace the image by an identity matrix \newinstance. - CImg get_identity_matrix() const { - return identity_matrix(std::max(_width,_height)); - } - - //! Fill image with a linear sequence of values. - /** - \param a0 Starting value of the sequence. - \param a1 Ending value of the sequence. - **/ - CImg& sequence(const T& a0, const T& a1) { - if (is_empty()) return *this; - const ulongT siz = size() - 1; - T* ptr = _data; - if (siz) { - const double delta = (double)a1 - (double)a0; - cimg_foroff(*this,l) *(ptr++) = (T)(a0 + delta*l/siz); - } else *ptr = a0; - return *this; - } - - //! Fill image with a linear sequence of values \newinstance. - CImg get_sequence(const T& a0, const T& a1) const { - return (+*this).sequence(a0,a1); - } - - //! Transpose the image, viewed as a matrix. - /** - \note Equivalent to \code permute_axes("yxzc"); \endcode. - **/ - CImg& transpose() { - if (_width==1) { _width = _height; _height = 1; return *this; } - if (_height==1) { _height = _width; _width = 1; return *this; } - if (_width==_height) { - cimg_forYZC(*this,y,z,c) for (int x = y; x get_transpose() const { - return get_permute_axes("yxzc"); - } - - //! Compute the cross product between two \c 1x3 images, viewed as 3D vectors. - /** - \param img Image used as the second argument of the cross product. - \note The first argument of the cross product is \c *this. - **/ - template - CImg& cross(const CImg& img) { - if (_width!=1 || _height<3 || img._width!=1 || img._height<3) - throw CImgInstanceException(_cimg_instance - "cross(): Instance and/or specified image (%u,%u,%u,%u,%p) are not 3D vectors.", - cimg_instance, - img._width,img._height,img._depth,img._spectrum,img._data); - - const T x = (*this)[0], y = (*this)[1], z = (*this)[2]; - (*this)[0] = (T)(y*img[2] - z*img[1]); - (*this)[1] = (T)(z*img[0] - x*img[2]); - (*this)[2] = (T)(x*img[1] - y*img[0]); - return *this; - } - - //! Compute the cross product between two \c 1x3 images, viewed as 3D vectors \newinstance. - template - CImg<_cimg_Tt> get_cross(const CImg& img) const { - return CImg<_cimg_Tt>(*this).cross(img); - } - - //! Invert the instance image, viewed as a matrix. - /** - If the instance matrix is not square, the Moore-Penrose pseudo-inverse is computed instead. - \param use_LU Choose the inverting algorithm. Can be: - - \c true: LU solver (faster but less precise). - - \c false: SVD solver (more precise but slower). - \param lambda is used only in the Moore-Penrose pseudoinverse for estimating A^t.(A^t.A + lambda.Id)^-1. - **/ - CImg& invert(const bool use_LU=false, const float lambda=0) { - if (_depth!=1 || _spectrum!=1) - throw CImgInstanceException(_cimg_instance - "invert(): Instance is not a matrix.", - cimg_instance); - if (lambda<0) - throw CImgArgumentException(_cimg_instance - "invert(): Specified lambda (%g) should be >=0.", - cimg_instance); - - if (_width!=_height) return get_invert(use_LU,lambda).move_to(*this); // Non-square matrix: Pseudoinverse - - // Square matrix. - const double dete = _width>3?-1.:det(); - if (dete!=0. && _width==2) { - const double - a = _data[0], c = _data[1], - b = _data[2], d = _data[3]; - _data[0] = (T)(d/dete); _data[1] = (T)(-c/dete); - _data[2] = (T)(-b/dete); _data[3] = (T)(a/dete); - } else if (dete!=0. && _width==3) { - const double - a = _data[0], d = _data[1], g = _data[2], - b = _data[3], e = _data[4], h = _data[5], - c = _data[6], f = _data[7], i = _data[8]; - _data[0] = (T)((i*e - f*h)/dete), _data[1] = (T)((g*f - i*d)/dete), _data[2] = (T)((d*h - g*e)/dete); - _data[3] = (T)((h*c - i*b)/dete), _data[4] = (T)((i*a - c*g)/dete), _data[5] = (T)((g*b - a*h)/dete); - _data[6] = (T)((b*f - e*c)/dete), _data[7] = (T)((d*c - a*f)/dete), _data[8] = (T)((a*e - d*b)/dete); - } else { - -#ifdef cimg_use_lapack - int INFO = (int)use_LU, N = _width, LWORK = 4*N, *const IPIV = new int[N]; - Tfloat - *const lapA = new Tfloat[N*N], - *const WORK = new Tfloat[LWORK]; - cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l)); - cimg::getrf(N,lapA,IPIV,INFO); - if (INFO) - cimg::warn(_cimg_instance - "invert(): LAPACK function dgetrf_() returned error code %d.", - cimg_instance, - INFO); - else { - cimg::getri(N,lapA,IPIV,WORK,LWORK,INFO); - if (INFO) - cimg::warn(_cimg_instance - "invert(): LAPACK function dgetri_() returned error code %d.", - cimg_instance, - INFO); - } - if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)(lapA[k*N + l]); else fill(0); - delete[] IPIV; delete[] lapA; delete[] WORK; -#else - if (use_LU) { // LU solver - CImg A(*this,false), indx; - bool d; - A._LU(indx,d); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(_width*_height,16*16)) - cimg_forX(*this,j) { - CImg col(1,_width,1,1,0); - col(j) = 1; - col._solve(A,indx); - cimg_forX(*this,i) (*this)(j,i) = (T)col(i); - } - } else _get_invert_svd(false).move_to(*this); // SVD solver -#endif - } - return *this; - } - - //! Invert the instance image, viewed as a matrix \newinstance. - CImg get_invert(const bool use_LU=false, const float lambda=0) const { - if (_depth!=1 || _spectrum!=1) - throw CImgInstanceException(_cimg_instance - "invert(): Instance is not a matrix.", - cimg_instance); - if (lambda<0) - throw CImgArgumentException(_cimg_instance - "invert(): Specified lambda (%g) should be >=0.", - cimg_instance); - - if (_width==_height) return CImg(*this,false).invert(use_LU,lambda); // Square matrix - - // Non-square matrix: Pseudoinverse - if (use_LU) { - if (_width<_height) { // under-solved system -> (A^t.A)^-1.A^t - CImg AtA(width(),width()); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(_width*_height,128*128)) - cimg_forY(AtA,i) - for (int j = 0; j<=i; ++j) { - double res = 0; - cimg_forY(*this,k) res+=(*this)(i,k)*(*this)(j,k); - AtA(j,i) = AtA(i,j) = (Tfloat)res; - } - if (lambda!=0) cimg_forY(AtA,i) AtA(i,i)+=lambda; - AtA.invert(true); - return AtA*get_transpose(); - } else { // over-resolved linear system -> A^t.(A.A^t)^-1 - CImg AAt(height(),height()); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(_width*_height,128*128)) - cimg_forY(AAt,i) - for (int j = 0; j<=i; ++j) { - double res = 0; - cimg_forX(*this,k) res+=(*this)(k,i)*(*this)(k,j); - AAt(j,i) = AAt(i,j) = (Tfloat)res; - } - if (lambda!=0) cimg_forY(AAt,i) AAt(i,i)+=lambda; - AAt.invert(true); - return get_transpose()*AAt; - } - } - return _get_invert_svd(lambda); - } - - // SVD solver, both used for inverse and pseudoinverse. - CImg _get_invert_svd(const float lambda) const { - CImg U, S, V; - SVD(U,S,V,false); - const Tfloat epsilon = (sizeof(Tfloat)<=4?5.96e-8f:1.11e-16f)*std::max(_width,_height)*S.max(); - cimg_forX(V,x) { - const Tfloat s = S(x), invs = lambda?1/(lambda + s):s>epsilon?1/s:0; - cimg_forY(V,y) V(x,y)*=invs; - } - return V*U.transpose(); - } - - //! Solve a system of linear equations. - /** - \param A Matrix of the linear system. - \param use_LU In case of non square system (least-square solution), - choose between SVD (\c false) or LU (\c true) solver. - LU solver is faster for large matrices, but numerically less stable. - \note Solve \c AX = B where \c B=*this. - **/ - template - CImg& solve(const CImg& A, const bool use_LU=false) { - if (_depth!=1 || _spectrum!=1 || _height!=A._height || A._depth!=1 || A._spectrum!=1) - throw CImgArgumentException(_cimg_instance - "solve(): Instance and specified matrix (%u,%u,%u,%u,%p) have " - "incompatible dimensions.", - cimg_instance, - A._width,A._height,A._depth,A._spectrum,A._data); - typedef _cimg_Ttfloat Ttfloat; - - if (A.size()==1) return (*this)/=A[0]; - if (A._width==2 && A._height==2 && _height==2) { // 2x2 linear system - const double a = (double)A[0], b = (double)A[1], c = (double)A[2], d = (double)A[3], - fa = std::fabs(a), fb = std::fabs(b), fc = std::fabs(c), fd = std::fabs(d), - det = a*d - b*c, fM = cimg::max(fa,fb,fc,fd); - if (fM==fa) - cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=256)) - cimg_forX(*this,k) { - const double u = (double)(*this)(k,0), v = (double)(*this)(k,1), y = (a*v - c*u)/det; - (*this)(k,0) = (T)((u - b*y)/a); (*this)(k,1) = (T)y; - } else if (fM==fc) - cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=256)) - cimg_forX(*this,k) { - const double u = (double)(*this)(k,0), v = (double)(*this)(k,1), y = (a*v - c*u)/det; - (*this)(k,0) = (T)((v - d*y)/c); (*this)(k,1) = (T)y; - } else if (fM==fb) - cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=256)) - cimg_forX(*this,k) { - const double u = (double)(*this)(k,0), v = (double)(*this)(k,1), x = (d*u - b*v)/det; - (*this)(k,0) = (T)x; (*this)(k,1) = (T)((u - a*x)/b); - } else - cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=256)) - cimg_forX(*this,k) { - const double u = (double)(*this)(k,0), v = (double)(*this)(k,1), x = (d*u - b*v)/det; - (*this)(k,0) = (T)x; (*this)(k,1) = (T)((v - c*x)/d); - } - return *this; - } - - if (A._width==A._height) { // Square linear system -#ifdef cimg_use_lapack - char TRANS = 'N'; - int INFO, N = _height, LWORK = 4*N, *const IPIV = new int[N]; - Ttfloat - *const lapA = new Ttfloat[N*N], - *const lapB = new Ttfloat[N], - *const WORK = new Ttfloat[LWORK]; - cimg_forXY(A,k,l) lapA[k*N + l] = (Ttfloat)(A(k,l)); - cimg_forX(*this,i) { - cimg_forY(*this,j) lapB[j] = (Ttfloat)((*this)(i,j)); - cimg::getrf(N,lapA,IPIV,INFO); - if (INFO) - cimg::warn(_cimg_instance - "solve(): LAPACK library function dgetrf_() returned error code %d.", - cimg_instance, - INFO); - else { - cimg::getrs(TRANS,N,lapA,IPIV,lapB,INFO); - if (INFO) - cimg::warn(_cimg_instance - "solve(): LAPACK library function dgetrs_() returned error code %d.", - cimg_instance, - INFO); - } - if (!INFO) cimg_forY(*this,j) (*this)(i,j) = (T)(lapB[j]); else cimg_forY(*this,j) (*this)(i,j) = (T)0; - } - delete[] IPIV; delete[] lapA; delete[] lapB; delete[] WORK; -#else - CImg lu(A,false); - CImg indx; - bool d; - lu._LU(indx,d); - CImg res(_width,A._width); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(_width*_height,16)) - cimg_forX(*this,i) res.draw_image(i,get_column(i)._solve(lu,indx)); - res.move_to(*this); -#endif - } else { // Least-square solution for non-square systems - -#ifdef cimg_use_lapack - char TRANS = 'N'; - int INFO, N = A._width, M = A._height, LWORK = -1, LDA = M, LDB = M, NRHS = _width; - Ttfloat WORK_QUERY; - Ttfloat - * const lapA = new Ttfloat[M*N], - * const lapB = new Ttfloat[M*NRHS]; - cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, &WORK_QUERY, LWORK, INFO); - LWORK = (int) WORK_QUERY; - Ttfloat *const WORK = new Ttfloat[LWORK]; - cimg_forXY(A,k,l) lapA[k*M + l] = (Ttfloat)(A(k,l)); - cimg_forXY(*this,k,l) lapB[k*M + l] = (Ttfloat)((*this)(k,l)); - cimg::sgels(TRANS, M, N, NRHS, lapA, LDA, lapB, LDB, WORK, LWORK, INFO); - if (INFO != 0) - cimg::warn(_cimg_instance - "solve(): LAPACK library function sgels() returned error code %d.", - cimg_instance, - INFO); - assign(NRHS, N); - if (!INFO) cimg_forXY(*this,k,l) (*this)(k,l) = (T)lapB[k*M + l]; - else (A.get_invert(use_LU)*(*this)).move_to(*this); - delete[] lapA; delete[] lapB; delete[] WORK; -#else - (A.get_invert(use_LU)*(*this)).move_to(*this); -#endif - } - return *this; - } - - //! Solve a system of linear equations \newinstance. - template - CImg<_cimg_Ttfloat> get_solve(const CImg& A, const bool use_LU=false) const { - typedef _cimg_Ttfloat Ttfloat; - return CImg(*this,false).solve(A,use_LU); - } - - template - CImg& _solve(const CImg& A, const CImg& indx) { - typedef _cimg_Ttfloat Ttfloat; - const int N = height(); - int ii = -1; - Ttfloat sum; - for (int i = 0; i=0) for (int j = ii; j<=i - 1; ++j) sum-=A(j,i)*(*this)(j); - else if (sum!=0) ii = i; - (*this)(i) = (T)sum; - } - for (int i = N - 1; i>=0; --i) { - sum = (*this)(i); - for (int j = i + 1; j - CImg& solve_tridiagonal(const CImg& A) { - const unsigned int siz = (unsigned int)size(); - if (A._width!=3 || A._height!=siz) - throw CImgArgumentException(_cimg_instance - "solve_tridiagonal(): Instance and tridiagonal matrix " - "(%u,%u,%u,%u,%p) have incompatible dimensions.", - cimg_instance, - A._width,A._height,A._depth,A._spectrum,A._data); - typedef _cimg_Ttfloat Ttfloat; - const Ttfloat epsilon = 1e-4f; - CImg B = A.get_column(1), V(*this,false); - for (int i = 1; i<(int)siz; ++i) { - const Ttfloat m = A(0,i)/(B[i - 1]?B[i - 1]:epsilon); - B[i] -= m*A(2,i - 1); - V[i] -= m*V[i - 1]; - } - (*this)[siz - 1] = (T)(V[siz - 1]/(B[siz - 1]?B[siz - 1]:epsilon)); - for (int i = (int)siz - 2; i>=0; --i) (*this)[i] = (T)((V[i] - A(2,i)*(*this)[i + 1])/(B[i]?B[i]:epsilon)); - return *this; - } - - //! Solve a tridiagonal system of linear equations \newinstance. - template - CImg<_cimg_Ttfloat> get_solve_tridiagonal(const CImg& A) const { - return CImg<_cimg_Ttfloat>(*this,false).solve_tridiagonal(A); - } - - //! Compute eigenvalues and eigenvectors of the instance image, viewed as a matrix. - /** - \param[out] val Vector of the estimated eigenvalues, in decreasing order. - \param[out] vec Matrix of the estimated eigenvectors, sorted by columns. - **/ - template - const CImg& eigen(CImg& val, CImg &vec) const { - if (is_empty()) { val.assign(); vec.assign(); } - else { - if (_width!=_height || _depth>1 || _spectrum>1) - throw CImgInstanceException(_cimg_instance - "eigen(): Instance is not a square matrix.", - cimg_instance); - - if (val.size()<(ulongT)_width) val.assign(1,_width); - if (vec.size()<(ulongT)_width*_width) vec.assign(_width,_width); - switch (_width) { - case 1 : { val[0] = (t)(*this)[0]; vec[0] = (t)1; } break; - case 2 : { - const double a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], e = a + d; - double f = e*e - 4*(a*d - b*c); - if (f<0) cimg::warn(_cimg_instance - "eigen(): Complex eigenvalues found.", - cimg_instance); - f = std::sqrt(f); - const double - l1 = 0.5*(e - f), - l2 = 0.5*(e + f), - b2 = b*b, - norm1 = std::sqrt(cimg::sqr(l2 - a) + b2), - norm2 = std::sqrt(cimg::sqr(l1 - a) + b2); - val[0] = (t)l2; - val[1] = (t)l1; - if (norm1>0) { vec(0,0) = (t)(b/norm1); vec(0,1) = (t)((l2 - a)/norm1); } else { vec(0,0) = 1; vec(0,1) = 0; } - if (norm2>0) { vec(1,0) = (t)(b/norm2); vec(1,1) = (t)((l1 - a)/norm2); } else { vec(1,0) = 1; vec(1,1) = 0; } - } break; - default : - throw CImgInstanceException(_cimg_instance - "eigen(): Eigenvalues computation of general matrices is limited " - "to 2x2 matrices.", - cimg_instance); - } - } - return *this; - } - - //! Compute eigenvalues and eigenvectors of the instance image, viewed as a matrix. - /** - \return A list of two images [val; vec], whose meaning is similar as in eigen(CImg&,CImg&) const. - **/ - CImgList get_eigen() const { - CImgList res(2); - eigen(res[0],res[1]); - return res; - } - - //! Compute eigenvalues and eigenvectors of the instance image, viewed as a symmetric matrix. - /** - \param[out] val Vector of the estimated eigenvalues, in decreasing order. - \param[out] vec Matrix of the estimated eigenvectors, sorted by columns. - **/ - template - const CImg& symmetric_eigen(CImg& val, CImg& vec) const { - if (is_empty()) { val.assign(); vec.assign(); return *this; } - if (_width!=_height || _depth>1 || _spectrum>1) - throw CImgInstanceException(_cimg_instance - "eigen(): Instance is not a square matrix.", - cimg_instance); - val.assign(1,_width); - vec.assign(_width,_width); - - if (_width==1) { val[0] = cimg::abs((*this)[0]); vec[0] = 1; return *this; } - if (_width==2) { - const double - a = (*this)[0], b = (*this)[1], c = (*this)[2], d = (*this)[3], - e = a + d, f = std::sqrt(std::max(e*e - 4*(a*d - b*c),0.0)), - l1 = 0.5*(e - f), l2 = 0.5*(e + f), - n = std::sqrt(cimg::sqr(l2 - a) + b*b); - val[0] = (t)l2; - val[1] = (t)l1; - if (n>0) { vec[0] = (t)(b/n); vec[2] = (t)((l2 - a)/n); } else { vec[0] = 1; vec[2] = 0; } - vec[1] = -vec[2]; - vec[3] = vec[0]; - return *this; - } - -#ifdef cimg_use_lapack - char JOB = 'V', UPLO = 'U'; - int N = _width, LWORK = 4*N, INFO; - Tfloat - *const lapA = new Tfloat[N*N], - *const lapW = new Tfloat[N], - *const WORK = new Tfloat[LWORK]; - cimg_forXY(*this,k,l) lapA[k*N + l] = (Tfloat)((*this)(k,l)); - cimg::syev(JOB,UPLO,N,lapA,lapW,WORK,LWORK,INFO); - if (INFO) - cimg::warn(_cimg_instance - "symmetric_eigen(): LAPACK library function dsyev_() returned error code %d.", - cimg_instance, - INFO); - if (!INFO) { - cimg_forY(val,i) val(i) = (T)lapW[N - 1 -i]; - cimg_forXY(vec,k,l) vec(k,l) = (T)(lapA[(N - 1 - k)*N + l]); - } else { val.fill(0); vec.fill(0); } - delete[] lapA; delete[] lapW; delete[] WORK; - -#else - CImg V(_width,_width); - Tfloat M = 0, m = (Tfloat)min_max(M), maxabs = cimg::max((Tfloat)1,cimg::abs(m),cimg::abs(M)); - (CImg(*this,false)/=maxabs).SVD(vec,val,V,false); - if (maxabs!=1) val*=maxabs; - - bool is_ambiguous = false; - float eig = 0; - cimg_forY(val,p) { // Check for ambiguous cases - if (val[p]>eig) eig = (float)val[p]; - t scal = 0; - cimg_forY(vec,y) scal+=vec(p,y)*V(p,y); - if (cimg::abs(scal)<0.9f) is_ambiguous = true; - if (scal<0) val[p] = -val[p]; - } - if (is_ambiguous) { - ++(eig*=2); - SVD(vec,val,V,false,40,eig); - val-=eig; - } - - CImg permutations; // Sort eigenvalues in decreasing order - CImg tmp(_width); - val.sort(permutations,false); - cimg_forY(vec,k) { - cimg_forY(permutations,y) tmp(y) = vec(permutations(y),k); - std::memcpy(vec.data(0,k),tmp._data,sizeof(t)*_width); - } -#endif - return *this; - } - - //! Compute eigenvalues and eigenvectors of the instance image, viewed as a symmetric matrix. - /** - \return A list of two images [val; vec], whose meaning are similar as in - symmetric_eigen(CImg&,CImg&) const. - **/ - CImgList get_symmetric_eigen() const { - CImgList res(2); - symmetric_eigen(res[0],res[1]); - return res; - } - - //! Sort pixel values and get sorting permutations. - /** - \param[out] permutations Permutation map used for the sorting. - \param is_increasing Tells if pixel values are sorted in an increasing (\c true) or decreasing (\c false) way. - **/ - template - CImg& sort(CImg& permutations, const bool is_increasing=true) { - permutations.assign(_width,_height,_depth,_spectrum); - if (is_empty()) return *this; - cimg_foroff(permutations,off) permutations[off] = (t)off; - return _quicksort(0,size() - 1,permutations,is_increasing,true); - } - - //! Sort pixel values and get sorting permutations \newinstance. - template - CImg get_sort(CImg& permutations, const bool is_increasing=true) const { - return (+*this).sort(permutations,is_increasing); - } - - //! Sort pixel values. - /** - \param is_increasing Tells if pixel values are sorted in an increasing (\c true) or decreasing (\c false) way. - \param axis Tells if the value sorting must be done along a specific axis. Can be: - - \c 0: All pixel values are sorted, independently on their initial position. - - \c 'x': Image columns are sorted, according to the first value in each column. - - \c 'y': Image rows are sorted, according to the first value in each row. - - \c 'z': Image slices are sorted, according to the first value in each slice. - - \c 'c': Image channels are sorted, according to the first value in each channel. - **/ - CImg& sort(const bool is_increasing=true, const char axis=0) { - if (is_empty()) return *this; - CImg perm; - switch (cimg::lowercase(axis)) { - case 0 : - _quicksort(0,size() - 1,perm,is_increasing,false); - break; - case 'x' : { - perm.assign(_width); - get_crop(0,0,0,0,_width - 1,0,0,0).sort(perm,is_increasing); - CImg img(*this,false); - cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(perm[x],y,z,c); - } break; - case 'y' : { - perm.assign(_height); - get_crop(0,0,0,0,0,_height - 1,0,0).sort(perm,is_increasing); - CImg img(*this,false); - cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,perm[y],z,c); - } break; - case 'z' : { - perm.assign(_depth); - get_crop(0,0,0,0,0,0,_depth - 1,0).sort(perm,is_increasing); - CImg img(*this,false); - cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,y,perm[z],c); - } break; - case 'c' : { - perm.assign(_spectrum); - get_crop(0,0,0,0,0,0,0,_spectrum - 1).sort(perm,is_increasing); - CImg img(*this,false); - cimg_forXYZC(*this,x,y,z,c) (*this)(x,y,z,c) = img(x,y,z,perm[c]); - } break; - default : - throw CImgArgumentException(_cimg_instance - "sort(): Invalid specified axis '%c' " - "(should be { x | y | z | c }).", - cimg_instance,axis); - } - return *this; - } - - //! Sort pixel values \newinstance. - CImg get_sort(const bool is_increasing=true, const char axis=0) const { - return (+*this).sort(is_increasing,axis); - } - - template - CImg& _quicksort(const long indm, const long indM, CImg& permutations, - const bool is_increasing, const bool is_permutations) { - if (indm(*this)[mid]) { - cimg::swap((*this)[indm],(*this)[mid]); - if (is_permutations) cimg::swap(permutations[indm],permutations[mid]); - } - if ((*this)[mid]>(*this)[indM]) { - cimg::swap((*this)[indM],(*this)[mid]); - if (is_permutations) cimg::swap(permutations[indM],permutations[mid]); - } - if ((*this)[indm]>(*this)[mid]) { - cimg::swap((*this)[indm],(*this)[mid]); - if (is_permutations) cimg::swap(permutations[indm],permutations[mid]); - } - } else { - if ((*this)[indm]<(*this)[mid]) { - cimg::swap((*this)[indm],(*this)[mid]); - if (is_permutations) cimg::swap(permutations[indm],permutations[mid]); - } - if ((*this)[mid]<(*this)[indM]) { - cimg::swap((*this)[indM],(*this)[mid]); - if (is_permutations) cimg::swap(permutations[indM],permutations[mid]); - } - if ((*this)[indm]<(*this)[mid]) { - cimg::swap((*this)[indm],(*this)[mid]); - if (is_permutations) cimg::swap(permutations[indm],permutations[mid]); - } - } - if (indM - indm>=3) { - const T pivot = (*this)[mid]; - long i = indm, j = indM; - if (is_increasing) { - do { - while ((*this)[i]pivot) --j; - if (i<=j) { - if (is_permutations) cimg::swap(permutations[i],permutations[j]); - cimg::swap((*this)[i++],(*this)[j--]); - } - } while (i<=j); - } else { - do { - while ((*this)[i]>pivot) ++i; - while ((*this)[j] A; // Input matrix (assumed to contain some values) - CImg<> U,S,V; - A.SVD(U,S,V) - \endcode - **/ - template - const CImg& SVD(CImg& U, CImg& S, CImg& V, const bool sorting=true, - const unsigned int max_iteration=40, const float lambda=0) const { - typedef _cimg_Ttfloat Ttfloat; - const Ttfloat epsilon = (Ttfloat)1e-25; - - if (is_empty()) { U.assign(); S.assign(); V.assign(); } - else if (_depth!=1 || _spectrum!=1) - throw CImgInstanceException(_cimg_instance - "SVD(): Instance has invalid dimensions (depth or channels different from 1).", - cimg_instance); - else { - U = *this; - if (lambda!=0) { - const unsigned int delta = std::min(U._width,U._height); - for (unsigned int i = 0; i rv1(_width); - Ttfloat anorm = 0, c, f, g = 0, h, s, scale = 0; - int l = 0; - - cimg_forX(U,i) { - l = i + 1; - rv1[i] = scale*g; - g = s = scale = 0; - if (i=0?-1:1)*std::sqrt(s)); - h = f*g - s; - U(i,i) = f - g; - for (int j = l; j=0?-1:1)*std::sqrt(s)); - h = f*g - s; - U(l,i) = f - g; - for (int k = l; k=0; --i) { - if (i=0; --i) { - l = i + 1; - g = S[i]; - for (int j = l; j=0; --k) { - int nm = 0; - for (unsigned int its = 0; its=1; --l) { - nm = l - 1; - if ((cimg::abs(rv1[l]) + anorm)==anorm) { flag = false; break; } - if ((cimg::abs(S[nm]) + anorm)==anorm) break; - } - if (flag) { - c = 0; - s = 1; - for (int i = l; i<=k; ++i) { - f = s*rv1[i]; - rv1[i] = c*rv1[i]; - if ((cimg::abs(f) + anorm)==anorm) break; - g = S[i]; - h = cimg::_hypot(f,g); - S[i] = h; - h = 1/h; - c = g*h; - s = -f*h; - cimg_forY(U,j) { - const t y = U(nm,j), z = U(i,j); - U(nm,j) = y*c + z*s; - U(i,j) = z*c - y*s; - } - } - } - - const t z = S[k]; - if (l==k) { if (z<0) { S[k] = -z; cimg_forX(U,j) V(k,j) = -V(k,j); } break; } - nm = k - 1; - t x = S[l], y = S[nm]; - g = rv1[nm]; - h = rv1[k]; - f = ((y - z)*(y + z) + (g - h)*(g + h))/std::max(epsilon,(Ttfloat)2*h*y); - g = cimg::_hypot(f,(Ttfloat)1); - f = ((x - z)*(x + z) + h*((y/(f + (f>=0?g:-g))) - h))/std::max(epsilon,(Ttfloat)x); - c = s = 1; - for (int j = l; j<=nm; ++j) { - const int i = j + 1; - g = rv1[i]; - h = s*g; - g = c*g; - t y1 = S[i], z1 = cimg::_hypot(f,h); - rv1[j] = z1; - c = f/std::max(epsilon,(Ttfloat)z1); - s = h/std::max(epsilon,(Ttfloat)z1); - f = x*c + g*s; - g = g*c - x*s; - h = y1*s; - y1*=c; - cimg_forX(U,jj) { - const t x2 = V(j,jj), z2 = V(i,jj); - V(j,jj) = x2*c + z2*s; - V(i,jj) = z2*c - x2*s; - } - z1 = cimg::_hypot(f,h); - S[j] = z1; - if (z1) { - z1 = 1/std::max(epsilon,(Ttfloat)z1); - c = f*z1; - s = h*z1; - } - f = c*g + s*y1; - x = c*y1 - s*g; - cimg_forY(U,jj) { - const t y2 = U(j,jj), z2 = U(i,jj); - U(j,jj) = y2*c + z2*s; - U(i,jj) = z2*c - y2*s; - } - } - rv1[l] = 0; - rv1[k] = f; - S[k] = x; - } - } - - if (sorting) { - CImg permutations; - CImg tmp(_width); - S.sort(permutations,false); - cimg_forY(U,k) { - cimg_forY(permutations,y) tmp(y) = U(permutations(y),k); - std::memcpy(U.data(0,k),tmp._data,sizeof(t)*_width); - } - cimg_forY(V,k) { - cimg_forY(permutations,y) tmp(y) = V(permutations(y),k); - std::memcpy(V.data(0,k),tmp._data,sizeof(t)*_width); - } - } - } - return *this; - } - - //! Compute the SVD of the instance image, viewed as a general matrix. - /** - \return A list of three images [U; S; V], whose meaning is similar as in - SVD(CImg&,CImg&,CImg&,bool,unsigned int,float) const. - **/ - CImgList get_SVD(const bool sorting=true, - const unsigned int max_iteration=40, const float lambda=0) const { - CImgList res(3); - SVD(res[0],res[1],res[2],sorting,max_iteration,lambda); - return res; - } - - // [internal] Compute the LU decomposition of a permuted matrix. - template - CImg& _LU(CImg& indx, bool& d) { - const int N = width(); - int imax = 0; - CImg vv(N); - indx.assign(N); - d = true; - - bool return0 = false; - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=512)) - cimg_forX(*this,i) { - Tfloat vmax = 0; - cimg_forX(*this,j) { - const Tfloat tmp = cimg::abs((*this)(j,i)); - if (tmp>vmax) vmax = tmp; - } - if (vmax==0) return0 = true; else vv[i] = 1/vmax; - } - if (return0) { indx.fill(0); return fill(0); } - - cimg_forX(*this,j) { - for (int i = 0; i=vmax) { vmax = tmp; imax = i; } - } - if (j!=imax) { - cimg_forX(*this,k) cimg::swap((*this)(k,imax),(*this)(k,j)); - d = !d; - vv[imax] = vv[j]; - } - indx[j] = (t)imax; - if ((*this)(j,j)==0) (*this)(j,j) = (T)1e-20; - if (j=3 = orthogonal matching pursuit where an orthogonal projection step is performed - every 'method-2' iterations. - \param max_iter Sets the max number of iterations processed for each signal. - If set to '0' (default), 'max_iter' is set to the number of dictionary columns. - (only meaningful for matching pursuit and its variants). - \param max_residual Gives a stopping criterion on signal reconstruction accuracy. - (only meaningful for matching pursuit and its variants). - \return A matrix W whose columns correspond to the sparse weights of associated to each input matrix column. - Thus, the matrix product D*W is an approximation of the input matrix. - **/ - template - CImg& project_matrix(const CImg& dictionary, const unsigned int method=0, - const unsigned int max_iter=0, const double max_residual=1e-6) { - return get_project_matrix(dictionary,method,max_iter,max_residual).move_to(*this); - } - - template - CImg get_project_matrix(const CImg& dictionary, const unsigned int method=0, - const unsigned int max_iter=0, const double max_residual=1e-6) const { - if (_depth!=1 || _spectrum!=1) - throw CImgInstanceException(_cimg_instance - "project_matrix(): Instance image is not a matrix.", - cimg_instance); - if (dictionary._height!=_height || dictionary._depth!=1 || dictionary._spectrum!=1) - throw CImgArgumentException(_cimg_instance - "project_matrix(): Specified dictionary (%u,%u,%u,%u) has an invalid size.", - cimg_instance, - dictionary._width,dictionary._height,dictionary._depth,dictionary._spectrum); - - if (!method) return get_solve(dictionary); - CImg W(_width,dictionary._width,1,1,0); - - // Compute dictionary norm and normalize it. - CImg D(dictionary,false), Dnorm(D._width); - cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=2 && _width*_height>=32)) - cimg_forX(Dnorm,d) { - Tfloat norm = 0; - cimg_forY(D,y) norm+=cimg::sqr(D(d,y)); - Dnorm[d] = std::max((Tfloat)1e-8,std::sqrt(norm)); - } - cimg_forXY(D,d,y) D(d,y)/=Dnorm[d]; - - // Matching pursuit. - const unsigned int proj_step = method<3?1:method - 2; - bool is_orthoproj = false; - - cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=2 && _width*_height>=32)) - cimg_forX(*this,x) { - CImg S = get_column(x); - const CImg S0 = method<2?CImg():S; - Tfloat residual = S.magnitude()/S._height; - const unsigned int nmax = max_iter?max_iter:D._width; - - for (unsigned int n = 0; nmax_residual; ++n) { - - // Find best matching column in D. - int dmax = 0; - Tfloat absdotmax = 0, dotmax = 0; - cimg_pragma_openmp(parallel for cimg_openmp_if(D._width>=2 && D._width*D._height>=32)) - cimg_forX(D,d) { - Tfloat _dot = 0; - cimg_forY(D,y) _dot+=S[y]*D(d,y); - Tfloat absdot = cimg::abs(_dot); - cimg_pragma_openmp(critical(get_project_matrix)) { - if (absdot>absdotmax) { - absdotmax = absdot; - dotmax = _dot; - dmax = d; - } - } - } - - if (!n || method<3 || n%proj_step) { - // Matching Pursuit: Subtract component to signal. - W(x,dmax)+=dotmax; - residual = 0; - cimg_forY(S,y) { - S[y]-=dotmax*D(dmax,y); - residual+=cimg::sqr(S[y]); - } - residual = std::sqrt(residual)/S._height; - is_orthoproj = false; - - } else { - // Orthogonal Matching Pursuit: Orthogonal projection step. - W(x,dmax) = 1; // Used as a marker only. - unsigned int nbW = 0; - cimg_forY(W,d) if (W(x,d)) ++nbW; - CImg sD(nbW,D._height); - CImg inds(nbW); - int sd = 0; - cimg_forY(W,d) if (W(x,d)) { - cimg_forY(sD,y) sD(sd,y) = D(d,y); - inds[sd++] = d; - } - S0.get_solve(sD).move_to(sD); // sD is now a one-column vector of weights - - // Recompute residual signal. - S = S0; - cimg_forY(sD,k) { - const Tfloat weight = sD[k]; - const unsigned int ind = inds[k]; - W(x,ind) = weight; - cimg_forY(S,y) S[y]-=weight*D(ind,y); - } - residual = S.magnitude()/S._height; - is_orthoproj = true; - } - } - - // Perform last orthoprojection step if needed. - if (method>=2 && !is_orthoproj) { - unsigned int nbW = 0; - cimg_forY(W,d) if (W(x,d)) ++nbW; - if (nbW) { // Avoid degenerated case where 0 coefs are used - CImg sD(nbW,D._height); - CImg inds(nbW); - int sd = 0; - cimg_forY(W,d) if (W(x,d)) { - cimg_forY(sD,y) sD(sd,y) = D(d,y); - inds[sd++] = d; - } - S0.get_solve(sD).move_to(sD); - cimg_forY(sD,k) W(x,inds[k]) = sD[k]; - } - } - } - - // Normalize resulting coefficients according to initial (non-normalized) dictionary. - cimg_forXY(W,x,y) W(x,y)/=Dnorm[y]; - return W; - } - - //! Compute minimal path in a graph, using the Dijkstra algorithm. - /** - \param distance An object having operator()(unsigned int i, unsigned int j) which returns distance - between two nodes (i,j). - \param nb_nodes Number of graph nodes. - \param starting_node Index of the starting node. - \param ending_node Index of the ending node (set to ~0U to ignore ending node). - \param previous_node Array that gives the previous node index in the path to the starting node - (optional parameter). - \return Array of distances of each node to the starting node. - **/ - template - static CImg dijkstra(const tf& distance, const unsigned int nb_nodes, - const unsigned int starting_node, const unsigned int ending_node, - CImg& previous_node) { - if (starting_node>=nb_nodes) - throw CImgArgumentException("CImg<%s>::dijkstra(): Specified index of starting node %u is higher " - "than number of nodes %u.", - pixel_type(),starting_node,nb_nodes); - CImg dist(1,nb_nodes,1,1,cimg::type::max()); - dist(starting_node) = 0; - previous_node.assign(1,nb_nodes,1,1,(t)-1); - previous_node(starting_node) = (t)starting_node; - CImg Q(nb_nodes); - cimg_forX(Q,u) Q(u) = (unsigned int)u; - cimg::swap(Q(starting_node),Q(0)); - unsigned int sizeQ = nb_nodes; - while (sizeQ) { - // Update neighbors from minimal vertex - const unsigned int umin = Q(0); - if (umin==ending_node) sizeQ = 0; - else { - const T dmin = dist(umin); - const T infty = cimg::type::max(); - for (unsigned int q = 1; qdist(Q(left))) || - (rightdist(Q(right)));) { - if (right - static CImg dijkstra(const tf& distance, const unsigned int nb_nodes, - const unsigned int starting_node, const unsigned int ending_node=~0U) { - CImg foo; - return dijkstra(distance,nb_nodes,starting_node,ending_node,foo); - } - - //! Return minimal path in a graph, using the Dijkstra algorithm. - /** - \param starting_node Index of the starting node. - \param ending_node Index of the ending node. - \param previous_node Array that gives the previous node index in the path to the starting node - (optional parameter). - \return Array of distances of each node to the starting node. - \note image instance corresponds to the adjacency matrix of the graph. - **/ - template - CImg& dijkstra(const unsigned int starting_node, const unsigned int ending_node, - CImg& previous_node) { - return get_dijkstra(starting_node,ending_node,previous_node).move_to(*this); - } - - //! Return minimal path in a graph, using the Dijkstra algorithm \newinstance. - template - CImg get_dijkstra(const unsigned int starting_node, const unsigned int ending_node, - CImg& previous_node) const { - if (_width!=_height || _depth!=1 || _spectrum!=1) - throw CImgInstanceException(_cimg_instance - "dijkstra(): Instance is not a graph adjacency matrix.", - cimg_instance); - - return dijkstra(*this,_width,starting_node,ending_node,previous_node); - } - - //! Return minimal path in a graph, using the Dijkstra algorithm. - CImg& dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) { - return get_dijkstra(starting_node,ending_node).move_to(*this); - } - - //! Return minimal path in a graph, using the Dijkstra algorithm \newinstance. - CImg get_dijkstra(const unsigned int starting_node, const unsigned int ending_node=~0U) const { - CImg foo; - return get_dijkstra(starting_node,ending_node,foo); - } - - //! Return an image containing the character codes of specified string. - /** - \param str input C-string to encode as an image. - \param is_last_zero Tells if the ending \c '0' character appear in the resulting image. - \param is_shared Return result that shares its buffer with \p str. - **/ - static CImg string(const char *const str, const bool is_last_zero=true, const bool is_shared=false) { - if (!str) return CImg(); - return CImg(str,(unsigned int)std::strlen(str) + (is_last_zero?1:0),1,1,1,is_shared); - } - - //! Return a \c 1x1 image containing specified value. - /** - \param a0 First vector value. - **/ - static CImg row_vector(const T& a0) { - return vector(a0); - } - - //! Return a \c 2x1 image containing specified values. - /** - \param a0 First vector value. - \param a1 Second vector value. - **/ - static CImg row_vector(const T& a0, const T& a1) { - CImg r(2,1); - r[0] = a0; r[1] = a1; - return r; - } - - //! Return a \c 3x1 image containing specified values. - /** - \param a0 First vector value. - \param a1 Second vector value. - \param a2 Third vector value. - **/ - static CImg row_vector(const T& a0, const T& a1, const T& a2) { - CImg r(3,1); - r[0] = a0; r[1] = a1; r[2] = a2; - return r; - } - - //! Return a \c 4x1 image containing specified values. - /** - \param a0 First vector value. - \param a1 Second vector value. - \param a2 Third vector value. - \param a3 Fourth vector value. - **/ - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3) { - CImg r(4,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; - return r; - } - - //! Return a \c 5x1 image containing specified values. - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) { - CImg r(5,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; - return r; - } - - //! Return a \c 6x1 image containing specified values. - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) { - CImg r(6,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; - return r; - } - - //! Return a \c 7x1 image containing specified values. - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6) { - CImg r(7,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; - return r; - } - - //! Return a \c 8x1 image containing specified values. - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7) { - CImg r(8,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; - return r; - } - - //! Return a \c 9x1 image containing specified values. - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8) { - CImg r(9,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; - return r; - } - - //! Return a \c 10x1 image containing specified values. - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9) { - CImg r(10,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - return r; - } - - //! Return a \c 11x1 image containing specified values. - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10) { - CImg r(11,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - r[10] = a10; - return r; - } - - //! Return a \c 12x1 image containing specified values. - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10, const T& a11) { - CImg r(12,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - r[10] = a10; r[11] = a11; - return r; - } - - //! Return a \c 13x1 image containing specified values. - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12) { - CImg r(13,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - r[10] = a10; r[11] = a11; r[12] = a12; - return r; - } - - //! Return a \c 14x1 image containing specified values. - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12, const T& a13) { - CImg r(14,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - r[10] = a10; r[11] = a11; r[12] = a12; r[13] = a13; - return r; - } - - //! Return a \c 15x1 image containing specified values. - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12, const T& a13, const T& a14) { - CImg r(15,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - r[10] = a10; r[11] = a11; r[12] = a12; r[13] = a13; r[14] = a14; - return r; - } - - //! Return a \c 16x1 image containing specified values. - static CImg row_vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12, const T& a13, const T& a14, const T& a15) { - CImg r(16,1); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - r[10] = a10; r[11] = a11; r[12] = a12; r[13] = a13; r[14] = a14; r[15] = a15; - return r; - } - - //! Return a \c 1x1 image containing specified value. - /** - \param a0 First vector value. - **/ - static CImg vector(const T& a0) { - CImg r(1,1); - r[0] = a0; - return r; - } - - //! Return a \c 1x2 image containing specified values. - /** - \param a0 First vector value. - \param a1 Second vector value. - **/ - static CImg vector(const T& a0, const T& a1) { - CImg r(1,2); - r[0] = a0; r[1] = a1; - return r; - } - - //! Return a \c 1x3 image containing specified values. - /** - \param a0 First vector value. - \param a1 Second vector value. - \param a2 Third vector value. - **/ - static CImg vector(const T& a0, const T& a1, const T& a2) { - CImg r(1,3); - r[0] = a0; r[1] = a1; r[2] = a2; - return r; - } - - //! Return a \c 1x4 image containing specified values. - /** - \param a0 First vector value. - \param a1 Second vector value. - \param a2 Third vector value. - \param a3 Fourth vector value. - **/ - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3) { - CImg r(1,4); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; - return r; - } - - //! Return a \c 1x5 image containing specified values. - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) { - CImg r(1,5); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; - return r; - } - - //! Return a \c 1x6 image containing specified values. - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) { - CImg r(1,6); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; - return r; - } - - //! Return a \c 1x7 image containing specified values. - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6) { - CImg r(1,7); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; - return r; - } - - //! Return a \c 1x8 image containing specified values. - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7) { - CImg r(1,8); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; - return r; - } - - //! Return a \c 1x9 image containing specified values. - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8) { - CImg r(1,9); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; - return r; - } - - //! Return a \c 1x10 image containing specified values. - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9) { - CImg r(1,10); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - return r; - } - - //! Return a \c 1x11 image containing specified values. - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10) { - CImg r(1,11); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - r[10] = a10; - return r; - } - - //! Return a \c 1x12 image containing specified values. - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10, const T& a11) { - CImg r(1,12); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - r[10] = a10; r[11] = a11; - return r; - } - - //! Return a \c 1x13 image containing specified values. - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12) { - CImg r(1,13); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - r[10] = a10; r[11] = a11; r[12] = a12; - return r; - } - - //! Return a \c 1x14 image containing specified values. - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12, const T& a13) { - CImg r(1,14); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - r[10] = a10; r[11] = a11; r[12] = a12; r[13] = a13; - return r; - } - - //! Return a \c 1x15 image containing specified values. - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12, const T& a13, const T& a14) { - CImg r(1,15); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - r[10] = a10; r[11] = a11; r[12] = a12; r[13] = a13; r[14] = a14; - return r; - } - - //! Return a \c 1x16 image containing specified values. - static CImg vector(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12, const T& a13, const T& a14, const T& a15) { - CImg r(1,16); - r[0] = a0; r[1] = a1; r[2] = a2; r[3] = a3; r[4] = a4; r[5] = a5; r[6] = a6; r[7] = a7; r[8] = a8; r[9] = a9; - r[10] = a10; r[11] = a11; r[12] = a12; r[13] = a13; r[14] = a14; r[15] = a15; - return r; - } - - //! Return a 1x1 matrix containing specified coefficients. - /** - \param a0 First matrix value. - \note Equivalent to vector(const T&). - **/ - static CImg matrix(const T& a0) { - return vector(a0); - } - - //! Return a 2x2 matrix containing specified coefficients. - /** - \param a0 First matrix value. - \param a1 Second matrix value. - \param a2 Third matrix value. - \param a3 Fourth matrix value. - **/ - static CImg matrix(const T& a0, const T& a1, - const T& a2, const T& a3) { - CImg r(2,2); T *ptr = r._data; - *(ptr++) = a0; *(ptr++) = a1; - *(ptr++) = a2; *(ptr++) = a3; - return r; - } - - //! Return a 3x3 matrix containing specified coefficients. - /** - \param a0 First matrix value. - \param a1 Second matrix value. - \param a2 Third matrix value. - \param a3 Fourth matrix value. - \param a4 Fifth matrix value. - \param a5 Sixth matrix value. - \param a6 Seventh matrix value. - \param a7 Eighth matrix value. - \param a8 Ninth matrix value. - **/ - static CImg matrix(const T& a0, const T& a1, const T& a2, - const T& a3, const T& a4, const T& a5, - const T& a6, const T& a7, const T& a8) { - CImg r(3,3); T *ptr = r._data; - *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; - *(ptr++) = a3; *(ptr++) = a4; *(ptr++) = a5; - *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; - return r; - } - - //! Return a 4x4 matrix containing specified coefficients. - static CImg matrix(const T& a0, const T& a1, const T& a2, const T& a3, - const T& a4, const T& a5, const T& a6, const T& a7, - const T& a8, const T& a9, const T& a10, const T& a11, - const T& a12, const T& a13, const T& a14, const T& a15) { - CImg r(4,4); T *ptr = r._data; - *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; - *(ptr++) = a4; *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; - *(ptr++) = a8; *(ptr++) = a9; *(ptr++) = a10; *(ptr++) = a11; - *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; *(ptr++) = a15; - return r; - } - - //! Return a 5x5 matrix containing specified coefficients. - static CImg matrix(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, - const T& a5, const T& a6, const T& a7, const T& a8, const T& a9, - const T& a10, const T& a11, const T& a12, const T& a13, const T& a14, - const T& a15, const T& a16, const T& a17, const T& a18, const T& a19, - const T& a20, const T& a21, const T& a22, const T& a23, const T& a24) { - CImg r(5,5); T *ptr = r._data; - *(ptr++) = a0; *(ptr++) = a1; *(ptr++) = a2; *(ptr++) = a3; *(ptr++) = a4; - *(ptr++) = a5; *(ptr++) = a6; *(ptr++) = a7; *(ptr++) = a8; *(ptr++) = a9; - *(ptr++) = a10; *(ptr++) = a11; *(ptr++) = a12; *(ptr++) = a13; *(ptr++) = a14; - *(ptr++) = a15; *(ptr++) = a16; *(ptr++) = a17; *(ptr++) = a18; *(ptr++) = a19; - *(ptr++) = a20; *(ptr++) = a21; *(ptr++) = a22; *(ptr++) = a23; *(ptr++) = a24; - return r; - } - - //! Return a 1x1 symmetric matrix containing specified coefficients. - /** - \param a0 First matrix value. - \note Equivalent to vector(const T&). - **/ - static CImg tensor(const T& a0) { - return matrix(a0); - } - - //! Return a 2x2 symmetric matrix tensor containing specified coefficients. - static CImg tensor(const T& a0, const T& a1, const T& a2) { - return matrix(a0,a1,a1,a2); - } - - //! Return a 3x3 symmetric matrix containing specified coefficients. - static CImg tensor(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4, const T& a5) { - return matrix(a0,a1,a2,a1,a3,a4,a2,a4,a5); - } - - //! Return a 1x1 diagonal matrix containing specified coefficients. - static CImg diagonal(const T& a0) { - return matrix(a0); - } - - //! Return a 2x2 diagonal matrix containing specified coefficients. - static CImg diagonal(const T& a0, const T& a1) { - return matrix(a0,0,0,a1); - } - - //! Return a 3x3 diagonal matrix containing specified coefficients. - static CImg diagonal(const T& a0, const T& a1, const T& a2) { - return matrix(a0,0,0,0,a1,0,0,0,a2); - } - - //! Return a 4x4 diagonal matrix containing specified coefficients. - static CImg diagonal(const T& a0, const T& a1, const T& a2, const T& a3) { - return matrix(a0,0,0,0,0,a1,0,0,0,0,a2,0,0,0,0,a3); - } - - //! Return a 5x5 diagonal matrix containing specified coefficients. - static CImg diagonal(const T& a0, const T& a1, const T& a2, const T& a3, const T& a4) { - return matrix(a0,0,0,0,0,0,a1,0,0,0,0,0,a2,0,0,0,0,0,a3,0,0,0,0,0,a4); - } - - //! Return a NxN identity matrix. - /** - \param N Dimension of the matrix. - **/ - static CImg identity_matrix(const unsigned int N) { - CImg res(N,N,1,1,0); - cimg_forX(res,x) res(x,x) = 1; - return res; - } - - //! Return a N-numbered sequence vector from \p a0 to \p a1. - /** - \param N Size of the resulting vector. - \param a0 Starting value of the sequence. - \param a1 Ending value of the sequence. - **/ - static CImg sequence(const unsigned int N, const T& a0, const T& a1) { - if (N) return CImg(1,N).sequence(a0,a1); - return CImg(); - } - - //! Return a 3x3 rotation matrix from an { axis + angle } or a quaternion. - /** - \param x X-coordinate of the rotation axis, or first quaternion coordinate. - \param y Y-coordinate of the rotation axis, or second quaternion coordinate. - \param z Z-coordinate of the rotation axis, or third quaternion coordinate. - \param w Angle of the rotation axis (in degree), or fourth quaternion coordinate. - \param is_quaternion Tell is the four arguments denotes a set { axis + angle } or a quaternion (x,y,z,w). - **/ - static CImg rotation_matrix(const float x, const float y, const float z, const float w, - const bool is_quaternion=false) { - double X, Y, Z, W, N; - if (is_quaternion) { - N = std::sqrt((double)x*x + (double)y*y + (double)z*z + (double)w*w); - if (N>0) { X = x/N; Y = y/N; Z = z/N; W = w/N; } - else { X = Y = Z = 0; W = 1; } - return CImg::matrix((T)(X*X + Y*Y - Z*Z - W*W),(T)(2*Y*Z - 2*X*W),(T)(2*X*Z + 2*Y*W), - (T)(2*X*W + 2*Y*Z),(T)(X*X - Y*Y + Z*Z - W*W),(T)(2*Z*W - 2*X*Y), - (T)(2*Y*W - 2*X*Z),(T)(2*X*Y + 2*Z*W),(T)(X*X - Y*Y - Z*Z + W*W)); - } - N = cimg::hypot((double)x,(double)y,(double)z); - if (N>0) { X = x/N; Y = y/N; Z = z/N; } - else { X = Y = 0; Z = 1; } - const double ang = w*cimg::PI/180, c = std::cos(ang), omc = 1 - c, s = std::sin(ang); - return CImg::matrix((T)(X*X*omc + c),(T)(X*Y*omc - Z*s),(T)(X*Z*omc + Y*s), - (T)(X*Y*omc + Z*s),(T)(Y*Y*omc + c),(T)(Y*Z*omc - X*s), - (T)(X*Z*omc - Y*s),(T)(Y*Z*omc + X*s),(T)(Z*Z*omc + c)); - } - - //@} - //----------------------------------- - // - //! \name Value Manipulation - //@{ - //----------------------------------- - - //! Fill all pixel values with specified value. - /** - \param val Fill value. - **/ - CImg& fill(const T& val) { - if (is_empty()) return *this; - if (val && sizeof(T)!=1) cimg_for(*this,ptrd,T) *ptrd = val; - else std::memset(_data,(int)(ulongT)val,sizeof(T)*size()); // Double cast to allow val to be (void*) - return *this; - } - - //! Fill all pixel values with specified value \newinstance. - CImg get_fill(const T& val) const { - return CImg(_width,_height,_depth,_spectrum).fill(val); - } - - //! Fill sequentially all pixel values with specified values. - /** - \param val0 First fill value. - \param val1 Second fill value. - **/ - CImg& fill(const T& val0, const T& val1) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 1; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 2; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 3; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 4; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 5; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 6; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 7; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 8; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 9; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9, const T& val10) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 10; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9, const T& val10) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 11; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, - val11); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, - const T& val12) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 12; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, - const T& val12) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, - val11,val12); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, - const T& val12, const T& val13) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 13; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, - const T& val12, const T& val13) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, - val11,val12,val13); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, - const T& val12, const T& val13, const T& val14) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 14; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, - const T& val12, const T& val13, const T& val14) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, - val11,val12,val13,val14); - } - - //! Fill sequentially all pixel values with specified values \overloading. - CImg& fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, - const T& val12, const T& val13, const T& val14, const T& val15) { - if (is_empty()) return *this; - T *ptrd, *ptre = end() - 15; - for (ptrd = _data; ptrd get_fill(const T& val0, const T& val1, const T& val2, const T& val3, const T& val4, const T& val5, - const T& val6, const T& val7, const T& val8, const T& val9, const T& val10, const T& val11, - const T& val12, const T& val13, const T& val14, const T& val15) const { - return CImg(_width,_height,_depth,_spectrum).fill(val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,val10, - val11,val12,val13,val14,val15); - } - - //! Fill sequentially pixel values according to a given expression. - /** - \param expression C-string describing a math formula, or a sequence of values. - \param repeat_values In case a list of values is provided, tells if this list must be repeated for the filling. - \param allow_formula Tells that mathematical formulas are authorized for the filling. - \param list_images In case of a mathematical expression, attach a list of images to the specified expression. - **/ - CImg& fill(const char *const expression, const bool repeat_values, const bool allow_formula=true, - CImgList *const list_images=0) { - return _fill(expression,repeat_values,allow_formula?1:0,list_images,"fill",0); - } - - // 'formula_mode' = { 0 = does not allow formula | 1 = allow formula | - // 2 = allow formula and do not fill image values }. - CImg& _fill(const char *const expression, const bool repeat_values, const unsigned int formula_mode, - CImgList *const list_images, const char *const calling_function, const CImg *provides_copy) { - if (is_empty() || !expression || !*expression) return *this; - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - CImg is_error_expr; - bool is_error_seq = false, is_value_sequence = false; - cimg_abort_init; - - if (formula_mode) { - - // Try to pre-detect regular value sequence to avoid exception thrown by _cimg_math_parser. - double value; - char sep; - const int err = cimg_sscanf(expression,"%lf %c",&value,&sep); - if (err==1 || (err==2 && sep==',')) { - if (err==1) { if (formula_mode==2) return *this; return fill((T)value); } - else is_value_sequence = true; - } - - // Try to fill values according to a formula. - _cimg_abort_init_openmp; - if (!is_value_sequence) try { - CImg base = provides_copy?provides_copy->get_shared():get_shared(); - _cimg_math_parser mp(expression + (*expression=='>' || *expression=='<' || - *expression=='*' || *expression==':'), - calling_function,base,this,list_images,true); - if (!provides_copy && expression && *expression!='>' && *expression!='<' && *expression!=':' && - mp.need_input_copy) - base.assign().assign(*this,false); // Needs input copy - - // Determine 2nd largest image dimension (used as axis for inner loop in parallelized evaluation). - unsigned int M; - if (mp.result_dim) { - M = cimg::max(_width,_height,_depth); - M = M==_width?std::max(_height,_depth):M==_height?std::max(_width,_depth):std::max(_width,_height); - } else { - M = cimg::max(_width,_height,_depth,_spectrum); - M = M==_width?cimg::max(_height,_depth,_spectrum): - M==_height?cimg::max(_width,_depth,_spectrum): - M==_depth?cimg::max(_width,_height,_spectrum):cimg::max(_width,_height,_depth); - } - - bool do_in_parallel = false; -#if cimg_use_openmp!=0 - if (mp.is_noncritical_run && (*expression=='*' || *expression==':')) - throw CImgArgumentException(_cimg_instance - "%s(): Cannot evaluate expression '%s' in parallel, " - "as 'run()' is used outside a 'critical()' section.", - cimg_instance,calling_function,expression); - cimg_openmp_if(!mp.is_noncritical_run && - (*expression=='*' || *expression==':' || - (mp.is_parallelizable && M>=(cimg_openmp_sizefactor)*320 && size()/M>=2))) - do_in_parallel = true; -#endif - if (mp.result_dim) { // Vector-valued expression - const unsigned int N = std::min(mp.result_dim,_spectrum); - const ulongT whd = (ulongT)_width*_height*_depth; - T *ptrd = *expression=='<'?_data + _width*_height*_depth - 1:_data; - - if (*expression=='<') { - CImg res(1,mp.result_dim); - mp.begin_t(); - cimg_rofYZ(*this,y,z) { - cimg_abort_test; - if (formula_mode==2) cimg_rofX(*this,x) mp(x,y,z,0); - else cimg_rofX(*this,x) { - mp(x,y,z,0,res._data); - const double *ptrs = res._data; - T *_ptrd = ptrd--; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; } - } - } - mp.end_t(); - - } else if (*expression=='>' || !do_in_parallel) { - CImg res(1,mp.result_dim); - mp.begin_t(); - cimg_forYZ(*this,y,z) { - cimg_abort_test; - if (formula_mode==2) cimg_forX(*this,x) mp(x,y,z,0); - else cimg_forX(*this,x) { - mp(x,y,z,0,res._data); - const double *ptrs = res._data; - T *_ptrd = ptrd++; for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; } - } - } - mp.end_t(); - - } else { - -#if cimg_use_openmp!=0 - cimg_pragma_openmp(parallel) - { - _cimg_math_parser - *const _mp = omp_get_thread_num()?new _cimg_math_parser(mp):&mp, - &lmp = *_mp; - lmp.is_fill = true; - cimg_pragma_openmp(barrier) - lmp.begin_t(); - -#define _cimg_fill_openmp_vector(_YZ,_y,_z,_X,_x,_sx,_sy,_sz,_off) \ - cimg_pragma_openmp(for cimg_openmp_collapse(2)) \ - cimg_for##_YZ(*this,_y,_z) _cimg_abort_try_openmp { \ - cimg_abort_test; \ - if (formula_mode==2) cimg_for##_X(*this,_x) lmp(x,y,z,0); \ - else { \ - CImg res(1,lmp.result_dim); \ - T *__ptrd = data(_sx,_sy,_sz,0); \ - const ulongT off = (ulongT)_off; \ - cimg_for##_X(*this,_x) { \ - lmp(x,y,z,0,res._data); \ - const double *ptrs = res._data; \ - T *_ptrd = __ptrd; \ - for (unsigned int n = N; n>0; --n) { *_ptrd = (T)(*ptrs++); _ptrd+=whd; } \ - __ptrd+=off; \ - } \ - } \ - } _cimg_abort_catch_openmp _cimg_abort_catch_fill_openmp - - if (M==_width) { _cimg_fill_openmp_vector(YZ,y,z,X,x,0,y,z,1) } - else if (M==_height) { _cimg_fill_openmp_vector(XZ,x,z,Y,y,x,0,z,_width) } - else { _cimg_fill_openmp_vector(XY,x,y,Z,z,x,y,0,_width*_height) } - - lmp.end_t(); - cimg_pragma_openmp(barrier) cimg_pragma_openmp(critical) { lmp.merge(mp); } - if (&lmp!=&mp) delete &lmp; - } -#endif - } - - } else { // Scalar-valued expression - T *ptrd = *expression=='<'?end() - 1:_data; - if (*expression=='<') { - mp.begin_t(); - if (formula_mode==2) cimg_rofYZC(*this,y,z,c) { cimg_abort_test; cimg_rofX(*this,x) mp(x,y,z,c); } - else cimg_rofYZC(*this,y,z,c) { cimg_abort_test; cimg_rofX(*this,x) *(ptrd--) = (T)mp(x,y,z,c); } - mp.end_t(); - - } else if (*expression=='>' || !do_in_parallel) { - mp.begin_t(); - if (formula_mode==2) cimg_forYZC(*this,y,z,c) { cimg_abort_test; cimg_forX(*this,x) mp(x,y,z,c); } - else cimg_forYZC(*this,y,z,c) { cimg_abort_test; cimg_forX(*this,x) *(ptrd++) = (T)mp(x,y,z,c); } - mp.end_t(); - - } else { - -#if cimg_use_openmp!=0 - cimg_pragma_openmp(parallel) - { - _cimg_math_parser - *const _mp = omp_get_thread_num()?new _cimg_math_parser(mp):&mp, - &lmp = *_mp; - lmp.is_fill = true; - cimg_pragma_openmp(barrier) - lmp.begin_t(); - -#define _cimg_fill_openmp_scalar(_YZC,_y,_z,_c,_X,_x,_sx,_sy,_sz,_sc,_off) \ - cimg_pragma_openmp(for cimg_openmp_collapse(3)) \ - cimg_for##_YZC(*this,_y,_z,_c) _cimg_abort_try_openmp { \ - cimg_abort_test; \ - if (formula_mode==2) cimg_for##_X(*this,_x) lmp(x,y,z,c); \ - else { \ - T *_ptrd = data(_sx,_sy,_sz,_sc); \ - const ulongT off = (ulongT)_off; \ - cimg_for##_X(*this,_x) { *_ptrd = (T)lmp(x,y,z,c); _ptrd+=off; } \ - } \ - } _cimg_abort_catch_openmp _cimg_abort_catch_fill_openmp - - if (M==_width) { _cimg_fill_openmp_scalar(YZC,y,z,c,X,x,0,y,z,c,1) } - else if (M==_height) { _cimg_fill_openmp_scalar(XZC,x,z,c,Y,y,x,0,z,c,_width) } - else if (M==_depth) { _cimg_fill_openmp_scalar(XYC,x,y,c,Z,z,x,y,0,c,_width*_height) } - else { _cimg_fill_openmp_scalar(XYZ,x,y,z,C,c,x,y,z,0,_width*_height*_depth) } - - lmp.end_t(); - cimg_pragma_openmp(barrier) cimg_pragma_openmp(critical) { lmp.merge(mp); } - if (&lmp!=&mp) delete &lmp; - } -#endif - } - } - mp.end(); - } catch (CImgException& e) { CImg::string(e._message).move_to(is_error_expr); } - } - - // Try to fill values according to a value sequence. - if (!formula_mode || is_value_sequence || is_error_expr) { - is_error_seq = _fill_from_values(expression,repeat_values); - cimg::exception_mode(omode); - if (is_error_seq) { - if (is_error_expr) throw CImgArgumentException("%s",is_error_expr._data); - else throw CImgArgumentException(_cimg_instance - "%s(): Invalid sequence of filling values '%s'.", - cimg_instance,calling_function,expression); - } - } - cimg::exception_mode(omode); - cimg_abort_test; - return *this; - } - - //! Fill sequentially pixel values according to a given expression \newinstance. - CImg get_fill(const char *const expression, const bool repeat_values, const bool allow_formula=true, - CImgList *const list_images=0) const { - return (+*this).fill(expression,repeat_values,allow_formula?1:0,list_images); - } - - //! Fill sequentially pixel values according to a value sequence, given as a string. - /** - \param values C-string describing a sequence of values. - \param repeat_values Tells if this sequence must be repeated when filling. - **/ - CImg& fill_from_values(const char *const values, const bool repeat_values) { - if (_fill_from_values(values,repeat_values)) - throw CImgArgumentException(_cimg_instance - "Invalid sequence of filling values '%s'.", - cimg_instance,values); - return *this; - } - - //! Fill sequentially pixel values according to a value sequence, given as a string \newinstance. - CImg get_fill_from_values(const char *const values, const bool repeat_values) const { - return (+*this).fill_from_values(values,repeat_values); - } - - // Fill image according to a value sequence, given as a string. - // Return 'true' if an error occured. - bool _fill_from_values(const char *const values, const bool repeat_values) { - CImg item(256); - const char *nvalues = values; - const ulongT siz = size(); - T *ptrd = _data; - ulongT nb = 0; - char sep = 0; - for (double val = 0; *nvalues && nb0 && cimg_sscanf(item,"%lf",&val)==1 && (sep==',' || sep==';' || err==1)) { - nvalues+=std::strlen(item) + (err>1); - *(ptrd++) = (T)val; - } else break; - } - if (nb - CImg& fill(const CImg& values, const bool repeat_values=true) { - if (is_empty() || !values) return *this; - T *ptrd = _data, *ptre = ptrd + size(); - for (t *ptrs = values._data, *ptrs_end = ptrs + values.size(); ptrs - CImg get_fill(const CImg& values, const bool repeat_values=true) const { - return repeat_values?CImg(_width,_height,_depth,_spectrum).fill(values,repeat_values): - (+*this).fill(values,repeat_values); - } - - //! Fill pixel values along the X-axis at a specified pixel position. - /** - \param y Y-coordinate of the filled column. - \param z Z-coordinate of the filled column. - \param c C-coordinate of the filled column. - \param a0 First fill value. - **/ - CImg& fillX(const unsigned int y, const unsigned int z, const unsigned int c, const int a0, ...) { -#define _cimg_fill1(x,y,z,c,off,siz,t) { \ - va_list ap; va_start(ap,a0); T *ptrd = data(x,y,z,c); *ptrd = (T)a0; \ - for (unsigned int k = 1; k& fillX(const unsigned int y, const unsigned int z, const unsigned int c, const double a0, ...) { - if (y<_height && z<_depth && c<_spectrum) _cimg_fill1(0,y,z,c,1,_width,double); - return *this; - } - - //! Fill pixel values along the Y-axis at a specified pixel position. - /** - \param x X-coordinate of the filled row. - \param z Z-coordinate of the filled row. - \param c C-coordinate of the filled row. - \param a0 First fill value. - **/ - CImg& fillY(const unsigned int x, const unsigned int z, const unsigned int c, const int a0, ...) { - if (x<_width && z<_depth && c<_spectrum) _cimg_fill1(x,0,z,c,_width,_height,int); - return *this; - } - - //! Fill pixel values along the Y-axis at a specified pixel position \overloading. - CImg& fillY(const unsigned int x, const unsigned int z, const unsigned int c, const double a0, ...) { - if (x<_width && z<_depth && c<_spectrum) _cimg_fill1(x,0,z,c,_width,_height,double); - return *this; - } - - //! Fill pixel values along the Z-axis at a specified pixel position. - /** - \param x X-coordinate of the filled slice. - \param y Y-coordinate of the filled slice. - \param c C-coordinate of the filled slice. - \param a0 First fill value. - **/ - CImg& fillZ(const unsigned int x, const unsigned int y, const unsigned int c, const int a0, ...) { - const ulongT wh = (ulongT)_width*_height; - if (x<_width && y<_height && c<_spectrum) _cimg_fill1(x,y,0,c,wh,_depth,int); - return *this; - } - - //! Fill pixel values along the Z-axis at a specified pixel position \overloading. - CImg& fillZ(const unsigned int x, const unsigned int y, const unsigned int c, const double a0, ...) { - const ulongT wh = (ulongT)_width*_height; - if (x<_width && y<_height && c<_spectrum) _cimg_fill1(x,y,0,c,wh,_depth,double); - return *this; - } - - //! Fill pixel values along the C-axis at a specified pixel position. - /** - \param x X-coordinate of the filled channel. - \param y Y-coordinate of the filled channel. - \param z Z-coordinate of the filled channel. - \param a0 First filling value. - **/ - CImg& fillC(const unsigned int x, const unsigned int y, const unsigned int z, const int a0, ...) { - const ulongT whd = (ulongT)_width*_height*_depth; - if (x<_width && y<_height && z<_depth) _cimg_fill1(x,y,z,0,whd,_spectrum,int); - return *this; - } - - //! Fill pixel values along the C-axis at a specified pixel position \overloading. - CImg& fillC(const unsigned int x, const unsigned int y, const unsigned int z, const double a0, ...) { - const ulongT whd = (ulongT)_width*_height*_depth; - if (x<_width && y<_height && z<_depth) _cimg_fill1(x,y,z,0,whd,_spectrum,double); - return *this; - } - - //! Discard specified sequence of values in the image buffer, along a specific axis. - /** - \param values Sequence of values to discard. - \param axis Axis along which the values are discarded. If set to \c 0 (default value) - the method does it for all the buffer values and returns a one-column vector. - \note Discarded values will change the image geometry, so the resulting image - is returned as a one-column vector. - **/ - template - CImg& discard(const CImg& values, const char axis=0) { - if (is_empty() || !values) return *this; - return get_discard(values,axis).move_to(*this); - } - - template - CImg get_discard(const CImg& values, const char axis=0) const { - if (!values) return +*this; - CImg res; - if (is_empty()) return res; - const ulongT vsiz = values.size(); - const char _axis = cimg::lowercase(axis); - ulongT j = 0; - unsigned int k = 0; - int i0 = 0; - res.assign(width(),height(),depth(),spectrum()); - switch (_axis) { - case 'x' : { - cimg_forX(*this,i) { - if ((*this)(i)!=(T)values[j]) { - if (j) --i; - res.draw_image(k,get_columns(i0,i)); - k+=i - i0 + 1; i0 = i + 1; j = 0; - } else { ++j; if (j>=vsiz) { j = 0; i0 = i + 1; } } - } - if (i0=vsiz) { j = 0; i0 = i + 1; } } - } - if (i0=vsiz) { j = 0; i0 = i + 1; } } - } - if (i0=vsiz) { j = 0; i0 = i + 1; } } - } - if (i0=vsiz) { j = 0; i0 = (int)i + 1; }} - } - if ((ulongT)i0& discard(const char axis=0) { - return get_discard(axis).move_to(*this); - } - - //! Discard neighboring duplicates in the image buffer, along the specified axis \newinstance. - CImg get_discard(const char axis=0) const { - CImg res; - if (is_empty()) return res; - const char _axis = cimg::lowercase(axis); - T current = *_data?(T)0:(T)1; - int j = 0; - res.assign(width(),height(),depth(),spectrum()); - switch (_axis) { - case 'x' : { - cimg_forX(*this,i) - if ((*this)(i)!=current) { res.draw_image(j++,get_column(i)); current = (*this)(i); } - res.resize(j,-100,-100,-100,0); - } break; - case 'y' : { - cimg_forY(*this,i) - if ((*this)(0,i)!=current) { res.draw_image(0,j++,get_row(i)); current = (*this)(0,i); } - res.resize(-100,j,-100,-100,0); - } break; - case 'z' : { - cimg_forZ(*this,i) - if ((*this)(0,0,i)!=current) { res.draw_image(0,0,j++,get_slice(i)); current = (*this)(0,0,i); } - res.resize(-100,-100,j,-100,0); - } break; - case 'c' : { - cimg_forC(*this,i) - if ((*this)(0,0,0,i)!=current) { res.draw_image(0,0,0,j++,get_channel(i)); current = (*this)(0,0,0,i); } - res.resize(-100,-100,-100,j,0); - } break; - default : { - res.unroll('y'); - cimg_foroff(*this,i) { - const T val = (*this)[i]; - if (val!=current) res[j++] = current = val; - } - res.resize(-100,j,-100,-100,0); - } - } - return res; - } - - //! Invert endianness of all pixel values. - /** - **/ - CImg& invert_endianness() { - cimg::invert_endianness(_data,size()); - return *this; - } - - //! Invert endianness of all pixel values \newinstance. - CImg get_invert_endianness() const { - return (+*this).invert_endianness(); - } - - //! Fill image with random values in specified range. - /** - \param val_min Minimal authorized random value. - \param val_max Maximal authorized random value. - \note Random variables are uniformly distributed in [val_min,val_max]. - **/ - CImg& rand(const T& val_min, const T& val_max) { - const float delta = (float)val_max - (float)val_min + (cimg::type::is_float()?0:1); - if (cimg::type::is_float()) cimg_pragma_openmp(parallel cimg_openmp_if_size(size(),524288)) { - cimg_uint64 rng = (cimg::_rand(),cimg::rng()); - -#if cimg_use_openmp!=0 - rng+=omp_get_thread_num(); -#endif - cimg_pragma_openmp(for) - cimg_rofoff(*this,off) _data[off] = (T)(val_min + delta*cimg::rand(1,&rng)); - cimg::srand(rng); - } else cimg_pragma_openmp(parallel cimg_openmp_if_size(size(),524288)) { - cimg_uint64 rng = (cimg::_rand(),cimg::rng()); - -#if cimg_use_openmp!=0 - rng+=omp_get_thread_num(); -#endif - cimg_pragma_openmp(for) - cimg_rofoff(*this,off) _data[off] = std::min(val_max,(T)(val_min + delta*cimg::rand(1,&rng))); - cimg::srand(rng); - } - return *this; - } - - //! Fill image with random values in specified range \newinstance. - CImg get_rand(const T& val_min, const T& val_max) const { - return (+*this).rand(val_min,val_max); - } - - //! Round pixel values. - /** - \param y Rounding precision. - \param rounding_type Rounding type. Can be: - - \c -1: Backward. - - \c 0: Nearest. - - \c 1: Forward. - **/ - CImg& round(const double y=1, const int rounding_type=0) { - if (y>0) cimg_openmp_for(*this,cimg::round(*ptr,y,rounding_type),8192); - return *this; - } - - //! Round pixel values \newinstance. - CImg get_round(const double y=1, const unsigned int rounding_type=0) const { - return (+*this).round(y,rounding_type); - } - - //! Add random noise to pixel values. - /** - \param sigma Amplitude of the random additive noise. If \p sigma<0, it stands for a percentage of the - global value range. - \param noise_type Type of additive noise (can be \p 0=gaussian, \p 1=uniform, \p 2=Salt and Pepper, - \p 3=Poisson or \p 4=Rician). - \return A reference to the modified image instance. - \note - - For Poisson noise (\p noise_type=3), parameter \p sigma is ignored, as Poisson noise only depends on - the image value itself. - - Function \p CImg::get_noise() is also defined. It returns a non-shared modified copy of the image instance. - \par Example - \code - const CImg img("reference.jpg"), res = img.get_noise(40); - (img,res.normalize(0,255)).display(); - \endcode - \image html ref_noise.jpg - **/ - CImg& noise(const double sigma, const unsigned int noise_type=0) { - if (is_empty()) return *this; - const Tfloat vmin = (Tfloat)cimg::type::min(), vmax = (Tfloat)cimg::type::max(); - Tfloat nsigma = (Tfloat)sigma, m = 0, M = 0; - if (nsigma==0 && noise_type!=3) return *this; - if (nsigma<0 || noise_type==2) m = (Tfloat)min_max(M); - if (nsigma<0) nsigma = (Tfloat)(-nsigma*(M-m)/100.); - switch (noise_type) { - case 0 : { // Gaussian noise - cimg_pragma_openmp(parallel cimg_openmp_if_size(size(),131072)) { - cimg_uint64 rng = (cimg::_rand(),cimg::rng()); - -#if cimg_use_openmp!=0 - rng+=omp_get_thread_num(); -#endif - cimg_pragma_openmp(for) - cimg_rofoff(*this,off) { - Tfloat val = (Tfloat)(_data[off] + nsigma*cimg::grand(&rng)); - if (val>vmax) val = vmax; - if (valvmax) val = vmax; - if (val::is_float()) { --m; ++M; } - else { m = (Tfloat)cimg::type::min(); M = (Tfloat)cimg::type::max(); } - } - cimg_pragma_openmp(parallel cimg_openmp_if_size(size(),131072)) { - cimg_uint64 rng = (cimg::_rand(),cimg::rng()); - -#if cimg_use_openmp!=0 - rng+=omp_get_thread_num(); -#endif - cimg_pragma_openmp(for) - cimg_rofoff(*this,off) if (cimg::rand(100,&rng)vmax) val = vmax; - if (val get_noise(const double sigma, const unsigned int noise_type=0) const { - return (+*this).noise(sigma,noise_type); - } - - //! Linearly normalize pixel values. - /** - \param min_value Minimum desired value of the resulting image. - \param max_value Maximum desired value of the resulting image. - \param constant_case_ratio In case of instance image having a constant value, tell what ratio - of [min_value,max_value] is used to fill the normalized image - (=0 for min_value, =1 for max_value, =0.5 for (min_value + max_value)/2). - \par Example - \code - const CImg img("reference.jpg"), res = img.get_normalize(160,220); - (img,res).display(); - \endcode - \image html ref_normalize2.jpg - **/ - CImg& normalize(const T& min_value, const T& max_value, - const float constant_case_ratio=0) { - if (is_empty()) return *this; - const T a = min_value get_normalize(const T& min_value, const T& max_value, - const float ratio_if_constant_image=0) const { - return CImg(*this,false).normalize((Tfloat)min_value,(Tfloat)max_value,ratio_if_constant_image); - } - - //! Normalize multi-valued pixels of the image instance, with respect to their L2-norm. - /** - \par Example - \code - const CImg img("reference.jpg"), res = img.get_normalize(); - (img,res.normalize(0,255)).display(); - \endcode - \image html ref_normalize.jpg - **/ - CImg& normalize() { - const ulongT whd = (ulongT)_width*_height*_depth; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 && - _height*_depth>=16)) - cimg_forYZ(*this,y,z) { - T *ptrd = data(0,y,z,0); - cimg_forX(*this,x) { - const T *ptrs = ptrd; - float n = 0; - cimg_forC(*this,c) { n+=cimg::sqr((float)*ptrs); ptrs+=whd; } - n = (float)std::sqrt(n); - T *_ptrd = ptrd++; - if (n>0) cimg_forC(*this,c) { *_ptrd = (T)(*_ptrd/n); _ptrd+=whd; } - else cimg_forC(*this,c) { *_ptrd = (T)0; _ptrd+=whd; } - } - } - return *this; - } - - //! Normalize multi-valued pixels of the image instance, with respect to their L2-norm \newinstance. - CImg get_normalize() const { - return CImg(*this,false).normalize(); - } - - //! Compute Lp-norm of each multi-valued pixel of the image instance. - /** - \param norm_type Type of computed vector norm (can be \p -1=Linf, or \p greater or equal than 0). - \par Example - \code - const CImg img("reference.jpg"), res = img.get_norm(); - (img,res.normalize(0,255)).display(); - \endcode - \image html ref_norm.jpg - **/ - CImg& norm(const int norm_type=2) { - if (_spectrum==1 && norm_type) return abs(); - return get_norm(norm_type).move_to(*this); - } - - //! Compute L2-norm of each multi-valued pixel of the image instance \newinstance. - CImg get_norm(const int norm_type=2) const { - if (is_empty()) return *this; - if (_spectrum==1 && norm_type) return get_abs(); - const ulongT whd = (ulongT)_width*_height*_depth; - CImg res(_width,_height,_depth); - switch (norm_type) { - case -1 : { // Linf-norm - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 && - _height*_depth>=16)) - cimg_forYZ(*this,y,z) { - const ulongT off = (ulongT)offset(0,y,z); - const T *ptrs = _data + off; - Tfloat *ptrd = res._data + off; - cimg_forX(*this,x) { - Tfloat n = 0; - const T *_ptrs = ptrs++; - cimg_forC(*this,c) { const Tfloat val = (Tfloat)cimg::abs(*_ptrs); if (val>n) n = val; _ptrs+=whd; } - *(ptrd++) = n; - } - } - } break; - case 0 : { // L0-norm - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 && - _height*_depth>=16)) - cimg_forYZ(*this,y,z) { - const ulongT off = (ulongT)offset(0,y,z); - const T *ptrs = _data + off; - Tfloat *ptrd = res._data + off; - cimg_forX(*this,x) { - unsigned int n = 0; - const T *_ptrs = ptrs++; - cimg_forC(*this,c) { n+=*_ptrs==0?0:1; _ptrs+=whd; } - *(ptrd++) = (Tfloat)n; - } - } - } break; - case 1 : { // L1-norm - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 && - _height*_depth>=16)) - cimg_forYZ(*this,y,z) { - const ulongT off = (ulongT)offset(0,y,z); - const T *ptrs = _data + off; - Tfloat *ptrd = res._data + off; - cimg_forX(*this,x) { - Tfloat n = 0; - const T *_ptrs = ptrs++; - cimg_forC(*this,c) { n+=cimg::abs(*_ptrs); _ptrs+=whd; } - *(ptrd++) = n; - } - } - } break; - case 2 : { // L2-norm - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 && - _height*_depth>=16)) - cimg_forYZ(*this,y,z) { - const ulongT off = (ulongT)offset(0,y,z); - const T *ptrs = _data + off; - Tfloat *ptrd = res._data + off; - cimg_forX(*this,x) { - Tfloat n = 0; - const T *_ptrs = ptrs++; - cimg_forC(*this,c) { n+=cimg::sqr((Tfloat)*_ptrs); _ptrs+=whd; } - *(ptrd++) = (Tfloat)std::sqrt((Tfloat)n); - } - } - } break; - default : { // Linf-norm - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 && - _height*_depth>=16)) - cimg_forYZ(*this,y,z) { - const ulongT off = (ulongT)offset(0,y,z); - const T *ptrs = _data + off; - Tfloat *ptrd = res._data + off; - cimg_forX(*this,x) { - Tfloat n = 0; - const T *_ptrs = ptrs++; - cimg_forC(*this,c) { n+=std::pow(cimg::abs((Tfloat)*_ptrs),(Tfloat)norm_type); _ptrs+=whd; } - *(ptrd++) = (Tfloat)std::pow((Tfloat)n,1/(Tfloat)norm_type); - } - } - } - } - return res; - } - - //! Cut pixel values in specified range. - /** - \param min_value Minimum desired value of the resulting image. - \param max_value Maximum desired value of the resulting image. - \par Example - \code - const CImg img("reference.jpg"), res = img.get_cut(160,220); - (img,res).display(); - \endcode - \image html ref_cut.jpg - **/ - CImg& cut(const T& min_value, const T& max_value) { - if (is_empty()) return *this; - const T a = min_value get_cut(const T& min_value, const T& max_value) const { - return (+*this).cut(min_value,max_value); - } - - //! Uniformly quantize pixel values. - /** - \param nb_levels Number of quantization levels. - \param keep_range Tells if resulting values keep the same range as the original ones. - \par Example - \code - const CImg img("reference.jpg"), res = img.get_quantize(4); - (img,res).display(); - \endcode - \image html ref_quantize.jpg - **/ - CImg& quantize(const unsigned int nb_levels, const bool keep_range=true) { - if (!nb_levels) - throw CImgArgumentException(_cimg_instance - "quantize(): Invalid quantization request with 0 values.", - cimg_instance); - - if (is_empty()) return *this; - Tfloat m, M = (Tfloat)max_min(m), range = M - m; - if (range>0) { - if (keep_range) - cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),32768)) - cimg_rofoff(*this,off) { - const unsigned int val = (unsigned int)((_data[off] - m)*nb_levels/range); - _data[off] = (T)(m + std::min(val,nb_levels - 1)*range/nb_levels); - } else - cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),32768)) - cimg_rofoff(*this,off) { - const unsigned int val = (unsigned int)((_data[off] - m)*nb_levels/range); - _data[off] = (T)std::min(val,nb_levels - 1); - } - } - return *this; - } - - //! Uniformly quantize pixel values \newinstance. - CImg get_quantize(const unsigned int n, const bool keep_range=true) const { - return (+*this).quantize(n,keep_range); - } - - //! Return the Otsu threshold. - /** - \param nb_levels Number of histogram levels used for the estimation. - **/ - T otsu(const unsigned int nb_levels=256) const { - T m,M = max_min(m); - CImg hist = get_histogram(nb_levels,m,M); - ulongT sum = 0, sumB = 0, wB = 0; - double best_variance = 0; - unsigned int best_t = 0; - cimg_forX(hist,t) sum+=t*hist[t]; - cimg_forX(hist,t) { - wB+=hist[t]; - if (wB) { - const ulongT wF = size() - wB; - if (!wF) break; - sumB+=t*hist[t]; - const double - mB = (double)sumB/wB, - mF = (double)(sum - sumB)/wF, - variance = wB*wF*cimg::sqr(mB - mF); - if (variance>best_variance) { best_variance = variance; best_t = t; } - } - } - return m + best_t*(M - m)/(hist.width() - 1); - } - - //! Threshold pixel values. - /** - \param value Threshold value - \param soft_threshold Tells if soft thresholding must be applied (instead of hard one). - \param strict_threshold Tells if threshold value is strict. - \par Example - \code - const CImg img("reference.jpg"), res = img.get_threshold(128); - (img,res.normalize(0,255)).display(); - \endcode - \image html ref_threshold.jpg - **/ - CImg& threshold(const T& value, const bool soft_threshold=false, const bool strict_threshold=false) { - if (is_empty()) return *this; - if (strict_threshold) { - if (soft_threshold) - cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),32768)) - cimg_rofoff(*this,off) { - const T v = _data[off]; - _data[off] = v>value?(T)(v-value):v<-(float)value?(T)(v + value):(T)0; - } - else - cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),65536)) - cimg_rofoff(*this,off) _data[off] = _data[off]>value?(T)1:(T)0; - } else { - if (soft_threshold) - cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),32768)) - cimg_rofoff(*this,off) { - const T v = _data[off]; - _data[off] = v>=value?(T)(v-value):v<=-(float)value?(T)(v + value):(T)0; - } - else - cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),65536)) - cimg_rofoff(*this,off) _data[off] = _data[off]>=value?(T)1:(T)0; - } - return *this; - } - - //! Threshold pixel values \newinstance. - CImg get_threshold(const T& value, const bool soft_threshold=false, const bool strict_threshold=false) const { - return (+*this).threshold(value,soft_threshold,strict_threshold); - } - - //! Compute the histogram of pixel values. - /** - \param nb_levels Number of desired histogram levels. - \param min_value Minimum pixel value considered for the histogram computation. - All pixel values lower than \p min_value will not be counted. - \param max_value Maximum pixel value considered for the histogram computation. - All pixel values higher than \p max_value will not be counted. - \note - - The histogram H of an image I is the 1D function where H(x) counts the number of occurrences of the value x - in the image I. - - The resulting histogram is always defined in 1D. Histograms of multi-valued images are not multi-dimensional. - \par Example - \code - const CImg img = CImg("reference.jpg").histogram(256); - img.display_graph(0,3); - \endcode - \image html ref_histogram.jpg - **/ - CImg& histogram(const unsigned int nb_levels, const T& min_value, const T& max_value) { - return get_histogram(nb_levels,min_value,max_value).move_to(*this); - } - - //! Compute the histogram of pixel values \overloading. - CImg& histogram(const unsigned int nb_levels) { - return get_histogram(nb_levels).move_to(*this); - } - - //! Compute the histogram of pixel values \newinstance. - CImg get_histogram(const unsigned int nb_levels, const T& min_value, const T& max_value) const { - if (!nb_levels || is_empty()) return CImg(); - const double - vmin = (double)(min_value res(nb_levels,1,1,1,0); - cimg_rof(*this,ptrs,T) { - const T val = *ptrs; - if (val>=vmin && val<=vmax) ++res[val==vmax?nb_levels - 1:(unsigned int)((val - vmin)*nb_levels/(vmax - vmin))]; - } - return res; - } - - //! Compute the histogram of pixel values \newinstance. - CImg get_histogram(const unsigned int nb_levels) const { - if (!nb_levels || is_empty()) return CImg(); - T vmax = 0, vmin = min_max(vmax); - return get_histogram(nb_levels,vmin,vmax); - } - - //! Equalize histogram of pixel values. - /** - \param nb_levels Number of histogram levels used for the equalization. - \param min_value Minimum pixel value considered for the histogram computation. - All pixel values lower than \p min_value will not be counted. - \param max_value Maximum pixel value considered for the histogram computation. - All pixel values higher than \p max_value will not be counted. - \par Example - \code - const CImg img("reference.jpg"), res = img.get_equalize(256); - (img,res).display(); - \endcode - \image html ref_equalize.jpg - **/ - CImg& equalize(const unsigned int nb_levels, const T& min_value, const T& max_value) { - if (!nb_levels || is_empty()) return *this; - const T - vmin = min_value hist = get_histogram(nb_levels,vmin,vmax); - ulongT cumul = 0; - cimg_forX(hist,pos) { cumul+=hist[pos]; hist[pos] = cumul; } - if (!cumul) cumul = 1; - cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),1048576)) - cimg_rofoff(*this,off) { - const int pos = (int)((_data[off] - vmin)*(nb_levels - 1.)/(vmax - vmin)); - if (pos>=0 && pos<(int)nb_levels) _data[off] = (T)(vmin + (vmax - vmin)*hist[pos]/cumul); - } - return *this; - } - - //! Equalize histogram of pixel values \overloading. - CImg& equalize(const unsigned int nb_levels) { - if (!nb_levels || is_empty()) return *this; - T vmax = 0, vmin = min_max(vmax); - return equalize(nb_levels,vmin,vmax); - } - - //! Equalize histogram of pixel values \newinstance. - CImg get_equalize(const unsigned int nblevels, const T& val_min, const T& val_max) const { - return (+*this).equalize(nblevels,val_min,val_max); - } - - //! Equalize histogram of pixel values \newinstance. - CImg get_equalize(const unsigned int nblevels) const { - return (+*this).equalize(nblevels); - } - - //! Index multi-valued pixels regarding to a specified colormap. - /** - \param colormap Multi-valued colormap used as the basis for multi-valued pixel indexing. - \param dithering Level of dithering (0=disable, 1=standard level). - \param map_indexes Tell if the values of the resulting image are the colormap indices or the colormap vectors. - \note - - \p img.index(colormap,dithering,1) is equivalent to img.index(colormap,dithering,0).map(colormap). - \par Example - \code - const CImg img("reference.jpg"), colormap(3,1,1,3, 0,128,255, 0,128,255, 0,128,255); - const CImg res = img.get_index(colormap,1,true); - (img,res).display(); - \endcode - \image html ref_index.jpg - **/ - template - CImg& index(const CImg& colormap, const float dithering=1, const bool map_indexes=false) { - return get_index(colormap,dithering,map_indexes).move_to(*this); - } - - //! Index multi-valued pixels regarding to a specified colormap \newinstance. - template - CImg::Tuint> - get_index(const CImg& colormap, const float dithering=1, const bool map_indexes=true) const { - if (colormap._spectrum!=_spectrum) - throw CImgArgumentException(_cimg_instance - "index(): Instance and specified colormap (%u,%u,%u,%u,%p) " - "have incompatible dimensions.", - cimg_instance, - colormap._width,colormap._height,colormap._depth,colormap._spectrum,colormap._data); - - typedef typename CImg::Tuint tuint; - if (is_empty()) return CImg(); - const ulongT - whd = (ulongT)_width*_height*_depth, - pwhd = (ulongT)colormap._width*colormap._height*colormap._depth; - CImg res(_width,_height,_depth,map_indexes?_spectrum:1); - if (dithering>0) { // Dithered versions - tuint *ptrd = res._data; - const float ndithering = cimg::cut(dithering,0,1)/16; - Tfloat valm = 0, valM = (Tfloat)max_min(valm); - if (valm==valM && valm>=0 && valM<=255) { valm = 0; valM = 255; } - CImg cache = get_crop(-1,0,0,0,_width,1,0,_spectrum - 1); - Tfloat *cache_current = cache.data(1,0,0,0), *cache_next = cache.data(1,1,0,0); - const ulongT cwhd = (ulongT)cache._width*cache._height*cache._depth; - switch (_spectrum) { - case 1 : { // Optimized for scalars - cimg_forYZ(*this,y,z) { - if (yvalM?valM:_val0; - Tfloat distmin = cimg::type::max(); const t *ptrmin0 = colormap._data; - for (const t *ptrp0 = colormap._data, *ptrp_end = ptrp0 + pwhd; ptrp0valM?valM:_val0, - _val1 = (Tfloat)*ptrs1, val1 = _val1valM?valM:_val1; - Tfloat distmin = cimg::type::max(); const t *ptrmin0 = colormap._data; - for (const t *ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp_end = ptrp1; ptrp0valM?valM:_val0, - _val1 = (Tfloat)*ptrs1, val1 = _val1valM?valM:_val1, - _val2 = (Tfloat)*ptrs2, val2 = _val2valM?valM:_val2; - Tfloat distmin = cimg::type::max(); const t *ptrmin0 = colormap._data; - for (const t *ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd, - *ptrp_end = ptrp1; ptrp0::max(); const t *ptrmin = colormap._data; - for (const t *ptrp = colormap._data, *ptrp_end = ptrp + pwhd; ptrpvalM?valM:_val; - dist+=cimg::sqr((*_ptrs=val) - (Tfloat)*_ptrp); _ptrs+=cwhd; _ptrp+=pwhd; - } - if (dist=(cimg_openmp_sizefactor)*64 && - _height*_depth>=16 && pwhd>=16)) - cimg_forYZ(*this,y,z) { - tuint *ptrd = res.data(0,y,z); - for (const T *ptrs0 = data(0,y,z), *ptrs_end = ptrs0 + _width; ptrs0::max(); const t *ptrmin0 = colormap._data; - for (const t *ptrp0 = colormap._data, *ptrp_end = ptrp0 + pwhd; ptrp0=(cimg_openmp_sizefactor)*64 && - _height*_depth>=16 && pwhd>=16)) - cimg_forYZ(*this,y,z) { - tuint *ptrd = res.data(0,y,z), *ptrd1 = ptrd + whd; - for (const T *ptrs0 = data(0,y,z), *ptrs1 = ptrs0 + whd, *ptrs_end = ptrs0 + _width; ptrs0::max(); const t *ptrmin0 = colormap._data; - for (const t *ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp_end = ptrp1; ptrp0=(cimg_openmp_sizefactor)*64 && - _height*_depth>=16 && pwhd>=16)) - cimg_forYZ(*this,y,z) { - tuint *ptrd = res.data(0,y,z), *ptrd1 = ptrd + whd, *ptrd2 = ptrd1 + whd; - for (const T *ptrs0 = data(0,y,z), *ptrs1 = ptrs0 + whd, *ptrs2 = ptrs1 + whd, - *ptrs_end = ptrs0 + _width; ptrs0::max(); const t *ptrmin0 = colormap._data; - for (const t *ptrp0 = colormap._data, *ptrp1 = ptrp0 + pwhd, *ptrp2 = ptrp1 + pwhd, - *ptrp_end = ptrp1; ptrp0=(cimg_openmp_sizefactor)*64 && - _height*_depth>=16 && pwhd>=16)) - cimg_forYZ(*this,y,z) { - tuint *ptrd = res.data(0,y,z); - for (const T *ptrs = data(0,y,z), *ptrs_end = ptrs + _width; ptrs::max(); const t *ptrmin = colormap._data; - for (const t *ptrp = colormap._data, *ptrp_end = ptrp + pwhd; ptrp img("reference.jpg"), - colormap1(3,1,1,3, 0,128,255, 0,128,255, 0,128,255), - colormap2(3,1,1,3, 255,0,0, 0,255,0, 0,0,255), - res = img.get_index(colormap1,0).map(colormap2); - (img,res).display(); - \endcode - \image html ref_map.jpg - **/ - template - CImg& map(const CImg& colormap, const unsigned int boundary_conditions=0) { - return get_map(colormap,boundary_conditions).move_to(*this); - } - - //! Map predefined colormap on the scalar (indexed) image instance \newinstance. - template - CImg get_map(const CImg& colormap, const unsigned int boundary_conditions=0) const { - const ulongT - whd = (ulongT)_width*_height*_depth, siz = size(), - cwhd = (ulongT)colormap._width*colormap._height*colormap._depth, - cwhd2 = 2*cwhd; - CImg res(_width,_height,_depth,_spectrum*colormap._spectrum); - switch (colormap._spectrum) { - - case 1 : { // Optimized for scalars - switch (boundary_conditions) { - case 3 : // Mirror - cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),256)) - for (longT off = 0; off<(longT)siz; ++off) { - const ulongT ind = ((ulongT)_data[off])%cwhd2; - res[off] = colormap[ind& label(const bool is_high_connectivity=false, const Tfloat tolerance=0, - const bool is_L2_norm=true) { - if (is_empty()) return *this; - return get_label(is_high_connectivity,tolerance,is_L2_norm).move_to(*this); - } - - //! Label connected components \newinstance. - CImg get_label(const bool is_high_connectivity=false, const Tfloat tolerance=0, - const bool is_L2_norm=true) const { - if (is_empty()) return CImg(); - - // Create neighborhood tables. - int dx[13], dy[13], dz[13], nb = 0; - dx[nb] = 1; dy[nb] = 0; dz[nb++] = 0; - dx[nb] = 0; dy[nb] = 1; dz[nb++] = 0; - if (is_high_connectivity) { - dx[nb] = 1; dy[nb] = 1; dz[nb++] = 0; - dx[nb] = 1; dy[nb] = -1; dz[nb++] = 0; - } - if (_depth>1) { // 3D version - dx[nb] = 0; dy[nb] = 0; dz[nb++]=1; - if (is_high_connectivity) { - dx[nb] = 1; dy[nb] = 1; dz[nb++] = -1; - dx[nb] = 1; dy[nb] = 0; dz[nb++] = -1; - dx[nb] = 1; dy[nb] = -1; dz[nb++] = -1; - dx[nb] = 0; dy[nb] = 1; dz[nb++] = -1; - - dx[nb] = 0; dy[nb] = 1; dz[nb++] = 1; - dx[nb] = 1; dy[nb] = -1; dz[nb++] = 1; - dx[nb] = 1; dy[nb] = 0; dz[nb++] = 1; - dx[nb] = 1; dy[nb] = 1; dz[nb++] = 1; - } - } - return _label(nb,dx,dy,dz,tolerance,is_L2_norm); - } - - //! Label connected components \overloading. - /** - \param connectivity_mask Mask of the neighboring pixels. - \param tolerance Tolerance used to determine if two neighboring pixels belong to the same region. - \param is_L2_norm If true, tolerance is compared against L2 difference, otherwise L1 is used. - **/ - template - CImg& label(const CImg& connectivity_mask, const Tfloat tolerance=0, - const bool is_L2_norm=true) { - if (is_empty()) return *this; - return get_label(connectivity_mask,tolerance,is_L2_norm).move_to(*this); - } - - //! Label connected components \newinstance. - template - CImg get_label(const CImg& connectivity_mask, const Tfloat tolerance=0, - const bool is_L2_norm=true) const { - if (is_empty()) return CImg(); - int nb = 0; - cimg_for(connectivity_mask,ptr,t) if (*ptr) ++nb; - CImg dx(nb,1,1,1,0), dy(nb,1,1,1,0), dz(nb,1,1,1,0); - nb = 0; - cimg_forXYZ(connectivity_mask,x,y,z) if ((x || y || z) && - connectivity_mask(x,y,z)) { - dx[nb] = x; dy[nb] = y; dz[nb++] = z; - } - return _label(nb,dx,dy,dz,tolerance,is_L2_norm); - } - - CImg _label(const unsigned int nb, const int *const dx, - const int *const dy, const int *const dz, - const Tfloat tolerance, const bool is_L2_norm) const { - CImg res(_width,_height,_depth); - const Tfloat _tolerance = _spectrum>1 && is_L2_norm?cimg::sqr(tolerance):tolerance; - - // Init label numbers. - ulongT *ptr = res.data(); - cimg_foroff(res,p) *(ptr++) = p; - - // For each neighbour-direction, label. - for (unsigned int n = 0; n& _system_strescape() { -#define cimg_system_strescape(c,s) case c : if (p!=ptrs) CImg(ptrs,(unsigned int)(p-ptrs),1,1,1,false).\ - move_to(list); \ - CImg(s,(unsigned int)std::strlen(s),1,1,1,false).move_to(list); ptrs = p + 1; break - CImgList list; - const T *ptrs = _data; - cimg_for(*this,p,T) switch ((int)*p) { - cimg_system_strescape('\\',"\\\\"); - cimg_system_strescape('\"',"\\\""); - cimg_system_strescape('!',"\"\\!\""); - cimg_system_strescape('`',"\\`"); - cimg_system_strescape('$',"\\$"); - } - if (ptrs(ptrs,(unsigned int)(end()-ptrs),1,1,1,false).move_to(list); - return (list>'x').move_to(*this); - } - - //@} - //--------------------------------- - // - //! \name Color Base Management - //@{ - //--------------------------------- - - //! Return colormap \e "default", containing 256 colors entries in RGB. - /** - \return The following \c 256x1x1x3 colormap is returned: - \image html ref_colormap_default.jpg - **/ - static const CImg& default_LUT256() { - static CImg colormap; - cimg::mutex(8); - if (!colormap) { - colormap.assign(1,256,1,3); - for (unsigned int index = 0, r = 16; r<256; r+=32) - for (unsigned int g = 16; g<256; g+=32) - for (unsigned int b = 32; b<256; b+=64) { - colormap(0,index,0) = (Tuchar)r; - colormap(0,index,1) = (Tuchar)g; - colormap(0,index++,2) = (Tuchar)b; - } - } - cimg::mutex(8,0); - return colormap; - } - - //! Return colormap \e "HSV", containing 256 colors entries in RGB. - /** - \return The following \c 256x1x1x3 colormap is returned: - \image html ref_colormap_hsv.jpg - **/ - static const CImg& HSV_LUT256() { - static CImg colormap; - cimg::mutex(8); - if (!colormap) { - CImg tmp(1,256,1,3,1); - tmp.get_shared_channel(0).sequence(0,359); - colormap = tmp.HSVtoRGB(); - } - cimg::mutex(8,0); - return colormap; - } - - //! Return colormap \e "lines", containing 256 colors entries in RGB. - /** - \return The following \c 256x1x1x3 colormap is returned: - \image html ref_colormap_lines.jpg - **/ - static const CImg& lines_LUT256() { - static const unsigned char pal[] = { - 0,255,255,0,0,28,125,125,235,210,186,182,36,0,125,255, - 53,32,255,210,89,186,65,45,125,210,210,97,130,194,0,125, - 206,53,190,89,255,146,20,190,154,73,255,36,130,215,0,138, - 101,210,61,194,206,0,77,45,255,154,174,0,190,239,89,125, - 16,36,158,223,117,0,97,69,223,255,40,239,0,0,255,0, - 97,170,93,255,138,40,117,210,0,170,53,158,186,255,0,121, - 227,121,186,40,20,190,89,255,77,57,130,142,255,73,186,85, - 210,8,32,166,243,130,210,40,255,45,61,142,223,49,121,255, - 20,162,158,73,89,255,53,138,210,190,57,235,36,73,255,49, - 210,0,210,85,57,97,255,121,85,174,40,255,162,178,0,121, - 166,125,53,146,166,255,97,121,65,89,235,231,12,170,36,190, - 85,255,166,97,198,77,20,146,109,166,255,28,40,202,121,81, - 247,0,210,255,49,0,65,255,36,166,93,77,255,85,251,0, - 170,178,0,182,255,0,162,16,154,142,162,223,223,0,0,81, - 215,4,215,162,215,125,77,206,121,36,125,231,101,16,255,121, - 0,57,190,215,65,125,89,142,255,101,73,53,146,223,125,125, - 0,255,0,255,0,206,93,138,49,255,0,202,154,85,45,219, - 251,53,0,255,40,130,219,158,16,117,186,130,202,49,65,239, - 89,202,49,28,247,134,150,0,255,117,202,4,215,81,186,57, - 202,89,73,210,40,93,45,251,206,28,223,142,40,134,162,125, - 32,247,97,170,0,255,57,134,73,247,162,0,251,40,142,142, - 8,166,206,81,154,194,93,89,125,243,28,109,227,0,190,65, - 194,186,0,255,53,45,109,186,186,0,255,130,49,170,69,210, - 154,0,109,227,45,255,125,105,81,81,255,0,219,134,170,85, - 146,28,170,89,223,97,8,210,255,158,49,40,125,174,174,125, - 0,227,166,28,219,130,0,93,239,0,85,255,81,178,125,49, - 89,255,53,206,73,113,146,255,0,150,36,219,162,0,210,125, - 69,134,255,85,40,89,235,49,215,121,0,206,36,223,174,69, - 40,182,178,130,69,45,255,210,85,77,215,0,231,146,0,194, - 125,174,0,255,40,89,121,206,57,0,206,170,231,150,81,0, - 125,255,4,174,4,190,121,255,4,166,109,130,49,239,170,93, - 16,174,210,0,255,16,105,158,93,255,0,125,0,255,158,85, - 0,255,0,0,255,170,166,61,121,28,198,215,45,243,61,97, - 255,53,81,130,109,255,8,117,235,121,40,178,174,0,182,49, - 162,121,255,69,206,0,219,125,0,101,255,239,121,32,210,130, - 36,231,32,125,81,142,215,158,4,178,255,0,40,251,125,125, - 219,89,130,0,166,255,24,65,194,125,255,125,77,125,93,125, - 202,24,138,174,178,32,255,85,194,40,85,36,174,174,125,210, - 85,255,53,16,93,206,40,130,170,202,93,255,0,24,117,255, - 97,113,105,81,255,186,194,57,69,206,57,53,223,190,4,255, - 85,97,130,255,85,0,125,223,85,219,0,215,146,77,40,239, - 89,36,142,154,227,0,255,85,162,0,162,0,235,178,45,166, - 0,247,255,20,69,210,89,142,53,255,40,146,166,255,69,0, - 174,154,142,130,162,0,215,255,0,89,40,255,166,61,146,69, - 162,40,255,32,121,255,117,178,0,186,206,0,57,215,215,81, - 158,77,166,210,77,89,210,0,24,202,150,186,0,255,20,97, - 57,170,235,251,16,73,142,251,93,0,202,0,255,121,219,4, - 73,219,8,162,206,16,219,93,117,0,255,8,130,174,223,45 }; - static const CImg colormap(pal,1,256,1,3,false); - return colormap; - } - - //! Return colormap \e "hot", containing 256 colors entries in RGB. - /** - \return The following \c 256x1x1x3 colormap is returned: - \image html ref_colormap_hot.jpg - **/ - static const CImg& hot_LUT256() { - static CImg colormap; - cimg::mutex(8); - if (!colormap) { - colormap.assign(1,4,1,3,(T)0); - colormap[1] = colormap[2] = colormap[3] = colormap[6] = colormap[7] = colormap[11] = 255; - colormap.resize(1,256,1,3,3); - } - cimg::mutex(8,0); - return colormap; - } - - //! Return colormap \e "cool", containing 256 colors entries in RGB. - /** - \return The following \c 256x1x1x3 colormap is returned: - \image html ref_colormap_cool.jpg - **/ - static const CImg& cool_LUT256() { - static CImg colormap; - cimg::mutex(8); - if (!colormap) colormap.assign(1,2,1,3).fill((T)0,(T)255,(T)255,(T)0,(T)255,(T)255).resize(1,256,1,3,3); - cimg::mutex(8,0); - return colormap; - } - - //! Return colormap \e "jet", containing 256 colors entries in RGB. - /** - \return The following \c 256x1x1x3 colormap is returned: - \image html ref_colormap_jet.jpg - **/ - static const CImg& jet_LUT256() { - static CImg colormap; - cimg::mutex(8); - if (!colormap) { - colormap.assign(1,4,1,3,(T)0); - colormap[2] = colormap[3] = colormap[5] = colormap[6] = colormap[8] = colormap[9] = 255; - colormap.resize(1,256,1,3,3); - } - cimg::mutex(8,0); - return colormap; - } - - //! Return colormap \e "flag", containing 256 colors entries in RGB. - /** - \return The following \c 256x1x1x3 colormap is returned: - \image html ref_colormap_flag.jpg - **/ - static const CImg& flag_LUT256() { - static CImg colormap; - cimg::mutex(8); - if (!colormap) { - colormap.assign(1,4,1,3,(T)0); - colormap[0] = colormap[1] = colormap[5] = colormap[9] = colormap[10] = 255; - colormap.resize(1,256,1,3,0,2); - } - cimg::mutex(8,0); - return colormap; - } - - //! Return colormap \e "cube", containing 256 colors entries in RGB. - /** - \return The following \c 256x1x1x3 colormap is returned: - \image html ref_colormap_cube.jpg - **/ - static const CImg& cube_LUT256() { - static CImg colormap; - cimg::mutex(8); - if (!colormap) { - colormap.assign(1,8,1,3,(T)0); - colormap[1] = colormap[3] = colormap[5] = colormap[7] = - colormap[10] = colormap[11] = colormap[12] = colormap[13] = - colormap[20] = colormap[21] = colormap[22] = colormap[23] = 255; - colormap.resize(1,256,1,3,3); - } - cimg::mutex(8,0); - return colormap; - } - - //! Convert pixel values from sRGB to RGB color spaces. - CImg& sRGBtoRGB() { - if (is_empty()) return *this; - cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),32)) - cimg_rofoff(*this,off) { - const Tfloat - sval = (Tfloat)_data[off]/255, - val = (Tfloat)(sval<=0.04045f?sval/12.92f:std::pow((sval + 0.055f)/(1.055f),2.4f)); - _data[off] = (T)cimg::cut(val*255,0,255); - } - return *this; - } - - //! Convert pixel values from sRGB to RGB color spaces \newinstance. - CImg get_sRGBtoRGB() const { - return CImg(*this,false).sRGBtoRGB(); - } - - //! Convert pixel values from RGB to sRGB color spaces. - CImg& RGBtosRGB() { - if (is_empty()) return *this; - cimg_pragma_openmp(parallel for cimg_openmp_if_size(size(),32)) - cimg_rofoff(*this,off) { - const Tfloat - val = (Tfloat)_data[off]/255, - sval = (Tfloat)(val<=0.0031308f?val*12.92f:1.055f*std::pow(val,0.416667f) - 0.055f); - _data[off] = (T)cimg::cut(sval*255,0,255); - } - return *this; - } - - //! Convert pixel values from RGB to sRGB color spaces \newinstance. - CImg get_RGBtosRGB() const { - return CImg(*this,false).RGBtosRGB(); - } - - //! Convert pixel values from RGB to HSI color spaces. - CImg& RGBtoHSI() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "RGBtoHSI(): Instance is not a RGB image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,256)) - for (longT N = 0; N get_RGBtoHSI() const { - return CImg(*this,false).RGBtoHSI(); - } - - //! Convert pixel values from HSI to RGB color spaces. - CImg& HSItoRGB() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "HSItoRGB(): Instance is not a HSI image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,256)) - for (longT N = 0; N get_HSItoRGB() const { - return CImg< Tuchar>(*this,false).HSItoRGB(); - } - - //! Convert pixel values from RGB to HSL color spaces. - CImg& RGBtoHSL() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "RGBtoHSL(): Instance is not a RGB image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,256)) - for (longT N = 0; N get_RGBtoHSL() const { - return CImg(*this,false).RGBtoHSL(); - } - - //! Convert pixel values from HSL to RGB color spaces. - CImg& HSLtoRGB() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "HSLtoRGB(): Instance is not a HSL image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,256)) - for (longT N = 0; N get_HSLtoRGB() const { - return CImg(*this,false).HSLtoRGB(); - } - - //! Convert pixel values from RGB to HSV color spaces. - CImg& RGBtoHSV() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "RGBtoHSV(): Instance is not a RGB image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,256)) - for (longT N = 0; N get_RGBtoHSV() const { - return CImg(*this,false).RGBtoHSV(); - } - - //! Convert pixel values from HSV to RGB color spaces. - CImg& HSVtoRGB() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "HSVtoRGB(): Instance is not a HSV image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,256)) - for (longT N = 0; N get_HSVtoRGB() const { - return CImg(*this,false).HSVtoRGB(); - } - - //! Convert pixel values from RGB to YCbCr color spaces. - CImg& RGBtoYCbCr() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "RGBtoYCbCr(): Instance is not a RGB image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,512)) - for (longT N = 0; N get_RGBtoYCbCr() const { - return CImg(*this,false).RGBtoYCbCr(); - } - - //! Convert pixel values from RGB to YCbCr color spaces. - CImg& YCbCrtoRGB() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "YCbCrtoRGB(): Instance is not a YCbCr image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,512)) - for (longT N = 0; N get_YCbCrtoRGB() const { - return CImg(*this,false).YCbCrtoRGB(); - } - - //! Convert pixel values from RGB to YUV color spaces. - CImg& RGBtoYUV() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "RGBtoYUV(): Instance is not a RGB image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,16384)) - for (longT N = 0; N get_RGBtoYUV() const { - return CImg(*this,false).RGBtoYUV(); - } - - //! Convert pixel values from YUV to RGB color spaces. - CImg& YUVtoRGB() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "YUVtoRGB(): Instance is not a YUV image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,16384)) - for (longT N = 0; N get_YUVtoRGB() const { - return CImg< Tuchar>(*this,false).YUVtoRGB(); - } - - //! Convert pixel values from RGB to CMY color spaces. - CImg& RGBtoCMY() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "RGBtoCMY(): Instance is not a RGB image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,2048)) - for (longT N = 0; N get_RGBtoCMY() const { - return CImg(*this,false).RGBtoCMY(); - } - - //! Convert pixel values from CMY to RGB color spaces. - CImg& CMYtoRGB() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "CMYtoRGB(): Instance is not a CMY image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,2048)) - for (longT N = 0; N get_CMYtoRGB() const { - return CImg(*this,false).CMYtoRGB(); - } - - //! Convert pixel values from CMY to CMYK color spaces. - CImg& CMYtoCMYK() { - return get_CMYtoCMYK().move_to(*this); - } - - //! Convert pixel values from CMY to CMYK color spaces \newinstance. - CImg get_CMYtoCMYK() const { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "CMYtoCMYK(): Instance is not a CMY image.", - cimg_instance); - - CImg res(_width,_height,_depth,4); - const T *ps1 = data(0,0,0,0), *ps2 = data(0,0,0,1), *ps3 = data(0,0,0,2); - Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2), *pd4 = res.data(0,0,0,3); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,1024)) - for (longT N = 0; N=255) C = M = Y = 0; - else { const Tfloat K1 = 255 - K; C = 255*(C - K)/K1; M = 255*(M - K)/K1; Y = 255*(Y - K)/K1; } - pd1[N] = (Tfloat)cimg::cut(C,0,255), - pd2[N] = (Tfloat)cimg::cut(M,0,255), - pd3[N] = (Tfloat)cimg::cut(Y,0,255), - pd4[N] = (Tfloat)cimg::cut(K,0,255); - } - return res; - } - - //! Convert pixel values from CMYK to CMY color spaces. - CImg& CMYKtoCMY() { - return get_CMYKtoCMY().move_to(*this); - } - - //! Convert pixel values from CMYK to CMY color spaces \newinstance. - CImg get_CMYKtoCMY() const { - if (_spectrum!=4) - throw CImgInstanceException(_cimg_instance - "CMYKtoCMY(): Instance is not a CMYK image.", - cimg_instance); - - CImg res(_width,_height,_depth,3); - const T *ps1 = data(0,0,0,0), *ps2 = data(0,0,0,1), *ps3 = data(0,0,0,2), *ps4 = data(0,0,0,3); - Tfloat *pd1 = res.data(0,0,0,0), *pd2 = res.data(0,0,0,1), *pd3 = res.data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,1024)) - for (longT N = 0; N& RGBtoXYZ(const bool use_D65=true) { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "RGBtoXYZ(): Instance is not a RGB image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,2048)) - for (longT N = 0; N get_RGBtoXYZ(const bool use_D65=true) const { - return CImg(*this,false).RGBtoXYZ(use_D65); - } - - //! Convert pixel values from XYZ to RGB color spaces. - /** - \param use_D65 Tell to use the D65 illuminant (D50 otherwise). - **/ - CImg& XYZtoRGB(const bool use_D65=true) { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "XYZtoRGB(): Instance is not a XYZ image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,2048)) - for (longT N = 0; N get_XYZtoRGB(const bool use_D65=true) const { - return CImg(*this,false).XYZtoRGB(use_D65); - } - - //! Convert pixel values from XYZ to Lab color spaces. - CImg& XYZtoLab(const bool use_D65=true) { -#define _cimg_Labf(x) (24389*(x)>216?cimg::cbrt(x):(24389*(x)/27 + 16)/116) - - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "XYZtoLab(): Instance is not a XYZ image.", - cimg_instance); - const CImg white = CImg(1,1,1,3,255).RGBtoXYZ(use_D65); - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,128)) - for (longT N = 0; N get_XYZtoLab(const bool use_D65=true) const { - return CImg(*this,false).XYZtoLab(use_D65); - } - - //! Convert pixel values from Lab to XYZ color spaces. - CImg& LabtoXYZ(const bool use_D65=true) { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "LabtoXYZ(): Instance is not a Lab image.", - cimg_instance); - const CImg white = CImg(1,1,1,3,255).RGBtoXYZ(use_D65); - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,128)) - for (longT N = 0; N216?cX*cX*cX:(116*cX - 16)*27/24389), - Y = (Tfloat)(27*L>216?cY*cY*cY:27*L/24389), - Z = (Tfloat)(24389*cZ>216?cZ*cZ*cZ:(116*cZ - 16)*27/24389); - p1[N] = (T)(X*white[0]); - p2[N] = (T)(Y*white[1]); - p3[N] = (T)(Z*white[2]); - } - return *this; - } - - //! Convert pixel values from Lab to XYZ color spaces \newinstance. - CImg get_LabtoXYZ(const bool use_D65=true) const { - return CImg(*this,false).LabtoXYZ(use_D65); - } - - //! Convert pixel values from XYZ to xyY color spaces. - CImg& XYZtoxyY() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "XYZtoxyY(): Instance is not a XYZ image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,4096)) - for (longT N = 0; N0?sum:1; - p1[N] = (T)(X/nsum); - p2[N] = (T)(Y/nsum); - p3[N] = (T)Y; - } - return *this; - } - - //! Convert pixel values from XYZ to xyY color spaces \newinstance. - CImg get_XYZtoxyY() const { - return CImg(*this,false).XYZtoxyY(); - } - - //! Convert pixel values from xyY pixels to XYZ color spaces. - CImg& xyYtoXYZ() { - if (_spectrum!=3) - throw CImgInstanceException(_cimg_instance - "xyYtoXYZ(): Instance is not a xyY image.", - cimg_instance); - - T *p1 = data(0,0,0,0), *p2 = data(0,0,0,1), *p3 = data(0,0,0,2); - const longT whd = (longT)width()*height()*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(whd,4096)) - for (longT N = 0; N0?py:1; - p1[N] = (T)(px*Y/ny); - p2[N] = (T)Y; - p3[N] = (T)((1 - px - py)*Y/ny); - } - return *this; - } - - //! Convert pixel values from xyY pixels to XYZ color spaces \newinstance. - CImg get_xyYtoXYZ() const { - return CImg(*this,false).xyYtoXYZ(); - } - - //! Convert pixel values from RGB to Lab color spaces. - CImg& RGBtoLab(const bool use_D65=true) { - return RGBtoXYZ(use_D65).XYZtoLab(use_D65); - } - - //! Convert pixel values from RGB to Lab color spaces \newinstance. - CImg get_RGBtoLab(const bool use_D65=true) const { - return CImg(*this,false).RGBtoLab(use_D65); - } - - //! Convert pixel values from Lab to RGB color spaces. - CImg& LabtoRGB(const bool use_D65=true) { - return LabtoXYZ().XYZtoRGB(use_D65); - } - - //! Convert pixel values from Lab to RGB color spaces \newinstance. - CImg get_LabtoRGB(const bool use_D65=true) const { - return CImg(*this,false).LabtoRGB(use_D65); - } - - //! Convert pixel values from RGB to xyY color spaces. - CImg& RGBtoxyY(const bool use_D65=true) { - return RGBtoXYZ(use_D65).XYZtoxyY(); - } - - //! Convert pixel values from RGB to xyY color spaces \newinstance. - CImg get_RGBtoxyY(const bool use_D65=true) const { - return CImg(*this,false).RGBtoxyY(use_D65); - } - - //! Convert pixel values from xyY to RGB color spaces. - CImg& xyYtoRGB(const bool use_D65=true) { - return xyYtoXYZ().XYZtoRGB(use_D65); - } - - //! Convert pixel values from xyY to RGB color spaces \newinstance. - CImg get_xyYtoRGB(const bool use_D65=true) const { - return CImg(*this,false).xyYtoRGB(use_D65); - } - - //! Convert pixel values from RGB to CMYK color spaces. - CImg& RGBtoCMYK() { - return RGBtoCMY().CMYtoCMYK(); - } - - //! Convert pixel values from RGB to CMYK color spaces \newinstance. - CImg get_RGBtoCMYK() const { - return CImg(*this,false).RGBtoCMYK(); - } - - //! Convert pixel values from CMYK to RGB color spaces. - CImg& CMYKtoRGB() { - return CMYKtoCMY().CMYtoRGB(); - } - - //! Convert pixel values from CMYK to RGB color spaces \newinstance. - CImg get_CMYKtoRGB() const { - return CImg(*this,false).CMYKtoRGB(); - } - - //@} - //------------------------------------------ - // - //! \name Geometric / Spatial Manipulation - //@{ - //------------------------------------------ - - static float _cimg_lanczos(const float x) { - if (x<=-2 || x>=2) return 0; - const float a = (float)cimg::PI*x, b = 0.5f*a; - return (float)(x?std::sin(a)*std::sin(b)/(a*b):1); - } - - //! Resize image to new dimensions. - /** - \param size_x Number of columns (new size along the X-axis). - \param size_y Number of rows (new size along the Y-axis). - \param size_z Number of slices (new size along the Z-axis). - \param size_c Number of vector-channels (new size along the C-axis). - \param interpolation_type Method of interpolation: - - -1 = no interpolation: raw memory resizing. - - 0 = no interpolation: additional space is filled according to \p boundary_conditions. - - 1 = nearest-neighbor interpolation. - - 2 = moving average interpolation. - - 3 = linear interpolation. - - 4 = grid interpolation. - - 5 = cubic interpolation. - - 6 = lanczos interpolation. - \param boundary_conditions Type of boundary conditions used if necessary. - \param centering_x Set centering type (only if \p interpolation_type=0). - \param centering_y Set centering type (only if \p interpolation_type=0). - \param centering_z Set centering type (only if \p interpolation_type=0). - \param centering_c Set centering type (only if \p interpolation_type=0). - \note If pd[x,y,z,v]<0, it corresponds to a percentage of the original size (the default value is -100). - **/ - CImg& resize(const int size_x, const int size_y=-100, - const int size_z=-100, const int size_c=-100, - const int interpolation_type=1, const unsigned int boundary_conditions=0, - const float centering_x = 0, const float centering_y = 0, - const float centering_z = 0, const float centering_c = 0) { - if (!size_x || !size_y || !size_z || !size_c) return assign(); - const unsigned int - _sx = (unsigned int)(size_x<0?-size_x*width()/100:size_x), - _sy = (unsigned int)(size_y<0?-size_y*height()/100:size_y), - _sz = (unsigned int)(size_z<0?-size_z*depth()/100:size_z), - _sc = (unsigned int)(size_c<0?-size_c*spectrum()/100:size_c), - sx = _sx?_sx:1, sy = _sy?_sy:1, sz = _sz?_sz:1, sc = _sc?_sc:1; - if (sx==_width && sy==_height && sz==_depth && sc==_spectrum) return *this; - if (is_empty()) return assign(sx,sy,sz,sc,(T)0); - if (interpolation_type==-1 && sx*sy*sz*sc==size()) { - _width = sx; _height = sy; _depth = sz; _spectrum = sc; - return *this; - } - return get_resize(sx,sy,sz,sc,interpolation_type,boundary_conditions, - centering_x,centering_y,centering_z,centering_c).move_to(*this); - } - - //! Resize image to new dimensions \newinstance. - CImg get_resize(const int size_x, const int size_y = -100, - const int size_z = -100, const int size_c = -100, - const int interpolation_type=1, const unsigned int boundary_conditions=0, - const float centering_x = 0, const float centering_y = 0, - const float centering_z = 0, const float centering_c = 0) const { - if (centering_x<0 || centering_x>1 || centering_y<0 || centering_y>1 || - centering_z<0 || centering_z>1 || centering_c<0 || centering_c>1) - throw CImgArgumentException(_cimg_instance - "resize(): Specified centering arguments (%g,%g,%g,%g) are outside range [0,1].", - cimg_instance, - centering_x,centering_y,centering_z,centering_c); - - if (!size_x || !size_y || !size_z || !size_c) return CImg(); - const unsigned int - sx = std::max(1U,(unsigned int)(size_x>=0?size_x:-size_x*width()/100)), - sy = std::max(1U,(unsigned int)(size_y>=0?size_y:-size_y*height()/100)), - sz = std::max(1U,(unsigned int)(size_z>=0?size_z:-size_z*depth()/100)), - sc = std::max(1U,(unsigned int)(size_c>=0?size_c:-size_c*spectrum()/100)); - if (sx==_width && sy==_height && sz==_depth && sc==_spectrum) return +*this; - if (is_empty()) return CImg(sx,sy,sz,sc,(T)0); - CImg res; - switch (interpolation_type) { - - // Raw resizing. - // - case -1 : - std::memcpy(res.assign(sx,sy,sz,sc,(T)0)._data,_data,sizeof(T)*std::min(size(),(ulongT)sx*sy*sz*sc)); - break; - - // No interpolation. - // - case 0 : { - const int - xc = (int)(centering_x*((int)sx - width())), - yc = (int)(centering_y*((int)sy - height())), - zc = (int)(centering_z*((int)sz - depth())), - cc = (int)(centering_c*((int)sc - spectrum())); - - switch (boundary_conditions) { - case 3 : { // Mirror - res.assign(sx,sy,sz,sc); - const int w2 = 2*width(), h2 = 2*height(), d2 = 2*depth(), s2 = 2*spectrum(); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),1024*1024)) - cimg_forXYZC(res,x,y,z,c) { - const int - mx = cimg::mod(x - xc,w2), my = cimg::mod(y - yc,h2), - mz = cimg::mod(z - zc,d2), mc = cimg::mod(c - cc,s2); - res(x,y,z,c) = (*this)(mx sprite; - if (xc>0) { // X-backward - res.get_crop(xc,yc,zc,cc,xc,yc + height() - 1,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); - for (int x = xc - 1; x>=0; --x) res.draw_image(x,yc,zc,cc,sprite); - } - if (xc + width()<(int)sx) { // X-forward - res.get_crop(xc + width() - 1,yc,zc,cc,xc + width() - 1,yc + height() - 1, - zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); - for (int x = xc + width(); x<(int)sx; ++x) res.draw_image(x,yc,zc,cc,sprite); - } - if (yc>0) { // Y-backward - res.get_crop(0,yc,zc,cc,sx - 1,yc,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); - for (int y = yc - 1; y>=0; --y) res.draw_image(0,y,zc,cc,sprite); - } - if (yc + height()<(int)sy) { // Y-forward - res.get_crop(0,yc + height() - 1,zc,cc,sx - 1,yc + height() - 1, - zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); - for (int y = yc + height(); y<(int)sy; ++y) res.draw_image(0,y,zc,cc,sprite); - } - if (zc>0) { // Z-backward - res.get_crop(0,0,zc,cc,sx - 1,sy - 1,zc,cc + spectrum() - 1).move_to(sprite); - for (int z = zc - 1; z>=0; --z) res.draw_image(0,0,z,cc,sprite); - } - if (zc + depth()<(int)sz) { // Z-forward - res.get_crop(0,0,zc +depth() - 1,cc,sx - 1,sy - 1,zc + depth() - 1,cc + spectrum() - 1).move_to(sprite); - for (int z = zc + depth(); z<(int)sz; ++z) res.draw_image(0,0,z,cc,sprite); - } - if (cc>0) { // C-backward - res.get_crop(0,0,0,cc,sx - 1,sy - 1,sz - 1,cc).move_to(sprite); - for (int c = cc - 1; c>=0; --c) res.draw_image(0,0,0,c,sprite); - } - if (cc + spectrum()<(int)sc) { // C-forward - res.get_crop(0,0,0,cc + spectrum() - 1,sx - 1,sy - 1,sz - 1,cc + spectrum() - 1).move_to(sprite); - for (int c = cc + spectrum(); c<(int)sc; ++c) res.draw_image(0,0,0,c,sprite); - } - } break; - default : // Dirichlet - res.assign(sx,sy,sz,sc,(T)0).draw_image(xc,yc,zc,cc,*this); - } - break; - } break; - - // Nearest neighbor interpolation. - // - case 1 : { - res.assign(sx,sy,sz,sc); - CImg off_x(sx), off_y(sy + 1), off_z(sz + 1), off_c(sc + 1); - const ulongT - wh = (ulongT)_width*_height, - whd = (ulongT)_width*_height*_depth, - sxy = (ulongT)sx*sy, - sxyz = (ulongT)sx*sy*sz, - one = (ulongT)1; - if (sx==_width) off_x.fill(1); - else { - ulongT *poff_x = off_x._data, curr = 0; - cimg_forX(res,x) { - const ulongT old = curr; - curr = (x + one)*_width/sx; - *(poff_x++) = curr - old; - } - } - if (sy==_height) off_y.fill(_width); - else { - ulongT *poff_y = off_y._data, curr = 0; - cimg_forY(res,y) { - const ulongT old = curr; - curr = (y + one)*_height/sy; - *(poff_y++) = _width*(curr - old); - } - *poff_y = 0; - } - if (sz==_depth) off_z.fill(wh); - else { - ulongT *poff_z = off_z._data, curr = 0; - cimg_forZ(res,z) { - const ulongT old = curr; - curr = (z + one)*_depth/sz; - *(poff_z++) = wh*(curr - old); - } - *poff_z = 0; - } - if (sc==_spectrum) off_c.fill(whd); - else { - ulongT *poff_c = off_c._data, curr = 0; - cimg_forC(res,c) { - const ulongT old = curr; - curr = (c + one)*_spectrum/sc; - *(poff_c++) = whd*(curr - old); - } - *poff_c = 0; - } - - T *ptrd = res._data; - const T* ptrc = _data; - const ulongT *poff_c = off_c._data; - for (unsigned int c = 0; c_width) get_resize(sx,_height,_depth,_spectrum,1).move_to(res); - else { - CImg tmp(sx,_height,_depth,_spectrum,0); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(sx>=256 && _height*_depth*_spectrum>=256)) - cimg_forYZC(tmp,y,z,v) { - for (unsigned int a = _width*sx, b = _width, c = sx, s = 0, t = 0; a; ) { - const unsigned int d = std::min(b,c); - a-=d; b-=d; c-=d; - tmp(t,y,z,v)+=(Tfloat)(*this)(s,y,z,v)*d; - if (!b) { tmp(t++,y,z,v)/=_width; b = _width; } - if (!c) { ++s; c = sx; } - } - } - tmp.move_to(res); - } - instance_first = false; - } - - if (sy!=_height) { - if (sy>_height) get_resize(sx,sy,_depth,_spectrum,1).move_to(res); - else { - CImg tmp(sx,sy,_depth,_spectrum,0); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(sy>=256 && _width*_depth*_spectrum>=256)) - cimg_forXZC(tmp,x,z,v) { - for (unsigned int a = _height*sy, b = _height, c = sy, s = 0, t = 0; a; ) { - const unsigned int d = std::min(b,c); - a-=d; b-=d; c-=d; - if (instance_first) tmp(x,t,z,v)+=(Tfloat)(*this)(x,s,z,v)*d; - else tmp(x,t,z,v)+=(Tfloat)res(x,s,z,v)*d; - if (!b) { tmp(x,t++,z,v)/=_height; b = _height; } - if (!c) { ++s; c = sy; } - } - } - tmp.move_to(res); - } - instance_first = false; - } - - if (sz!=_depth) { - if (sz>_depth) get_resize(sx,sy,sz,_spectrum,1).move_to(res); - else { - CImg tmp(sx,sy,sz,_spectrum,0); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(sz>=256 && _width*_height*_spectrum>=256)) - cimg_forXYC(tmp,x,y,v) { - for (unsigned int a = _depth*sz, b = _depth, c = sz, s = 0, t = 0; a; ) { - const unsigned int d = std::min(b,c); - a-=d; b-=d; c-=d; - if (instance_first) tmp(x,y,t,v)+=(Tfloat)(*this)(x,y,s,v)*d; - else tmp(x,y,t,v)+=(Tfloat)res(x,y,s,v)*d; - if (!b) { tmp(x,y,t++,v)/=_depth; b = _depth; } - if (!c) { ++s; c = sz; } - } - } - tmp.move_to(res); - } - instance_first = false; - } - - if (sc!=_spectrum) { - if (sc>_spectrum) get_resize(sx,sy,sz,sc,1).move_to(res); - else { - CImg tmp(sx,sy,sz,sc,0); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(sc>=256 && _width*_height*_depth>=256)) - cimg_forXYZ(tmp,x,y,z) { - for (unsigned int a = _spectrum*sc, b = _spectrum, c = sc, s = 0, t = 0; a; ) { - const unsigned int d = std::min(b,c); - a-=d; b-=d; c-=d; - if (instance_first) tmp(x,y,z,t)+=(Tfloat)(*this)(x,y,z,s)*d; - else tmp(x,y,z,t)+=(Tfloat)res(x,y,z,s)*d; - if (!b) { tmp(x,y,z,t++)/=_spectrum; b = _spectrum; } - if (!c) { ++s; c = sc; } - } - } - tmp.move_to(res); - } - instance_first = false; - } - - } break; - - // Linear interpolation. - // - case 3 : { - CImg off(cimg::max(sx,sy,sz,sc)); - CImg foff(off._width); - CImg resx, resy, resz, resc; - double curr, old; - - if (sx!=_width) { - if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx); - else if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx); - else { - const double fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.)/(sx - 1):0): - (double)_width/sx; - resx.assign(sx,_height,_depth,_spectrum); - curr = old = 0; - { - unsigned int *poff = off._data; - double *pfoff = foff._data; - cimg_forX(resx,x) { - *(pfoff++) = curr - (unsigned int)curr; - old = curr; - curr = std::min(width() - 1.,curr + fx); - *(poff++) = (unsigned int)curr - (unsigned int)old; - } - } - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(resx._width>=256 && resx._height*resx._depth*resx._spectrum>=256)) - cimg_forYZC(resx,y,z,c) { - const T *ptrs = data(0,y,z,c), *const ptrsmax = ptrs + _width - 1; - T *ptrd = resx.data(0,y,z,c); - const unsigned int *poff = off._data; - const double *pfoff = foff._data; - cimg_forX(resx,x) { - const double alpha = *(pfoff++); - const T val1 = *ptrs, val2 = ptrssy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy); - else { - const double fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.)/(sy - 1):0): - (double)_height/sy; - resy.assign(sx,sy,_depth,_spectrum); - curr = old = 0; - { - unsigned int *poff = off._data; - double *pfoff = foff._data; - cimg_forY(resy,y) { - *(pfoff++) = curr - (unsigned int)curr; - old = curr; - curr = std::min(height() - 1.,curr + fy); - *(poff++) = sx*((unsigned int)curr - (unsigned int)old); - } - } - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(resy._height>=256 && resy._width*resy._depth*resy._spectrum>=256)) - cimg_forXZC(resy,x,z,c) { - const T *ptrs = resx.data(x,0,z,c), *const ptrsmax = ptrs + (_height - 1)*sx; - T *ptrd = resy.data(x,0,z,c); - const unsigned int *poff = off._data; - const double *pfoff = foff._data; - cimg_forY(resy,y) { - const double alpha = *(pfoff++); - const T val1 = *ptrs, val2 = ptrssz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz); - else { - const double fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.)/(sz - 1):0): - (double)_depth/sz; - const unsigned int sxy = sx*sy; - resz.assign(sx,sy,sz,_spectrum); - curr = old = 0; - { - unsigned int *poff = off._data; - double *pfoff = foff._data; - cimg_forZ(resz,z) { - *(pfoff++) = curr - (unsigned int)curr; - old = curr; - curr = std::min(depth() - 1.,curr + fz); - *(poff++) = sxy*((unsigned int)curr - (unsigned int)old); - } - } - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(resz._depth>=256 && resz._width*resz._height*resz._spectrum>=256)) - cimg_forXYC(resz,x,y,c) { - const T *ptrs = resy.data(x,y,0,c), *const ptrsmax = ptrs + (_depth - 1)*sxy; - T *ptrd = resz.data(x,y,0,c); - const unsigned int *poff = off._data; - const double *pfoff = foff._data; - cimg_forZ(resz,z) { - const double alpha = *(pfoff++); - const T val1 = *ptrs, val2 = ptrssc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc); - else { - const double fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.)/(sc - 1):0): - (double)_spectrum/sc; - const unsigned int sxyz = sx*sy*sz; - resc.assign(sx,sy,sz,sc); - curr = old = 0; - { - unsigned int *poff = off._data; - double *pfoff = foff._data; - cimg_forC(resc,c) { - *(pfoff++) = curr - (unsigned int)curr; - old = curr; - curr = std::min(spectrum() - 1.,curr + fc); - *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old); - } - } - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(resc._spectrum>=256 && resc._width*resc._height*resc._depth>=256)) - cimg_forXYZ(resc,x,y,z) { - const T *ptrs = resz.data(x,y,z,0), *const ptrsmax = ptrs + (_spectrum - 1)*sxyz; - T *ptrd = resc.data(x,y,z,0); - const unsigned int *poff = off._data; - const double *pfoff = foff._data; - cimg_forC(resc,c) { - const double alpha = *(pfoff++); - const T val1 = *ptrs, val2 = ptrs resx, resy, resz, resc; - if (sx!=_width) { - if (sx<_width) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx); - else { - resx.assign(sx,_height,_depth,_spectrum,(T)0); - const int dx = (int)(2*sx), dy = 2*width(); - int err = (int)(dy + centering_x*(sx*dy/width() - dy)), xs = 0; - cimg_forX(resx,x) if ((err-=dy)<=0) { - cimg_forYZC(resx,y,z,c) resx(x,y,z,c) = (*this)(xs,y,z,c); - ++xs; - err+=dx; - } - } - } else resx.assign(*this,true); - - if (sy!=_height) { - if (sy<_height) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy); - else { - resy.assign(sx,sy,_depth,_spectrum,(T)0); - const int dx = (int)(2*sy), dy = 2*height(); - int err = (int)(dy + centering_y*(sy*dy/height() - dy)), ys = 0; - cimg_forY(resy,y) if ((err-=dy)<=0) { - cimg_forXZC(resy,x,z,c) resy(x,y,z,c) = resx(x,ys,z,c); - ++ys; - err+=dx; - } - } - resx.assign(); - } else resy.assign(resx,true); - - if (sz!=_depth) { - if (sz<_depth) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz); - else { - resz.assign(sx,sy,sz,_spectrum,(T)0); - const int dx = (int)(2*sz), dy = 2*depth(); - int err = (int)(dy + centering_z*(sz*dy/depth() - dy)), zs = 0; - cimg_forZ(resz,z) if ((err-=dy)<=0) { - cimg_forXYC(resz,x,y,c) resz(x,y,z,c) = resy(x,y,zs,c); - ++zs; - err+=dx; - } - } - resy.assign(); - } else resz.assign(resy,true); - - if (sc!=_spectrum) { - if (sc<_spectrum) resz.get_resize(sx,sy,sz,sc,1).move_to(resc); - else { - resc.assign(sx,sy,sz,sc,(T)0); - const int dx = (int)(2*sc), dy = 2*spectrum(); - int err = (int)(dy + centering_c*(sc*dy/spectrum() - dy)), cs = 0; - cimg_forC(resc,c) if ((err-=dy)<=0) { - cimg_forXYZ(resc,x,y,z) resc(x,y,z,c) = resz(x,y,z,cs); - ++cs; - err+=dx; - } - } - resz.assign(); - } else resc.assign(resz,true); - - return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc; - } break; - - // Cubic interpolation. - // - case 5 : { - const Tfloat vmin = (Tfloat)cimg::type::min(), vmax = (Tfloat)cimg::type::max(); - CImg off(cimg::max(sx,sy,sz,sc)); - CImg foff(off._width); - CImg resx, resy, resz, resc; - double curr, old; - - if (sx!=_width) { - if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx); - else { - if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx); - else { - const double fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.)/(sx - 1):0): - (double)_width/sx; - resx.assign(sx,_height,_depth,_spectrum); - curr = old = 0; - { - unsigned int *poff = off._data; - double *pfoff = foff._data; - cimg_forX(resx,x) { - *(pfoff++) = curr - (unsigned int)curr; - old = curr; - curr = std::min(width() - 1.,curr + fx); - *(poff++) = (unsigned int)curr - (unsigned int)old; - } - } - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(resx._width>=256 && resx._height*resx._depth*resx._spectrum>=256)) - cimg_forYZC(resx,y,z,c) { - const T *const ptrs0 = data(0,y,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_width - 2); - T *ptrd = resx.data(0,y,z,c); - const unsigned int *poff = off._data; - const double *pfoff = foff._data; - cimg_forX(resx,x) { - const double - t = *(pfoff++), - val1 = (double)*ptrs, - val0 = ptrs>ptrs0?(double)*(ptrs - 1):val1, - val2 = ptrs<=ptrsmax?(double)*(ptrs + 1):val1, - val3 = ptrsvmax?vmax:val); - ptrs+=*(poff++); - } - } - } - } - } else resx.assign(*this,true); - - if (sy!=_height) { - if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy); - else { - if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy); - else { - const double fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.)/(sy - 1):0): - (double)_height/sy; - resy.assign(sx,sy,_depth,_spectrum); - curr = old = 0; - { - unsigned int *poff = off._data; - double *pfoff = foff._data; - cimg_forY(resy,y) { - *(pfoff++) = curr - (unsigned int)curr; - old = curr; - curr = std::min(height() - 1.,curr + fy); - *(poff++) = sx*((unsigned int)curr - (unsigned int)old); - } - } - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(resy._height>=256 && resy._width*resy._depth*resy._spectrum>=256)) - cimg_forXZC(resy,x,z,c) { - const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_height - 2)*sx; - T *ptrd = resy.data(x,0,z,c); - const unsigned int *poff = off._data; - const double *pfoff = foff._data; - cimg_forY(resy,y) { - const double - t = *(pfoff++), - val1 = (double)*ptrs, - val0 = ptrs>ptrs0?(double)*(ptrs - sx):val1, - val2 = ptrs<=ptrsmax?(double)*(ptrs + sx):val1, - val3 = ptrsvmax?vmax:val); - ptrd+=sx; - ptrs+=*(poff++); - } - } - } - } - resx.assign(); - } else resy.assign(resx,true); - - if (sz!=_depth) { - if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz); - else { - if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz); - else { - const double fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.)/(sz - 1):0): - (double)_depth/sz; - const unsigned int sxy = sx*sy; - resz.assign(sx,sy,sz,_spectrum); - curr = old = 0; - { - unsigned int *poff = off._data; - double *pfoff = foff._data; - cimg_forZ(resz,z) { - *(pfoff++) = curr - (unsigned int)curr; - old = curr; - curr = std::min(depth() - 1.,curr + fz); - *(poff++) = sxy*((unsigned int)curr - (unsigned int)old); - } - } - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(resz._depth>=256 && resz._width*resz._height*resz._spectrum>=256)) - cimg_forXYC(resz,x,y,c) { - const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmax = ptrs + (_depth - 2)*sxy; - T *ptrd = resz.data(x,y,0,c); - const unsigned int *poff = off._data; - const double *pfoff = foff._data; - cimg_forZ(resz,z) { - const double - t = *(pfoff++), - val1 = (double)*ptrs, - val0 = ptrs>ptrs0?(double)*(ptrs - sxy):val1, - val2 = ptrs<=ptrsmax?(double)*(ptrs + sxy):val1, - val3 = ptrsvmax?vmax:val); - ptrd+=sxy; - ptrs+=*(poff++); - } - } - } - } - resy.assign(); - } else resz.assign(resy,true); - - if (sc!=_spectrum) { - if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc); - else { - if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc); - else { - const double fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.)/(sc - 1):0): - (double)_spectrum/sc; - const unsigned int sxyz = sx*sy*sz; - resc.assign(sx,sy,sz,sc); - curr = old = 0; - { - unsigned int *poff = off._data; - double *pfoff = foff._data; - cimg_forC(resc,c) { - *(pfoff++) = curr - (unsigned int)curr; - old = curr; - curr = std::min(spectrum() - 1.,curr + fc); - *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old); - } - } - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(resc._spectrum>=256 && resc._width*resc._height*resc._depth>=256)) - cimg_forXYZ(resc,x,y,z) { - const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmax = ptrs + (_spectrum - 2)*sxyz; - T *ptrd = resc.data(x,y,z,0); - const unsigned int *poff = off._data; - const double *pfoff = foff._data; - cimg_forC(resc,c) { - const double - t = *(pfoff++), - val1 = (double)*ptrs, - val0 = ptrs>ptrs0?(double)*(ptrs - sxyz):val1, - val2 = ptrs<=ptrsmax?(double)*(ptrs + sxyz):val1, - val3 = ptrsvmax?vmax:val); - ptrd+=sxyz; - ptrs+=*(poff++); - } - } - } - } - resz.assign(); - } else resc.assign(resz,true); - - return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc; - } break; - - // Lanczos interpolation. - // - case 6 : { - const double vmin = (double)cimg::type::min(), vmax = (double)cimg::type::max(); - CImg off(cimg::max(sx,sy,sz,sc)); - CImg foff(off._width); - CImg resx, resy, resz, resc; - double curr, old; - - if (sx!=_width) { - if (_width==1) get_resize(sx,_height,_depth,_spectrum,1).move_to(resx); - else { - if (_width>sx) get_resize(sx,_height,_depth,_spectrum,2).move_to(resx); - else { - const double fx = (!boundary_conditions && sx>_width)?(sx>1?(_width - 1.)/(sx - 1):0): - (double)_width/sx; - resx.assign(sx,_height,_depth,_spectrum); - curr = old = 0; - { - unsigned int *poff = off._data; - double *pfoff = foff._data; - cimg_forX(resx,x) { - *(pfoff++) = curr - (unsigned int)curr; - old = curr; - curr = std::min(width() - 1.,curr + fx); - *(poff++) = (unsigned int)curr - (unsigned int)old; - } - } - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(resx._width>=256 && resx._height*resx._depth*resx._spectrum>=256)) - cimg_forYZC(resx,y,z,c) { - const T *const ptrs0 = data(0,y,z,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + 1, - *const ptrsmax = ptrs0 + (_width - 2); - T *ptrd = resx.data(0,y,z,c); - const unsigned int *poff = off._data; - const double *pfoff = foff._data; - cimg_forX(resx,x) { - const double - t = *(pfoff++), - w0 = _cimg_lanczos(t + 2), - w1 = _cimg_lanczos(t + 1), - w2 = _cimg_lanczos(t), - w3 = _cimg_lanczos(t - 1), - w4 = _cimg_lanczos(t - 2), - val2 = (double)*ptrs, - val1 = ptrs>=ptrsmin?(double)*(ptrs - 1):val2, - val0 = ptrs>ptrsmin?(double)*(ptrs - 2):val1, - val3 = ptrs<=ptrsmax?(double)*(ptrs + 1):val2, - val4 = ptrsvmax?vmax:val); - ptrs+=*(poff++); - } - } - } - } - } else resx.assign(*this,true); - - if (sy!=_height) { - if (_height==1) resx.get_resize(sx,sy,_depth,_spectrum,1).move_to(resy); - else { - if (_height>sy) resx.get_resize(sx,sy,_depth,_spectrum,2).move_to(resy); - else { - const double fy = (!boundary_conditions && sy>_height)?(sy>1?(_height - 1.)/(sy - 1):0): - (double)_height/sy; - resy.assign(sx,sy,_depth,_spectrum); - curr = old = 0; - { - unsigned int *poff = off._data; - double *pfoff = foff._data; - cimg_forY(resy,y) { - *(pfoff++) = curr - (unsigned int)curr; - old = curr; - curr = std::min(height() - 1.,curr + fy); - *(poff++) = sx*((unsigned int)curr - (unsigned int)old); - } - } - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(resy._height>=256 && resy._width*resy._depth*resy._spectrum>=256)) - cimg_forXZC(resy,x,z,c) { - const T *const ptrs0 = resx.data(x,0,z,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sx, - *const ptrsmax = ptrs0 + (_height - 2)*sx; - T *ptrd = resy.data(x,0,z,c); - const unsigned int *poff = off._data; - const double *pfoff = foff._data; - cimg_forY(resy,y) { - const double - t = *(pfoff++), - w0 = _cimg_lanczos(t + 2), - w1 = _cimg_lanczos(t + 1), - w2 = _cimg_lanczos(t), - w3 = _cimg_lanczos(t - 1), - w4 = _cimg_lanczos(t - 2), - val2 = (double)*ptrs, - val1 = ptrs>=ptrsmin?(double)*(ptrs - sx):val2, - val0 = ptrs>ptrsmin?(double)*(ptrs - 2*sx):val1, - val3 = ptrs<=ptrsmax?(double)*(ptrs + sx):val2, - val4 = ptrsvmax?vmax:val); - ptrd+=sx; - ptrs+=*(poff++); - } - } - } - } - resx.assign(); - } else resy.assign(resx,true); - - if (sz!=_depth) { - if (_depth==1) resy.get_resize(sx,sy,sz,_spectrum,1).move_to(resz); - else { - if (_depth>sz) resy.get_resize(sx,sy,sz,_spectrum,2).move_to(resz); - else { - const double fz = (!boundary_conditions && sz>_depth)?(sz>1?(_depth - 1.)/(sz - 1):0): - (double)_depth/sz; - const unsigned int sxy = sx*sy; - resz.assign(sx,sy,sz,_spectrum); - curr = old = 0; - { - unsigned int *poff = off._data; - double *pfoff = foff._data; - cimg_forZ(resz,z) { - *(pfoff++) = curr - (unsigned int)curr; - old = curr; - curr = std::min(depth() - 1.,curr + fz); - *(poff++) = sxy*((unsigned int)curr - (unsigned int)old); - } - } - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(resz._depth>=256 && resz._width*resz._height*resz._spectrum>=256)) - cimg_forXYC(resz,x,y,c) { - const T *const ptrs0 = resy.data(x,y,0,c), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sxy, - *const ptrsmax = ptrs0 + (_depth - 2)*sxy; - T *ptrd = resz.data(x,y,0,c); - const unsigned int *poff = off._data; - const double *pfoff = foff._data; - cimg_forZ(resz,z) { - const double - t = *(pfoff++), - w0 = _cimg_lanczos(t + 2), - w1 = _cimg_lanczos(t + 1), - w2 = _cimg_lanczos(t), - w3 = _cimg_lanczos(t - 1), - w4 = _cimg_lanczos(t - 2), - val2 = (double)*ptrs, - val1 = ptrs>=ptrsmin?(double)*(ptrs - sxy):val2, - val0 = ptrs>ptrsmin?(double)*(ptrs - 2*sxy):val1, - val3 = ptrs<=ptrsmax?(double)*(ptrs + sxy):val2, - val4 = ptrsvmax?vmax:val); - ptrd+=sxy; - ptrs+=*(poff++); - } - } - } - } - resy.assign(); - } else resz.assign(resy,true); - - if (sc!=_spectrum) { - if (_spectrum==1) resz.get_resize(sx,sy,sz,sc,1).move_to(resc); - else { - if (_spectrum>sc) resz.get_resize(sx,sy,sz,sc,2).move_to(resc); - else { - const double fc = (!boundary_conditions && sc>_spectrum)?(sc>1?(_spectrum - 1.)/(sc - 1):0): - (double)_spectrum/sc; - const unsigned int sxyz = sx*sy*sz; - resc.assign(sx,sy,sz,sc); - curr = old = 0; - { - unsigned int *poff = off._data; - double *pfoff = foff._data; - cimg_forC(resc,c) { - *(pfoff++) = curr - (unsigned int)curr; - old = curr; - curr = std::min(spectrum() - 1.,curr + fc); - *(poff++) = sxyz*((unsigned int)curr - (unsigned int)old); - } - } - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(resc._spectrum>=256 && resc._width*resc._height*resc._depth>=256)) - cimg_forXYZ(resc,x,y,z) { - const T *const ptrs0 = resz.data(x,y,z,0), *ptrs = ptrs0, *const ptrsmin = ptrs0 + sxyz, - *const ptrsmax = ptrs + (_spectrum - 2)*sxyz; - T *ptrd = resc.data(x,y,z,0); - const unsigned int *poff = off._data; - const double *pfoff = foff._data; - cimg_forC(resc,c) { - const double - t = *(pfoff++), - w0 = _cimg_lanczos(t + 2), - w1 = _cimg_lanczos(t + 1), - w2 = _cimg_lanczos(t), - w3 = _cimg_lanczos(t - 1), - w4 = _cimg_lanczos(t - 2), - val2 = (double)*ptrs, - val1 = ptrs>=ptrsmin?(double)*(ptrs - sxyz):val2, - val0 = ptrs>ptrsmin?(double)*(ptrs - 2*sxyz):val1, - val3 = ptrs<=ptrsmax?(double)*(ptrs + sxyz):val2, - val4 = ptrsvmax?vmax:val); - ptrd+=sxyz; - ptrs+=*(poff++); - } - } - } - } - resz.assign(); - } else resc.assign(resz,true); - - return resc._is_shared?(resz._is_shared?(resy._is_shared?(resx._is_shared?(+(*this)):resx):resy):resz):resc; - } break; - - // Unknown interpolation. - // - default : - throw CImgArgumentException(_cimg_instance - "resize(): Invalid specified interpolation %d " - "(should be { -1=raw | 0=none | 1=nearest | 2=average | 3=linear | 4=grid | " - "5=cubic | 6=lanczos }).", - cimg_instance, - interpolation_type); - } - return res; - } - - //! Resize image to dimensions of another image. - /** - \param src Reference image used for dimensions. - \param interpolation_type Interpolation method. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - \param centering_x Set centering type (only if \p interpolation_type=0). - \param centering_y Set centering type (only if \p interpolation_type=0). - \param centering_z Set centering type (only if \p interpolation_type=0). - \param centering_c Set centering type (only if \p interpolation_type=0). - **/ - template - CImg& resize(const CImg& src, - const int interpolation_type=1, const unsigned int boundary_conditions=0, - const float centering_x = 0, const float centering_y = 0, - const float centering_z = 0, const float centering_c = 0) { - return resize(src._width,src._height,src._depth,src._spectrum,interpolation_type,boundary_conditions, - centering_x,centering_y,centering_z,centering_c); - } - - //! Resize image to dimensions of another image \newinstance. - template - CImg get_resize(const CImg& src, - const int interpolation_type=1, const unsigned int boundary_conditions=0, - const float centering_x = 0, const float centering_y = 0, - const float centering_z = 0, const float centering_c = 0) const { - return get_resize(src._width,src._height,src._depth,src._spectrum,interpolation_type,boundary_conditions, - centering_x,centering_y,centering_z,centering_c); - } - - //! Resize image to dimensions of a display window. - /** - \param disp Reference display window used for dimensions. - \param interpolation_type Interpolation method. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - \param centering_x Set centering type (only if \p interpolation_type=0). - \param centering_y Set centering type (only if \p interpolation_type=0). - \param centering_z Set centering type (only if \p interpolation_type=0). - \param centering_c Set centering type (only if \p interpolation_type=0). - **/ - CImg& resize(const CImgDisplay& disp, - const int interpolation_type=1, const unsigned int boundary_conditions=0, - const float centering_x = 0, const float centering_y = 0, - const float centering_z = 0, const float centering_c = 0) { - return resize(disp.width(),disp.height(),_depth,_spectrum,interpolation_type,boundary_conditions, - centering_x,centering_y,centering_z,centering_c); - } - - //! Resize image to dimensions of a display window \newinstance. - CImg get_resize(const CImgDisplay& disp, - const int interpolation_type=1, const unsigned int boundary_conditions=0, - const float centering_x = 0, const float centering_y = 0, - const float centering_z = 0, const float centering_c = 0) const { - return get_resize(disp.width(),disp.height(),_depth,_spectrum,interpolation_type,boundary_conditions, - centering_x,centering_y,centering_z,centering_c); - } - - //! Resize image to half-size along XY axes, using an optimized filter. - CImg& resize_halfXY() { - return get_resize_halfXY().move_to(*this); - } - - //! Resize image to half-size along XY axes, using an optimized filter \newinstance. - CImg get_resize_halfXY() const { - if (is_empty()) return *this; - static const Tfloat kernel[9] = { 0.07842776544f, 0.1231940459f, 0.07842776544f, - 0.1231940459f, 0.1935127547f, 0.1231940459f, - 0.07842776544f, 0.1231940459f, 0.07842776544f }; - CImg I(9), res(_width/2,_height/2,_depth,_spectrum); - T *ptrd = res._data; - cimg_forZC(*this,z,c) cimg_for3x3(*this,x,y,z,c,I,T) - if (x%2 && y%2) *(ptrd++) = (T) - (I[0]*kernel[0] + I[1]*kernel[1] + I[2]*kernel[2] + - I[3]*kernel[3] + I[4]*kernel[4] + I[5]*kernel[5] + - I[6]*kernel[6] + I[7]*kernel[7] + I[8]*kernel[8]); - return res; - } - - //! Resize image to double-size, using the Scale2X algorithm. - /** - \note Use anisotropic upscaling algorithm - described here. - **/ - CImg& resize_doubleXY() { - return get_resize_doubleXY().move_to(*this); - } - - //! Resize image to double-size, using the Scale2X algorithm \newinstance. - CImg get_resize_doubleXY() const { -#define _cimg_gs2x_for3(bound,i) \ - for (int i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound) - 1:1; \ - _n1##i<(int)(bound) || i==--_n1##i; \ - _p1##i = i++, ++_n1##i, ptrd1+=(res)._width, ptrd2+=(res)._width) - -#define _cimg_gs2x_for3x3(img,x,y,z,c,I,T) \ - _cimg_gs2x_for3((img)._height,y) for (int x = 0, \ - _p1##x = 0, \ - _n1##x = (int)( \ - (I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \ - (I[3] = I[4] = (T)(img)(0,y,z,c)), \ - (I[7] = (T)(img)(0,_n1##y,z,c)), \ - 1>=(img)._width?(img).width() - 1:1); \ - (_n1##x<(img).width() && ( \ - (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[5] = (T)(img)(_n1##x,y,z,c)), \ - (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ - x==--_n1##x; \ - I[1] = I[2], \ - I[3] = I[4], I[4] = I[5], \ - I[7] = I[8], \ - _p1##x = x++, ++_n1##x) - - if (is_empty()) return *this; - CImg res(_width<<1,_height<<1,_depth,_spectrum); - CImg_3x3(I,T); - cimg_forZC(*this,z,c) { - T - *ptrd1 = res.data(0,0,z,c), - *ptrd2 = ptrd1 + res._width; - _cimg_gs2x_for3x3(*this,x,y,z,c,I,T) { - if (Icp!=Icn && Ipc!=Inc) { - *(ptrd1++) = Ipc==Icp?Ipc:Icc; - *(ptrd1++) = Icp==Inc?Inc:Icc; - *(ptrd2++) = Ipc==Icn?Ipc:Icc; - *(ptrd2++) = Icn==Inc?Inc:Icc; - } else { *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; } - } - } - return res; - } - - //! Resize image to triple-size, using the Scale3X algorithm. - /** - \note Use anisotropic upscaling algorithm - described here. - **/ - CImg& resize_tripleXY() { - return get_resize_tripleXY().move_to(*this); - } - - //! Resize image to triple-size, using the Scale3X algorithm \newinstance. - CImg get_resize_tripleXY() const { -#define _cimg_gs3x_for3(bound,i) \ - for (int i = 0, _p1##i = 0, \ - _n1##i = 1>=(bound)?(int)(bound) - 1:1; \ - _n1##i<(int)(bound) || i==--_n1##i; \ - _p1##i = i++, ++_n1##i, ptrd1+=2*(res)._width, ptrd2+=2*(res)._width, ptrd3+=2*(res)._width) - -#define _cimg_gs3x_for3x3(img,x,y,z,c,I,T) \ - _cimg_gs3x_for3((img)._height,y) for (int x = 0, \ - _p1##x = 0, \ - _n1##x = (int)( \ - (I[0] = I[1] = (T)(img)(_p1##x,_p1##y,z,c)), \ - (I[3] = I[4] = (T)(img)(0,y,z,c)), \ - (I[6] = I[7] = (T)(img)(0,_n1##y,z,c)), \ - 1>=(img)._width?(img).width() - 1:1); \ - (_n1##x<(img).width() && ( \ - (I[2] = (T)(img)(_n1##x,_p1##y,z,c)), \ - (I[5] = (T)(img)(_n1##x,y,z,c)), \ - (I[8] = (T)(img)(_n1##x,_n1##y,z,c)),1)) || \ - x==--_n1##x; \ - I[0] = I[1], I[1] = I[2], \ - I[3] = I[4], I[4] = I[5], \ - I[6] = I[7], I[7] = I[8], \ - _p1##x = x++, ++_n1##x) - - if (is_empty()) return *this; - CImg res(3*_width,3*_height,_depth,_spectrum); - CImg_3x3(I,T); - cimg_forZC(*this,z,c) { - T - *ptrd1 = res.data(0,0,z,c), - *ptrd2 = ptrd1 + res._width, - *ptrd3 = ptrd2 + res._width; - _cimg_gs3x_for3x3(*this,x,y,z,c,I,T) { - if (Icp != Icn && Ipc != Inc) { - *(ptrd1++) = Ipc==Icp?Ipc:Icc; - *(ptrd1++) = (Ipc==Icp && Icc!=Inp) || (Icp==Inc && Icc!=Ipp)?Icp:Icc; - *(ptrd1++) = Icp==Inc?Inc:Icc; - *(ptrd2++) = (Ipc==Icp && Icc!=Ipn) || (Ipc==Icn && Icc!=Ipp)?Ipc:Icc; - *(ptrd2++) = Icc; - *(ptrd2++) = (Icp==Inc && Icc!=Inn) || (Icn==Inc && Icc!=Inp)?Inc:Icc; - *(ptrd3++) = Ipc==Icn?Ipc:Icc; - *(ptrd3++) = (Ipc==Icn && Icc!=Inn) || (Icn==Inc && Icc!=Ipn)?Icn:Icc; - *(ptrd3++) = Icn==Inc?Inc:Icc; - } else { - *(ptrd1++) = Icc; *(ptrd1++) = Icc; *(ptrd1++) = Icc; - *(ptrd2++) = Icc; *(ptrd2++) = Icc; *(ptrd2++) = Icc; - *(ptrd3++) = Icc; *(ptrd3++) = Icc; *(ptrd3++) = Icc; - } - } - } - return res; - } - - //! Mirror image content along specified axis. - /** - \param axis Mirror axis - **/ - CImg& mirror(const char axis) { - if (is_empty()) return *this; - T *pf, *pb, *buf = 0; - switch (cimg::lowercase(axis)) { - case 'x' : { - pf = _data; pb = data(_width - 1); - const unsigned int width2 = _width/2; - for (unsigned int yzv = 0; yzv<_height*_depth*_spectrum; ++yzv) { - for (unsigned int x = 0; x get_mirror(const char axis) const { - return (+*this).mirror(axis); - } - - //! Mirror image content along specified axes. - /** - \param axes Mirror axes, as a C-string. - \note \c axes may contains multiple characters, e.g. \c "xyz" - **/ - CImg& mirror(const char *const axes) { - for (const char *s = axes; *s; ++s) mirror(*s); - return *this; - } - - //! Mirror image content along specified axes \newinstance. - CImg get_mirror(const char *const axes) const { - return (+*this).mirror(axes); - } - - //! Shift image content. - /** - \param delta_x Amount of displacement along the X-axis. - \param delta_y Amount of displacement along the Y-axis. - \param delta_z Amount of displacement along the Z-axis. - \param delta_c Amount of displacement along the C-axis. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - **/ - CImg& shift(const int delta_x, const int delta_y=0, const int delta_z=0, const int delta_c=0, - const unsigned int boundary_conditions=0) { - if (is_empty()) return *this; - if (boundary_conditions==3) - return get_crop(-delta_x,-delta_y,-delta_z,-delta_c, - width() - delta_x - 1, - height() - delta_y - 1, - depth() - delta_z - 1, - spectrum() - delta_c - 1,3).move_to(*this); - if (delta_x) // Shift along X-axis - switch (boundary_conditions) { - case 2 : { // Periodic - const int ml = cimg::mod(-delta_x,width()), ndelta_x = (ml<=width()/2)?ml:(ml-width()); - if (!ndelta_x) return *this; - CImg buf(cimg::abs(ndelta_x)); - if (ndelta_x>0) cimg_forYZC(*this,y,z,c) { - std::memcpy(buf,data(0,y,z,c),ndelta_x*sizeof(T)); - std::memmove(data(0,y,z,c),data(ndelta_x,y,z,c),(_width-ndelta_x)*sizeof(T)); - std::memcpy(data(_width-ndelta_x,y,z,c),buf,ndelta_x*sizeof(T)); - } else cimg_forYZC(*this,y,z,c) { - std::memcpy(buf,data(_width + ndelta_x,y,z,c),-ndelta_x*sizeof(T)); - std::memmove(data(-ndelta_x,y,z,c),data(0,y,z,c),(_width + ndelta_x)*sizeof(T)); - std::memcpy(data(0,y,z,c),buf,-ndelta_x*sizeof(T)); - } - } break; - case 1 : // Neumann - if (delta_x<0) { - const int ndelta_x = (-delta_x>=width())?width() - 1:-delta_x; - if (!ndelta_x) return *this; - cimg_forYZC(*this,y,z,c) { - std::memmove(data(0,y,z,c),data(ndelta_x,y,z,c),(_width-ndelta_x)*sizeof(T)); - T *ptrd = data(_width - 1,y,z,c); - const T val = *ptrd; - for (int l = 0; l=width())?width() - 1:delta_x; - if (!ndelta_x) return *this; - cimg_forYZC(*this,y,z,c) { - std::memmove(data(ndelta_x,y,z,c),data(0,y,z,c),(_width-ndelta_x)*sizeof(T)); - T *ptrd = data(0,y,z,c); - const T val = *ptrd; - for (int l = 0; l=width()) return fill((T)0); - if (delta_x<0) cimg_forYZC(*this,y,z,c) { - std::memmove(data(0,y,z,c),data(-delta_x,y,z,c),(_width + delta_x)*sizeof(T)); - std::memset(data(_width + delta_x,y,z,c),0,-delta_x*sizeof(T)); - } else cimg_forYZC(*this,y,z,c) { - std::memmove(data(delta_x,y,z,c),data(0,y,z,c),(_width-delta_x)*sizeof(T)); - std::memset(data(0,y,z,c),0,delta_x*sizeof(T)); - } - } - - if (delta_y) // Shift along Y-axis - switch (boundary_conditions) { - case 2 : { // Periodic - const int ml = cimg::mod(-delta_y,height()), ndelta_y = (ml<=height()/2)?ml:(ml-height()); - if (!ndelta_y) return *this; - CImg buf(width(),cimg::abs(ndelta_y)); - if (ndelta_y>0) cimg_forZC(*this,z,c) { - std::memcpy(buf,data(0,0,z,c),_width*ndelta_y*sizeof(T)); - std::memmove(data(0,0,z,c),data(0,ndelta_y,z,c),_width*(_height-ndelta_y)*sizeof(T)); - std::memcpy(data(0,_height-ndelta_y,z,c),buf,_width*ndelta_y*sizeof(T)); - } else cimg_forZC(*this,z,c) { - std::memcpy(buf,data(0,_height + ndelta_y,z,c),-ndelta_y*_width*sizeof(T)); - std::memmove(data(0,-ndelta_y,z,c),data(0,0,z,c),_width*(_height + ndelta_y)*sizeof(T)); - std::memcpy(data(0,0,z,c),buf,-ndelta_y*_width*sizeof(T)); - } - } break; - case 1 : // Neumann - if (delta_y<0) { - const int ndelta_y = (-delta_y>=height())?height() - 1:-delta_y; - if (!ndelta_y) return *this; - cimg_forZC(*this,z,c) { - std::memmove(data(0,0,z,c),data(0,ndelta_y,z,c),_width*(_height-ndelta_y)*sizeof(T)); - T *ptrd = data(0,_height-ndelta_y,z,c), *ptrs = data(0,_height - 1,z,c); - for (int l = 0; l=height())?height() - 1:delta_y; - if (!ndelta_y) return *this; - cimg_forZC(*this,z,c) { - std::memmove(data(0,ndelta_y,z,c),data(0,0,z,c),_width*(_height-ndelta_y)*sizeof(T)); - T *ptrd = data(0,1,z,c), *ptrs = data(0,0,z,c); - for (int l = 0; l=height()) return fill((T)0); - if (delta_y<0) cimg_forZC(*this,z,c) { - std::memmove(data(0,0,z,c),data(0,-delta_y,z,c),_width*(_height + delta_y)*sizeof(T)); - std::memset(data(0,_height + delta_y,z,c),0,-delta_y*_width*sizeof(T)); - } else cimg_forZC(*this,z,c) { - std::memmove(data(0,delta_y,z,c),data(0,0,z,c),_width*(_height-delta_y)*sizeof(T)); - std::memset(data(0,0,z,c),0,delta_y*_width*sizeof(T)); - } - } - - if (delta_z) // Shift along Z-axis - switch (boundary_conditions) { - case 2 : { // Periodic - const int ml = cimg::mod(-delta_z,depth()), ndelta_z = (ml<=depth()/2)?ml:(ml-depth()); - if (!ndelta_z) return *this; - CImg buf(width(),height(),cimg::abs(ndelta_z)); - if (ndelta_z>0) cimg_forC(*this,c) { - std::memcpy(buf,data(0,0,0,c),_width*_height*ndelta_z*sizeof(T)); - std::memmove(data(0,0,0,c),data(0,0,ndelta_z,c),_width*_height*(_depth-ndelta_z)*sizeof(T)); - std::memcpy(data(0,0,_depth-ndelta_z,c),buf,_width*_height*ndelta_z*sizeof(T)); - } else cimg_forC(*this,c) { - std::memcpy(buf,data(0,0,_depth + ndelta_z,c),-ndelta_z*_width*_height*sizeof(T)); - std::memmove(data(0,0,-ndelta_z,c),data(0,0,0,c),_width*_height*(_depth + ndelta_z)*sizeof(T)); - std::memcpy(data(0,0,0,c),buf,-ndelta_z*_width*_height*sizeof(T)); - } - } break; - case 1 : // Neumann - if (delta_z<0) { - const int ndelta_z = (-delta_z>=depth())?depth() - 1:-delta_z; - if (!ndelta_z) return *this; - cimg_forC(*this,c) { - std::memmove(data(0,0,0,c),data(0,0,ndelta_z,c),_width*_height*(_depth-ndelta_z)*sizeof(T)); - T *ptrd = data(0,0,_depth-ndelta_z,c), *ptrs = data(0,0,_depth - 1,c); - for (int l = 0; l=depth())?depth() - 1:delta_z; - if (!ndelta_z) return *this; - cimg_forC(*this,c) { - std::memmove(data(0,0,ndelta_z,c),data(0,0,0,c),_width*_height*(_depth-ndelta_z)*sizeof(T)); - T *ptrd = data(0,0,1,c), *ptrs = data(0,0,0,c); - for (int l = 0; l=depth()) return fill((T)0); - if (delta_z<0) cimg_forC(*this,c) { - std::memmove(data(0,0,0,c),data(0,0,-delta_z,c),_width*_height*(_depth + delta_z)*sizeof(T)); - std::memset(data(0,0,_depth + delta_z,c),0,_width*_height*(-delta_z)*sizeof(T)); - } else cimg_forC(*this,c) { - std::memmove(data(0,0,delta_z,c),data(0,0,0,c),_width*_height*(_depth-delta_z)*sizeof(T)); - std::memset(data(0,0,0,c),0,delta_z*_width*_height*sizeof(T)); - } - } - - if (delta_c) // Shift along C-axis - switch (boundary_conditions) { - case 2 : { // Periodic - const int ml = cimg::mod(-delta_c,spectrum()), ndelta_c = (ml<=spectrum()/2)?ml:(ml-spectrum()); - if (!ndelta_c) return *this; - CImg buf(width(),height(),depth(),cimg::abs(ndelta_c)); - if (ndelta_c>0) { - std::memcpy(buf,_data,_width*_height*_depth*ndelta_c*sizeof(T)); - std::memmove(_data,data(0,0,0,ndelta_c),_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T)); - std::memcpy(data(0,0,0,_spectrum-ndelta_c),buf,_width*_height*_depth*ndelta_c*sizeof(T)); - } else { - std::memcpy(buf,data(0,0,0,_spectrum + ndelta_c),-ndelta_c*_width*_height*_depth*sizeof(T)); - std::memmove(data(0,0,0,-ndelta_c),_data,_width*_height*_depth*(_spectrum + ndelta_c)*sizeof(T)); - std::memcpy(_data,buf,-ndelta_c*_width*_height*_depth*sizeof(T)); - } - } break; - case 1 : // Neumann - if (delta_c<0) { - const int ndelta_c = (-delta_c>=spectrum())?spectrum() - 1:-delta_c; - if (!ndelta_c) return *this; - std::memmove(_data,data(0,0,0,ndelta_c),_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T)); - T *ptrd = data(0,0,0,_spectrum-ndelta_c), *ptrs = data(0,0,0,_spectrum - 1); - for (int l = 0; l=spectrum())?spectrum() - 1:delta_c; - if (!ndelta_c) return *this; - std::memmove(data(0,0,0,ndelta_c),_data,_width*_height*_depth*(_spectrum-ndelta_c)*sizeof(T)); - T *ptrd = data(0,0,0,1); - for (int l = 0; l=spectrum()) return fill((T)0); - if (delta_c<0) { - std::memmove(_data,data(0,0,0,-delta_c),_width*_height*_depth*(_spectrum + delta_c)*sizeof(T)); - std::memset(data(0,0,0,_spectrum + delta_c),0,_width*_height*_depth*(-delta_c)*sizeof(T)); - } else { - std::memmove(data(0,0,0,delta_c),_data,_width*_height*_depth*(_spectrum-delta_c)*sizeof(T)); - std::memset(_data,0,delta_c*_width*_height*_depth*sizeof(T)); - } - } - return *this; - } - - //! Shift image content \newinstance. - CImg get_shift(const int delta_x, const int delta_y=0, const int delta_z=0, const int delta_c=0, - const unsigned int boundary_conditions=0) const { - return (+*this).shift(delta_x,delta_y,delta_z,delta_c,boundary_conditions); - } - - //! Permute axes order. - /** - \param axes_order Axes permutations, as a C-string of 4 characters. - This function permutes image content regarding the specified axes permutation. - **/ - CImg& permute_axes(const char *const axes_order) { - return get_permute_axes(axes_order).move_to(*this); - } - - //! Permute axes order \newinstance. - CImg get_permute_axes(const char *const axes_order) const { - const T foo = (T)0; - return _permute_axes(axes_order,foo); - } - - template - CImg _permute_axes(const char *const axes_order, const t&) const { - if (is_empty() || !axes_order) return CImg(*this,false); - CImg res; - const T* ptrs = _data; - unsigned char s_code[4] = { 0,1,2,3 }, n_code[4] = { 0 }; - for (unsigned int l = 0; axes_order[l]; ++l) { - int c = cimg::lowercase(axes_order[l]); - if (l>=4 || (c!='x' && c!='y' && c!='z' && c!='c')) { *s_code = 4; break; } - else { ++n_code[c%=4]; s_code[l] = (unsigned char)c; } - } - if (*axes_order && *s_code<4 && *n_code<=1 && n_code[1]<=1 && n_code[2]<=1 && n_code[3]<=1) { - const unsigned int code = (s_code[0]<<12) | (s_code[1]<<8) | (s_code[2]<<4) | (s_code[3]); - ulongT wh, whd; - switch (code) { - case 0x0123 : // xyzc - return +*this; - case 0x0132 : // xycz - res.assign(_width,_height,_spectrum,_depth); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(x,y,c,z,wh,whd) = (t)*(ptrs++); - break; - case 0x0213 : // xzyc - res.assign(_width,_depth,_height,_spectrum); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(x,z,y,c,wh,whd) = (t)*(ptrs++); - break; - case 0x0231 : // xzcy - res.assign(_width,_depth,_spectrum,_height); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(x,z,c,y,wh,whd) = (t)*(ptrs++); - break; - case 0x0312 : // xcyz - res.assign(_width,_spectrum,_height,_depth); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(x,c,y,z,wh,whd) = (t)*(ptrs++); - break; - case 0x0321 : // xczy - res.assign(_width,_spectrum,_depth,_height); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(x,c,z,y,wh,whd) = (t)*(ptrs++); - break; - case 0x1023 : // yxzc - res.assign(_height,_width,_depth,_spectrum); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(y,x,z,c,wh,whd) = (t)*(ptrs++); - break; - case 0x1032 : // yxcz - res.assign(_height,_width,_spectrum,_depth); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(y,x,c,z,wh,whd) = (t)*(ptrs++); - break; - case 0x1203 : // yzxc - res.assign(_height,_depth,_width,_spectrum); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(y,z,x,c,wh,whd) = (t)*(ptrs++); - break; - case 0x1230 : // yzcx - res.assign(_height,_depth,_spectrum,_width); - switch (_width) { - case 1 : { - t *ptr_r = res.data(0,0,0,0); - for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) { - *(ptr_r++) = (t)*(ptrs++); - } - } break; - case 2 : { - t *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1); - for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) { - *(ptr_r++) = (t)ptrs[0]; - *(ptr_g++) = (t)ptrs[1]; - ptrs+=2; - } - } break; - case 3 : { // Optimization for the classical conversion from interleaved RGB to planar RGB - t *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1), *ptr_b = res.data(0,0,0,2); - for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) { - *(ptr_r++) = (t)ptrs[0]; - *(ptr_g++) = (t)ptrs[1]; - *(ptr_b++) = (t)ptrs[2]; - ptrs+=3; - } - } break; - case 4 : { // Optimization for the classical conversion from interleaved RGBA to planar RGBA - t - *ptr_r = res.data(0,0,0,0), *ptr_g = res.data(0,0,0,1), - *ptr_b = res.data(0,0,0,2), *ptr_a = res.data(0,0,0,3); - for (unsigned int siz = _height*_depth*_spectrum; siz; --siz) { - *(ptr_r++) = (t)ptrs[0]; - *(ptr_g++) = (t)ptrs[1]; - *(ptr_b++) = (t)ptrs[2]; - *(ptr_a++) = (t)ptrs[3]; - ptrs+=4; - } - } break; - default : { - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(y,z,c,x,wh,whd) = *(ptrs++); - return res; - } - } - break; - case 0x1302 : // ycxz - res.assign(_height,_spectrum,_width,_depth); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(y,c,x,z,wh,whd) = (t)*(ptrs++); - break; - case 0x1320 : // yczx - res.assign(_height,_spectrum,_depth,_width); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(y,c,z,x,wh,whd) = (t)*(ptrs++); - break; - case 0x2013 : // zxyc - res.assign(_depth,_width,_height,_spectrum); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(z,x,y,c,wh,whd) = (t)*(ptrs++); - break; - case 0x2031 : // zxcy - res.assign(_depth,_width,_spectrum,_height); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(z,x,c,y,wh,whd) = (t)*(ptrs++); - break; - case 0x2103 : // zyxc - res.assign(_depth,_height,_width,_spectrum); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(z,y,x,c,wh,whd) = (t)*(ptrs++); - break; - case 0x2130 : // zycx - res.assign(_depth,_height,_spectrum,_width); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(z,y,c,x,wh,whd) = (t)*(ptrs++); - break; - case 0x2301 : // zcxy - res.assign(_depth,_spectrum,_width,_height); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(z,c,x,y,wh,whd) = (t)*(ptrs++); - break; - case 0x2310 : // zcyx - res.assign(_depth,_spectrum,_height,_width); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(z,c,y,x,wh,whd) = (t)*(ptrs++); - break; - case 0x3012 : // cxyz - res.assign(_spectrum,_width,_height,_depth); - switch (_spectrum) { - case 1 : { - const T *ptr_r = data(0,0,0,0); - t *ptrd = res._data; - for (ulongT siz = (ulongT)_width*_height*_depth; siz; --siz) *(ptrd++) = (t)*(ptr_r++); - } break; - case 2 : { - const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1); - t *ptrd = res._data; - for (ulongT siz = (ulongT)_width*_height*_depth; siz; --siz) { - ptrd[0] = (t)*(ptr_r++); - ptrd[1] = (t)*(ptr_g++); - ptrd+=2; - } - } break; - case 3 : { // Optimization for the classical conversion from planar RGB to interleaved RGB - const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); - t *ptrd = res._data; - for (ulongT siz = (ulongT)_width*_height*_depth; siz; --siz) { - ptrd[0] = (t)*(ptr_r++); - ptrd[1] = (t)*(ptr_g++); - ptrd[2] = (t)*(ptr_b++); - ptrd+=3; - } - } break; - case 4 : { // Optimization for the classical conversion from planar RGBA to interleaved RGBA - const T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3); - t *ptrd = res._data; - for (ulongT siz = (ulongT)_width*_height*_depth; siz; --siz) { - ptrd[0] = (t)*(ptr_r++); - ptrd[1] = (t)*(ptr_g++); - ptrd[2] = (t)*(ptr_b++); - ptrd[3] = (t)*(ptr_a++); - ptrd+=4; - } - } break; - default : { - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(c,x,y,z,wh,whd) = (t)*(ptrs++); - } - } - break; - case 0x3021 : // cxzy - res.assign(_spectrum,_width,_depth,_height); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(c,x,z,y,wh,whd) = (t)*(ptrs++); - break; - case 0x3102 : // cyxz - res.assign(_spectrum,_height,_width,_depth); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(c,y,x,z,wh,whd) = (t)*(ptrs++); - break; - case 0x3120 : // cyzx - res.assign(_spectrum,_height,_depth,_width); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(c,y,z,x,wh,whd) = (t)*(ptrs++); - break; - case 0x3201 : // czxy - res.assign(_spectrum,_depth,_width,_height); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(c,z,x,y,wh,whd) = (t)*(ptrs++); - break; - case 0x3210 : // czyx - res.assign(_spectrum,_depth,_height,_width); - wh = (ulongT)res._width*res._height; whd = wh*res._depth; - cimg_forXYZC(*this,x,y,z,c) res(c,z,y,x,wh,whd) = (t)*(ptrs++); - break; - } - } - if (!res) - throw CImgArgumentException(_cimg_instance - "permute_axes(): Invalid specified axes order '%s'.", - cimg_instance, - axes_order); - return res; - } - - //! Unroll pixel values along specified axis. - /** - \param axis Unroll axis (can be \c 'x', \c 'y', \c 'z' or c 'c'). - **/ - CImg& unroll(const char axis) { - const unsigned int siz = (unsigned int)size(); - if (siz) switch (cimg::lowercase(axis)) { - case 'x' : _width = siz; _height = _depth = _spectrum = 1; break; - case 'y' : _height = siz; _width = _depth = _spectrum = 1; break; - case 'z' : _depth = siz; _width = _height = _spectrum = 1; break; - case 'c' : _spectrum = siz; _width = _height = _depth = 1; break; - } - return *this; - } - - //! Unroll pixel values along specified axis \newinstance. - CImg get_unroll(const char axis) const { - return (+*this).unroll(axis); - } - - //! Rotate image with arbitrary angle. - /** - \param angle Rotation angle, in degrees. - \param interpolation Type of interpolation. Can be { 0=nearest | 1=linear | 2=cubic }. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - \note The size of the image is modified. - **/ - CImg& rotate(const float angle, const unsigned int interpolation=1, - const unsigned int boundary_conditions=0) { - const float nangle = cimg::mod(angle,360.f); - if (nangle==0.f) return *this; - return get_rotate(nangle,interpolation,boundary_conditions).move_to(*this); - } - - //! Rotate image with arbitrary angle \newinstance. - CImg get_rotate(const float angle, const unsigned int interpolation=1, - const unsigned int boundary_conditions=0) const { - if (is_empty()) return *this; - CImg res; - const float nangle = cimg::mod(angle,360.f); - if (boundary_conditions!=1 && cimg::mod(nangle,90.f)==0) { // Optimized version for orthogonal angles - const int wm1 = width() - 1, hm1 = height() - 1; - const int iangle = (int)nangle/90; - switch (iangle) { - case 1 : { // 90 deg - res.assign(_height,_width,_depth,_spectrum); - T *ptrd = res._data; - cimg_forXYZC(res,x,y,z,c) *(ptrd++) = (*this)(y,hm1 - x,z,c); - } break; - case 2 : { // 180 deg - res.assign(_width,_height,_depth,_spectrum); - T *ptrd = res._data; - cimg_forXYZC(res,x,y,z,c) *(ptrd++) = (*this)(wm1 - x,hm1 - y,z,c); - } break; - case 3 : { // 270 deg - res.assign(_height,_width,_depth,_spectrum); - T *ptrd = res._data; - cimg_forXYZC(res,x,y,z,c) *(ptrd++) = (*this)(wm1 - y,x,z,c); - } break; - default : // 0 deg - return *this; - } - } else { // Generic angle - const float - rad = (float)(nangle*cimg::PI/180.), - ca = (float)std::cos(rad), sa = (float)std::sin(rad), - ux = cimg::abs((_width - 1)*ca), uy = cimg::abs((_width - 1)*sa), - vx = cimg::abs((_height - 1)*sa), vy = cimg::abs((_height - 1)*ca), - w2 = 0.5f*(_width - 1), h2 = 0.5f*(_height - 1); - res.assign((int)cimg::round(1 + ux + vx),(int)cimg::round(1 + uy + vy),_depth,_spectrum); - const float rw2 = 0.5f*(res._width - 1), rh2 = 0.5f*(res._height - 1); - _rotate(res,nangle,interpolation,boundary_conditions,w2,h2,rw2,rh2); - } - return res; - } - - //! Rotate image with arbitrary angle, around a center point. - /** - \param angle Rotation angle, in degrees. - \param cx X-coordinate of the rotation center. - \param cy Y-coordinate of the rotation center. - \param interpolation Type of interpolation, { 0=nearest | 1=linear | 2=cubic | 3=mirror }. - \param boundary_conditions Boundary conditions, { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - **/ - CImg& rotate(const float angle, const float cx, const float cy, - const unsigned int interpolation, const unsigned int boundary_conditions=0) { - return get_rotate(angle,cx,cy,interpolation,boundary_conditions).move_to(*this); - } - - //! Rotate image with arbitrary angle, around a center point \newinstance. - CImg get_rotate(const float angle, const float cx, const float cy, - const unsigned int interpolation, const unsigned int boundary_conditions=0) const { - if (is_empty()) return *this; - CImg res(_width,_height,_depth,_spectrum); - _rotate(res,angle,interpolation,boundary_conditions,cx,cy,cx,cy); - return res; - } - - // [internal] Perform 2D rotation with arbitrary angle. - void _rotate(CImg& res, const float angle, - const unsigned int interpolation, const unsigned int boundary_conditions, - const float w2, const float h2, - const float rw2, const float rh2) const { - const float - rad = (float)(angle*cimg::PI/180.), - ca = (float)std::cos(rad), sa = (float)std::sin(rad); - - switch (boundary_conditions) { - case 3 : { // Mirror - - switch (interpolation) { - case 2 : { // Cubic interpolation - const float ww = 2.f*width(), hh = 2.f*height(); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),2048)) - cimg_forXYZC(res,x,y,z,c) { - const float xc = x - rw2, yc = y - rh2, - mx = cimg::mod(w2 + xc*ca + yc*sa,ww), - my = cimg::mod(h2 - xc*sa + yc*ca,hh); - res(x,y,z,c) = _cubic_atXY_c(mx{ 0=nearest | 1=linear | 2=cubic }. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - \note Most of the time, size of the image is modified. - **/ - CImg rotate(const float u, const float v, const float w, const float angle, - const unsigned int interpolation, const unsigned int boundary_conditions) { - const float nangle = cimg::mod(angle,360.f); - if (nangle==0.f) return *this; - return get_rotate(u,v,w,nangle,interpolation,boundary_conditions).move_to(*this); - } - - //! Rotate volumetric image with arbitrary angle and axis \newinstance. - CImg get_rotate(const float u, const float v, const float w, const float angle, - const unsigned int interpolation, const unsigned int boundary_conditions) const { - if (is_empty()) return *this; - CImg res; - const float - w1 = _width - 1, h1 = _height - 1, d1 = _depth -1, - w2 = 0.5f*w1, h2 = 0.5f*h1, d2 = 0.5f*d1; - CImg R = CImg::rotation_matrix(u,v,w,angle); - const CImg - X = R*CImg(8,3,1,1, - 0.f,w1,w1,0.f,0.f,w1,w1,0.f, - 0.f,0.f,h1,h1,0.f,0.f,h1,h1, - 0.f,0.f,0.f,0.f,d1,d1,d1,d1); - float - xm, xM = X.get_shared_row(0).max_min(xm), - ym, yM = X.get_shared_row(1).max_min(ym), - zm, zM = X.get_shared_row(2).max_min(zm); - const int - dx = (int)cimg::round(xM - xm), - dy = (int)cimg::round(yM - ym), - dz = (int)cimg::round(zM - zm); - R.transpose(); - res.assign(1 + dx,1 + dy,1 + dz,_spectrum); - const float rw2 = 0.5f*dx, rh2 = 0.5f*dy, rd2 = 0.5f*dz; - _rotate(res,R,interpolation,boundary_conditions,w2,h2,d2,rw2,rh2,rd2); - return res; - } - - //! Rotate volumetric image with arbitrary angle and axis, around a center point. - /** - \param u X-coordinate of the 3D rotation axis. - \param v Y-coordinate of the 3D rotation axis. - \param w Z-coordinate of the 3D rotation axis. - \param angle Rotation angle, in degrees. - \param cx X-coordinate of the rotation center. - \param cy Y-coordinate of the rotation center. - \param cz Z-coordinate of the rotation center. - \param interpolation Type of interpolation. Can be { 0=nearest | 1=linear | 2=cubic | 3=mirror }. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic }. - \note Most of the time, size of the image is modified. - **/ - CImg rotate(const float u, const float v, const float w, const float angle, - const float cx, const float cy, const float cz, - const unsigned int interpolation=1, const unsigned int boundary_conditions=0) { - const float nangle = cimg::mod(angle,360.f); - if (nangle==0.f) return *this; - return get_rotate(u,v,w,nangle,cx,cy,cz,interpolation,boundary_conditions).move_to(*this); - } - - //! Rotate volumetric image with arbitrary angle and axis, around a center point \newinstance. - CImg get_rotate(const float u, const float v, const float w, const float angle, - const float cx, const float cy, const float cz, - const unsigned int interpolation=1, const unsigned int boundary_conditions=0) const { - if (is_empty()) return *this; - CImg res(_width,_height,_depth,_spectrum); - CImg R = CImg::rotation_matrix(u,v,w,-angle); - _rotate(res,R,interpolation,boundary_conditions,cx,cy,cz,cx,cy,cz); - return res; - } - - // [internal] Perform 3D rotation with arbitrary axis and angle. - void _rotate(CImg& res, const CImg& R, - const unsigned int interpolation, const unsigned int boundary_conditions, - const float w2, const float h2, const float d2, - const float rw2, const float rh2, const float rd2) const { - switch (boundary_conditions) { - case 3 : // Mirror - switch (interpolation) { - case 2 : { // Cubic interpolation - const float ww = 2.f*width(), hh = 2.f*height(), dd = 2.f*depth(); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(res.size(),2048)) - cimg_forXYZ(res,x,y,z) { - const float - xc = x - rw2, yc = y - rh2, zc = z - rd2, - X = cimg::mod((float)(w2 + R(0,0)*xc + R(1,0)*yc + R(2,0)*zc),ww), - Y = cimg::mod((float)(h2 + R(0,1)*xc + R(1,1)*yc + R(2,1)*zc),hh), - Z = cimg::mod((float)(d2 + R(0,2)*xc + R(1,2)*yc + R(2,2)*zc),dd); - cimg_forC(res,c) res(x,y,z,c) = _cubic_atXYZ_c(X{ 0=nearest | 1=linear | 2=cubic }. - \param boundary_conditions Boundary conditions { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - **/ - template - CImg& warp(const CImg& p_warp, const unsigned int mode=0, - const unsigned int interpolation=1, const unsigned int boundary_conditions=0) { - return get_warp(p_warp,mode,interpolation,boundary_conditions).move_to(*this); - } - - //! Warp image content by a warping field \newinstance - template - CImg get_warp(const CImg& p_warp, const unsigned int mode=0, - const unsigned int interpolation=1, const unsigned int boundary_conditions=0) const { - if (is_empty() || !p_warp) return *this; - if (mode && !is_sameXYZ(p_warp)) - throw CImgArgumentException(_cimg_instance - "warp(): Instance and specified relative warping field (%u,%u,%u,%u,%p) " - "have different XYZ dimensions.", - cimg_instance, - p_warp._width,p_warp._height,p_warp._depth,p_warp._spectrum,p_warp._data); - - CImg res(p_warp._width,p_warp._height,p_warp._depth,_spectrum); - - if (p_warp._spectrum==1) { // 1D warping - if (mode>=3) { // Forward-relative warp - res.fill((T)0); - if (interpolation>=1) // Linear interpolation - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),4096)) - cimg_forYZC(res,y,z,c) { - const t *ptrs0 = p_warp.data(0,y,z); const T *ptrs = data(0,y,z,c); - cimg_forX(res,x) res.set_linear_atX(*(ptrs++),x + (float)*(ptrs0++),y,z,c); - } - else // Nearest-neighbor interpolation - cimg_forYZC(res,y,z,c) { - const t *ptrs0 = p_warp.data(0,y,z); const T *ptrs = data(0,y,z,c); - cimg_forX(res,x) { - const int X = x + (int)cimg::round(*(ptrs0++)); - if (X>=0 && X=1) // Linear interpolation - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),4096)) - cimg_forYZC(res,y,z,c) { - const t *ptrs0 = p_warp.data(0,y,z); const T *ptrs = data(0,y,z,c); - cimg_forX(res,x) res.set_linear_atX(*(ptrs++),(float)*(ptrs0++),y,z,c); - } - else // Nearest-neighbor interpolation - cimg_forYZC(res,y,z,c) { - const t *ptrs0 = p_warp.data(0,y,z); const T *ptrs = data(0,y,z,c); - cimg_forX(res,x) { - const int X = (int)cimg::round(*(ptrs0++)); - if (X>=0 && X=3) { // Forward-relative warp - res.fill((T)0); - if (interpolation>=1) // Linear interpolation - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),4096)) - cimg_forYZC(res,y,z,c) { - const t *ptrs0 = p_warp.data(0,y,z,0), *ptrs1 = p_warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c); - cimg_forX(res,x) res.set_linear_atXY(*(ptrs++),x + (float)*(ptrs0++),y + (float)*(ptrs1++),z,c); - } - else // Nearest-neighbor interpolation - cimg_forYZC(res,y,z,c) { - const t *ptrs0 = p_warp.data(0,y,z,0), *ptrs1 = p_warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c); - cimg_forX(res,x) { - const int X = x + (int)cimg::round(*(ptrs0++)), Y = y + (int)cimg::round(*(ptrs1++)); - if (X>=0 && X=0 && Y=1) // Linear interpolation - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),4096)) - cimg_forYZC(res,y,z,c) { - const t *ptrs0 = p_warp.data(0,y,z,0), *ptrs1 = p_warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c); - cimg_forX(res,x) res.set_linear_atXY(*(ptrs++),(float)*(ptrs0++),(float)*(ptrs1++),z,c); - } - else // Nearest-neighbor interpolation - cimg_forYZC(res,y,z,c) { - const t *ptrs0 = p_warp.data(0,y,z,0), *ptrs1 = p_warp.data(0,y,z,1); const T *ptrs = data(0,y,z,c); - cimg_forX(res,x) { - const int X = (int)cimg::round(*(ptrs0++)), Y = (int)cimg::round(*(ptrs1++)); - if (X>=0 && X=0 && Y=3) { // Forward-relative warp - res.fill((T)0); - if (interpolation>=1) // Linear interpolation - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),4096)) - cimg_forYZC(res,y,z,c) { - const t *ptrs0 = p_warp.data(0,y,z,0), *ptrs1 = p_warp.data(0,y,z,1), *ptrs2 = p_warp.data(0,y,z,2); - const T *ptrs = data(0,y,z,c); - cimg_forX(res,x) res.set_linear_atXYZ(*(ptrs++),x + (float)*(ptrs0++),y + (float)*(ptrs1++), - z + (float)*(ptrs2++),c); - } - else // Nearest-neighbor interpolation - cimg_forYZC(res,y,z,c) { - const t *ptrs0 = p_warp.data(0,y,z,0), *ptrs1 = p_warp.data(0,y,z,1), *ptrs2 = p_warp.data(0,y,z,2); - const T *ptrs = data(0,y,z,c); - cimg_forX(res,x) { - const int - X = x + (int)cimg::round(*(ptrs0++)), - Y = y + (int)cimg::round(*(ptrs1++)), - Z = z + (int)cimg::round(*(ptrs2++)); - if (X>=0 && X=0 && Y=0 && Z=1) // Linear interpolation - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(res.size(),4096)) - cimg_forYZC(res,y,z,c) { - const t *ptrs0 = p_warp.data(0,y,z,0), *ptrs1 = p_warp.data(0,y,z,1), *ptrs2 = p_warp.data(0,y,z,2); - const T *ptrs = data(0,y,z,c); - cimg_forX(res,x) res.set_linear_atXYZ(*(ptrs++),(float)*(ptrs0++),(float)*(ptrs1++),(float)*(ptrs2++),c); - } - else // Nearest-neighbor interpolation - cimg_forYZC(res,y,z,c) { - const t *ptrs0 = p_warp.data(0,y,z,0), *ptrs1 = p_warp.data(0,y,z,1), *ptrs2 = p_warp.data(0,y,z,2); - const T *ptrs = data(0,y,z,c); - cimg_forX(res,x) { - const int - X = (int)cimg::round(*(ptrs0++)), - Y = (int)cimg::round(*(ptrs1++)), - Z = (int)cimg::round(*(ptrs2++)); - if (X>=0 && X=0 && Y=0 && Z get_projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0) const { - if (is_empty() || _depth<2) return +*this; - const unsigned int - _x0 = (x0>=_width)?_width - 1:x0, - _y0 = (y0>=_height)?_height - 1:y0, - _z0 = (z0>=_depth)?_depth - 1:z0; - const CImg - img_xy = get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1), - img_zy = get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1).permute_axes("xzyc"). - resize(_depth,_height,1,-100,-1), - img_xz = get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1).resize(_width,_depth,1,-100,-1); - return CImg(_width + _depth,_height + _depth,1,_spectrum,cimg::min(img_xy.min(),img_zy.min(),img_xz.min())). - draw_image(0,0,img_xy).draw_image(img_xy._width,0,img_zy). - draw_image(0,img_xy._height,img_xz); - } - - //! Construct a 2D representation of a 3D image, with XY,XZ and YZ views \inplace. - CImg& projections2d(const unsigned int x0, const unsigned int y0, const unsigned int z0) { - if (_depth<2) return *this; - return get_projections2d(x0,y0,z0).move_to(*this); - } - - //! Crop image region. - /** - \param x0 = X-coordinate of the upper-left crop rectangle corner. - \param y0 = Y-coordinate of the upper-left crop rectangle corner. - \param z0 = Z-coordinate of the upper-left crop rectangle corner. - \param c0 = C-coordinate of the upper-left crop rectangle corner. - \param x1 = X-coordinate of the lower-right crop rectangle corner. - \param y1 = Y-coordinate of the lower-right crop rectangle corner. - \param z1 = Z-coordinate of the lower-right crop rectangle corner. - \param c1 = C-coordinate of the lower-right crop rectangle corner. - \param boundary_conditions = Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - **/ - CImg& crop(const int x0, const int y0, const int z0, const int c0, - const int x1, const int y1, const int z1, const int c1, - const unsigned int boundary_conditions=0) { - return get_crop(x0,y0,z0,c0,x1,y1,z1,c1,boundary_conditions).move_to(*this); - } - - //! Crop image region \newinstance. - CImg get_crop(const int x0, const int y0, const int z0, const int c0, - const int x1, const int y1, const int z1, const int c1, - const unsigned int boundary_conditions=0) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "crop(): Empty instance.", - cimg_instance); - const int - nx0 = x0=0 && nx1=0 && ny1=0 && nz1=0 && nc1 res(1U + nx1 - nx0,1U + ny1 - ny0,1U + nz1 - nz0,1U + nc1 - nc0); - if (nx0<0 || nx1>=width() || ny0<0 || ny1>=height() || nz0<0 || nz1>=depth() || nc0<0 || nc1>=spectrum()) - switch (_boundary_conditions) { - case 3 : { // Mirror - const int w2 = 2*width(), h2 = 2*height(), d2 = 2*depth(), s2 = 2*spectrum(); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*16 && - _height*_depth*_spectrum>=4)) - cimg_forXYZC(res,x,y,z,c) { - const int - mx = cimg::mod(nx0 + x,w2), - my = cimg::mod(ny0 + y,h2), - mz = cimg::mod(nz0 + z,d2), - mc = cimg::mod(nc0 + c,s2); - res(x,y,z,c) = (*this)(mx=(cimg_openmp_sizefactor)*16 && - _height*_depth*_spectrum>=4)) - cimg_forXYZC(res,x,y,z,c) { - res(x,y,z,c) = (*this)(cimg::mod(nx0 + x,width()),cimg::mod(ny0 + y,height()), - cimg::mod(nz0 + z,depth()),cimg::mod(nc0 + c,spectrum())); - } - } break; - case 1 : // Neumann - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*16 && - _height*_depth*_spectrum>=4)) - cimg_forXYZC(res,x,y,z,c) res(x,y,z,c) = _atXYZC(nx0 + x,ny0 + y,nz0 + z,nc0 + c); - break; - default : // Dirichlet - res.fill((T)0).draw_image(-nx0,-ny0,-nz0,-nc0,*this); - } - else res.draw_image(-nx0,-ny0,-nz0,-nc0,*this); - return res; - } - - //! Crop image region \overloading. - CImg& crop(const int x0, const int y0, const int z0, - const int x1, const int y1, const int z1, - const unsigned int boundary_conditions=0) { - return crop(x0,y0,z0,0,x1,y1,z1,_spectrum - 1,boundary_conditions); - } - - //! Crop image region \newinstance. - CImg get_crop(const int x0, const int y0, const int z0, - const int x1, const int y1, const int z1, - const unsigned int boundary_conditions=0) const { - return get_crop(x0,y0,z0,0,x1,y1,z1,_spectrum - 1,boundary_conditions); - } - - //! Crop image region \overloading. - CImg& crop(const int x0, const int y0, - const int x1, const int y1, - const unsigned int boundary_conditions=0) { - return crop(x0,y0,0,0,x1,y1,_depth - 1,_spectrum - 1,boundary_conditions); - } - - //! Crop image region \newinstance. - CImg get_crop(const int x0, const int y0, - const int x1, const int y1, - const unsigned int boundary_conditions=0) const { - return get_crop(x0,y0,0,0,x1,y1,_depth - 1,_spectrum - 1,boundary_conditions); - } - - //! Crop image region \overloading. - CImg& crop(const int x0, const int x1, const unsigned int boundary_conditions=0) { - return crop(x0,0,0,0,x1,_height - 1,_depth - 1,_spectrum - 1,boundary_conditions); - } - - //! Crop image region \newinstance. - CImg get_crop(const int x0, const int x1, const unsigned int boundary_conditions=0) const { - return get_crop(x0,0,0,0,x1,_height - 1,_depth - 1,_spectrum - 1,boundary_conditions); - } - - //! Autocrop image region, regarding the specified background value. - CImg& autocrop(const T& value, const char *const axes="czyx") { - if (is_empty()) return *this; - for (const char *s = axes; *s; ++s) { - const char axis = cimg::lowercase(*s); - const CImg coords = _autocrop(value,axis); - if (coords[0]==-1 && coords[1]==-1) return assign(); // Image has only 'value' pixels - else switch (axis) { - case 'x' : { - const int x0 = coords[0], x1 = coords[1]; - if (x0>=0 && x1>=0) crop(x0,x1); - } break; - case 'y' : { - const int y0 = coords[0], y1 = coords[1]; - if (y0>=0 && y1>=0) crop(0,y0,_width - 1,y1); - } break; - case 'z' : { - const int z0 = coords[0], z1 = coords[1]; - if (z0>=0 && z1>=0) crop(0,0,z0,_width - 1,_height - 1,z1); - } break; - default : { - const int c0 = coords[0], c1 = coords[1]; - if (c0>=0 && c1>=0) crop(0,0,0,c0,_width - 1,_height - 1,_depth - 1,c1); - } - } - } - return *this; - } - - //! Autocrop image region, regarding the specified background value \newinstance. - CImg get_autocrop(const T& value, const char *const axes="czyx") const { - return (+*this).autocrop(value,axes); - } - - //! Autocrop image region, regarding the specified background color. - /** - \param color Color used for the crop. If \c 0, color is guessed. - \param axes Axes used for the crop. - **/ - CImg& autocrop(const T *const color=0, const char *const axes="zyx") { - if (is_empty()) return *this; - if (!color) { // Guess color - const CImg col1 = get_vector_at(0,0,0); - const unsigned int w = _width, h = _height, d = _depth, s = _spectrum; - autocrop(col1,axes); - if (_width==w && _height==h && _depth==d && _spectrum==s) { - const CImg col2 = get_vector_at(w - 1,h - 1,d - 1); - autocrop(col2,axes); - } - return *this; - } - for (const char *s = axes; *s; ++s) { - const char axis = cimg::lowercase(*s); - switch (axis) { - case 'x' : { - int x0 = width(), x1 = -1; - cimg_forC(*this,c) { - const CImg coords = get_shared_channel(c)._autocrop(color[c],'x'); - const int nx0 = coords[0], nx1 = coords[1]; - if (nx0>=0 && nx1>=0) { x0 = std::min(x0,nx0); x1 = std::max(x1,nx1); } - } - if (x0==width() && x1==-1) return assign(); else crop(x0,x1); - } break; - case 'y' : { - int y0 = height(), y1 = -1; - cimg_forC(*this,c) { - const CImg coords = get_shared_channel(c)._autocrop(color[c],'y'); - const int ny0 = coords[0], ny1 = coords[1]; - if (ny0>=0 && ny1>=0) { y0 = std::min(y0,ny0); y1 = std::max(y1,ny1); } - } - if (y0==height() && y1==-1) return assign(); else crop(0,y0,_width - 1,y1); - } break; - default : { - int z0 = depth(), z1 = -1; - cimg_forC(*this,c) { - const CImg coords = get_shared_channel(c)._autocrop(color[c],'z'); - const int nz0 = coords[0], nz1 = coords[1]; - if (nz0>=0 && nz1>=0) { z0 = std::min(z0,nz0); z1 = std::max(z1,nz1); } - } - if (z0==depth() && z1==-1) return assign(); else crop(0,0,z0,_width - 1,_height - 1,z1); - } - } - } - return *this; - } - - //! Autocrop image region, regarding the specified background color \newinstance. - CImg get_autocrop(const T *const color=0, const char *const axes="zyx") const { - return (+*this).autocrop(color,axes); - } - - CImg _autocrop(const T& value, const char axis) const { - CImg res; - switch (cimg::lowercase(axis)) { - case 'x' : { - int x0 = -1, x1 = -1; - cimg_forX(*this,x) cimg_forYZC(*this,y,z,c) - if ((*this)(x,y,z,c)!=value) { x0 = x; x = width(); y = height(); z = depth(); c = spectrum(); } - if (x0>=0) { - for (int x = width() - 1; x>=0; --x) cimg_forYZC(*this,y,z,c) - if ((*this)(x,y,z,c)!=value) { x1 = x; x = 0; y = height(); z = depth(); c = spectrum(); } - } - res = CImg::vector(x0,x1); - } break; - case 'y' : { - int y0 = -1, y1 = -1; - cimg_forY(*this,y) cimg_forXZC(*this,x,z,c) - if ((*this)(x,y,z,c)!=value) { y0 = y; x = width(); y = height(); z = depth(); c = spectrum(); } - if (y0>=0) { - for (int y = height() - 1; y>=0; --y) cimg_forXZC(*this,x,z,c) - if ((*this)(x,y,z,c)!=value) { y1 = y; x = width(); y = 0; z = depth(); c = spectrum(); } - } - res = CImg::vector(y0,y1); - } break; - case 'z' : { - int z0 = -1, z1 = -1; - cimg_forZ(*this,z) cimg_forXYC(*this,x,y,c) - if ((*this)(x,y,z,c)!=value) { z0 = z; x = width(); y = height(); z = depth(); c = spectrum(); } - if (z0>=0) { - for (int z = depth() - 1; z>=0; --z) cimg_forXYC(*this,x,y,c) - if ((*this)(x,y,z,c)!=value) { z1 = z; x = width(); y = height(); z = 0; c = spectrum(); } - } - res = CImg::vector(z0,z1); - } break; - default : { - int c0 = -1, c1 = -1; - cimg_forC(*this,c) cimg_forXYZ(*this,x,y,z) - if ((*this)(x,y,z,c)!=value) { c0 = c; x = width(); y = height(); z = depth(); c = spectrum(); } - if (c0>=0) { - for (int c = spectrum() - 1; c>=0; --c) cimg_forXYZ(*this,x,y,z) - if ((*this)(x,y,z,c)!=value) { c1 = c; x = width(); y = height(); z = depth(); c = 0; } - } - res = CImg::vector(c0,c1); - } - } - return res; - } - - //! Return specified image column. - /** - \param x0 Image column. - **/ - CImg get_column(const int x0) const { - return get_columns(x0,x0); - } - - //! Return specified image column \inplace. - CImg& column(const int x0) { - return columns(x0,x0); - } - - //! Return specified range of image columns. - /** - \param x0 Starting image column. - \param x1 Ending image column. - **/ - CImg& columns(const int x0, const int x1) { - return get_columns(x0,x1).move_to(*this); - } - - //! Return specified range of image columns \inplace. - CImg get_columns(const int x0, const int x1) const { - return get_crop(x0,0,0,0,x1,height() - 1,depth() - 1,spectrum() - 1); - } - - //! Return specified image row. - CImg get_row(const int y0) const { - return get_rows(y0,y0); - } - - //! Return specified image row \inplace. - /** - \param y0 Image row. - **/ - CImg& row(const int y0) { - return rows(y0,y0); - } - - //! Return specified range of image rows. - /** - \param y0 Starting image row. - \param y1 Ending image row. - **/ - CImg get_rows(const int y0, const int y1) const { - return get_crop(0,y0,0,0,width() - 1,y1,depth() - 1,spectrum() - 1); - } - - //! Return specified range of image rows \inplace. - CImg& rows(const int y0, const int y1) { - return get_rows(y0,y1).move_to(*this); - } - - //! Return specified image slice. - /** - \param z0 Image slice. - **/ - CImg get_slice(const int z0) const { - return get_slices(z0,z0); - } - - //! Return specified image slice \inplace. - CImg& slice(const int z0) { - return slices(z0,z0); - } - - //! Return specified range of image slices. - /** - \param z0 Starting image slice. - \param z1 Ending image slice. - **/ - CImg get_slices(const int z0, const int z1) const { - return get_crop(0,0,z0,0,width() - 1,height() - 1,z1,spectrum() - 1); - } - - //! Return specified range of image slices \inplace. - CImg& slices(const int z0, const int z1) { - return get_slices(z0,z1).move_to(*this); - } - - //! Return specified image channel. - /** - \param c0 Image channel. - **/ - CImg get_channel(const int c0) const { - return get_channels(c0,c0); - } - - //! Return specified image channel \inplace. - CImg& channel(const int c0) { - return channels(c0,c0); - } - - //! Return specified range of image channels. - /** - \param c0 Starting image channel. - \param c1 Ending image channel. - **/ - CImg get_channels(const int c0, const int c1) const { - return get_crop(0,0,0,c0,width() - 1,height() - 1,depth() - 1,c1); - } - - //! Return specified range of image channels \inplace. - CImg& channels(const int c0, const int c1) { - return get_channels(c0,c1).move_to(*this); - } - - //! Return stream line of a 2D or 3D vector field. - CImg get_streamline(const float x, const float y, const float z, - const float L=256, const float dl=0.1f, - const unsigned int interpolation_type=2, const bool is_backward_tracking=false, - const bool is_oriented_only=false) const { - if (_spectrum!=2 && _spectrum!=3) - throw CImgInstanceException(_cimg_instance - "streamline(): Instance is not a 2D or 3D vector field.", - cimg_instance); - if (_spectrum==2) { - if (is_oriented_only) { - typename CImg::_functor4d_streamline2d_oriented func(*this); - return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true, - 0,0,0,_width - 1.f,_height - 1.f,0.f); - } else { - typename CImg::_functor4d_streamline2d_directed func(*this); - return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false, - 0,0,0,_width - 1.f,_height - 1.f,0.f); - } - } - if (is_oriented_only) { - typename CImg::_functor4d_streamline3d_oriented func(*this); - return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,true, - 0,0,0,_width - 1.f,_height - 1.f,_depth - 1.f); - } - typename CImg::_functor4d_streamline3d_directed func(*this); - return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,false, - 0,0,0,_width - 1.f,_height - 1.f,_depth - 1.f); - } - - //! Return stream line of a 3D vector field. - /** - \param func Vector field function. - \param x X-coordinate of the starting point of the streamline. - \param y Y-coordinate of the starting point of the streamline. - \param z Z-coordinate of the starting point of the streamline. - \param L Streamline length. - \param dl Streamline length increment. - \param interpolation_type Type of interpolation. - Can be { 0=nearest int | 1=linear | 2=2nd-order RK | 3=4th-order RK. }. - \param is_backward_tracking Tells if the streamline is estimated forward or backward. - \param is_oriented_only Tells if the direction of the vectors must be ignored. - \param x0 X-coordinate of the first bounding-box vertex. - \param y0 Y-coordinate of the first bounding-box vertex. - \param z0 Z-coordinate of the first bounding-box vertex. - \param x1 X-coordinate of the second bounding-box vertex. - \param y1 Y-coordinate of the second bounding-box vertex. - \param z1 Z-coordinate of the second bounding-box vertex. - **/ - template - static CImg streamline(const tfunc& func, - const float x, const float y, const float z, - const float L=256, const float dl=0.1f, - const unsigned int interpolation_type=2, const bool is_backward_tracking=false, - const bool is_oriented_only=false, - const float x0=0, const float y0=0, const float z0=0, - const float x1=0, const float y1=0, const float z1=0) { - if (dl<=0) - throw CImgArgumentException("CImg<%s>::streamline(): Invalid specified integration length %g " - "(should be >0).", - pixel_type(), - dl); - - const bool is_bounded = (x0!=x1 || y0!=y1 || z0!=z1); - if (L<=0 || (is_bounded && (xx1 || yy1 || zz1))) return CImg(); - const unsigned int size_L = (unsigned int)cimg::round(L/dl + 1); - CImg coordinates(size_L,3); - const float dl2 = dl/2; - float - *ptr_x = coordinates.data(0,0), - *ptr_y = coordinates.data(0,1), - *ptr_z = coordinates.data(0,2), - pu = (float)(dl*func(x,y,z,0)), - pv = (float)(dl*func(x,y,z,1)), - pw = (float)(dl*func(x,y,z,2)), - X = x, Y = y, Z = z; - - switch (interpolation_type) { - case 0 : { // Nearest integer interpolation - cimg_forX(coordinates,l) { - *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; - const int - xi = (int)(X>0?X + 0.5f:X - 0.5f), - yi = (int)(Y>0?Y + 0.5f:Y - 0.5f), - zi = (int)(Z>0?Z + 0.5f:Z - 0.5f); - float - u = (float)(dl*func((float)xi,(float)yi,(float)zi,0)), - v = (float)(dl*func((float)xi,(float)yi,(float)zi,1)), - w = (float)(dl*func((float)xi,(float)yi,(float)zi,2)); - if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; } - if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } - if (is_bounded && (Xx1 || Yy1 || Zz1)) break; - } - } break; - case 1 : { // First-order interpolation - cimg_forX(coordinates,l) { - *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; - float - u = (float)(dl*func(X,Y,Z,0)), - v = (float)(dl*func(X,Y,Z,1)), - w = (float)(dl*func(X,Y,Z,2)); - if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; } - if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } - if (is_bounded && (Xx1 || Yy1 || Zz1)) break; - } - } break; - case 2 : { // Second order interpolation - cimg_forX(coordinates,l) { - *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; - float - u0 = (float)(dl2*func(X,Y,Z,0)), - v0 = (float)(dl2*func(X,Y,Z,1)), - w0 = (float)(dl2*func(X,Y,Z,2)); - if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; } - float - u = (float)(dl*func(X + u0,Y + v0,Z + w0,0)), - v = (float)(dl*func(X + u0,Y + v0,Z + w0,1)), - w = (float)(dl*func(X + u0,Y + v0,Z + w0,2)); - if (is_oriented_only && u*pu + v*pv + w*pw<0) { u = -u; v = -v; w = -w; } - if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } - if (is_bounded && (Xx1 || Yy1 || Zz1)) break; - } - } break; - default : { // Fourth order interpolation - cimg_forX(coordinates,k) { - *(ptr_x++) = X; *(ptr_y++) = Y; *(ptr_z++) = Z; - float - u0 = (float)(dl2*func(X,Y,Z,0)), - v0 = (float)(dl2*func(X,Y,Z,1)), - w0 = (float)(dl2*func(X,Y,Z,2)); - if (is_oriented_only && u0*pu + v0*pv + w0*pw<0) { u0 = -u0; v0 = -v0; w0 = -w0; } - float - u1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,0)), - v1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,1)), - w1 = (float)(dl2*func(X + u0,Y + v0,Z + w0,2)); - if (is_oriented_only && u1*pu + v1*pv + w1*pw<0) { u1 = -u1; v1 = -v1; w1 = -w1; } - float - u2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,0)), - v2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,1)), - w2 = (float)(dl2*func(X + u1,Y + v1,Z + w1,2)); - if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u2 = -u2; v2 = -v2; w2 = -w2; } - float - u3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,0)), - v3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,1)), - w3 = (float)(dl2*func(X + u2,Y + v2,Z + w2,2)); - if (is_oriented_only && u2*pu + v2*pv + w2*pw<0) { u3 = -u3; v3 = -v3; w3 = -w3; } - const float - u = (u0 + u3)/3 + (u1 + u2)/1.5f, - v = (v0 + v3)/3 + (v1 + v2)/1.5f, - w = (w0 + w3)/3 + (w1 + w2)/1.5f; - if (is_backward_tracking) { X-=(pu=u); Y-=(pv=v); Z-=(pw=w); } else { X+=(pu=u); Y+=(pv=v); Z+=(pw=w); } - if (is_bounded && (Xx1 || Yy1 || Zz1)) break; - } - } - } - if (ptr_x!=coordinates.data(0,1)) coordinates.resize((int)(ptr_x-coordinates.data()),3,1,1,0); - return coordinates; - } - - //! Return stream line of a 3D vector field \overloading. - static CImg streamline(const char *const expression, - const float x, const float y, const float z, - const float L=256, const float dl=0.1f, - const unsigned int interpolation_type=2, const bool is_backward_tracking=true, - const bool is_oriented_only=false, - const float x0=0, const float y0=0, const float z0=0, - const float x1=0, const float y1=0, const float z1=0) { - _functor4d_streamline_expr func(expression); - return streamline(func,x,y,z,L,dl,interpolation_type,is_backward_tracking,is_oriented_only,x0,y0,z0,x1,y1,z1); - } - - struct _functor4d_streamline2d_directed { - const CImg& ref; - _functor4d_streamline2d_directed(const CImg& pref):ref(pref) {} - float operator()(const float x, const float y, const float z, const unsigned int c) const { - return c<2?(float)ref._linear_atXY(x,y,(int)z,c):0; - } - }; - - struct _functor4d_streamline3d_directed { - const CImg& ref; - _functor4d_streamline3d_directed(const CImg& pref):ref(pref) {} - float operator()(const float x, const float y, const float z, const unsigned int c) const { - return (float)ref._linear_atXYZ(x,y,z,c); - } - }; - - struct _functor4d_streamline2d_oriented { - const CImg& ref; - CImg *pI; - _functor4d_streamline2d_oriented(const CImg& pref):ref(pref),pI(0) { pI = new CImg(2,2,1,2); } - ~_functor4d_streamline2d_oriented() { delete pI; } - float operator()(const float x, const float y, const float z, const unsigned int c) const { -#define _cimg_vecalign2d(i,j) \ - if (I(i,j,0)*I(0,0,0) + I(i,j,1)*I(0,0,1)<0) { I(i,j,0) = -I(i,j,0); I(i,j,1) = -I(i,j,1); } - int - xi = (int)x - (x>=0?0:1), nxi = xi + 1, - yi = (int)y - (y>=0?0:1), nyi = yi + 1, - zi = (int)z; - const float - dx = x - xi, - dy = y - yi; - if (c==0) { - CImg& I = *pI; - if (xi<0) xi = 0; - if (nxi<0) nxi = 0; - if (xi>=ref.width()) xi = ref.width() - 1; - if (nxi>=ref.width()) nxi = ref.width() - 1; - if (yi<0) yi = 0; - if (nyi<0) nyi = 0; - if (yi>=ref.height()) yi = ref.height() - 1; - if (nyi>=ref.height()) nyi = ref.height() - 1; - I(0,0,0) = (float)ref(xi,yi,zi,0); I(0,0,1) = (float)ref(xi,yi,zi,1); - I(1,0,0) = (float)ref(nxi,yi,zi,0); I(1,0,1) = (float)ref(nxi,yi,zi,1); - I(1,1,0) = (float)ref(nxi,nyi,zi,0); I(1,1,1) = (float)ref(nxi,nyi,zi,1); - I(0,1,0) = (float)ref(xi,nyi,zi,0); I(0,1,1) = (float)ref(xi,nyi,zi,1); - _cimg_vecalign2d(1,0); _cimg_vecalign2d(1,1); _cimg_vecalign2d(0,1); - } - return c<2?(float)pI->_linear_atXY(dx,dy,0,c):0; - } - }; - - struct _functor4d_streamline3d_oriented { - const CImg& ref; - CImg *pI; - _functor4d_streamline3d_oriented(const CImg& pref):ref(pref),pI(0) { pI = new CImg(2,2,2,3); } - ~_functor4d_streamline3d_oriented() { delete pI; } - float operator()(const float x, const float y, const float z, const unsigned int c) const { -#define _cimg_vecalign3d(i,j,k) if (I(i,j,k,0)*I(0,0,0,0) + I(i,j,k,1)*I(0,0,0,1) + I(i,j,k,2)*I(0,0,0,2)<0) { \ - I(i,j,k,0) = -I(i,j,k,0); I(i,j,k,1) = -I(i,j,k,1); I(i,j,k,2) = -I(i,j,k,2); } - int - xi = (int)x - (x>=0?0:1), nxi = xi + 1, - yi = (int)y - (y>=0?0:1), nyi = yi + 1, - zi = (int)z - (z>=0?0:1), nzi = zi + 1; - const float - dx = x - xi, - dy = y - yi, - dz = z - zi; - if (c==0) { - CImg& I = *pI; - if (xi<0) xi = 0; - if (nxi<0) nxi = 0; - if (xi>=ref.width()) xi = ref.width() - 1; - if (nxi>=ref.width()) nxi = ref.width() - 1; - if (yi<0) yi = 0; - if (nyi<0) nyi = 0; - if (yi>=ref.height()) yi = ref.height() - 1; - if (nyi>=ref.height()) nyi = ref.height() - 1; - if (zi<0) zi = 0; - if (nzi<0) nzi = 0; - if (zi>=ref.depth()) zi = ref.depth() - 1; - if (nzi>=ref.depth()) nzi = ref.depth() - 1; - I(0,0,0,0) = (float)ref(xi,yi,zi,0); I(0,0,0,1) = (float)ref(xi,yi,zi,1); - I(0,0,0,2) = (float)ref(xi,yi,zi,2); I(1,0,0,0) = (float)ref(nxi,yi,zi,0); - I(1,0,0,1) = (float)ref(nxi,yi,zi,1); I(1,0,0,2) = (float)ref(nxi,yi,zi,2); - I(1,1,0,0) = (float)ref(nxi,nyi,zi,0); I(1,1,0,1) = (float)ref(nxi,nyi,zi,1); - I(1,1,0,2) = (float)ref(nxi,nyi,zi,2); I(0,1,0,0) = (float)ref(xi,nyi,zi,0); - I(0,1,0,1) = (float)ref(xi,nyi,zi,1); I(0,1,0,2) = (float)ref(xi,nyi,zi,2); - I(0,0,1,0) = (float)ref(xi,yi,nzi,0); I(0,0,1,1) = (float)ref(xi,yi,nzi,1); - I(0,0,1,2) = (float)ref(xi,yi,nzi,2); I(1,0,1,0) = (float)ref(nxi,yi,nzi,0); - I(1,0,1,1) = (float)ref(nxi,yi,nzi,1); I(1,0,1,2) = (float)ref(nxi,yi,nzi,2); - I(1,1,1,0) = (float)ref(nxi,nyi,nzi,0); I(1,1,1,1) = (float)ref(nxi,nyi,nzi,1); - I(1,1,1,2) = (float)ref(nxi,nyi,nzi,2); I(0,1,1,0) = (float)ref(xi,nyi,nzi,0); - I(0,1,1,1) = (float)ref(xi,nyi,nzi,1); I(0,1,1,2) = (float)ref(xi,nyi,nzi,2); - _cimg_vecalign3d(1,0,0); _cimg_vecalign3d(1,1,0); _cimg_vecalign3d(0,1,0); - _cimg_vecalign3d(0,0,1); _cimg_vecalign3d(1,0,1); _cimg_vecalign3d(1,1,1); _cimg_vecalign3d(0,1,1); - } - return (float)pI->_linear_atXYZ(dx,dy,dz,c); - } - }; - - struct _functor4d_streamline_expr { - _cimg_math_parser *mp; - ~_functor4d_streamline_expr() { mp->end(); delete mp; } - _functor4d_streamline_expr(const char *const expr):mp(0) { - mp = new _cimg_math_parser(expr,"streamline",CImg::const_empty(),0); - } - float operator()(const float x, const float y, const float z, const unsigned int c) const { - return (float)(*mp)(x,y,z,c); - } - }; - - //! Return a shared-memory image referencing a range of pixels of the image instance. - /** - \param x0 X-coordinate of the starting pixel. - \param x1 X-coordinate of the ending pixel. - \param y0 Y-coordinate. - \param z0 Z-coordinate. - \param c0 C-coordinate. - **/ - CImg get_shared_points(const unsigned int x0, const unsigned int x1, - const unsigned int y0=0, const unsigned int z0=0, const unsigned int c0=0) { - const ulongT - beg = (ulongT)offset(x0,y0,z0,c0), - end = (ulongT)offset(x1,y0,z0,c0); - if (beg>end || beg>=size() || end>=size()) - throw CImgArgumentException(_cimg_instance - "get_shared_points(): Invalid request of a shared-memory subset (%u->%u,%u,%u,%u).", - cimg_instance, - x0,x1,y0,z0,c0); - return CImg(_data + beg,x1 - x0 + 1,1,1,1,true); - } - - //! Return a shared-memory image referencing a range of pixels of the image instance \const. - const CImg get_shared_points(const unsigned int x0, const unsigned int x1, - const unsigned int y0=0, const unsigned int z0=0, const unsigned int c0=0) const { - const ulongT - beg = (ulongT)offset(x0,y0,z0,c0), - end = (ulongT)offset(x1,y0,z0,c0); - if (beg>end || beg>=size() || end>=size()) - throw CImgArgumentException(_cimg_instance - "get_shared_points(): Invalid request of a shared-memory subset (%u->%u,%u,%u,%u).", - cimg_instance, - x0,x1,y0,z0,c0); - return CImg(_data + beg,x1 - x0 + 1,1,1,1,true); - } - - //! Return a shared-memory image referencing a range of rows of the image instance. - /** - \param y0 Y-coordinate of the starting row. - \param y1 Y-coordinate of the ending row. - \param z0 Z-coordinate. - \param c0 C-coordinate. - **/ - CImg get_shared_rows(const unsigned int y0, const unsigned int y1, - const unsigned int z0=0, const unsigned int c0=0) { - const ulongT - beg = (ulongT)offset(0,y0,z0,c0), - end = (ulongT)offset(0,y1,z0,c0); - if (beg>end || beg>=size() || end>=size()) - throw CImgArgumentException(_cimg_instance - "get_shared_rows(): Invalid request of a shared-memory subset " - "(0->%u,%u->%u,%u,%u).", - cimg_instance, - _width - 1,y0,y1,z0,c0); - return CImg(_data + beg,_width,y1 - y0 + 1,1,1,true); - } - - //! Return a shared-memory image referencing a range of rows of the image instance \const. - const CImg get_shared_rows(const unsigned int y0, const unsigned int y1, - const unsigned int z0=0, const unsigned int c0=0) const { - const ulongT - beg = (ulongT)offset(0,y0,z0,c0), - end = (ulongT)offset(0,y1,z0,c0); - if (beg>end || beg>=size() || end>=size()) - throw CImgArgumentException(_cimg_instance - "get_shared_rows(): Invalid request of a shared-memory subset " - "(0->%u,%u->%u,%u,%u).", - cimg_instance, - _width - 1,y0,y1,z0,c0); - return CImg(_data + beg,_width,y1 - y0 + 1,1,1,true); - } - - //! Return a shared-memory image referencing one row of the image instance. - /** - \param y0 Y-coordinate. - \param z0 Z-coordinate. - \param c0 C-coordinate. - **/ - CImg get_shared_row(const unsigned int y0, const unsigned int z0=0, const unsigned int c0=0) { - return get_shared_rows(y0,y0,z0,c0); - } - - //! Return a shared-memory image referencing one row of the image instance \const. - const CImg get_shared_row(const unsigned int y0, const unsigned int z0=0, const unsigned int c0=0) const { - return get_shared_rows(y0,y0,z0,c0); - } - - //! Return a shared memory image referencing a range of slices of the image instance. - /** - \param z0 Z-coordinate of the starting slice. - \param z1 Z-coordinate of the ending slice. - \param c0 C-coordinate. - **/ - CImg get_shared_slices(const unsigned int z0, const unsigned int z1, const unsigned int c0=0) { - const ulongT - beg = (ulongT)offset(0,0,z0,c0), - end = (ulongT)offset(0,0,z1,c0); - if (beg>end || beg>=size() || end>=size()) - throw CImgArgumentException(_cimg_instance - "get_shared_slices(): Invalid request of a shared-memory subset " - "(0->%u,0->%u,%u->%u,%u).", - cimg_instance, - _width - 1,_height - 1,z0,z1,c0); - return CImg(_data + beg,_width,_height,z1 - z0 + 1,1,true); - } - - //! Return a shared memory image referencing a range of slices of the image instance \const. - const CImg get_shared_slices(const unsigned int z0, const unsigned int z1, const unsigned int c0=0) const { - const ulongT - beg = (ulongT)offset(0,0,z0,c0), - end = (ulongT)offset(0,0,z1,c0); - if (beg>end || beg>=size() || end>=size()) - throw CImgArgumentException(_cimg_instance - "get_shared_slices(): Invalid request of a shared-memory subset " - "(0->%u,0->%u,%u->%u,%u).", - cimg_instance, - _width - 1,_height - 1,z0,z1,c0); - return CImg(_data + beg,_width,_height,z1 - z0 + 1,1,true); - } - - //! Return a shared-memory image referencing one slice of the image instance. - /** - \param z0 Z-coordinate. - \param c0 C-coordinate. - **/ - CImg get_shared_slice(const unsigned int z0, const unsigned int c0=0) { - return get_shared_slices(z0,z0,c0); - } - - //! Return a shared-memory image referencing one slice of the image instance \const. - const CImg get_shared_slice(const unsigned int z0, const unsigned int c0=0) const { - return get_shared_slices(z0,z0,c0); - } - - //! Return a shared-memory image referencing a range of channels of the image instance. - /** - \param c0 C-coordinate of the starting channel. - \param c1 C-coordinate of the ending channel. - **/ - CImg get_shared_channels(const unsigned int c0, const unsigned int c1) { - const ulongT - beg = (ulongT)offset(0,0,0,c0), - end = (ulongT)offset(0,0,0,c1); - if (beg>end || beg>=size() || end>=size()) - throw CImgArgumentException(_cimg_instance - "get_shared_channels(): Invalid request of a shared-memory subset " - "(0->%u,0->%u,0->%u,%u->%u).", - cimg_instance, - _width - 1,_height - 1,_depth - 1,c0,c1); - return CImg(_data + beg,_width,_height,_depth,c1 - c0 + 1,true); - } - - //! Return a shared-memory image referencing a range of channels of the image instance \const. - const CImg get_shared_channels(const unsigned int c0, const unsigned int c1) const { - const ulongT - beg = (ulongT)offset(0,0,0,c0), - end = (ulongT)offset(0,0,0,c1); - if (beg>end || beg>=size() || end>=size()) - throw CImgArgumentException(_cimg_instance - "get_shared_channels(): Invalid request of a shared-memory subset " - "(0->%u,0->%u,0->%u,%u->%u).", - cimg_instance, - _width - 1,_height - 1,_depth - 1,c0,c1); - return CImg(_data + beg,_width,_height,_depth,c1 - c0 + 1,true); - } - - //! Return a shared-memory image referencing one channel of the image instance. - /** - \param c0 C-coordinate. - **/ - CImg get_shared_channel(const unsigned int c0) { - return get_shared_channels(c0,c0); - } - - //! Return a shared-memory image referencing one channel of the image instance \const. - const CImg get_shared_channel(const unsigned int c0) const { - return get_shared_channels(c0,c0); - } - - //! Return a shared-memory version of the image instance. - CImg get_shared() { - return CImg(_data,_width,_height,_depth,_spectrum,true); - } - - //! Return a shared-memory version of the image instance \const. - const CImg get_shared() const { - return CImg(_data,_width,_height,_depth,_spectrum,true); - } - - //! Split image into a list along specified axis. - /** - \param axis Splitting axis. Can be { 'x' | 'y' | 'z' | 'c' }. - \param nb Number of split parts. - \note - - If \c nb==0, instance image is split into blocs of equal values along the specified axis. - - If \c nb<=0, instance image is split into blocs of -\c nb pixel wide. - - If \c nb>0, instance image is split into \c nb blocs. - **/ - CImgList get_split(const char axis, const int nb=-1) const { - CImgList res; - if (is_empty()) return res; - const char _axis = cimg::lowercase(axis); - - if (nb<0) { // Split by block size - const unsigned int dp = (unsigned int)(nb?-nb:1); - switch (_axis) { - case 'x': { - if (_width>dp) { - res.assign(_width/dp + (_width%dp?1:0),1,1); - const unsigned int pe = _width - dp; - cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*128 && - _height*_depth*_spectrum>=128)) - for (int p = 0; p<(int)pe; p+=dp) - get_crop(p,0,0,0,p + dp - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res[p/dp]); - get_crop((res._width - 1)*dp,0,0,0,_width - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res.back()); - } else res.assign(*this); - } break; - case 'y': { - if (_height>dp) { - res.assign(_height/dp + (_height%dp?1:0),1,1); - const unsigned int pe = _height - dp; - cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*128 && - _width*_depth*_spectrum>=128)) - for (int p = 0; p<(int)pe; p+=dp) - get_crop(0,p,0,0,_width - 1,p + dp - 1,_depth - 1,_spectrum - 1).move_to(res[p/dp]); - get_crop(0,(res._width - 1)*dp,0,0,_width - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res.back()); - } else res.assign(*this); - } break; - case 'z': { - if (_depth>dp) { - res.assign(_depth/dp + (_depth%dp?1:0),1,1); - const unsigned int pe = _depth - dp; - cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*128 && - _width*_height*_spectrum>=128)) - for (int p = 0; p<(int)pe; p+=dp) - get_crop(0,0,p,0,_width - 1,_height - 1,p + dp - 1,_spectrum - 1).move_to(res[p/dp]); - get_crop(0,0,(res._width - 1)*dp,0,_width - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res.back()); - } else res.assign(*this); - } break; - case 'c' : { - if (_spectrum>dp) { - res.assign(_spectrum/dp + (_spectrum%dp?1:0),1,1); - const unsigned int pe = _spectrum - dp; - cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*128 && - _width*_height*_depth>=128)) - for (int p = 0; p<(int)pe; p+=dp) - get_crop(0,0,0,p,_width - 1,_height - 1,_depth - 1,p + dp - 1).move_to(res[p/dp]); - get_crop(0,0,0,(res._width - 1)*dp,_width - 1,_height - 1,_depth - 1,_spectrum - 1).move_to(res.back()); - } else res.assign(*this); - } - } - } else if (nb>0) { // Split by number of (non-homogeneous) blocs - const unsigned int siz = _axis=='x'?_width:_axis=='y'?_height:_axis=='z'?_depth:_axis=='c'?_spectrum:0; - if ((unsigned int)nb>siz) - throw CImgArgumentException(_cimg_instance - "get_split(): Instance cannot be split along %c-axis into %u blocs.", - cimg_instance, - axis,nb); - if (nb==1) res.assign(*this); - else { - int err = (int)siz; - unsigned int _p = 0; - switch (_axis) { - case 'x' : { - cimg_forX(*this,p) if ((err-=nb)<=0) { - get_crop(_p,0,0,0,p,_height - 1,_depth - 1,_spectrum - 1).move_to(res); - err+=(int)siz; - _p = p + 1U; - } - } break; - case 'y' : { - cimg_forY(*this,p) if ((err-=nb)<=0) { - get_crop(0,_p,0,0,_width - 1,p,_depth - 1,_spectrum - 1).move_to(res); - err+=(int)siz; - _p = p + 1U; - } - } break; - case 'z' : { - cimg_forZ(*this,p) if ((err-=nb)<=0) { - get_crop(0,0,_p,0,_width - 1,_height - 1,p,_spectrum - 1).move_to(res); - err+=(int)siz; - _p = p + 1U; - } - } break; - case 'c' : { - cimg_forC(*this,p) if ((err-=nb)<=0) { - get_crop(0,0,0,_p,_width - 1,_height - 1,_depth - 1,p).move_to(res); - err+=(int)siz; - _p = p + 1U; - } - } - } - } - } else { // Split by equal values according to specified axis - T current = *_data; - switch (_axis) { - case 'x' : { - int i0 = 0; - cimg_forX(*this,i) - if ((*this)(i)!=current) { get_columns(i0,i - 1).move_to(res); i0 = i; current = (*this)(i); } - get_columns(i0,width() - 1).move_to(res); - } break; - case 'y' : { - int i0 = 0; - cimg_forY(*this,i) - if ((*this)(0,i)!=current) { get_rows(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,i); } - get_rows(i0,height() - 1).move_to(res); - } break; - case 'z' : { - int i0 = 0; - cimg_forZ(*this,i) - if ((*this)(0,0,i)!=current) { get_slices(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,0,i); } - get_slices(i0,depth() - 1).move_to(res); - } break; - case 'c' : { - int i0 = 0; - cimg_forC(*this,i) - if ((*this)(0,0,0,i)!=current) { get_channels(i0,i - 1).move_to(res); i0 = i; current = (*this)(0,0,0,i); } - get_channels(i0,spectrum() - 1).move_to(res); - } break; - default : { - longT i0 = 0; - cimg_foroff(*this,i) - if ((*this)[i]!=current) { - CImg(_data + i0,1,(unsigned int)(i - i0)).move_to(res); - i0 = (longT)i; current = (*this)[i]; - } - CImg(_data + i0,1,(unsigned int)(size() - i0)).move_to(res); - } - } - } - return res; - } - - //! Split image into a list of sub-images, according to a specified splitting value sequence and optionally axis. - /** - \param values Splitting value sequence. - \param axis Axis along which the splitting is performed. Can be '0' to ignore axis. - \param keep_values Tells if the splitting sequence must be kept in the split blocs. - **/ - template - CImgList get_split(const CImg& values, const char axis=0, const bool keep_values=true) const { - typedef _cimg_Tt Tt; - - CImgList res; - if (is_empty()) return res; - const ulongT vsiz = values.size(); - const char _axis = cimg::lowercase(axis); - if (!vsiz) return CImgList(*this); - if (vsiz==1) { // Split according to a single value - const T value = (T)*values; - switch (_axis) { - case 'x' : { - unsigned int i0 = 0, i = 0; - do { - while (i<_width && (*this)(i)==value) ++i; - if (i>i0) { if (keep_values) get_columns(i0,i - 1).move_to(res); i0 = i; } - while (i<_width && (*this)(i)!=value) ++i; - if (i>i0) { get_columns(i0,i - 1).move_to(res); i0 = i; } - } while (i<_width); - } break; - case 'y' : { - unsigned int i0 = 0, i = 0; - do { - while (i<_height && (*this)(0,i)==value) ++i; - if (i>i0) { if (keep_values) get_rows(i0,i - 1).move_to(res); i0 = i; } - while (i<_height && (*this)(0,i)!=value) ++i; - if (i>i0) { get_rows(i0,i - 1).move_to(res); i0 = i; } - } while (i<_height); - } break; - case 'z' : { - unsigned int i0 = 0, i = 0; - do { - while (i<_depth && (*this)(0,0,i)==value) ++i; - if (i>i0) { if (keep_values) get_slices(i0,i - 1).move_to(res); i0 = i; } - while (i<_depth && (*this)(0,0,i)!=value) ++i; - if (i>i0) { get_slices(i0,i - 1).move_to(res); i0 = i; } - } while (i<_depth); - } break; - case 'c' : { - unsigned int i0 = 0, i = 0; - do { - while (i<_spectrum && (*this)(0,0,0,i)==value) ++i; - if (i>i0) { if (keep_values) get_channels(i0,i - 1).move_to(res); i0 = i; } - while (i<_spectrum && (*this)(0,0,0,i)!=value) ++i; - if (i>i0) { get_channels(i0,i - 1).move_to(res); i0 = i; } - } while (i<_spectrum); - } break; - default : { - const ulongT siz = size(); - ulongT i0 = 0, i = 0; - do { - while (ii0) { - if (keep_values) CImg(_data + i0,1,(unsigned int)(i - i0)).move_to(res); - i0 = i; - } - while (ii0) { CImg(_data + i0,1,(unsigned int)(i - i0)).move_to(res); i0 = i; } - } while (i=vsiz) j = 0; } - i-=(unsigned int)j; - if (i>i1) { - if (i1>i0) get_columns(i0,i1 - 1).move_to(res); - if (keep_values) get_columns(i1,i - 1).move_to(res); - i0 = i; - } else ++i; - } else ++i; - } while (i<_width); - if (i0<_width) get_columns(i0,width() - 1).move_to(res); - } break; - case 'y' : { - unsigned int i0 = 0, i1 = 0, i = 0; - do { - if ((Tt)(*this)(0,i)==(Tt)*values) { - i1 = i; j = 0; - while (i<_height && (Tt)(*this)(0,i)==(Tt)values[j]) { ++i; if (++j>=vsiz) j = 0; } - i-=(unsigned int)j; - if (i>i1) { - if (i1>i0) get_rows(i0,i1 - 1).move_to(res); - if (keep_values) get_rows(i1,i - 1).move_to(res); - i0 = i; - } else ++i; - } else ++i; - } while (i<_height); - if (i0<_height) get_rows(i0,height() - 1).move_to(res); - } break; - case 'z' : { - unsigned int i0 = 0, i1 = 0, i = 0; - do { - if ((Tt)(*this)(0,0,i)==(Tt)*values) { - i1 = i; j = 0; - while (i<_depth && (Tt)(*this)(0,0,i)==(Tt)values[j]) { ++i; if (++j>=vsiz) j = 0; } - i-=(unsigned int)j; - if (i>i1) { - if (i1>i0) get_slices(i0,i1 - 1).move_to(res); - if (keep_values) get_slices(i1,i - 1).move_to(res); - i0 = i; - } else ++i; - } else ++i; - } while (i<_depth); - if (i0<_depth) get_slices(i0,depth() - 1).move_to(res); - } break; - case 'c' : { - unsigned int i0 = 0, i1 = 0, i = 0; - do { - if ((Tt)(*this)(0,0,0,i)==(Tt)*values) { - i1 = i; j = 0; - while (i<_spectrum && (Tt)(*this)(0,0,0,i)==(Tt)values[j]) { ++i; if (++j>=vsiz) j = 0; } - i-=(unsigned int)j; - if (i>i1) { - if (i1>i0) get_channels(i0,i1 - 1).move_to(res); - if (keep_values) get_channels(i1,i - 1).move_to(res); - i0 = i; - } else ++i; - } else ++i; - } while (i<_spectrum); - if (i0<_spectrum) get_channels(i0,spectrum() - 1).move_to(res); - } break; - default : { - const ulongT siz = size(); - ulongT i0 = 0, i1 = 0, i = 0; - do { - if ((Tt)(*this)[i]==(Tt)*values) { - i1 = i; j = 0; - while (i=vsiz) j = 0; } - i-=(unsigned int)j; - if (i>i1) { - if (i1>i0) CImg(_data + i0,1,(unsigned int)(i1 - i0)).move_to(res); - if (keep_values) CImg(_data + i1,1,(unsigned int)(i - i1)).move_to(res); - i0 = i; - } else ++i; - } else ++i; - } while (i(_data + i0,1,(unsigned int)(siz - i0)).move_to(res); - } break; - } - } - return res; - } - - //! Append two images along specified axis. - /** - \param img Image to append with instance image. - \param axis Appending axis. Can be { 'x' | 'y' | 'z' | 'c' }. - \param align Append alignment in \c [0,1]. - **/ - template - CImg& append(const CImg& img, const char axis='x', const float align=0) { - if (is_empty()) return assign(img,false); - if (!img) return *this; - return CImgList(*this,true).insert(img).get_append(axis,align).move_to(*this); - } - - //! Append two images along specified axis \specialization. - CImg& append(const CImg& img, const char axis='x', const float align=0) { - if (is_empty()) return assign(img,false); - if (!img) return *this; - return CImgList(*this,img,true).get_append(axis,align).move_to(*this); - } - - //! Append two images along specified axis \const. - template - CImg<_cimg_Tt> get_append(const CImg& img, const char axis='x', const float align=0) const { - if (is_empty()) return +img; - if (!img) return +*this; - return CImgList<_cimg_Tt>(*this,true).insert(img).get_append(axis,align); - } - - //! Append two images along specified axis \specialization. - CImg get_append(const CImg& img, const char axis='x', const float align=0) const { - if (is_empty()) return +img; - if (!img) return +*this; - return CImgList(*this,img,true).get_append(axis,align); - } - - //@} - //--------------------------------------- - // - //! \name Filtering / Transforms - //@{ - //--------------------------------------- - - //! Correlate image by a kernel. - /** - \param kernel = the correlation kernel. - \param boundary_conditions Boundary condition. Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - \param is_normalized = enable local normalization. - \param channel_mode Channel processing mode. - Can be { 0=all | 1=one for one (default) | 2=partial sum | 3=full sum }. - \param xcenter X-coordinate of the kernel center (~0U>>1 means 'centered'). - \param ycenter Y-coordinate of the kernel center (~0U>>1 means 'centered'). - \param zcenter Z-coordinate of the kernel center (~0U>>1 means 'centered'). - \param xstart Starting X-coordinate of the instance image. - \param ystart Starting Y-coordinate of the instance image. - \param zstart Starting Z-coordinate of the instance image. - \param xend Ending X-coordinate of the instance image. - \param yend Ending Y-coordinate of the instance image. - \param zend Ending Z-coordinate of the instance image. - \param xstride Stride along the X-axis. - \param ystride Stride along the Y-axis. - \param zstride Stride along the Z-axis. - \param xdilation Dilation along the X-axis. - \param ydilation Dilation along the Y-axis. - \param zdilation Dilation along the Z-axis. - \param interpolation_type Can be { false=nearest | true=linear }. - \note - - The correlation of the image instance \p *this by the kernel \p kernel is defined to be: - res(x,y,z) = sum_{i,j,k} (*this)(\alpha_x\;x + \beta_x\;(i - c_x),\alpha_y\;y + \beta_y\;(j - - c_y),\alpha_z\;z + \beta_z\;(k - c_z))*kernel(i,j,k). - **/ - template - CImg& correlate(const CImg& kernel, const unsigned int boundary_conditions=1, - const bool is_normalized=false, const unsigned int channel_mode=1, - const int xcenter=(int)(~0U>>1), - const int ycenter=(int)(~0U>>1), - const int zcenter=(int)(~0U>>1), - const int xstart=0, - const int ystart=0, - const int zstart=0, - const int xend=(int)(~0U>>1), - const int yend=(int)(~0U>>1), - const int zend=(int)(~0U>>1), - const float xstride=1, const float ystride=1, const float zstride=1, - const float xdilation=1, const float ydilation=1, const float zdilation=1, - const bool interpolation_type=false) { - if (is_empty() || !kernel) return *this; - return get_correlate(kernel,boundary_conditions,is_normalized,channel_mode, - xcenter,ycenter,zcenter,xstart,ystart,zstart,xend,yend,zend, - xstride,ystride,zstride,xdilation,ydilation,zdilation, - interpolation_type).move_to(*this); - } - - template - CImg<_cimg_Ttfloat> get_correlate(const CImg& kernel, const unsigned int boundary_conditions=1, - const bool is_normalized=false, const unsigned int channel_mode=1, - const int xcenter=(int)(~0U>>1), - const int ycenter=(int)(~0U>>1), - const int zcenter=(int)(~0U>>1), - const int xstart=0, - const int ystart=0, - const int zstart=0, - const int xend=(int)(~0U>>1), - const int yend=(int)(~0U>>1), - const int zend=(int)(~0U>>1), - const float xstride=1, const float ystride=1, const float zstride=1, - const float xdilation=1, const float ydilation=1, const float zdilation=1, - const bool interpolation_type=false) const { - return _correlate(kernel,boundary_conditions,is_normalized,channel_mode, - xcenter,ycenter,zcenter,xstart,ystart,zstart,xend,yend,zend, - xstride,ystride,zstride,xdilation,ydilation,zdilation, - interpolation_type,false); - } - - //! Correlate image by a kernel \newinstance. - template - CImg<_cimg_Ttfloat> _correlate(const CImg& kernel, const unsigned int boundary_conditions, - const bool is_normalized, const unsigned int channel_mode, - const int xcenter, const int ycenter, const int zcenter, - const int xstart, const int ystart, const int zstart, - const int xend, const int yend, const int zend, - const float xstride, const float ystride, const float zstride, - const float xdilation, const float ydilation, const float zdilation, - const bool interpolation_type, const bool is_convolve) const { - typedef _cimg_Ttfloat Ttfloat; - CImg res; - _cimg_abort_init_openmp; - cimg_abort_init; - - if (xstart>xend || ystart>yend || zstart>zend) - throw CImgArgumentException(_cimg_instance - "%s(): Invalid xyz-start/end arguments (start = (%d,%d,%d), end = (%d,%d,%d)).", - cimg_instance, - is_convolve?"convolve":"correlate", - xstart,ystart,zstart,xend,yend,zend); - if (xstride<=0 || ystride<=0 || zstride<=0) - throw CImgArgumentException(_cimg_instance - "%s(): Invalid stride arguments (%g,%g,%g).", - cimg_instance, - is_convolve?"convolve":"correlate", - xstride,ystride,zstride); - - if (is_empty() || !kernel) return *this; - int - _xcenter = xcenter==(int)(~0U>>1)?kernel.width()/2 - 1 + (kernel.width()%2): - std::min(xcenter,kernel.width() - 1), - _ycenter = ycenter==(int)(~0U>>1)?kernel.height()/2 - 1 + (kernel.height()%2): - std::min(ycenter,kernel.height() - 1), - _zcenter = zcenter==(int)(~0U>>1)?kernel.depth()/2 - 1 + (kernel.depth()%2): - std::min(zcenter,kernel.depth() - 1); - float _xdilation = xdilation, _ydilation = ydilation, _zdilation = zdilation; - - CImg _kernel; - if (is_convolve) { // If convolution, go back to correlation - if (kernel.size()/kernel.spectrum()<=27) { - _kernel = CImg(kernel._data,kernel.size()/kernel._spectrum,1,1,kernel._spectrum,true). - get_mirror('x').resize(kernel,-1); - _xcenter = kernel.width() - 1 - _xcenter; - _ycenter = kernel.height() - 1 - _ycenter; - _zcenter = kernel.depth() - _zcenter - 1; - } else { _kernel = kernel.get_shared(); _xdilation*=-1; _ydilation*=-1; _zdilation*=-1; } - } else _kernel = kernel.get_shared(); - - const int - _xend = xend==(int)(~0U>>1)?width() - 1:xend, - _yend = yend==(int)(~0U>>1)?height() - 1:yend, - _zend = zend==(int)(~0U>>1)?depth() - 1:zend, - i_xstride = (int)cimg::round(xstride), - i_ystride = (int)cimg::round(ystride), - i_zstride = (int)cimg::round(zstride), - i_xdilation = (int)cimg::round(_xdilation), - i_ydilation = (int)cimg::round(_ydilation), - i_zdilation = (int)cimg::round(_zdilation), - res_width = _xend - xstart + 1, - res_height = _yend - ystart + 1, - res_depth = _zend + zstart + 1, - smin = std::min(spectrum(),_kernel.spectrum()), - smax = std::max(spectrum(),_kernel.spectrum()), - cend = !channel_mode?spectrum()*_kernel.spectrum():smax; - const ulongT - res_wh = (ulongT)res_width*res_height, - res_whd = res_wh*res_depth, - res_siz = res_whd*res._spectrum; - - if (!res_whd) return CImg(); - res.assign(res_width,res_height,res_depth, - !channel_mode?_spectrum*_kernel._spectrum: - channel_mode==1?smax: - channel_mode==2?(int)std::ceil((float)smax/smin):1); - if (channel_mode>=2) res.fill(0); - - const bool -#if cimg_use_openmp==1 - is_master_thread = !omp_get_thread_num(), -#else - is_master_thread = true, -#endif - is_outer_parallel = is_master_thread && - (res._spectrum>=cimg::nb_cpus() || res_siz<=(cimg_openmp_sizefactor)*32768), - is_inner_parallel = is_master_thread && - (!is_outer_parallel && res_whd>=(cimg_openmp_sizefactor)*32768), - is_int_stride_dilation = xstride==i_xstride && ystride==i_ystride && zstride==i_zstride && - _xdilation==i_xdilation && _ydilation==i_ydilation && _zdilation==i_zdilation; - cimg::unused(is_inner_parallel,is_outer_parallel); - const int - w = width(), h = height(), d = depth(), - w1 = w - 1, h1 = h - 1, d1 = d - 1, - w2 = 2*w, h2 = 2*h, d2 = 2*d; - const ulongT wh = (ulongT)w*h, whd = wh*d; - - // Reshape kernel to enable optimizations for a few cases. - if (boundary_conditions==1 && - _kernel._width>1 && _kernel._height>1 && - ((_kernel._depth==1 && _kernel._width<=5 && _kernel._height<=5) || - (_kernel._depth<=3 && _kernel._width<=3 && _kernel._height<=3)) && - xstart>=0 && ystart>=0 && zstart>=0 && - _xend=0 && i_ydilation>=0 && i_zdilation>=0) { - const unsigned int M = cimg::max(_kernel._width,_kernel._height,_kernel._depth); - _kernel.assign(_kernel.get_resize(M + 1 - (M%2),M + 1 - (M%2),_kernel._depth>1?M + 1 - (M%2):1,-100, - 0,0, - 1,1,1),false); - _xcenter = _ycenter = (int)M/2; - if (_kernel._depth>1) _ycenter = (int)M/2; - } - - // Optimized version for a few particular cases (3x3, 5x5 and 3x3x3 kernels, with a few other conditions). - if (boundary_conditions==1 && - _kernel._width==_kernel._height && - ((_kernel._depth==1 && (_kernel._width==3 || _kernel._width==5)) || - (_kernel._depth==_kernel._width && _kernel._width==3)) && - _xcenter==_kernel.width()/2 && _ycenter==_kernel.height()/2 && _zcenter==_kernel.depth()/2 && - xstart>=0 && ystart>=0 && zstart>=0 && - _xend=0 && i_ydilation>=0 && i_zdilation>=0) { - - switch (_kernel._depth) { - case 3 : { // 3x3x3 centered kernel - cimg_pragma_openmp(parallel for cimg_openmp_if(is_outer_parallel)) - for (int c = 0; c I = get_shared_channel(c%_spectrum); - const CImg K = _kernel.get_shared_channel(!channel_mode?c/_spectrum:c%_kernel._spectrum); - CImg _resu = channel_mode<=1?res.get_shared_channel(c): - CImg(res.width(),res.height(),res.depth(),1); - if (is_normalized) { - const Ttfloat M = (Ttfloat)K.magnitude(2), M2 = M*M; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(is_inner_parallel)) - cimg_forXYZ(res,X,Y,Z) { - const int - x = xstart + X, y = ystart + Y, z = zstart + Z, - px = x - i_xdilation>0?x - i_xdilation:0, nx = x + i_xdilation0?y - i_ydilation:0, ny = y + i_ydilation0?z - i_zdilation:0, nz = z + i_zdilation0?x - i_xdilation:0, nx = x + i_xdilation0?y - i_ydilation:0, ny = y + i_ydilation0?z - i_zdilation:0, nz = z + i_zdilation I = get_shared_channel(c%_spectrum); - const CImg K = _kernel.get_shared_channel(!channel_mode?c/_spectrum:c%_kernel._spectrum); - CImg _resu = channel_mode<=1?res.get_shared_channel(c): - CImg(res.width(),res.height(),res.depth(),1); - if (is_normalized) { - const Ttfloat M = (Ttfloat)K.magnitude(2), M2 = M*M; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(is_inner_parallel)) - cimg_forXYZ(res,X,Y,z) { - const int - x = xstart + X, y = ystart + Y, - px = x - i_xdilation>0?x - i_xdilation:0, bx = px - i_xdilation>0?px - i_xdilation:0, - nx = x + i_xdilation0?y - i_ydilation:0, by = py - i_ydilation>0?py - i_ydilation:0, - ny = y + i_ydilation0?x - i_xdilation:0, bx = px - i_xdilation>0?px - i_xdilation:0, - nx = x + i_xdilation0?y - i_ydilation:0, by = py - i_ydilation>0?py - i_ydilation:0, - ny = y + i_ydilation I = get_shared_channel(c%_spectrum); - const CImg K = _kernel.get_shared_channel(!channel_mode?c/_spectrum:c%_kernel._spectrum); - CImg _resu = channel_mode<=1?res.get_shared_channel(c): - CImg(res.width(),res.height(),res.depth(),1); - if (is_normalized) { - const Ttfloat M = (Ttfloat)K.magnitude(2), M2 = M*M; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(is_inner_parallel)) - cimg_forXYZ(res,X,Y,z) { - const int - x = xstart + X, y = ystart + Y, - px = x - i_xdilation>0?x - i_xdilation:0, nx = x + i_xdilation0?y - i_ydilation:0, ny = y + i_ydilation0?x - i_xdilation:0, nx = x + i_xdilation0?y - i_ydilation:0, ny = y + i_ydilation=0 && ystart>=0 && zstart>=0 && - _xend I = get_crop(xstart,ystart,zstart,c%_spectrum,_xend,_yend,_zend,c%_spectrum)*=valK; - if (is_normalized) I.sign(); - switch (channel_mode) { - case 0 : // All - case 1 : // One for one - res.get_shared_channel(c) = I; - break; - case 2 : // Partial sum - cimg_pragma_openmp(critical(_correlate)) res.get_shared_channel(c/smin)+=I; - break; - case 3 : // Full sum - cimg_pragma_openmp(critical(_correlate)) res.get_shared_channel(0)+=I; - break; - } - } - } else { // Generic version - cimg_pragma_openmp(parallel for cimg_openmp_if(is_outer_parallel)) - for (int c = 0; c I = get_shared_channel(c%_spectrum); - const CImg K = _kernel.get_shared_channel(!channel_mode?c/_spectrum:c%_kernel._spectrum); - CImg _resu = channel_mode<=1?res.get_shared_channel(c): - CImg(res.width(),res.height(),res.depth(),1); - Ttfloat M = 0, M2 = 0; - if (is_normalized) { M = (Ttfloat)K.magnitude(2); M2 = cimg::sqr(M); } - -#define _cimg_correlate_x_int const int ix = xstart + i_xstride*x + i_xdilation*(p - _xcenter) -#define _cimg_correlate_y_int const int iy = ystart + i_ystride*y + i_ydilation*(q - _ycenter) -#define _cimg_correlate_z_int const int iz = zstart + i_zstride*z + i_zdilation*(r - _zcenter) -#define _cimg_correlate_x_float const float ix = xstart + xstride*x + _xdilation*(p - _xcenter) -#define _cimg_correlate_y_float const float iy = ystart + ystride*y + _ydilation*(q - _ycenter) -#define _cimg_correlate_z_float const float iz = zstart + zstride*z + _zdilation*(r - _zcenter) - -#define _cimg_correlate_x_int_dirichlet const bool is_in_x = ix>=0 && ix=0 && iy=0 && iz - CImg& convolve(const CImg& kernel, const unsigned int boundary_conditions=1, - const bool is_normalized=false, const unsigned int channel_mode=1, - const int xcenter=(int)(~0U>>1), - const int ycenter=(int)(~0U>>1), - const int zcenter=(int)(~0U>>1), - const int xstart=0, - const int ystart=0, - const int zstart=0, - const int xend=(int)(~0U>>1), - const int yend=(int)(~0U>>1), - const int zend=(int)(~0U>>1), - const float xstride=1, const float ystride=1, const float zstride=1, - const float xdilation=1, const float ydilation=1, const float zdilation=1, - const bool interpolation_type=false) { - if (is_empty() || !kernel) return *this; - return get_convolve(kernel,boundary_conditions,is_normalized,channel_mode, - xcenter,ycenter,zcenter,xstart,ystart,zstart,xend,yend,zend, - xstride,ystride,zstride,xdilation,ydilation,zdilation, - interpolation_type).move_to(*this); - } - - //! Convolve image by a kernel \newinstance. - template - CImg<_cimg_Ttfloat> get_convolve(const CImg& kernel, const unsigned int boundary_conditions=1, - const bool is_normalized=false, const unsigned int channel_mode=1, - const int xcenter=(int)(~0U>>1), - const int ycenter=(int)(~0U>>1), - const int zcenter=(int)(~0U>>1), - const int xstart=0, - const int ystart=0, - const int zstart=0, - const int xend=(int)(~0U>>1), - const int yend=(int)(~0U>>1), - const int zend=(int)(~0U>>1), - const float xstride=1, const float ystride=1, const float zstride=1, - const float xdilation=1, const float ydilation=1, const float zdilation=1, - const bool interpolation_type=false) const { - return _correlate(kernel,boundary_conditions,is_normalized,channel_mode, - xcenter,ycenter,zcenter,xstart,ystart,zstart,xend,yend,zend, - xstride,ystride,zstride,xdilation,ydilation,zdilation, - interpolation_type,true); - } - - //! Cumulate image values, optionally along specified axis. - /** - \param axis Cumulation axis. Set it to 0 to cumulate all values globally without taking axes into account. - **/ - CImg& cumulate(const char axis=0) { - switch (cimg::lowercase(axis)) { - case 'x' : - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 && - _height*_depth*_spectrum>=16)) - cimg_forYZC(*this,y,z,c) { - T *ptrd = data(0,y,z,c); - Tlong cumul = (Tlong)0; - cimg_forX(*this,x) { cumul+=(Tlong)*ptrd; *(ptrd++) = (T)cumul; } - } - break; - case 'y' : { - const ulongT w = (ulongT)_width; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_height>=(cimg_openmp_sizefactor)*512 && - _width*_depth*_spectrum>=16)) - cimg_forXZC(*this,x,z,c) { - T *ptrd = data(x,0,z,c); - Tlong cumul = (Tlong)0; - cimg_forY(*this,y) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; ptrd+=w; } - } - } break; - case 'z' : { - const ulongT wh = (ulongT)_width*_height; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_depth>=(cimg_openmp_sizefactor)*512 && - _width*_depth*_spectrum>=16)) - cimg_forXYC(*this,x,y,c) { - T *ptrd = data(x,y,0,c); - Tlong cumul = (Tlong)0; - cimg_forZ(*this,z) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; ptrd+=wh; } - } - } break; - case 'c' : { - const ulongT whd = (ulongT)_width*_height*_depth; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(_spectrum>=(cimg_openmp_sizefactor)*512 && _width*_height*_depth>=16)) - cimg_forXYZ(*this,x,y,z) { - T *ptrd = data(x,y,z,0); - Tlong cumul = (Tlong)0; - cimg_forC(*this,c) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; ptrd+=whd; } - } - } break; - default : { // Global cumulation - Tlong cumul = (Tlong)0; - cimg_for(*this,ptrd,T) { cumul+=(Tlong)*ptrd; *ptrd = (T)cumul; } - } - } - return *this; - } - - //! Cumulate image values, optionally along specified axis \newinstance. - CImg get_cumulate(const char axis=0) const { - return CImg(*this,false).cumulate(axis); - } - - //! Cumulate image values, along specified axes. - /** - \param axes Cumulation axes, as a C-string. - \note \c axes may contains multiple characters, e.g. \c "xyz" - **/ - CImg& cumulate(const char *const axes) { - for (const char *s = axes; *s; ++s) cumulate(*s); - return *this; - } - - //! Cumulate image values, along specified axes \newinstance. - CImg get_cumulate(const char *const axes) const { - return CImg(*this,false).cumulate(axes); - } - - //! Erode image by a structuring element. - /** - \param kernel Structuring element. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - \param is_real Do the erosion in real (a.k.a 'non-flat') mode (\c true) rather than binary mode (\c false). - **/ - template - CImg& erode(const CImg& kernel, const unsigned int boundary_conditions=1, - const bool is_real=false) { - if (is_empty() || !kernel) return *this; - return get_erode(kernel,boundary_conditions,is_real).move_to(*this); - } - - //! Erode image by a structuring element \newinstance. - template - CImg<_cimg_Tt> get_erode(const CImg& kernel, const unsigned int boundary_conditions=1, - const bool is_real=false) const { - if (is_empty() || !kernel) return *this; - if (!is_real && kernel==0) return CImg(width(),height(),depth(),spectrum(),0); - typedef _cimg_Tt Tt; - CImg res(_width,_height,_depth,std::max(_spectrum,kernel._spectrum)); - const int - mx2 = kernel.width()/2, my2 = kernel.height()/2, mz2 = kernel.depth()/2, - mx1 = kernel.width() - mx2 - 1, my1 = kernel.height() - my2 - 1, mz1 = kernel.depth() - mz2 - 1, - mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2, - w2 = 2*width(), h2 = 2*height(), d2 = 2*depth(); - const bool - is_inner_parallel = _width*_height*_depth>=(cimg_openmp_sizefactor)*32768, - is_outer_parallel = res.size()>=(cimg_openmp_sizefactor)*32768; - cimg::unused(is_inner_parallel,is_outer_parallel); - _cimg_abort_init_openmp; - cimg_abort_init; - cimg_pragma_openmp(parallel for cimg_openmp_if(!is_inner_parallel && is_outer_parallel)) - cimg_forC(res,c) _cimg_abort_try_openmp { - cimg_abort_test; - const CImg img = get_shared_channel(c%_spectrum); - const CImg K = kernel.get_shared_channel(c%kernel._spectrum); - if (is_real) { // Real erosion - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(is_inner_parallel)) - for (int z = mz1; z::max(); - for (int zm = -mz1; zm<=mz2; ++zm) - for (int ym = -my1; ym<=my2; ++ym) - for (int xm = -mx1; xm<=mx2; ++xm) { - const t mval = K(mx1 + xm,my1 + ym,mz1 + zm); - const Tt cval = (Tt)(img(x + xm,y + ym,z + zm) - mval); - if (cval=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { - Tt min_val = cimg::type::max(); - for (int zm = -mz1; zm<=mz2; ++zm) - for (int ym = -my1; ym<=my2; ++ym) - for (int xm = -mx1; xm<=mx2; ++xm) { - const t mval = K(mx1 + xm,my1 + ym,mz1 + zm); - Tt cval; - switch (boundary_conditions) { - case 0 : cval = (Tt)(img.atXYZ(x + xm,y + ym,z + zm,0,(T)0) - mval); break; - case 1 : cval = (Tt)(img._atXYZ(x + xm,y + ym,z + zm) - mval); break; - case 2 : { - const int - nx = cimg::mod(x + xm,width()), - ny = cimg::mod(y + ym,height()), - nz = cimg::mod(z + zm,depth()); - cval = img(nx,ny,nz) - mval; - } break; - default : { - const int - tx = cimg::mod(x + xm,w2), - ty = cimg::mod(y + ym,h2), - tz = cimg::mod(z + zm,d2), - nx = tx::max(); - for (int zm = -mz1; zm<=mz2; ++zm) - for (int ym = -my1; ym<=my2; ++ym) - for (int xm = -mx1; xm<=mx2; ++xm) - if (K(mx1 + xm,my1 + ym,mz1 + zm)) { - const Tt cval = (Tt)img(x + xm,y + ym,z + zm); - if (cval=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { - Tt min_val = cimg::type::max(); - for (int zm = -mz1; zm<=mz2; ++zm) - for (int ym = -my1; ym<=my2; ++ym) - for (int xm = -mx1; xm<=mx2; ++xm) { - if (K(mx1 + xm,my1 + ym,mz1 + zm)) { - Tt cval; - switch (boundary_conditions) { - case 0 : cval = (Tt)img.atXYZ(x + xm,y + ym,z + zm,0,(T)0); break; - case 1 : cval = (Tt)img._atXYZ(x + xm,y + ym,z + zm); break; - case 2 : { - const int - nx = cimg::mod(x + xm,width()), - ny = cimg::mod(y + ym,height()), - nz = cimg::mod(z + zm,depth()); - cval = img(nx,ny,nz); - } break; - default : { - const int - tx = cimg::mod(x + xm,w2), - ty = cimg::mod(y + ym,h2), - tz = cimg::mod(z + zm,d2), - nx = tx& erode(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) { - if (is_empty() || (sx<=1 && sy<=1 && sz<=1)) return *this; - if (sx>1 && _width>1) { // Along X-axis - const int L = width(), off = 1, s = (int)sx, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; - CImg buf(L); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) firstprivate(buf) if (size()>524288)) - cimg_forYZC(*this,y,z,c) { - T *const ptrdb = buf._data, *ptrd = buf._data, *const ptrde = buf._data + L - 1; - const T *const ptrsb = data(0,y,z,c), *ptrs = ptrsb, *const ptrse = ptrs + (ulongT)L*off - off; - T cur = *ptrs; ptrs+=off; bool is_first = true; - for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) { - const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; }} - *(ptrd++) = cur; - if (ptrs>=ptrse) { - T *pd = data(0,y,z,c); cur = std::min(cur,*ptrse); cimg_forX(buf,k) { *pd = cur; pd+=off; } - } else { - for (int p = s1; p>0 && ptrd<=ptrde; --p) { - const T val = *ptrs; if (ptrs0; --p) { - const T val = *ptrs; ptrs+=off; - if (is_first) { - const T *nptrs = ptrs - off; cur = val; - for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval0 && ptrs>=ptrsb; --p) { - const T val = *ptrs; ptrs-=off; if (val0 && ptrd>=ptrdb; --p) { - const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val1 && _height>1) { // Along Y-axis - const int L = height(), off = width(), s = (int)sy, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, - s2 = _s2>L?L:_s2; - CImg buf(L); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) firstprivate(buf) if (size()>524288)) - cimg_forXZC(*this,x,z,c) { - T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; - const T *const ptrsb = data(x,0,z,c), *ptrs = ptrsb, *const ptrse = ptrs + (ulongT)L*off - off; - T cur = *ptrs; ptrs+=off; bool is_first = true; - for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) { - const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; } - } - *(ptrd++) = cur; - if (ptrs>=ptrse) { - T *pd = data(x,0,z,c); cur = std::min(cur,*ptrse); cimg_forX(buf,k) { *pd = cur; pd+=off; } - } else { - for (int p = s1; p>0 && ptrd<=ptrde; --p) { - const T val = *ptrs; if (ptrs0; --p) { - const T val = *ptrs; ptrs+=off; - if (is_first) { - const T *nptrs = ptrs - off; cur = val; - for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval0 && ptrs>=ptrsb; --p) { - const T val = *ptrs; ptrs-=off; if (val0 && ptrd>=ptrdb; --p) { - const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val1 && _depth>1) { // Along Z-axis - const int L = depth(), off = width()*height(), s = (int)sz, _s2 = s/2 + 1, _s1 = s - _s2, s1 = _s1>L?L:_s1, - s2 = _s2>L?L:_s2; - CImg buf(L); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) firstprivate(buf) if (size()>524288)) - cimg_forXYC(*this,x,y,c) { - T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; - const T *const ptrsb = data(x,y,0,c), *ptrs = ptrsb, *const ptrse = ptrs + (ulongT)L*off - off; - T cur = *ptrs; ptrs+=off; bool is_first = true; - for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) { - const T val = *ptrs; ptrs+=off; if (val<=cur) { cur = val; is_first = false; } - } - *(ptrd++) = cur; - if (ptrs>=ptrse) { - T *pd = data(x,y,0,c); cur = std::min(cur,*ptrse); cimg_forX(buf,k) { *pd = cur; pd+=off; } - } else { - for (int p = s1; p>0 && ptrd<=ptrde; --p) { - const T val = *ptrs; if (ptrs0; --p) { - const T val = *ptrs; ptrs+=off; - if (is_first) { - const T *nptrs = ptrs - off; cur = val; - for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval0 && ptrs>=ptrsb; --p) { - const T val = *ptrs; ptrs-=off; if (val0 && ptrd>=ptrdb; --p) { - const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val get_erode(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) const { - return (+*this).erode(sx,sy,sz); - } - - //! Erode the image by a square structuring element of specified size. - /** - \param s Size of the structuring element. - **/ - CImg& erode(const unsigned int s) { - return erode(s,s,s); - } - - //! Erode the image by a square structuring element of specified size \newinstance. - CImg get_erode(const unsigned int s) const { - return (+*this).erode(s); - } - - //! Dilate image by a structuring element. - /** - \param kernel Structuring element. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - \param is_real Do the dilation in real (a.k.a 'non-flat') mode (\c true) rather than binary mode (\c false). - **/ - template - CImg& dilate(const CImg& kernel, const unsigned int boundary_conditions=1, - const bool is_real=false) { - if (is_empty() || !kernel) return *this; - return get_dilate(kernel,boundary_conditions,is_real).move_to(*this); - } - - //! Dilate image by a structuring element \newinstance. - template - CImg<_cimg_Tt> get_dilate(const CImg& kernel, const unsigned int boundary_conditions=1, - const bool is_real=false) const { - if (is_empty() || !kernel || (!is_real && kernel==0)) return *this; - typedef _cimg_Tt Tt; - CImg res(_width,_height,_depth,std::max(_spectrum,kernel._spectrum)); - const int - mx1 = kernel.width()/2, my1 = kernel.height()/2, mz1 = kernel.depth()/2, - mx2 = kernel.width() - mx1 - 1, my2 = kernel.height() - my1 - 1, mz2 = kernel.depth() - mz1 - 1, - mxe = width() - mx2, mye = height() - my2, mze = depth() - mz2, - w2 = 2*width(), h2 = 2*height(), d2 = 2*depth(); - const bool - is_inner_parallel = _width*_height*_depth>=(cimg_openmp_sizefactor)*32768, - is_outer_parallel = res.size()>=(cimg_openmp_sizefactor)*32768; - cimg::unused(is_inner_parallel,is_outer_parallel); - _cimg_abort_init_openmp; - cimg_abort_init; - cimg_pragma_openmp(parallel for cimg_openmp_if(!is_inner_parallel && is_outer_parallel)) - cimg_forC(res,c) _cimg_abort_try_openmp { - cimg_abort_test; - const CImg img = get_shared_channel(c%_spectrum); - const CImg K = kernel.get_shared_channel(c%kernel._spectrum); - if (is_real) { // Real dilation - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(is_inner_parallel)) - for (int z = mz1; z::min(); - for (int zm = -mz1; zm<=mz2; ++zm) - for (int ym = -my1; ym<=my2; ++ym) - for (int xm = -mx1; xm<=mx2; ++xm) { - const t mval = K(mx2 - xm,my2 - ym,mz2 - zm); - const Tt cval = (Tt)(img(x + xm,y + ym,z + zm) + mval); - if (cval>max_val) max_val = cval; - } - res(x,y,z,c) = max_val; - } _cimg_abort_catch_openmp2 - - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(is_inner_parallel)) - cimg_forYZ(res,y,z) _cimg_abort_try_openmp2 { - cimg_abort_test2; - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { - Tt max_val = cimg::type::min(); - for (int zm = -mz1; zm<=mz2; ++zm) - for (int ym = -my1; ym<=my2; ++ym) - for (int xm = -mx1; xm<=mx2; ++xm) { - const t mval = K(mx2 - xm,my2 - ym,mz2 - zm); - Tt cval; - switch (boundary_conditions) { - case 0 : cval = (Tt)(img.atXYZ(x + xm,y + ym,z + zm,0,(T)0) + mval); break; - case 1 : cval = (Tt)(img._atXYZ(x + xm,y + ym,z + zm) + mval); break; - case 2 : { - const int - nx = cimg::mod(x + xm,width()), - ny = cimg::mod(y + ym,height()), - nz = cimg::mod(z + zm,depth()); - cval = img(nx,ny,nz) + mval; - } break; - default : { - const int - tx = cimg::mod(x + xm,w2), - ty = cimg::mod(y + ym,h2), - tz = cimg::mod(z + zm,d2), - nx = txmax_val) max_val = cval; - } - res(x,y,z,c) = max_val; - } - } _cimg_abort_catch_openmp2 - - } else { // Binary dilation - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(is_inner_parallel)) - for (int z = mz1; z::min(); - for (int zm = -mz1; zm<=mz2; ++zm) - for (int ym = -my1; ym<=my2; ++ym) - for (int xm = -mx1; xm<=mx2; ++xm) - if (K(mx2 - xm,my2 - ym,mz2 - zm)) { - const Tt cval = (Tt)img(x + xm,y + ym,z + zm); - if (cval>max_val) max_val = cval; - } - res(x,y,z,c) = max_val; - } _cimg_abort_catch_openmp2 - - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(is_inner_parallel)) - cimg_forYZ(res,y,z) _cimg_abort_try_openmp2 { - cimg_abort_test2; - for (int x = 0; x=mye || z=mze)?++x:((x=mxe)?++x:(x=mxe))) { - Tt max_val = cimg::type::min(); - for (int zm = -mz1; zm<=mz2; ++zm) - for (int ym = -my1; ym<=my2; ++ym) - for (int xm = -mx1; xm<=mx2; ++xm) { - if (K(mx2 - xm,my2 - ym,mz2 - zm)) { - Tt cval; - switch (boundary_conditions) { - case 0 : cval = (Tt)img.atXYZ(x + xm,y + ym,z + zm,0,(T)0); break; - case 1 : cval = (Tt)img._atXYZ(x + xm,y + ym,z + zm); break; - case 2 : { - const int - nx = cimg::mod(x + xm,width()), - ny = cimg::mod(y + ym,height()), - nz = cimg::mod(z + zm,depth()); - cval = img(nx,ny,nz); - } break; - default : { - const int - tx = cimg::mod(x + xm,w2), - ty = cimg::mod(y + ym,h2), - tz = cimg::mod(z + zm,d2), - nx = txmax_val) max_val = cval; - } - } - res(x,y,z,c) = max_val; - } - } _cimg_abort_catch_openmp2 - - } - } _cimg_abort_catch_openmp - cimg_abort_test; - return res; - } - - //! Dilate image by a rectangular structuring element of specified size. - /** - \param sx Width of the structuring element. - \param sy Height of the structuring element. - \param sz Depth of the structuring element. - **/ - CImg& dilate(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) { - if (is_empty() || (sx<=1 && sy<=1 && sz<=1)) return *this; - if (sx>1 && _width>1) { // Along X-axis - const int L = width(), off = 1, s = (int)sx, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1, s2 = _s2>L?L:_s2; - CImg buf(L); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) firstprivate(buf) if (size()>524288)) - cimg_forYZC(*this,y,z,c) { - T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; - const T *const ptrsb = data(0,y,z,c), *ptrs = ptrsb, *const ptrse = ptrs + (ulongT)L*off - off; - T cur = *ptrs; ptrs+=off; bool is_first = true; - for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) { - const T val = *ptrs; ptrs+=off; if (val>=cur) { cur = val; is_first = false; } - } - *(ptrd++) = cur; - if (ptrs>=ptrse) { - T *pd = data(0,y,z,c); cur = std::max(cur,*ptrse); cimg_forX(buf,k) { *pd = cur; pd+=off; } - } else { - for (int p = s1; p>0 && ptrd<=ptrde; --p) { - const T val = *ptrs; if (ptrs=cur) { cur = val; is_first = false; } - *(ptrd++) = cur; - } - for (int p = L - s - 1; p>0; --p) { - const T val = *ptrs; ptrs+=off; - if (is_first) { - const T *nptrs = ptrs - off; cur = val; - for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval>cur) cur = nval; } - nptrs-=off; const T nval = *nptrs; if (nval>cur) { cur = nval; is_first = true; } else is_first = false; - } else { if (val>=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; } - *(ptrd++) = cur; - } - ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off; - for (int p = s1; p>0 && ptrs>=ptrsb; --p) { - const T val = *ptrs; ptrs-=off; if (val>cur) cur = val; - } - *(ptrd--) = cur; - for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) { - const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val>cur) cur = val; *(ptrd--) = cur; - } - T *pd = data(0,y,z,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; } - } - } - } - - if (sy>1 && _height>1) { // Along Y-axis - const int L = height(), off = width(), s = (int)sy, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1, - s2 = _s2>L?L:_s2; - CImg buf(L); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) firstprivate(buf) if (size()>524288)) - cimg_forXZC(*this,x,z,c) { - T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; - const T *const ptrsb = data(x,0,z,c), *ptrs = ptrsb, *const ptrse = ptrs + (ulongT)L*off - off; - T cur = *ptrs; ptrs+=off; bool is_first = true; - for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) { - const T val = *ptrs; ptrs+=off; if (val>=cur) { cur = val; is_first = false; } - } - *(ptrd++) = cur; - if (ptrs>=ptrse) { - T *pd = data(x,0,z,c); cur = std::max(cur,*ptrse); cimg_forX(buf,k) { *pd = cur; pd+=off; } - } else { - for (int p = s1; p>0 && ptrd<=ptrde; --p) { - const T val = *ptrs; if (ptrs=cur) { cur = val; is_first = false; } - *(ptrd++) = cur; - } - for (int p = L - s - 1; p>0; --p) { - const T val = *ptrs; ptrs+=off; - if (is_first) { - const T *nptrs = ptrs - off; cur = val; - for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval>cur) cur = nval; } - nptrs-=off; const T nval = *nptrs; if (nval>cur) { cur = nval; is_first = true; } else is_first = false; - } else { if (val>=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; } - *(ptrd++) = cur; - } - ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off; - for (int p = s1; p>0 && ptrs>=ptrsb; --p) { - const T val = *ptrs; ptrs-=off; if (val>cur) cur = val; - } - *(ptrd--) = cur; - for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) { - const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val>cur) cur = val; *(ptrd--) = cur; - } - T *pd = data(x,0,z,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; } - } - } - } - - if (sz>1 && _depth>1) { // Along Z-axis - const int L = depth(), off = width()*height(), s = (int)sz, _s1 = s/2, _s2 = s - _s1, s1 = _s1>L?L:_s1, - s2 = _s2>L?L:_s2; - CImg buf(L); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) firstprivate(buf) if (size()>524288)) - cimg_forXYC(*this,x,y,c) { - T *const ptrdb = buf._data, *ptrd = ptrdb, *const ptrde = buf._data + L - 1; - const T *const ptrsb = data(x,y,0,c), *ptrs = ptrsb, *const ptrse = ptrs + (ulongT)L*off - off; - T cur = *ptrs; ptrs+=off; bool is_first = true; - for (int p = s2 - 1; p>0 && ptrs<=ptrse; --p) { - const T val = *ptrs; ptrs+=off; if (val>=cur) { cur = val; is_first = false; } - } - *(ptrd++) = cur; - if (ptrs>=ptrse) { - T *pd = data(x,y,0,c); cur = std::max(cur,*ptrse); cimg_forX(buf,k) { *pd = cur; pd+=off; } - } else { - for (int p = s1; p>0 && ptrd<=ptrde; --p) { - const T val = *ptrs; if (ptrs=cur) { cur = val; is_first = false; } - *(ptrd++) = cur; - } - for (int p = L - s - 1; p>0; --p) { - const T val = *ptrs; ptrs+=off; - if (is_first) { - const T *nptrs = ptrs - off; cur = val; - for (int q = s - 2; q>0; --q) { nptrs-=off; const T nval = *nptrs; if (nval>cur) cur = nval; } - nptrs-=off; const T nval = *nptrs; if (nval>cur) { cur = nval; is_first = true; } else is_first = false; - } else { if (val>=cur) cur = val; else if (cur==*(ptrs-s*off)) is_first = true; } - *(ptrd++) = cur; - } - ptrd = ptrde; ptrs = ptrse; cur = *ptrs; ptrs-=off; - for (int p = s1; p>0 && ptrs>=ptrsb; --p) { - const T val = *ptrs; ptrs-=off; if (val>cur) cur = val; - } - *(ptrd--) = cur; - for (int p = s2 - 1; p>0 && ptrd>=ptrdb; --p) { - const T val = *ptrs; if (ptrs>ptrsb) ptrs-=off; if (val>cur) cur = val; *(ptrd--) = cur; - } - T *pd = data(x,y,0,c); cimg_for(buf,ps,T) { *pd = *ps; pd+=off; } - } - } - } - return *this; - } - - //! Dilate image by a rectangular structuring element of specified size \newinstance. - CImg get_dilate(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) const { - return (+*this).dilate(sx,sy,sz); - } - - //! Dilate image by a square structuring element of specified size. - /** - \param s Size of the structuring element. - **/ - CImg& dilate(const unsigned int s) { - return dilate(s,s,s); - } - - //! Dilate image by a square structuring element of specified size \newinstance. - CImg get_dilate(const unsigned int s) const { - return (+*this).dilate(s); - } - - //! Apply morphological closing by a structuring element. - /** - \param kernel Structuring element. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - \param is_real Do the closing in real (a.k.a 'non-flat') mode (\c true) rather than binary mode (\c false). - **/ - template - CImg& closing(const CImg& kernel, const unsigned int boundary_conditions=1, - const bool is_real=false) { - const int sx = kernel.width(), sy = kernel.height(), sz = kernel.depth(); - if (is_empty() || (sx<=1 && sy<=1 && sz<=1)) return *this; - return get_closing(kernel,boundary_conditions,is_real).move_to(*this); - } - - //! Apply morphological closing by a structuring element \newinstance. - template - CImg get_closing(const CImg& kernel, const unsigned int boundary_conditions=1, - const bool is_real=false) const { - const int sx = kernel.width(), sy = kernel.height(), sz = kernel.depth(); - if (is_empty() || (sx<=1 && sy<=1 && sz<=1)) return *this; - const int sx1 = (int)(sx - 1)/2, sy1 = (int)(sy - 1)/2, sz1 = (int)(sz - 1)/2; - CImg res; - if (_depth>1) { // 3D - get_resize(width() + sx + 1,height() + sy + 1,depth() + sz + 1,spectrum(),0,boundary_conditions,0.5,0.5,0.5). - dilate(kernel,1,is_real).erode(kernel,1,is_real). - crop(sx1 + 1,sy1 + 1,sz1 + 1,sx1 + width(),sy1 + height(),sz1 + depth()).move_to(res); - } else if (_height>1) { // 2D - get_resize(width() + sx + 1,height() + sy + 1,1,spectrum(),0,boundary_conditions,0.5,0.5). - dilate(kernel,1,is_real).erode(kernel,1,is_real). - crop(sx1 + 1,sy1 + 1,sx1 + width(),sy1 + height()).move_to(res); - } else if (_width>1) { // 1D - get_resize(width() + sx + 1,1,1,spectrum(),0,boundary_conditions,0.5). - dilate(kernel,1,is_real).erode(kernel,1,is_real). - crop(sx1 + 1,sx1 + width()).move_to(res); - } - return res; - } - - //! Apply morphological closing by a rectangular structuring element of specified size. - CImg& closing(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) { - if (is_empty() || (sx<=1 && sy<=1 && sz<=1)) return *this; - return get_closing(sx,sy,sz).move_to(*this); - } - - //! Apply morphological closing by a rectangular structuring element of specified size \newinstance. - CImg get_closing(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) const { - if (is_empty() || (sx<=1 && sy<=1 && sz<=1)) return *this; - const int sx1 = (int)(sx - 1)/2, sy1 = (int)(sy - 1)/2, sz1 = (int)(sz - 1)/2; - CImg res; - if (_depth>1) { // 3D - get_resize(width() + sx + 1,height() + sy + 1,depth() + sz + 1,spectrum(),0,1,0.5,0.5,0.5). - dilate(sx,sy,sz).erode(sx,sy,sz). - crop(sx1 + 1,sy1 + 1,sz1 + 1,sx1 + width(),sy1 + height(),sz1 + depth()).move_to(res); - } else if (_height>1) { // 2D - get_resize(width() + sx + 1,height() + sy + 1,1,spectrum(),0,1,0.5,0.5). - dilate(sx,sy).erode(sx,sy). - crop(sx1 + 1,sy1 + 1,sx1 + width(),sy1 + height()).move_to(res); - } else if (_width>1) { // 1D - get_resize(width() + sx + 1,1,1,spectrum(),0,1,0.5). - dilate(sx,1).erode(sx,1). - crop(sx1 + 1,sx1 + width()).move_to(res); - } - return res; - } - - //! Apply morphological closing by a square structuring element of specified size. - /** - \param s Size of the structuring element. - **/ - CImg& closing(const unsigned int s) { - return closing(s,s,s); - } - - //! Apply morphological closing by a square structuring element of specified size \newinstance. - CImg get_closing(const unsigned int s) const { - return (+*this).closing(s); - } - - //! Apply morphological opening by a structuring element. - /** - \param kernel Structuring element. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - \param is_real Do the opening in real (a.k.a 'non-flat') mode (\c true) rather than binary mode (\c false). - **/ - template - CImg& opening(const CImg& kernel, const unsigned int boundary_conditions=1, - const bool is_real=false) { - const int sx = kernel.width(), sy = kernel.height(), sz = kernel.depth(); - if (is_empty() || (sx<=1 && sy<=1 && sz<=1)) return *this; - return get_opening(kernel,boundary_conditions,is_real).move_to(*this); - } - - //! Apply morphological opening by a structuring element \newinstance. - template - CImg get_opening(const CImg& kernel, const unsigned int boundary_conditions=1, - const bool is_real=false) const { - const int sx = kernel.width(), sy = kernel.height(), sz = kernel.depth(); - if (is_empty() || (sx<=1 && sy<=1 && sz<=1)) return *this; - const int sx1 = (int)(sx - 1)/2, sy1 = (int)(sy - 1)/2, sz1 = (int)(sz - 1)/2; - CImg res; - if (_depth>1) { // 3D - get_resize(width() + sx + 1,height() + sy + 1,depth() + sz + 1,spectrum(),0,boundary_conditions,0.5,0.5,0.5). - erode(kernel,1,is_real).dilate(kernel,1,is_real). - crop(sx1 + 1,sy1 + 1,sz1 + 1,sx1 + width(),sy1 + height(),sz1 + depth()).move_to(res); - } else if (_height>1) { // 2D - get_resize(width() + sx + 1,height() + sy + 1,1,spectrum(),0,boundary_conditions,0.5,0.5). - erode(kernel,1,is_real).dilate(kernel,1,is_real). - crop(sx1 + 1,sy1 + 1,sx1 + width(),sy1 + height()).move_to(res); - } else if (_width>1) { // 1D - get_resize(width() + sx + 1,1,1,spectrum(),0,boundary_conditions,0.5). - erode(kernel,1,is_real).dilate(kernel,1,is_real). - crop(sx1 + 1,sx1 + width()).move_to(res); - } - return res; - } - - //! Apply morphological opening by a rectangular structuring element of specified size. - CImg& opening(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) { - if (is_empty() || (sx<=1 && sy<=1 && sz<=1)) return *this; - return get_opening(sx,sy,sz).move_to(*this); - } - - //! Apply morphological opening by a rectangular structuring element of specified size \newinstance. - CImg get_opening(const unsigned int sx, const unsigned int sy, const unsigned int sz=1) const { - if (is_empty() || (sx<=1 && sy<=1 && sz<=1)) return *this; - const int sx1 = (int)(sx - 1)/2, sy1 = (int)(sy - 1)/2, sz1 = (int)(sz - 1)/2; - CImg res; - if (_depth>1) { // 3D - get_resize(width() + sx + 1,height() + sy + 1,depth() + sz + 1,spectrum(),0,1,0.5,0.5,0.5). - erode(sx,sy,sz).dilate(sx,sy,sz). - crop(sx1 + 1,sy1 + 1,sz1 + 1,sx1 + width(),sy1 + height(),sz1 + depth()).move_to(res); - } else if (_height>1) { // 2D - get_resize(width() + sx + 1,height() + sy + 1,1,spectrum(),0,1,0.5,0.5). - erode(sx,sy).dilate(sx,sy). - crop(sx1 + 1,sy1 + 1,sx1 + width(),sy1 + height()).move_to(res); - } else if (_width>1) { // 1D - get_resize(width() + sx + 1,1,1,spectrum(),0,1,0.5). - erode(sx,1).dilate(sx,1). - crop(sx1 + 1,sx1 + width()).move_to(res); - } - return res; - } - - //! Apply morphological opening by a square structuring element of specified size. - /** - \param s Size of the structuring element. - **/ - CImg& opening(const unsigned int s) { - return opening(s,s,s); - } - - //! Apply morphological opening by a square structuring element of specified size \newinstance. - CImg get_opening(const unsigned int s) const { - return (+*this).opening(s); - } - - //! Compute watershed transform. - /** - \param priority Priority map. - \param is_high_connectivity Boolean that choose between 4(false)- or 8(true)-connectivity - in 2D case, and between 6(false)- or 26(true)-connectivity in 3D case. - \note Non-zero values of the instance instance are propagated to zero-valued ones according to - specified the priority map. - **/ - template - CImg& watershed(const CImg& priority, const bool is_high_connectivity=false) { -#define _cimg_watershed_init(cond,X,Y,Z) \ - if (cond && !(*this)(X,Y,Z)) Q._priority_queue_insert(labels,sizeQ,priority(X,Y,Z),X,Y,Z,nb_seeds) - -#define _cimg_watershed_propagate(cond,X,Y,Z) \ - if (cond) { \ - if ((*this)(X,Y,Z)) { \ - ns = labels(X,Y,Z) - 1; xs = seeds(ns,0); ys = seeds(ns,1); zs = seeds(ns,2); \ - d = cimg::sqr((float)x - xs) + cimg::sqr((float)y - ys) + cimg::sqr((float)z - zs); \ - if (d labels(_width,_height,_depth,1,0), seeds(64,3); - CImg::type> Q; - unsigned int sizeQ = 0; - int px, nx, py, ny, pz, nz; - bool is_px, is_nx, is_py, is_ny, is_pz, is_nz; - const bool is_3d = _depth>1; - - // Find seed points and insert them in priority queue. - unsigned int nb_seeds = 0; - const T *ptrs = _data; - cimg_forXYZ(*this,x,y,z) if (*(ptrs++)) { // 3D version - if (nb_seeds>=seeds._width) seeds.resize(2*seeds._width,3,1,1,0); - seeds(nb_seeds,0) = x; seeds(nb_seeds,1) = y; seeds(nb_seeds++,2) = z; - px = x - 1; nx = x + 1; - py = y - 1; ny = y + 1; - pz = z - 1; nz = z + 1; - is_px = px>=0; is_nx = nx=0; is_ny = ny=0; is_nz = nz=0; is_nx = nx=0; is_ny = ny=0; is_nz = nz::inf(); - T nlabel = (T)0; - _cimg_watershed_propagate(is_px,px,y,z); - _cimg_watershed_propagate(is_nx,nx,y,z); - _cimg_watershed_propagate(is_py,x,py,z); - _cimg_watershed_propagate(is_ny,x,ny,z); - if (is_3d) { - _cimg_watershed_propagate(is_pz,x,y,pz); - _cimg_watershed_propagate(is_nz,x,y,nz); - } - if (is_high_connectivity) { - _cimg_watershed_propagate(is_px && is_py,px,py,z); - _cimg_watershed_propagate(is_nx && is_py,nx,py,z); - _cimg_watershed_propagate(is_px && is_ny,px,ny,z); - _cimg_watershed_propagate(is_nx && is_ny,nx,ny,z); - if (is_3d) { - _cimg_watershed_propagate(is_px && is_pz,px,y,pz); - _cimg_watershed_propagate(is_nx && is_pz,nx,y,pz); - _cimg_watershed_propagate(is_px && is_nz,px,y,nz); - _cimg_watershed_propagate(is_nx && is_nz,nx,y,nz); - _cimg_watershed_propagate(is_py && is_pz,x,py,pz); - _cimg_watershed_propagate(is_ny && is_pz,x,ny,pz); - _cimg_watershed_propagate(is_py && is_nz,x,py,nz); - _cimg_watershed_propagate(is_ny && is_nz,x,ny,nz); - _cimg_watershed_propagate(is_px && is_py && is_pz,px,py,pz); - _cimg_watershed_propagate(is_nx && is_py && is_pz,nx,py,pz); - _cimg_watershed_propagate(is_px && is_ny && is_pz,px,ny,pz); - _cimg_watershed_propagate(is_nx && is_ny && is_pz,nx,ny,pz); - _cimg_watershed_propagate(is_px && is_py && is_nz,px,py,nz); - _cimg_watershed_propagate(is_nx && is_py && is_nz,nx,py,nz); - _cimg_watershed_propagate(is_px && is_ny && is_nz,px,ny,nz); - _cimg_watershed_propagate(is_nx && is_ny && is_nz,nx,ny,nz); - } - } - (*this)(x,y,z) = nlabel; - labels(x,y,z) = ++nmin; - } - return *this; - } - - //! Compute watershed transform \newinstance. - template - CImg get_watershed(const CImg& priority, const bool is_high_connectivity=false) const { - return (+*this).watershed(priority,is_high_connectivity); - } - - // [internal] Insert/Remove items in priority queue, for watershed/distance transforms. - template - bool _priority_queue_insert(CImg& is_queued, unsigned int& siz, const tv value, - const unsigned int x, const unsigned int y, const unsigned int z, - const unsigned int n=1) { - if (is_queued(x,y,z)) return false; - is_queued(x,y,z) = (tq)n; - if (++siz>=_width) { if (!is_empty()) resize(_width*2,4,1,1,0); else assign(64,4); } - (*this)(siz - 1,0) = (T)value; - (*this)(siz - 1,1) = (T)x; - (*this)(siz - 1,2) = (T)y; - (*this)(siz - 1,3) = (T)z; - for (unsigned int pos = siz - 1, par = 0; pos && value>(tv)(*this)(par=(pos + 1)/2 - 1,0); pos = par) { - cimg::swap((*this)(pos,0),(*this)(par,0)); - cimg::swap((*this)(pos,1),(*this)(par,1)); - cimg::swap((*this)(pos,2),(*this)(par,2)); - cimg::swap((*this)(pos,3),(*this)(par,3)); - } - return true; - } - - CImg& _priority_queue_remove(unsigned int& siz) { - (*this)(0,0) = (*this)(--siz,0); - (*this)(0,1) = (*this)(siz,1); - (*this)(0,2) = (*this)(siz,2); - (*this)(0,3) = (*this)(siz,3); - const float value = (*this)(0,0); - unsigned int pos = 0, swap = 0; - do { - const unsigned int left = 2*pos + 1, right = left + 1; - if (right(*this)(right,0)?left:right; - else if (left{ 0=smooth-filter | 1=1st-derivative | 2=2nd-derivative }. - \param axis Axis along which the filter is computed. Can be { 'x' | 'y' | 'z' | 'c' }. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - **/ - CImg& deriche(const float sigma, const unsigned int order=0, const char axis='x', - const unsigned int boundary_conditions=1) { -#define _cimg_deriche_apply \ - CImg Y(N); \ - double *ptrY = Y._data, yb = 0, yp = 0; \ - T xp = (T)0; \ - if (boundary_conditions) { xp = *ptrX; yb = yp = (double)(coefp*xp); } \ - for (int m = 0; m=0; --n) { \ - const T xc = *(ptrX-=off); \ - const double yc = (double)(a2*xn + a3*xa - b1*yn - b2*ya); \ - xa = xn; xn = xc; ya = yn; yn = yc; \ - *ptrX = (T)(*(--ptrY)+yc); \ - } - - if (order>2) - throw CImgArgumentException(_cimg_instance - "deriche(): Invalid specified order '%d' " - "('order' can be { 0=smoothing | 1=1st-derivative | 2=2nd-derivative }).", - cimg_instance, - order); - - const char naxis = cimg::lowercase(axis); - if (naxis!='x' && naxis!='y' && naxis!='z' && naxis!='c') - throw CImgArgumentException(_cimg_instance - "deriche(): Invalid specified axis '%c'.", - cimg_instance, - axis); - const double - nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?_width: - naxis=='y'?_height: - naxis=='z'?_depth:_spectrum)/100, - nnsigma = nsigma<0.1f?0.1f:nsigma; - - if (is_empty() || (nsigma<0.1f && !order)) return *this; - if (boundary_conditions>1) { - const int w = width(), h = height(), d = depth(), s = spectrum(), border = (int)cimg::round(1 + 3*nnsigma); - switch (naxis) { - case 'x' : - return draw_image(get_resize(w + 2*border,h,d,s,0,boundary_conditions,0.5). - deriche(nnsigma,order,naxis,1).columns(border,w - 1 + border)); - case 'y' : - return draw_image(get_resize(w,h + 2*border,d,s,0,boundary_conditions,0,0.5). - deriche(nnsigma,order,naxis,1).rows(border,h - 1 + border)); - case 'z' : - return draw_image(get_resize(w,h,d + 2*border,s,0,boundary_conditions,0,0,0.5). - deriche(nnsigma,order,naxis,1).slices(border,d - 1 + border)); - default : - return draw_image(get_resize(w,h,d,s + 2*border,0,boundary_conditions,0,0,0,0.5). - deriche(nnsigma,order,naxis,1).channels(border,d - 1 + border)); - } - } - - const double - alpha = 1.695f/nnsigma, - ema = std::exp(-alpha), - ema2 = std::exp(-2*alpha), - b1 = -2*ema, - b2 = ema2; - double a0 = 0, a1 = 0, a2 = 0, a3 = 0, coefp = 0, coefn = 0; - switch (order) { - case 0 : { - const double k = (1-ema)*(1-ema)/(1 + 2*alpha*ema-ema2); - a0 = k; - a1 = k*(alpha - 1)*ema; - a2 = k*(alpha + 1)*ema; - a3 = -k*ema2; - } break; - case 1 : { - const double k = -(1-ema)*(1-ema)*(1-ema)/(2*(ema + 1)*ema); - a0 = a3 = 0; - a1 = k*ema; - a2 = -a1; - } break; - default : { - const double - ea = std::exp(-alpha), - k = -(ema2 - 1)/(2*alpha*ema), - kn = (-2*(-1 + 3*ea - 3*ea*ea + ea*ea*ea)/(3*ea + 1 + 3*ea*ea + ea*ea*ea)); - a0 = kn; - a1 = -kn*(1 + k*alpha)*ema; - a2 = kn*(1 - k*alpha)*ema; - a3 = -kn*ema2; - } break; - } - - coefp = (a0 + a1)/(1 + b1 + b2); - coefn = (a2 + a3)/(1 + b1 + b2); - switch (naxis) { - case 'x' : { - const int N = width(); - const ulongT off = 1U; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth*_spectrum>=16)) - cimg_forYZC(*this,y,z,c) { T *ptrX = data(0,y,z,c); _cimg_deriche_apply; } - } break; - case 'y' : { - const int N = height(); - const ulongT off = (ulongT)_width; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth*_spectrum>=16)) - cimg_forXZC(*this,x,z,c) { T *ptrX = data(x,0,z,c); _cimg_deriche_apply; } - } break; - case 'z' : { - const int N = depth(); - const ulongT off = (ulongT)_width*_height; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth*_spectrum>=16)) - cimg_forXYC(*this,x,y,c) { T *ptrX = data(x,y,0,c); _cimg_deriche_apply; } - } break; - default : { - const int N = spectrum(); - const ulongT off = (ulongT)_width*_height*_depth; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth*_spectrum>=16)) - cimg_forXYZ(*this,x,y,z) { T *ptrX = data(x,y,z,0); _cimg_deriche_apply; } - } - } - return *this; - } - - //! Apply recursive Deriche filter \newinstance. - CImg get_deriche(const float sigma, const unsigned int order=0, const char axis='x', - const unsigned int boundary_conditions=1) const { - return CImg(*this,false).deriche(sigma,order,axis,boundary_conditions); - } - - // [internal] Apply a recursive filter (used by CImg::vanvliet()). - /* - \param ptr the pointer of the data - \param filter the coefficient of the filter in the following order [n,n - 1,n - 2,n - 3]. - \param N size of the data - \param off the offset between two data point - \param order the order of the filter 0 (smoothing), 1st derivative, 2nd derivative, 3rd derivative - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann }. - \note Boundary condition using B. Triggs method (IEEE trans on Sig Proc 2005). - */ - static void _cimg_recursive_apply(T *data, const double filter[], const int N, const ulongT off, - const unsigned int order, const bool boundary_conditions) { - double val[4] = { 0 }; // res[n,n - 1,n - 2,n - 3,..] or res[n,n + 1,n + 2,n + 3,..] - const double - sumsq = filter[0], sum = sumsq * sumsq, - a1 = filter[1], a2 = filter[2], a3 = filter[3], - scaleM = 1. / ( (1. + a1 - a2 + a3) * (1. - a1 - a2 - a3) * (1. + a2 + (a1 - a3) * a3) ); - double M[9]; // Triggs matrix - M[0] = scaleM * (-a3 * a1 + 1. - a3 * a3 - a2); - M[1] = scaleM * (a3 + a1) * (a2 + a3 * a1); - M[2] = scaleM * a3 * (a1 + a3 * a2); - M[3] = scaleM * (a1 + a3 * a2); - M[4] = -scaleM * (a2 - 1.) * (a2 + a3 * a1); - M[5] = -scaleM * a3 * (a3 * a1 + a3 * a3 + a2 - 1.); - M[6] = scaleM * (a3 * a1 + a2 + a1 * a1 - a2 * a2); - M[7] = scaleM * (a1 * a2 + a3 * a2 * a2 - a1 * a3 * a3 - a3 * a3 * a3 - a3 * a2 + a3); - M[8] = scaleM * a3 * (a1 + a3 * a2); - switch (order) { - case 0 : { - const double iplus = (boundary_conditions?data[(N - 1)*off]:(T)0); - for (int pass = 0; pass<2; ++pass) { - if (!pass) { - for (int k = 1; k<4; ++k) val[k] = (boundary_conditions?*data/sumsq:0); - } else { - // Apply Triggs boundary conditions - const double - uplus = iplus/(1. - a1 - a2 - a3), vplus = uplus/(1. - a1 - a2 - a3), - unp = val[1] - uplus, unp1 = val[2] - uplus, unp2 = val[3] - uplus; - val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2 + vplus) * sum; - val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2 + vplus) * sum; - val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2 + vplus) * sum; - *data = (T)val[0]; - data -= off; - for (int k = 3; k>0; --k) val[k] = val[k - 1]; - } - for (int n = pass; n0; --k) val[k] = val[k - 1]; - } - if (!pass) data -= off; - } - } break; - case 1 : { - double x[3]; // [front,center,back] - for (int pass = 0; pass<2; ++pass) { - if (!pass) { - for (int k = 0; k<3; ++k) x[k] = (boundary_conditions?*data:(T)0); - for (int k = 0; k<4; ++k) val[k] = 0; - } else { - // Apply Triggs boundary conditions - const double - unp = val[1], unp1 = val[2], unp2 = val[3]; - val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2) * sum; - val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2) * sum; - val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2) * sum; - *data = (T)val[0]; - data -= off; - for (int k = 3; k>0; --k) val[k] = val[k - 1]; - } - for (int n = pass; n0; --k) x[k] = x[k - 1]; - } else { data-=off;} - for (int k = 3; k>0; --k) val[k] = val[k - 1]; - } - *data = (T)0; - } - } break; - case 2: { - double x[3]; // [front,center,back] - for (int pass = 0; pass<2; ++pass) { - if (!pass) { - for (int k = 0; k<3; ++k) x[k] = (boundary_conditions?*data:(T)0); - for (int k = 0; k<4; ++k) val[k] = 0; - } else { - // Apply Triggs boundary conditions - const double - unp = val[1], unp1 = val[2], unp2 = val[3]; - val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2) * sum; - val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2) * sum; - val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2) * sum; - *data = (T)val[0]; - data -= off; - for (int k = 3; k>0; --k) val[k] = val[k - 1]; - } - for (int n = pass; n0; --k) x[k] = x[k - 1]; - for (int k = 3; k>0; --k) val[k] = val[k - 1]; - } - *data = (T)0; - } - } break; - case 3: { - double x[3]; // [front,center,back] - for (int pass = 0; pass<2; ++pass) { - if (!pass) { - for (int k = 0; k<3; ++k) x[k] = (boundary_conditions?*data:(T)0); - for (int k = 0; k<4; ++k) val[k] = 0; - } else { - // Apply Triggs boundary conditions - const double - unp = val[1], unp1 = val[2], unp2 = val[3]; - val[0] = (M[0] * unp + M[1] * unp1 + M[2] * unp2) * sum; - val[1] = (M[3] * unp + M[4] * unp1 + M[5] * unp2) * sum; - val[2] = (M[6] * unp + M[7] * unp1 + M[8] * unp2) * sum; - *data = (T)val[0]; - data -= off; - for (int k = 3; k>0; --k) val[k] = val[k - 1]; - } - for (int n = pass; n0; --k) x[k] = x[k - 1]; - for (int k = 3; k>0; --k) val[k] = val[k - 1]; - } - *data = (T)0; - } - } break; - } - } - - //! Van Vliet recursive Gaussian filter. - /** - \param sigma standard deviation of the Gaussian filter - \param order the order of the filter 0,1,2,3 - \param axis Axis along which the filter is computed. Can be { 'x' | 'y' | 'z' | 'c' }. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - \note dirichlet boundary condition has a strange behavior - - I.T. Young, L.J. van Vliet, M. van Ginkel, Recursive Gabor filtering. - IEEE Trans. Sig. Proc., vol. 50, pp. 2799-2805, 2002. - - (this is an improvement over Young-Van Vliet, Sig. Proc. 44, 1995) - - Boundary conditions (only for order 0) using Triggs matrix, from - B. Triggs and M. Sdika. Boundary conditions for Young-van Vliet - recursive filtering. IEEE Trans. Signal Processing, - vol. 54, pp. 2365-2367, 2006. - **/ - CImg& vanvliet(const float sigma, const unsigned int order, const char axis='x', - const unsigned int boundary_conditions=1) { - - if (order>2) - throw CImgArgumentException(_cimg_instance - "deriche(): Invalid specified order '%d' " - "('order' can be { 0=smoothing | 1=1st-derivative | 2=2nd-derivative }).", - cimg_instance, - order); - - const char naxis = cimg::lowercase(axis); - if (naxis!='x' && naxis!='y' && naxis!='z' && naxis!='c') - throw CImgArgumentException(_cimg_instance - "deriche(): Invalid specified axis '%c'.", - cimg_instance, - axis); - const double - nsigma = sigma>=0?sigma:-sigma*(naxis=='x'?_width: - naxis=='y'?_height: - naxis=='z'?_depth:_spectrum)/100, - nnsigma = nsigma<0.5f?0.5f:nsigma; - - if (is_empty() || (nsigma<0.1f && !order)) return *this; - if (nsigma<0.5f) return deriche(nsigma,order,axis,boundary_conditions); - if (!cimg::type::is_float()) - return CImg(*this,false).vanvliet(sigma,order,axis,boundary_conditions).move_to(*this); - - if (boundary_conditions>1) { - const int w = width(), h = height(), d = depth(), s = spectrum(), border = (int)cimg::round(1 + 3*nnsigma); - switch (naxis) { - case 'x' : - return draw_image(get_resize(w + 2*border,h,d,s,0,boundary_conditions,0.5). - vanvliet(nnsigma,order,naxis,1).columns(border,w - 1 + border)); - case 'y' : - return draw_image(get_resize(w,h + 2*border,d,s,0,boundary_conditions,0,0.5). - vanvliet(nnsigma,order,naxis,1).rows(border,h - 1 + border)); - case 'z' : - return draw_image(get_resize(w,h,d + 2*border,s,0,boundary_conditions,0,0,0.5). - vanvliet(nnsigma,order,naxis,1).slices(border,d - 1 + border)); - default : - return draw_image(get_resize(w,h,d,s + 2*border,0,boundary_conditions,0,0,0,0.5). - vanvliet(nnsigma,order,naxis,1).channels(border,d - 1 + border)); - } - } - - const double - m0 = 1.16680, m1 = 1.10783, m2 = 1.40586, - m1sq = m1 * m1, m2sq = m2 * m2, - q = (nnsigma<3.556?-0.2568 + 0.5784*nnsigma + 0.0561*nnsigma*nnsigma:2.5091 + 0.9804*(nnsigma - 3.556)), - qsq = q * q, - scale = (m0 + q) * (m1sq + m2sq + 2 * m1 * q + qsq), - b1 = -q * (2 * m0 * m1 + m1sq + m2sq + (2 * m0 + 4 * m1) * q + 3 * qsq) / scale, - b2 = qsq * (m0 + 2 * m1 + 3 * q) / scale, - b3 = -qsq * q / scale, - B = ( m0 * (m1sq + m2sq) ) / scale; - double filter[4]; - filter[0] = B; filter[1] = -b1; filter[2] = -b2; filter[3] = -b3; - switch (naxis) { - case 'x' : { - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth*_spectrum>=16)) - cimg_forYZC(*this,y,z,c) - _cimg_recursive_apply(data(0,y,z,c),filter,_width,1U,order,boundary_conditions); - } break; - case 'y' : { - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth*_spectrum>=16)) - cimg_forXZC(*this,x,z,c) - _cimg_recursive_apply(data(x,0,z,c),filter,_height,(ulongT)_width,order,boundary_conditions); - } break; - case 'z' : { - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth*_spectrum>=16)) - cimg_forXYC(*this,x,y,c) - _cimg_recursive_apply(data(x,y,0,c),filter,_depth,(ulongT)_width*_height, - order,boundary_conditions); - } break; - default : { - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth*_spectrum>=16)) - cimg_forXYZ(*this,x,y,z) - _cimg_recursive_apply(data(x,y,z,0),filter,_spectrum,(ulongT)_width*_height*_depth, - order,boundary_conditions); - } - } - return *this; - } - - //! Blur image using Van Vliet recursive Gaussian filter. \newinstance. - CImg get_vanvliet(const float sigma, const unsigned int order, const char axis='x', - const unsigned int boundary_conditions=1) const { - return CImg(*this,false).vanvliet(sigma,order,axis,boundary_conditions); - } - - //! Blur image. - /** - \param sigma_x Standard deviation of the blur, along the X-axis. - \param sigma_y Standard deviation of the blur, along the Y-axis. - \param sigma_z Standard deviation of the blur, along the Z-axis. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - \param is_gaussian Tells if the blur uses a gaussian (\c true) or quasi-gaussian (\c false) kernel. - \note - - The blur is computed as a 0-order Vanvliet (gaussian) or Deriche filter (quasi-gaussian). - - This is a recursive algorithm, not depending on the values of the standard deviations. - \see deriche(), vanvliet(). - **/ - CImg& blur(const float sigma_x, const float sigma_y, const float sigma_z, - const unsigned int boundary_conditions=1, const bool is_gaussian=true) { - if (is_empty()) return *this; - if (is_gaussian) { - if (_width>1) vanvliet(sigma_x,0,'x',boundary_conditions); - if (_height>1) vanvliet(sigma_y,0,'y',boundary_conditions); - if (_depth>1) vanvliet(sigma_z,0,'z',boundary_conditions); - } else { - if (_width>1) deriche(sigma_x,0,'x',boundary_conditions); - if (_height>1) deriche(sigma_y,0,'y',boundary_conditions); - if (_depth>1) deriche(sigma_z,0,'z',boundary_conditions); - } - return *this; - } - - //! Blur image \newinstance. - CImg get_blur(const float sigma_x, const float sigma_y, const float sigma_z, - const unsigned int boundary_conditions=1, const bool is_gaussian=true) const { - return CImg(*this,false).blur(sigma_x,sigma_y,sigma_z,boundary_conditions,is_gaussian); - } - - //! Blur image isotropically. - /** - \param sigma Standard deviation of the blur. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }.a - \param is_gaussian Use a gaussian kernel (VanVliet) is set, a quasi-gaussian (Deriche) otherwise. - \see deriche(), vanvliet(). - **/ - CImg& blur(const float sigma, const unsigned int boundary_conditions=1, const bool is_gaussian=true) { - const float nsigma = sigma>=0?sigma:-sigma*cimg::max(_width,_height,_depth)/100; - return blur(nsigma,nsigma,nsigma,boundary_conditions,is_gaussian); - } - - //! Blur image isotropically \newinstance. - CImg get_blur(const float sigma, const unsigned int boundary_conditions=1, - const bool is_gaussian=true) const { - return CImg(*this,false).blur(sigma,boundary_conditions,is_gaussian); - } - - //! Blur image anisotropically, directed by a field of diffusion tensors. - /** - \param G Field of square roots of diffusion tensors/vectors used to drive the smoothing. - \param amplitude Amplitude of the smoothing. - \param dl Spatial discretization. - \param da Angular discretization. - \param gauss_prec Precision of the diffusion process. - \param interpolation_type Interpolation scheme. - Can be { 0=nearest-neighbor | 1=linear | 2=Runge-Kutta }. - \param is_fast_approx Tells if a fast approximation of the gaussian function is used or not. - **/ - template - CImg& blur_anisotropic(const CImg& G, - const float amplitude=60, const float dl=0.8f, const float da=30, - const float gauss_prec=2, const unsigned int interpolation_type=0, - const bool is_fast_approx=1) { - - // Check arguments and init variables - if (!is_sameXYZ(G) || (G._spectrum!=3 && G._spectrum!=6)) - throw CImgArgumentException(_cimg_instance - "blur_anisotropic(): Invalid specified diffusion tensor field (%u,%u,%u,%u,%p).", - cimg_instance, - G._width,G._height,G._depth,G._spectrum,G._data); - if (is_empty() || dl<0) return *this; - const float namplitude = amplitude>=0?amplitude:-amplitude*cimg::max(_width,_height,_depth)/100; - unsigned int iamplitude = cimg::round(namplitude); - const bool is_3d = (G._spectrum==6); - T val_min, val_max = max_min(val_min); - _cimg_abort_init_openmp; - cimg_abort_init; - - if (da<=0) { // Iterated oriented Laplacians - CImg velocity(_width,_height,_depth,_spectrum); - for (unsigned int iteration = 0; iterationveloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; - } - } - else // 2D version - cimg_forZC(*this,z,c) { - cimg_abort_test; - CImg_3x3(I,Tfloat); - cimg_for3x3(*this,x,y,z,c,I,Tfloat) { - const Tfloat - ixx = Inc + Ipc - 2*Icc, - ixy = (Inn + Ipp - Inp - Ipn)/4, - iyy = Icn + Icp - 2*Icc, - veloc = (Tfloat)(G(x,y,0,0)*ixx + 2*G(x,y,0,1)*ixy + G(x,y,0,2)*iyy); - *(ptrd++) = veloc; - if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; - } - } - if (veloc_max>0) *this+=(velocity*=dl/veloc_max); - } - } else { // LIC-based smoothing - const ulongT whd = (ulongT)_width*_height*_depth; - const float sqrt2amplitude = (float)std::sqrt(2*namplitude); - const int dx1 = width() - 1, dy1 = height() - 1, dz1 = depth() - 1; - CImg res(_width,_height,_depth,_spectrum,0), W(_width,_height,_depth,is_3d?4:3), val(_spectrum,1,1,1,0); - int N = 0; - if (is_3d) { // 3D version - for (float phi = cimg::mod(180.f,da)/2.f; phi<=180; phi+=da) { - const float phir = (float)(phi*cimg::PI/180), datmp = (float)(da/std::cos(phir)), - da2 = datmp<1?360.f:datmp; - for (float theta = 0; theta<360; (theta+=da2),++N) { - const float - thetar = (float)(theta*cimg::PI/180), - vx = (float)(std::cos(thetar)*std::cos(phir)), - vy = (float)(std::sin(thetar)*std::cos(phir)), - vz = (float)std::sin(phir); - const t - *pa = G.data(0,0,0,0), *pb = G.data(0,0,0,1), *pc = G.data(0,0,0,2), - *pd = G.data(0,0,0,3), *pe = G.data(0,0,0,4), *pf = G.data(0,0,0,5); - Tfloat *pd0 = W.data(0,0,0,0), *pd1 = W.data(0,0,0,1), *pd2 = W.data(0,0,0,2), *pd3 = W.data(0,0,0,3); - cimg_forXYZ(G,xg,yg,zg) { - const t a = *(pa++), b = *(pb++), c = *(pc++), d = *(pd++), e = *(pe++), f = *(pf++); - const float - u = (float)(a*vx + b*vy + c*vz), - v = (float)(b*vx + d*vy + e*vz), - w = (float)(c*vx + e*vy + f*vz), - n = 1e-5f + cimg::hypot(u,v,w), - dln = dl/n; - *(pd0++) = (Tfloat)(u*dln); - *(pd1++) = (Tfloat)(v*dln); - *(pd2++) = (Tfloat)(w*dln); - *(pd3++) = (Tfloat)n; - } - - cimg_abort_test; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && _height*_depth>=2) - firstprivate(val)) - cimg_forYZ(*this,y,z) _cimg_abort_try_openmp2 { - cimg_abort_test2; - cimg_forX(*this,x) { - val.fill(0); - const float - n = (float)W(x,y,z,3), - fsigma = (float)(n*sqrt2amplitude), - fsigma2 = 2*fsigma*fsigma, - length = gauss_prec*fsigma; - float - S = 0, - X = (float)x, - Y = (float)y, - Z = (float)z; - switch (interpolation_type) { - case 0 : { // Nearest neighbor - for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { - const int - cx = (int)(X + 0.5f), - cy = (int)(Y + 0.5f), - cz = (int)(Z + 0.5f); - const float - u = (float)W(cx,cy,cz,0), - v = (float)W(cx,cy,cz,1), - w = (float)W(cx,cy,cz,2); - if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)(*this)(cx,cy,cz,c); ++S; } - else { - const float coef = (float)std::exp(-l*l/fsigma2); - cimg_forC(*this,c) val[c]+=(Tfloat)(coef*(*this)(cx,cy,cz,c)); - S+=coef; - } - X+=u; Y+=v; Z+=w; - } - } break; - case 1 : { // Linear interpolation - for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { - const float - u = (float)(W._linear_atXYZ(X,Y,Z,0)), - v = (float)(W._linear_atXYZ(X,Y,Z,1)), - w = (float)(W._linear_atXYZ(X,Y,Z,2)); - if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXYZ(X,Y,Z,c); ++S; } - else { - const float coef = (float)std::exp(-l*l/fsigma2); - cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,c)); - S+=coef; - } - X+=u; Y+=v; Z+=w; - } - } break; - default : { // 2nd order Runge Kutta - for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1 && Z>=0 && Z<=dz1; l+=dl) { - const float - u0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,0)), - v0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,1)), - w0 = (float)(0.5f*W._linear_atXYZ(X,Y,Z,2)), - u = (float)(W._linear_atXYZ(X + u0,Y + v0,Z + w0,0)), - v = (float)(W._linear_atXYZ(X + u0,Y + v0,Z + w0,1)), - w = (float)(W._linear_atXYZ(X + u0,Y + v0,Z + w0,2)); - if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXYZ(X,Y,Z,c); ++S; } - else { - const float coef = (float)std::exp(-l*l/fsigma2); - cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXYZ(X,Y,Z,c)); - S+=coef; - } - X+=u; Y+=v; Z+=w; - } - } break; - } - Tfloat *ptrd = res.data(x,y,z); - if (S>0) cimg_forC(res,c) { *ptrd+=val[c]/S; ptrd+=whd; } - else cimg_forC(res,c) { *ptrd+=(Tfloat)((*this)(x,y,z,c)); ptrd+=whd; } - } - } _cimg_abort_catch_openmp2 - } - } - } else { // 2D LIC algorithm - for (float theta = cimg::mod(360.f,da)/2.f; theta<360; (theta+=da),++N) { - const float thetar = (float)(theta*cimg::PI/180), - vx = (float)(std::cos(thetar)), vy = (float)(std::sin(thetar)); - const t *pa = G.data(0,0,0,0), *pb = G.data(0,0,0,1), *pc = G.data(0,0,0,2); - Tfloat *pd0 = W.data(0,0,0,0), *pd1 = W.data(0,0,0,1), *pd2 = W.data(0,0,0,2); - cimg_forXY(G,xg,yg) { - const t a = *(pa++), b = *(pb++), c = *(pc++); - const float - u = (float)(a*vx + b*vy), - v = (float)(b*vx + c*vy), - n = std::max(1e-5f,cimg::hypot(u,v)), - dln = dl/n; - *(pd0++) = (Tfloat)(u*dln); - *(pd1++) = (Tfloat)(v*dln); - *(pd2++) = (Tfloat)n; - } - - cimg_abort_test; - cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && _height>=2) - firstprivate(val)) - cimg_forY(*this,y) _cimg_abort_try_openmp2 { - cimg_abort_test2; - cimg_forX(*this,x) { - val.fill(0); - const float - n = (float)W(x,y,0,2), - fsigma = (float)(n*sqrt2amplitude), - fsigma2 = 2*fsigma*fsigma, - length = gauss_prec*fsigma; - float - S = 0, - X = (float)x, - Y = (float)y; - switch (interpolation_type) { - case 0 : { // Nearest-neighbor - for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { - const int - cx = (int)(X + 0.5f), - cy = (int)(Y + 0.5f); - const float - u = (float)W(cx,cy,0,0), - v = (float)W(cx,cy,0,1); - if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)(*this)(cx,cy,0,c); ++S; } - else { - const float coef = (float)std::exp(-l*l/fsigma2); - cimg_forC(*this,c) val[c]+=(Tfloat)(coef*(*this)(cx,cy,0,c)); - S+=coef; - } - X+=u; Y+=v; - } - } break; - case 1 : { // Linear interpolation - for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { - const float - u = (float)(W._linear_atXY(X,Y,0,0)), - v = (float)(W._linear_atXY(X,Y,0,1)); - if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXY(X,Y,0,c); ++S; } - else { - const float coef = (float)std::exp(-l*l/fsigma2); - cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXY(X,Y,0,c)); - S+=coef; - } - X+=u; Y+=v; - } - } break; - default : { // 2nd-order Runge-kutta interpolation - for (float l = 0; l=0 && X<=dx1 && Y>=0 && Y<=dy1; l+=dl) { - const float - u0 = (float)(0.5f*W._linear_atXY(X,Y,0,0)), - v0 = (float)(0.5f*W._linear_atXY(X,Y,0,1)), - u = (float)(W._linear_atXY(X + u0,Y + v0,0,0)), - v = (float)(W._linear_atXY(X + u0,Y + v0,0,1)); - if (is_fast_approx) { cimg_forC(*this,c) val[c]+=(Tfloat)_linear_atXY(X,Y,0,c); ++S; } - else { - const float coef = (float)std::exp(-l*l/fsigma2); - cimg_forC(*this,c) val[c]+=(Tfloat)(coef*_linear_atXY(X,Y,0,c)); - S+=coef; - } - X+=u; Y+=v; - } - } - } - Tfloat *ptrd = res.data(x,y); - if (S>0) cimg_forC(res,c) { *ptrd+=val[c]/S; ptrd+=whd; } - else cimg_forC(res,c) { *ptrd+=(Tfloat)((*this)(x,y,0,c)); ptrd+=whd; } - } - } _cimg_abort_catch_openmp2 - } - } - const Tfloat *ptrs = res._data; - cimg_for(*this,ptrd,T) { - const Tfloat _val = *(ptrs++)/N; - *ptrd = _valval_max?val_max:(T)_val); - } - } - cimg_abort_test; - return *this; - } - - //! Blur image anisotropically, directed by a field of diffusion tensors \newinstance. - template - CImg get_blur_anisotropic(const CImg& G, - const float amplitude=60, const float dl=0.8f, const float da=30, - const float gauss_prec=2, const unsigned int interpolation_type=0, - const bool is_fast_approx=true) const { - return CImg(*this,false).blur_anisotropic(G,amplitude,dl,da,gauss_prec,interpolation_type,is_fast_approx); - } - - //! Blur image anisotropically, in an edge-preserving way. - /** - \param amplitude Amplitude of the smoothing. - \param sharpness Sharpness. - \param anisotropy Anisotropy. - \param alpha Standard deviation of the gradient blur. - \param sigma Standard deviation of the structure tensor blur. - \param dl Spatial discretization. - \param da Angular discretization. - \param gauss_prec Precision of the diffusion process. - \param interpolation_type Interpolation scheme. - Can be { 0=nearest-neighbor | 1=linear | 2=Runge-Kutta }. - \param is_fast_approx Tells if a fast approximation of the gaussian function is used or not. - **/ - CImg& blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.6f, - const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, const float da=30, - const float gauss_prec=2, const unsigned int interpolation_type=0, - const bool is_fast_approx=true) { - const float nalpha = alpha>=0?alpha:-alpha*cimg::max(_width,_height,_depth)/100; - const float nsigma = sigma>=0?sigma:-sigma*cimg::max(_width,_height,_depth)/100; - return blur_anisotropic(get_diffusion_tensors(sharpness,anisotropy,nalpha,nsigma,interpolation_type!=3), - amplitude,dl,da,gauss_prec,interpolation_type,is_fast_approx); - } - - //! Blur image anisotropically, in an edge-preserving way \newinstance. - CImg get_blur_anisotropic(const float amplitude, const float sharpness=0.7f, const float anisotropy=0.6f, - const float alpha=0.6f, const float sigma=1.1f, const float dl=0.8f, - const float da=30, const float gauss_prec=2, - const unsigned int interpolation_type=0, - const bool is_fast_approx=true) const { - return CImg(*this,false).blur_anisotropic(amplitude,sharpness,anisotropy,alpha,sigma,dl,da,gauss_prec, - interpolation_type,is_fast_approx); - } - - //! Blur image, with the joint bilateral filter. - /** - \param guide Image used to model the smoothing weights. - \param sigma_x Amount of blur along the X-axis. - \param sigma_y Amount of blur along the Y-axis. - \param sigma_z Amount of blur along the Z-axis. - \param sigma_r Amount of blur along the value axis. - \param sampling_x Amount of downsampling along the X-axis used for the approximation. - Defaults (0) to sigma_x. - \param sampling_y Amount of downsampling along the Y-axis used for the approximation. - Defaults (0) to sigma_y. - \param sampling_z Amount of downsampling along the Z-axis used for the approximation. - Defaults (0) to sigma_z. - \param sampling_r Amount of downsampling along the value axis used for the approximation. - Defaults (0) to sigma_r. - \note This algorithm uses the optimisation technique proposed by S. Paris and F. Durand, in ECCV'2006 - (extended for 3D volumetric images). - It is based on the reference implementation http://people.csail.mit.edu/jiawen/software/bilateralFilter.m - **/ - template - CImg& blur_bilateral(const CImg& guide, - const float sigma_x, const float sigma_y, - const float sigma_z, const float sigma_r, - const float sampling_x, const float sampling_y, - const float sampling_z, const float sampling_r) { - if (!is_sameXYZ(guide)) - throw CImgArgumentException(_cimg_instance - "blur_bilateral(): Invalid size for specified guide image (%u,%u,%u,%u,%p).", - cimg_instance, - guide._width,guide._height,guide._depth,guide._spectrum,guide._data); - if (is_empty() || (!sigma_x && !sigma_y && !sigma_z)) return *this; - T edge_min, edge_max = guide.max_min(edge_min); - if (edge_min==edge_max) return blur(sigma_x,sigma_y,sigma_z); - const float - edge_delta = (float)(edge_max - edge_min), - _sigma_x = sigma_x>=0?sigma_x:-sigma_x*_width/100, - _sigma_y = sigma_y>=0?sigma_y:-sigma_y*_height/100, - _sigma_z = sigma_z>=0?sigma_z:-sigma_z*_depth/100, - _sigma_r = sigma_r>=0?sigma_r:-sigma_r*edge_delta/100, - _sampling_x = sampling_x?sampling_x:std::max(_sigma_x,1.f), - _sampling_y = sampling_y?sampling_y:std::max(_sigma_y,1.f), - _sampling_z = sampling_z?sampling_z:std::max(_sigma_z,1.f), - _sampling_r = sampling_r?sampling_r:std::max(_sigma_r,edge_delta/256), - derived_sigma_x = _sigma_x / _sampling_x, - derived_sigma_y = _sigma_y / _sampling_y, - derived_sigma_z = _sigma_z / _sampling_z, - derived_sigma_r = _sigma_r / _sampling_r; - const int - padding_x = (int)(2*derived_sigma_x) + 1, - padding_y = (int)(2*derived_sigma_y) + 1, - padding_z = (int)(2*derived_sigma_z) + 1, - padding_r = (int)(2*derived_sigma_r) + 1; - const unsigned int - bx = (unsigned int)((_width - 1)/_sampling_x + 1 + 2*padding_x), - by = (unsigned int)((_height - 1)/_sampling_y + 1 + 2*padding_y), - bz = (unsigned int)((_depth - 1)/_sampling_z + 1 + 2*padding_z), - br = (unsigned int)(edge_delta/_sampling_r + 1 + 2*padding_r); - if (bx>0 || by>0 || bz>0 || br>0) { - const bool is_3d = (_depth>1); - if (is_3d) { // 3D version of the algorithm - CImg bgrid(bx,by,bz,br), bgridw(bx,by,bz,br); - cimg_forC(*this,c) { - const CImg _guide = guide.get_shared_channel(c%guide._spectrum); - bgrid.fill(0); bgridw.fill(0); - cimg_forXYZ(*this,x,y,z) { - const T val = (*this)(x,y,z,c); - const float edge = (float)_guide(x,y,z); - const int - X = (int)cimg::round(x/_sampling_x) + padding_x, - Y = (int)cimg::round(y/_sampling_y) + padding_y, - Z = (int)cimg::round(z/_sampling_z) + padding_z, - R = (int)cimg::round((edge - edge_min)/_sampling_r) + padding_r; - bgrid(X,Y,Z,R)+=(float)val; - bgridw(X,Y,Z,R)+=1; - } - bgrid.blur(derived_sigma_x,derived_sigma_y,derived_sigma_z,true).deriche(derived_sigma_r,0,'c',false); - bgridw.blur(derived_sigma_x,derived_sigma_y,derived_sigma_z,true).deriche(derived_sigma_r,0,'c',false); - - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(size(),4096)) - cimg_forXYZ(*this,x,y,z) { - const float edge = (float)_guide(x,y,z); - const float - X = x/_sampling_x + padding_x, - Y = y/_sampling_y + padding_y, - Z = z/_sampling_z + padding_z, - R = (edge - edge_min)/_sampling_r + padding_r; - const float bval0 = bgrid._linear_atXYZC(X,Y,Z,R), bval1 = bgridw._linear_atXYZC(X,Y,Z,R); - (*this)(x,y,z,c) = (T)(bval0/bval1); - } - } - } else { // 2D version of the algorithm - CImg bgrid(bx,by,br,2); - cimg_forC(*this,c) { - const CImg _guide = guide.get_shared_channel(c%guide._spectrum); - bgrid.fill(0); - cimg_forXY(*this,x,y) { - const T val = (*this)(x,y,c); - const float edge = (float)_guide(x,y); - const int - X = (int)cimg::round(x/_sampling_x) + padding_x, - Y = (int)cimg::round(y/_sampling_y) + padding_y, - R = (int)cimg::round((edge - edge_min)/_sampling_r) + padding_r; - bgrid(X,Y,R,0)+=(float)val; - bgrid(X,Y,R,1)+=1; - } - bgrid.blur(derived_sigma_x,derived_sigma_y,0,true).blur(0,0,derived_sigma_r,false); - - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(size(),4096)) - cimg_forXY(*this,x,y) { - const float edge = (float)_guide(x,y); - const float - X = x/_sampling_x + padding_x, - Y = y/_sampling_y + padding_y, - R = (edge - edge_min)/_sampling_r + padding_r; - const float bval0 = bgrid._linear_atXYZ(X,Y,R,0), bval1 = bgrid._linear_atXYZ(X,Y,R,1); - (*this)(x,y,c) = (T)(bval0/bval1); - } - } - } - } - return *this; - } - - //! Blur image, with the joint bilateral filter \newinstance. - template - CImg get_blur_bilateral(const CImg& guide, - const float sigma_x, const float sigma_y, - const float sigma_z, const float sigma_r, - const float sampling_x, const float sampling_y, - const float sampling_z, const float sampling_r) const { - return CImg(*this,false).blur_bilateral(guide,sigma_x,sigma_y,sigma_z,sigma_r, - sampling_x,sampling_y,sampling_z,sampling_r); - } - - //! Blur image using the joint bilateral filter. - /** - \param guide Image used to model the smoothing weights. - \param sigma_s Amount of blur along the XYZ-axes. - \param sigma_r Amount of blur along the value axis. - \param sampling_s Amount of downsampling along the XYZ-axes used for the approximation. Defaults to sigma_s. - \param sampling_r Amount of downsampling along the value axis used for the approximation. Defaults to sigma_r. - **/ - template - CImg& blur_bilateral(const CImg& guide, - const float sigma_s, const float sigma_r, - const float sampling_s=0, const float sampling_r=0) { - const float _sigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(_width,_height,_depth)/100; - return blur_bilateral(guide,_sigma_s,_sigma_s,_sigma_s,sigma_r,sampling_s,sampling_s,sampling_s,sampling_r); - } - - //! Blur image using the bilateral filter \newinstance. - template - CImg get_blur_bilateral(const CImg& guide, - const float sigma_s, const float sigma_r, - const float sampling_s=0, const float sampling_r=0) const { - return CImg(*this,false).blur_bilateral(guide,sigma_s,sigma_r,sampling_s,sampling_r); - } - - // [internal] Apply a box filter (used by CImg::boxfilter() and CImg::blur_box()). - /* - \param ptr the pointer of the data - \param N size of the data - \param boxsize Size of the box filter (can be subpixel). - \param off the offset between two data point - \param order the order of the filter 0 (smoothing), 1st derivative and 2nd derivative. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - */ - static void _cimg_blur_box_apply(T *ptr, const float boxsize, const int N, const ulongT off, - const int order, const unsigned int boundary_conditions, - const unsigned int nb_iter) { - const int nboundary_conditions = boundary_conditions>1 && boxsize<=3?1:boundary_conditions; - - // Smooth. - if (boxsize>1 && nb_iter) { - const int w2 = (int)(boxsize - 1)/2; - const unsigned int winsize = 2*w2 + 1U; - const double frac = (boxsize - winsize)/2.; - CImg win(winsize); - for (unsigned int iter = 0; iter=N?(T)0:ptr[x*off]; - case 1 : { // Neumann - const int nx = x<0?0:x>=N?N - 1:x; - return ptr[nx*off]; - } - case 2 : { // Periodic - const int nx = cimg::mod(x,N); - return ptr[nx*off]; - } - default : { // Mirror - const int - N2 = 2*N, - tx = cimg::mod(x,N2), - nx = tx{ 'x' | 'y' | 'z' | 'c' }. - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }. - \param nb_iter Number of filter iterations. - **/ - CImg& boxfilter(const float boxsize, const int order, const char axis='x', - const unsigned int boundary_conditions=1, - const unsigned int nb_iter=1) { - const char naxis = cimg::lowercase(axis); - const float nboxsize = boxsize>=0?boxsize:-boxsize* - (naxis=='x'?_width:naxis=='y'?_height:naxis=='z'?_depth:_spectrum)/100; - if (is_empty() || !nboxsize || (nboxsize<=1 && !order)) return *this; - switch (naxis) { - case 'x' : { - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth*_spectrum>=16)) - cimg_forYZC(*this,y,z,c) - _cimg_blur_box_apply(data(0,y,z,c),nboxsize,_width,1U,order,boundary_conditions,nb_iter); - } break; - case 'y' : { - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth*_spectrum>=16)) - cimg_forXZC(*this,x,z,c) - _cimg_blur_box_apply(data(x,0,z,c),nboxsize,_height,(ulongT)_width,order,boundary_conditions,nb_iter); - } break; - case 'z' : { - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth*_spectrum>=16)) - cimg_forXYC(*this,x,y,c) - _cimg_blur_box_apply(data(x,y,0,c),nboxsize,_depth,(ulongT)_width*_height,order,boundary_conditions,nb_iter); - } break; - default : { - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth*_spectrum>=16)) - cimg_forXYZ(*this,x,y,z) - _cimg_blur_box_apply(data(x,y,z,0),nboxsize,_spectrum,(ulongT)_width*_height*_depth, - order,boundary_conditions,nb_iter); - } - } - return *this; - } - - // Apply box filter of order 0,1 or 2 \newinstance. - CImg get_boxfilter(const float boxsize, const int order, const char axis='x', - const unsigned int boundary_conditions=1, - const unsigned int nb_iter=1) const { - return CImg(*this,false).boxfilter(boxsize,order,axis,boundary_conditions,nb_iter); - } - - //! Blur image with a box filter. - /** - \param boxsize_x Size of the box window, along the X-axis (can be subpixel). - \param boxsize_y Size of the box window, along the Y-axis (can be subpixel). - \param boxsize_z Size of the box window, along the Z-axis (can be subpixel). - \param boundary_conditions Boundary conditions. - Can be { false=dirichlet | true=neumann | 2=periodic | 3=mirror }. - \param nb_iter Number of filter iterations. - \note - - This is a recursive algorithm, not depending on the values of the box kernel size. - \see blur(). - **/ - CImg& blur_box(const float boxsize_x, const float boxsize_y, const float boxsize_z, - const unsigned int boundary_conditions=1, - const unsigned int nb_iter=1) { - if (is_empty()) return *this; - if (_width>1) boxfilter(boxsize_x,0,'x',boundary_conditions,nb_iter); - if (_height>1) boxfilter(boxsize_y,0,'y',boundary_conditions,nb_iter); - if (_depth>1) boxfilter(boxsize_z,0,'z',boundary_conditions,nb_iter); - return *this; - } - - //! Blur image with a box filter \newinstance. - CImg get_blur_box(const float boxsize_x, const float boxsize_y, const float boxsize_z, - const unsigned int boundary_conditions=1) const { - return CImg(*this,false).blur_box(boxsize_x,boxsize_y,boxsize_z,boundary_conditions); - } - - //! Blur image with a box filter. - /** - \param boxsize Size of the box window (can be subpixel). - \param boundary_conditions Boundary conditions. - Can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }.a - \see deriche(), vanvliet(). - **/ - CImg& blur_box(const float boxsize, const unsigned int boundary_conditions=1) { - const float nboxsize = boxsize>=0?boxsize:-boxsize*cimg::max(_width,_height,_depth)/100; - return blur_box(nboxsize,nboxsize,nboxsize,boundary_conditions); - } - - //! Blur image with a box filter \newinstance. - CImg get_blur_box(const float boxsize, const unsigned int boundary_conditions=1) const { - return CImg(*this,false).blur_box(boxsize,boundary_conditions); - } - - //! Blur image, with the image guided filter. - /** - \param guide Image used to guide the smoothing process. - \param radius Spatial radius. If negative, it is expressed as a percentage of the largest image size. - \param regularization Regularization parameter. - If negative, it is expressed as a percentage of the guide value range. - \note This method implements the filtering algorithm described in: - He, Kaiming; Sun, Jian; Tang, Xiaoou, "Guided Image Filtering," Pattern Analysis and Machine Intelligence, - IEEE Transactions on , vol.35, no.6, pp.1397,1409, June 2013 - **/ - template - CImg& blur_guided(const CImg& guide, const float radius, const float regularization) { - return get_blur_guided(guide,radius,regularization).move_to(*this); - } - - //! Blur image, with the image guided filter \newinstance. - template - CImg get_blur_guided(const CImg& guide, const float radius, const float regularization) const { - if (!is_sameXYZ(guide)) - throw CImgArgumentException(_cimg_instance - "blur_guided(): Invalid size for specified guide image (%u,%u,%u,%u,%p).", - cimg_instance, - guide._width,guide._height,guide._depth,guide._spectrum,guide._data); - if (is_empty() || !radius) return *this; - const int _radius = radius>=0?(int)radius:(int)(-radius*cimg::max(_width,_height,_depth)/100); - float _regularization = regularization; - if (regularization<0) { - T edge_min, edge_max = guide.max_min(edge_min); - if (edge_min==edge_max) return *this; - _regularization = -regularization*(edge_max - edge_min)/100; - } - _regularization = std::max(_regularization,0.01f); - const unsigned int psize = (unsigned int)(1 + 2*_radius); - CImg - mean_p = get_blur_box(psize,true), - mean_I = guide.get_blur_box(psize,true).resize(mean_p), - cov_Ip = get_mul(guide).blur_box(psize,true)-=mean_p.get_mul(mean_I), - var_I = guide.get_sqr().blur_box(psize,true)-=mean_I.get_sqr(), - &a = cov_Ip.div(var_I+=_regularization), - &b = mean_p-=a.get_mul(mean_I); - a.blur_box(psize,true); - b.blur_box(psize,true); - return a.mul(guide)+=b; - } - - //! Blur image using patch-based space. - /** - \param guide Image used to model the smoothing weights. - \param sigma_s Amount of blur along the XYZ-axes. - \param sigma_r Amount of blur along the value axis. - \param patch_size Size of the patches. - \param lookup_size Size of the window to search similar patches. - \param smoothness Smoothness for the patch comparison. - \param is_fast_approx Tells if a fast approximation of the gaussian function is used or not. - **/ - template - CImg& blur_patch(const CImg& guide, - const float sigma_s, const float sigma_r, const unsigned int patch_size=3, - const unsigned int lookup_size=4, const float smoothness=0, const bool is_fast_approx=true) { - if (is_empty() || !patch_size || !lookup_size) return *this; - return get_blur_patch(guide,sigma_s,sigma_r,patch_size,lookup_size,smoothness,is_fast_approx).move_to(*this); - } - - //! Blur image using patch-based space \newinstance. - template - CImg get_blur_patch(const CImg& guide, - const float sigma_s, const float sigma_r, const unsigned int patch_size=3, - const unsigned int lookup_size=4, const float smoothness=0, - const bool is_fast_approx=true) const { - -#define _cimg_blur_patch3d_fast(N) { \ - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) \ - cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*32 && res._height*res._depth>=4) \ - firstprivate(P,Q)) \ - cimg_forXYZ(res,x,y,z) _cimg_abort_try_openmp2 { \ - cimg_abort_test2; \ - cimg_def##N##x##N##x##N(res,x,y,z); \ - tfloat *pP = P._data; cimg_forC(_guide,c) { cimg_get##N##x##N##x##N(_guide,x,y,z,c,pP,tfloat); pP+=N3; } \ - const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, \ - x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \ - tfloat sum_weights = 0; \ - cimg_for_in##N##XYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) \ - if (cimg::abs(_guide(x,y,z,0) - _guide(p,q,r,0))3?0:1; \ - sum_weights+=weight; \ - cimg_forC(res,c) res(x,y,z,c)+=(Tfloat)weight*(*this)(p,q,r,c); \ - } \ - if (sum_weights>1e-10) cimg_forC(res,c) res(x,y,z,c)/=(Tfloat)sum_weights; \ - else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); \ - } _cimg_abort_catch_openmp2 } - -#define _cimg_blur_patch3d(N) { \ - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) \ - cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*32 && res._height*res._depth>=4) \ - firstprivate(P,Q)) \ - cimg_forXYZ(res,x,y,z) _cimg_abort_try_openmp2 { \ - cimg_abort_test2; \ - cimg_def##N##x##N##x##N(res,x,y,z); \ - tfloat *pP = P._data; cimg_forC(_guide,c) { cimg_get##N##x##N##x##N(_guide,x,y,z,c,pP,tfloat); pP+=N3; } \ - const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, \ - x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; \ - tfloat sum_weights = 0, weight_max = 0; \ - cimg_for_in##N##XYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (p!=x || q!=y || r!=z) { \ - tfloat *pQ = Q._data; cimg_forC(_guide,c) { cimg_get##N##x##N##x##N(_guide,p,q,r,c,pQ,tfloat); pQ+=N3; } \ - tfloat distance2 = 0; \ - pQ = Q._data; cimg_for(P,_pP,tfloat) { const tfloat dI = *_pP - *(pQ++); distance2+=dI*dI; } \ - distance2/=Pnorm; \ - const tfloat dx = (tfloat)p - x, dy = (tfloat)q - y, dz = (tfloat)r - z, \ - alldist = distance2 + (dx*dx + dy*dy + dz*dz)/sigma_s2, weight = std::exp(-alldist); \ - if (weight>weight_max) weight_max = weight; \ - sum_weights+=weight; \ - cimg_forC(res,c) res(x,y,z,c)+=(Tfloat)weight*(*this)(p,q,r,c); \ - } \ - sum_weights+=weight_max; cimg_forC(res,c) res(x,y,z,c)+=(Tfloat)weight_max*(*this)(x,y,z,c); \ - if (sum_weights>1e-10) cimg_forC(res,c) res(x,y,z,c)/=(Tfloat)sum_weights; \ - else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); \ - } _cimg_abort_catch_openmp2 } - -#define _cimg_blur_patch2d_fast(N) { \ - cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*32 && res._height>=4) \ - firstprivate(P,Q)) \ - cimg_forXY(res,x,y) _cimg_abort_try_openmp2 { \ - cimg_abort_test2; \ - cimg_def##N##x##N(res,x,y); \ - tfloat *pP = P._data; cimg_forC(_guide,c) { cimg_get##N##x##N(_guide,x,y,0,c,pP,tfloat); pP+=N2; } \ - const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; \ - tfloat sum_weights = 0; \ - cimg_for_in##N##XY(res,x0,y0,x1,y1,p,q) \ - if (cimg::abs(_guide(x,y,0,0) - _guide(p,q,0,0))3?0:1; \ - sum_weights+=weight; \ - cimg_forC(res,c) res(x,y,c)+=(Tfloat)weight*(*this)(p,q,c); \ - } \ - if (sum_weights>1e-10) cimg_forC(res,c) res(x,y,c)/=(Tfloat)sum_weights; \ - else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); \ - } _cimg_abort_catch_openmp2 } - -#define _cimg_blur_patch2d(N) { \ - cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*32 && res._height>=4) \ - firstprivate(P,Q)) \ - cimg_forXY(res,x,y) _cimg_abort_try_openmp2 { \ - cimg_abort_test2; \ - cimg_def##N##x##N(res,x,y); \ - tfloat *pP = P._data; cimg_forC(_guide,c) { cimg_get##N##x##N(_guide,x,y,0,c,pP,tfloat); pP+=N2; } \ - const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; \ - tfloat sum_weights = 0, weight_max = 0; \ - cimg_for_in##N##XY(res,x0,y0,x1,y1,p,q) if (p!=x || q!=y) { \ - tfloat *pQ = Q._data; cimg_forC(_guide,c) { cimg_get##N##x##N(_guide,p,q,0,c,pQ,tfloat); pQ+=N2; } \ - tfloat distance2 = 0; \ - pQ = Q._data; cimg_for(P,_pP,tfloat) { const tfloat dI = *_pP - *(pQ++); distance2+=dI*dI; } \ - distance2/=Pnorm; \ - const tfloat dx = (tfloat)p - x, dy = (tfloat)q - y, \ - alldist = distance2 + (dx*dx+dy*dy)/sigma_s2, weight = std::exp(-alldist); \ - if (weight>weight_max) weight_max = weight; \ - sum_weights+=weight; \ - cimg_forC(res,c) res(x,y,c)+=(Tfloat)weight*(*this)(p,q,c); \ - } \ - sum_weights+=weight_max; cimg_forC(res,c) res(x,y,c)+=(Tfloat)weight_max*(*this)(x,y,c); \ - if (sum_weights>1e-10) cimg_forC(res,c) res(x,y,c)/=(Tfloat)sum_weights; \ - else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); \ - } _cimg_abort_catch_openmp2 } - - typedef _cimg_tfloat tfloat; - if (!is_sameXYZ(guide)) - throw CImgArgumentException(_cimg_instance - "blur_patch(): Invalid size for specified guide image (%u,%u,%u,%u,%p).", - cimg_instance, - guide._width,guide._height,guide._depth,guide._spectrum,guide._data); - if (is_empty() || !patch_size || !lookup_size) return +*this; - Tfloat val_min, val_max = (Tfloat)max_min(val_min); - _cimg_abort_init_openmp; - cimg_abort_init; - - CImg res(_width,_height,_depth,_spectrum,0); - const CImg - __guide = guide?CImg(guide,guide.pixel_type()==cimg::type::string()): - CImg(*this,pixel_type()==cimg::type::string()), - _guide = smoothness>0?__guide.get_blur(smoothness):__guide.get_shared(); - CImg P(_guide._spectrum*patch_size*patch_size*(_depth>1?patch_size:1)), Q(P); - - t guide_min = (t)0, guide_max = (t)0; - if (sigma_r<0) guide_max = guide.max_min(guide_min); - const float - guide_delta = (float)(guide_max - guide_min), - _sigma_s = sigma_s>=0?sigma_s:-sigma_s*cimg::max(_width,_height,_depth)/100, - _sigma_r = sigma_r>=0?sigma_r:-sigma_r*guide_delta/100, - sigma_s2 = _sigma_s*_sigma_s, - sigma_r2 = _sigma_r*_sigma_r, - sigma_r3 = 3*_sigma_r, - Pnorm = P.size()*sigma_r2; - const int rsize2 = (int)lookup_size/2, rsize1 = (int)lookup_size - rsize2 - 1; - const unsigned int N2 = patch_size*patch_size, N3 = N2*patch_size; - cimg::unused(N2,N3); - if (_depth>1) switch (patch_size) { // 3D - case 2 : if (is_fast_approx) _cimg_blur_patch3d_fast(2) else _cimg_blur_patch3d(2) break; - case 3 : if (is_fast_approx) _cimg_blur_patch3d_fast(3) else _cimg_blur_patch3d(3) break; - default : { - const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1; - if (is_fast_approx) { - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*32 && res._height*res._depth>=4) - firstprivate(P,Q)) - cimg_forXYZ(res,x,y,z) _cimg_abort_try_openmp2 { // Fast - cimg_abort_test2; - P = _guide.get_crop(x - psize1,y - psize1,z - psize1,x + psize2,y + psize2,z + psize2,true); - const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, - x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; - tfloat sum_weights = 0; - cimg_for_inXYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) - if (cimg::abs(_guide(x,y,z,0) - _guide(p,q,r,0))3?0:1; - sum_weights+=weight; - cimg_forC(res,c) res(x,y,z,c)+=(Tfloat)weight*(*this)(p,q,r,c); - } - if (sum_weights>1e-10) cimg_forC(res,c) res(x,y,z,c)/=(Tfloat)sum_weights; - else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); - } _cimg_abort_catch_openmp2 - } else { - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*32 && res._height*res._depth>=4) - firstprivate(P,Q)) - cimg_forXYZ(res,x,y,z) _cimg_abort_try_openmp2 { // Exact - cimg_abort_test2; - P = _guide.get_crop(x - psize1,y - psize1,z - psize1,x + psize2,y + psize2,z + psize2,true); - const int x0 = x - rsize1, y0 = y - rsize1, z0 = z - rsize1, - x1 = x + rsize2, y1 = y + rsize2, z1 = z + rsize2; - tfloat sum_weights = 0, weight_max = 0; - cimg_for_inXYZ(res,x0,y0,z0,x1,y1,z1,p,q,r) if (p!=x || q!=y || r!=z) { - (Q = _guide.get_crop(p - psize1,q - psize1,r - psize1,p + psize2,q + psize2,r + psize2,true))-=P; - const tfloat - dx = (tfloat)x - p, dy = (tfloat)y - q, dz = (tfloat)z - r, - distance2 = (tfloat)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy + dz*dz)/sigma_s2), - weight = std::exp(-distance2); - if (weight>weight_max) weight_max = weight; - sum_weights+=weight; - cimg_forC(res,c) res(x,y,z,c)+=(Tfloat)weight*(*this)(p,q,r,c); - } - sum_weights+=weight_max; cimg_forC(res,c) res(x,y,z,c)+=(Tfloat)weight_max*(*this)(x,y,z,c); - if (sum_weights>1e-10) cimg_forC(res,c) res(x,y,z,c)/=(Tfloat)sum_weights; - else cimg_forC(res,c) res(x,y,z,c) = (Tfloat)((*this)(x,y,z,c)); - } _cimg_abort_catch_openmp2 - } - } - } else switch (patch_size) { // 2D - case 2 : if (is_fast_approx) _cimg_blur_patch2d_fast(2) else _cimg_blur_patch2d(2) break; - case 3 : if (is_fast_approx) _cimg_blur_patch2d_fast(3) else _cimg_blur_patch2d(3) break; - case 4 : if (is_fast_approx) _cimg_blur_patch2d_fast(4) else _cimg_blur_patch2d(4) break; - case 5 : if (is_fast_approx) _cimg_blur_patch2d_fast(5) else _cimg_blur_patch2d(5) break; - case 6 : if (is_fast_approx) _cimg_blur_patch2d_fast(6) else _cimg_blur_patch2d(6) break; - case 7 : if (is_fast_approx) _cimg_blur_patch2d_fast(7) else _cimg_blur_patch2d(7) break; - case 8 : if (is_fast_approx) _cimg_blur_patch2d_fast(8) else _cimg_blur_patch2d(8) break; - case 9 : if (is_fast_approx) _cimg_blur_patch2d_fast(9) else _cimg_blur_patch2d(9) break; - default : { // Fast - const int psize2 = (int)patch_size/2, psize1 = (int)patch_size - psize2 - 1; - if (is_fast_approx) { - cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*32 && res._height>=4) - firstprivate(P,Q)) - cimg_forXY(res,x,y) _cimg_abort_try_openmp2 { // Fast - cimg_abort_test2; - P = _guide.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true); - const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; - tfloat sum_weights = 0; - cimg_for_inXY(res,x0,y0,x1,y1,p,q) - if (cimg::abs(_guide(x,y,0) - _guide(p,q,0))3?0:1; - sum_weights+=weight; - cimg_forC(res,c) res(x,y,c)+=(Tfloat)weight*(*this)(p,q,c); - } - if (sum_weights>1e-10) cimg_forC(res,c) res(x,y,c)/=(Tfloat)sum_weights; - else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); - } _cimg_abort_catch_openmp2 - } else { - cimg_pragma_openmp(parallel for cimg_openmp_if(res._width>=(cimg_openmp_sizefactor)*32 && res._height>=4) - firstprivate(P,Q)) - cimg_forXY(res,x,y) _cimg_abort_try_openmp2 { // Exact - cimg_abort_test2; - P = _guide.get_crop(x - psize1,y - psize1,x + psize2,y + psize2,true); - const int x0 = x - rsize1, y0 = y - rsize1, x1 = x + rsize2, y1 = y + rsize2; - tfloat sum_weights = 0, weight_max = 0; - cimg_for_inXY(res,x0,y0,x1,y1,p,q) if (p!=x || q!=y) { - (Q = _guide.get_crop(p - psize1,q - psize1,p + psize2,q + psize2,true))-=P; - const tfloat - dx = (tfloat)x - p, dy = (tfloat)y - q, - distance2 = (tfloat)(Q.pow(2).sum()/Pnorm + (dx*dx + dy*dy)/sigma_s2), - weight = std::exp(-distance2); - if (weight>weight_max) weight_max = weight; - sum_weights+=weight; - cimg_forC(res,c) res(x,y,c)+=(Tfloat)weight*(*this)(p,q,c); - } - sum_weights+=weight_max; cimg_forC(res,c) res(x,y,c)+=(Tfloat)weight_max*(*this)(x,y,c); - if (sum_weights>1e-10) cimg_forC(res,c) res(x,y,c)/=(Tfloat)sum_weights; - else cimg_forC(res,c) res(x,y,c) = (Tfloat)((*this)(x,y,c)); - } _cimg_abort_catch_openmp2 - } - } - } - cimg_abort_test; - return res.cut(val_min,val_max); - } - - //! Blur image using patch-based space \simplification. - CImg& blur_patch(const float sigma_s, const float sigma_r, const unsigned int patch_size=3, - const unsigned int lookup_size=4, const float smoothness=0, const bool is_fast_approx=true) { - return blur_patch(*this,sigma_s,sigma_r,patch_size,lookup_size,smoothness,is_fast_approx); - } - - //! Blur image using patch-based space \simplification \newinstance. - CImg get_blur_patch(const float sigma_s, const float sigma_r, const unsigned int patch_size=3, - const unsigned int lookup_size=4, const float smoothness=0, - const bool is_fast_approx=true) const { - return get_blur_patch(*this,sigma_s,sigma_r,patch_size,lookup_size,smoothness,is_fast_approx); - } - - //! Blur image with the median filter. - /** - \param n Size of the median filter. - \param threshold Threshold used to discard pixels too far from the current pixel value in the median computation. - **/ - CImg& blur_median(const unsigned int n, const float threshold=0) { - if (!n) return *this; - return get_blur_median(n,threshold).move_to(*this); - } - - //! Blur image with the median filter \newinstance. - CImg get_blur_median(const unsigned int n, const float threshold=0) const { - if (is_empty() || n<=1) return +*this; - CImg res(_width,_height,_depth,_spectrum); - T *ptrd = res._data; - cimg::unused(ptrd); - const int hr = (int)n/2, hl = n - hr - 1; - if (res._depth!=1) { // 3D - if (threshold>0) - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*16 && - _height*_depth*_spectrum>=4)) - cimg_forXYZC(*this,x,y,z,c) { // With threshold - const int - x0 = x - hl, y0 = y - hl, z0 = z - hl, x1 = x + hr, y1 = y + hr, z1 = z + hr, - nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0, - nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1, nz1 = z1>=depth()?depth() - 1:z1; - const Tfloat val0 = (Tfloat)(*this)(x,y,z,c); - CImg values(n*n*n); - unsigned int nb_values = 0; - T *_ptrd = values.data(); - cimg_for_inXYZ(*this,nx0,ny0,nz0,nx1,ny1,nz1,p,q,r) - if (cimg::abs((*this)(p,q,r,c) - val0)<=threshold) { *(_ptrd++) = (*this)(p,q,r,c); ++nb_values; } - res(x,y,z,c) = nb_values?values.get_shared_points(0,nb_values - 1).median():(*this)(x,y,z,c); - } - else - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*16 && - _height*_depth*_spectrum>=4)) - cimg_forXYZC(*this,x,y,z,c) { // Without threshold - const int - x0 = x - hl, y0 = y - hl, z0 = z - hl, x1 = x + hr, y1 = y + hr, z1 = z + hr, - nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, nz0 = z0<0?0:z0, - nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1, nz1 = z1>=depth()?depth() - 1:z1; - res(x,y,z,c) = get_crop(nx0,ny0,nz0,c,nx1,ny1,nz1,c).median(); - } - } else { - if (threshold>0) - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*16 && - _height*_spectrum>=4)) - cimg_forXYC(*this,x,y,c) { // With threshold - const int - x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr, - nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, - nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1; - const Tfloat val0 = (Tfloat)(*this)(x,y,c); - CImg values(n*n); - unsigned int nb_values = 0; - T *_ptrd = values.data(); - cimg_for_inXY(*this,nx0,ny0,nx1,ny1,p,q) - if (cimg::abs((*this)(p,q,c) - val0)<=threshold) { *(_ptrd++) = (*this)(p,q,c); ++nb_values; } - res(x,y,c) = nb_values?values.get_shared_points(0,nb_values - 1).median():(*this)(x,y,c); - } - else { - const int - w1 = width() - 1, h1 = height() - 1, - w2 = width() - 2, h2 = height() - 2, - w3 = width() - 3, h3 = height() - 3, - w4 = width() - 4, h4 = height() - 4; - switch (n) { // Without threshold - case 3 : { - cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2)) - cimg_forC(*this,c) { - CImg I(9); - cimg_for_in3x3(*this,1,1,w2,h2,x,y,0,c,I,T) - res(x,y,c) = cimg::median(I[0],I[1],I[2],I[3],I[4],I[5],I[6],I[7],I[8]); - cimg_for_borderXY(*this,x,y,1) - res(x,y,c) = get_crop(std::max(0,x - 1),std::max(0,y - 1),0,c, - std::min(w1,x + 1),std::min(h1,y + 1),0,c).median(); - } - } break; - case 5 : { - cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2)) - cimg_forC(*this,c) { - CImg I(25); - cimg_for_in5x5(*this,2,2,w3,h3,x,y,0,c,I,T) - res(x,y,c) = cimg::median(I[0],I[1],I[2],I[3],I[4], - I[5],I[6],I[7],I[8],I[9], - I[10],I[11],I[12],I[13],I[14], - I[15],I[16],I[17],I[18],I[19], - I[20],I[21],I[22],I[23],I[24]); - cimg_for_borderXY(*this,x,y,2) - res(x,y,c) = get_crop(std::max(0,x - 2),std::max(0,y - 2),0,c, - std::min(w1,x + 2),std::min(h1,y + 2),0,c).median(); - } - } break; - case 7 : { - cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2)) - cimg_forC(*this,c) { - CImg I(49); - cimg_for_in7x7(*this,3,3,w4,h4,x,y,0,c,I,T) - res(x,y,c) = cimg::median(I[0],I[1],I[2],I[3],I[4],I[5],I[6], - I[7],I[8],I[9],I[10],I[11],I[12],I[13], - I[14],I[15],I[16],I[17],I[18],I[19],I[20], - I[21],I[22],I[23],I[24],I[25],I[26],I[27], - I[28],I[29],I[30],I[31],I[32],I[33],I[34], - I[35],I[36],I[37],I[38],I[39],I[40],I[41], - I[42],I[43],I[44],I[45],I[46],I[47],I[48]); - cimg_for_borderXY(*this,x,y,3) - res(x,y,c) = get_crop(std::max(0,x - 3),std::max(0,y - 3),0,c, - std::min(w1,x + 3),std::min(h1,y + 3),0,c).median(); - } - } break; - default : { - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*16 && _height*_spectrum>=4)) - cimg_forXYC(*this,x,y,c) { - const int - x0 = x - hl, y0 = y - hl, x1 = x + hr, y1 = y + hr, - nx0 = x0<0?0:x0, ny0 = y0<0?0:y0, - nx1 = x1>=width()?width() - 1:x1, ny1 = y1>=height()?height() - 1:y1; - res(x,y,c) = get_crop(nx0,ny0,0,c,nx1,ny1,0,c).median(); - } - } - } - } - } - return res; - } - - //! Sharpen image. - /** - \param amplitude Sharpening amplitude - \param sharpen_type Select sharpening method. Can be { false=inverse diffusion | true=shock filters }. - \param edge Edge threshold (shock filters only). - \param alpha Gradient smoothness (shock filters only). - \param sigma Tensor smoothness (shock filters only). - **/ - CImg& sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, - const float alpha=0, const float sigma=0) { - if (is_empty()) return *this; - T val_min, val_max = max_min(val_min); - const float nedge = edge/2; - CImg velocity(_width,_height,_depth,_spectrum), _veloc_max(_spectrum); - - if (_depth>1) { // 3D - if (sharpen_type) { // Shock filters - CImg G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors()); - if (sigma>0) G.blur(sigma); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*32 && - _height*_depth>=16)) - cimg_forYZ(G,y,z) { - Tfloat *ptrG0 = G.data(0,y,z,0), *ptrG1 = G.data(0,y,z,1), - *ptrG2 = G.data(0,y,z,2), *ptrG3 = G.data(0,y,z,3); - CImg val, vec; - cimg_forX(G,x) { - G.get_tensor_at(x,y,z).symmetric_eigen(val,vec); - if (val[0]<0) val[0] = 0; - if (val[1]<0) val[1] = 0; - if (val[2]<0) val[2] = 0; - *(ptrG0++) = vec(0,0); - *(ptrG1++) = vec(0,1); - *(ptrG2++) = vec(0,2); - *(ptrG3++) = 1 - (Tfloat)std::pow(1 + val[0] + val[1] + val[2],-(Tfloat)nedge); - } - } - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*512 && - _spectrum>=2)) - cimg_forC(*this,c) { - Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0; - CImg_3x3x3(I,Tfloat); - cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { - const Tfloat - u = G(x,y,z,0), - v = G(x,y,z,1), - w = G(x,y,z,2), - amp = G(x,y,z,3), - ixx = Incc + Ipcc - 2*Iccc, - ixy = (Innc + Ippc - Inpc - Ipnc)/4, - ixz = (Incn + Ipcp - Incp - Ipcn)/4, - iyy = Icnc + Icpc - 2*Iccc, - iyz = (Icnn + Icpp - Icnp - Icpn)/4, - izz = Iccn + Iccp - 2*Iccc, - ixf = Incc - Iccc, - ixb = Iccc - Ipcc, - iyf = Icnc - Iccc, - iyb = Iccc - Icpc, - izf = Iccn - Iccc, - izb = Iccc - Iccp, - itt = u*u*ixx + v*v*iyy + w*w*izz + 2*u*v*ixy + 2*u*w*ixz + 2*v*w*iyz, - it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb) + w*cimg::minmod(izf,izb), - veloc = -amp*cimg::sign(itt)*cimg::abs(it); - *(ptrd++) = veloc; - if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; - } - _veloc_max[c] = veloc_max; - } - } else // Inverse diffusion - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*512 && - _spectrum>=2)) - cimg_forC(*this,c) { - Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0; - CImg_3x3x3(I,Tfloat); - cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { - const Tfloat veloc = -Ipcc - Incc - Icpc - Icnc - Iccp - Iccn + 6*Iccc; - *(ptrd++) = veloc; - if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; - } - _veloc_max[c] = veloc_max; - } - } else { // 2D - if (sharpen_type) { // Shock filters - CImg G = (alpha>0?get_blur(alpha).get_structure_tensors():get_structure_tensors()); - if (sigma>0) G.blur(sigma); - cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*32 && - _height>=(cimg_openmp_sizefactor)*16)) - cimg_forY(G,y) { - CImg val, vec; - Tfloat *ptrG0 = G.data(0,y,0,0), *ptrG1 = G.data(0,y,0,1), *ptrG2 = G.data(0,y,0,2); - cimg_forX(G,x) { - G.get_tensor_at(x,y).symmetric_eigen(val,vec); - if (val[0]<0) val[0] = 0; - if (val[1]<0) val[1] = 0; - *(ptrG0++) = vec(0,0); - *(ptrG1++) = vec(0,1); - *(ptrG2++) = 1 - (Tfloat)std::pow(1 + val[0] + val[1],-(Tfloat)nedge); - } - } - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*512 && - _spectrum>=2)) - cimg_forC(*this,c) { - Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0; - CImg_3x3(I,Tfloat); - cimg_for3x3(*this,x,y,0,c,I,Tfloat) { - const Tfloat - u = G(x,y,0), - v = G(x,y,1), - amp = G(x,y,2), - ixx = Inc + Ipc - 2*Icc, - ixy = (Inn + Ipp - Inp - Ipn)/4, - iyy = Icn + Icp - 2*Icc, - ixf = Inc - Icc, - ixb = Icc - Ipc, - iyf = Icn - Icc, - iyb = Icc - Icp, - itt = u*u*ixx + v*v*iyy + 2*u*v*ixy, - it = u*cimg::minmod(ixf,ixb) + v*cimg::minmod(iyf,iyb), - veloc = -amp*cimg::sign(itt)*cimg::abs(it); - *(ptrd++) = veloc; - if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; - } - _veloc_max[c] = veloc_max; - } - } else // Inverse diffusion - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*512 && - _spectrum>=2)) - cimg_forC(*this,c) { - Tfloat *ptrd = velocity.data(0,0,0,c), veloc_max = 0; - CImg_3x3(I,Tfloat); - cimg_for3x3(*this,x,y,0,c,I,Tfloat) { - const Tfloat veloc = -Ipc - Inc - Icp - Icn + 4*Icc; - *(ptrd++) = veloc; - if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; - } - _veloc_max[c] = veloc_max; - } - } - const Tfloat veloc_max = _veloc_max.max(); - if (veloc_max<=0) return *this; - return ((velocity*=amplitude/veloc_max)+=*this).cut(val_min,val_max).move_to(*this); - } - - //! Sharpen image \newinstance. - CImg get_sharpen(const float amplitude, const bool sharpen_type=false, const float edge=1, - const float alpha=0, const float sigma=0) const { - return (+*this).sharpen(amplitude,sharpen_type,edge,alpha,sigma); - } - - //! Return image gradient. - /** - \param axes Axes considered for the gradient computation, as a C-string (e.g "xy"). - \param scheme = Numerical scheme used for the gradient computation: - - -1 = Backward finite differences - - 0 = Centered finite differences (default) - - 1 = Forward finite differences - - 2 = Using Sobel kernels - - 3 = Using rotation invariant kernels - - 4 = Using Deriche recursive filter. - - 5 = Using Van Vliet recursive filter. - **/ - CImgList get_gradient(const char *const axes=0, const int scheme=0) const { - CImgList res; - char __axes[4] = { 0 }; - const char *_axes = axes?axes:__axes; - if (!axes) { - unsigned int k = 0; - if (_width>1) __axes[k++] = 'x'; - if (_height>1) __axes[k++] = 'y'; - if (_depth>1) __axes[k++] = 'z'; - } - - CImg grad; - while (*_axes) { - const char axis = cimg::lowercase(*(_axes++)); - if (axis!='x' && axis!='y' && axis!='z') - throw CImgArgumentException(_cimg_instance - "get_gradient(): Invalid specified axes '%s'.", - cimg_instance, - axes); - const longT off = axis=='x'?1:axis=='y'?_width:_width*_height; - if ((axis=='x' && _width==1) || (axis=='y' && _height==1) || (axis=='z' && _depth==1)) { - grad.assign(_width,_height,_depth,_spectrum,0).move_to(res); - continue; - } - - const int _scheme = axis=='z' && (scheme==2 || scheme==3)?0:scheme; - switch (_scheme) { - case -1 : { // Backward finite differences - grad.assign(_width,_height,_depth,_spectrum); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(size(),16384)) - cimg_forXYZC(*this,x,y,z,c) { - const ulongT pos = offset(x,y,z,c); - if ((axis=='x' && !x) || (axis=='y' && !y) || (axis=='z' && !z)) - grad[pos] = 0; - else - grad[pos] = (Tfloat)_data[pos] - _data[pos - off]; - } - grad.move_to(res); - } break; - case 1 : { // Forward finite differences - grad.assign(_width,_height,_depth,_spectrum); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(size(),16384)) - cimg_forXYZC(*this,x,y,z,c) { - const ulongT pos = offset(x,y,z,c); - if ((axis=='x' && x==width() - 1) || (axis=='y' && y==height() - 1) || (axis=='z' && z==depth() - 1)) - grad[pos] = 0; - else - grad[pos] = (Tfloat)_data[pos + off] - _data[pos]; - } - grad.move_to(res); - } break; - case 2 : { // Sobel scheme - grad.assign(_width,_height,_depth,_spectrum); - if (axis=='x') // X-axis - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*16384 && - _depth*_spectrum>=2)) - cimg_forZC(*this,z,c) { - CImg_3x3(I,Tfloat); - cimg_for3x3(*this,x,y,z,c,I,Tfloat) grad(x,y,z,c) = - Ipp + Inp - 2*Ipc + 2*Inc - Ipn + Inn; - } - else // Y-axis - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*16384 && - _depth*_spectrum>=2)) - cimg_forZC(*this,z,c) { - CImg_3x3(I,Tfloat); - cimg_for3x3(*this,x,y,z,c,I,Tfloat) grad(x,y,z,c) = - Ipp - 2*Icp - Inp + Ipn + 2*Icn + Inn; - } - grad.move_to(res); - } break; - case 3 : { // Rotation invariant scheme - const Tfloat a = (Tfloat)(0.25f*(2 - std::sqrt(2.f))), b = (Tfloat)(0.5f*(std::sqrt(2.f) - 1)); - grad.assign(_width,_height,_depth,_spectrum); - if (axis=='x') // X-axis - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*16384 && - _depth*_spectrum>=2)) - cimg_forZC(*this,z,c) { - CImg_3x3(I,Tfloat); - cimg_for3x3(*this,x,y,z,c,I,Tfloat) grad(x,y,z,c) = -a*Ipp - b*Ipc - a*Ipn + a*Inp + b*Inc + a*Inn; - } - else // Y-axis - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*16384 && - _depth*_spectrum>=2)) - cimg_forZC(*this,z,c) { - CImg_3x3(I,Tfloat); - cimg_for3x3(*this,x,y,z,c,I,Tfloat) grad(x,y,z,c) = -a*Ipp - b*Icp - a*Inp + a*Ipn + b*Icn + a*Inn; - } - grad.move_to(res); - } break; - case 4 : // Deriche filter - get_deriche(0,1,axis).move_to(res); - break; - case 5 : // Van Vliet filter - get_vanvliet(0,1,axis).move_to(res); - break; - default : { // Central finite differences - grad.assign(_width,_height,_depth,_spectrum); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) cimg_openmp_if_size(size(),16384)) - cimg_forXYZC(*this,x,y,z,c) { - const ulongT pos = offset(x,y,z,c); - if ((axis=='x' && !x) || (axis=='y' && !y) || (axis=='z' && !z)) - grad[pos] = ((Tfloat)_data[pos + off] - _data[pos])/2; - else if ((axis=='x' && x==width() - 1) || (axis=='y' && y==height() - 1) || (axis=='z' && z==depth() - 1)) - grad[pos] = ((Tfloat)_data[pos] - _data[pos - off])/2; - else - grad[pos] = ((Tfloat)_data[pos + off] - _data[pos - off])/2; - } - grad.move_to(res); - } break; - } - } - return res; - } - - //! Return image hessian. - /** - \param axes Axes considered for the hessian computation, as a C-string (e.g "xy"). - **/ - CImgList get_hessian(const char *const axes=0) const { - CImgList res; - char __axes[12] = { 0 }; - const char *_axes = axes?axes:__axes; - if (!axes) { - unsigned int k = 0; - if (_width>1) { __axes[k++] = 'x'; __axes[k++] = 'x'; } - if (_width>1 && _height>1) { __axes[k++] = 'x'; __axes[k++] = 'y'; } - if (_width>1 && _depth>1) { __axes[k++] = 'x'; __axes[k++] = 'z'; } - if (_height>1) { __axes[k++] = 'y'; __axes[k++] = 'y'; } - if (_height>1 && _depth>1) { __axes[k++] = 'y'; __axes[k++] = 'z'; } - if (_depth>1) { __axes[k++] = 'z'; __axes[k++] = 'z'; } - } - const unsigned int len = (unsigned int)std::strlen(_axes); - if (len%2) - throw CImgArgumentException(_cimg_instance - "get_hessian(): Invalid specified axes '%s'.", - cimg_instance, - axes); - CImg hess; - for (unsigned int k = 0; k=(cimg_openmp_sizefactor)*16384 && - _depth*_spectrum>=2)) - cimg_forZC(*this,z,c) { - CImg_3x3(I,Tfloat); - cimg_for3x3(*this,x,y,z,c,I,Tfloat) hess(x,y,z,c) = (Inn + Ipp - Inp - Ipn)/4; - } - else if (axis1=='x' && axis2=='z') // Ixz - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*16384 && - _spectrum>=2)) - cimg_forC(*this,c) { - CImg_3x3x3(I,Tfloat); - cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) hess(x,y,z,c) = (Incn + Ipcp - Incp - Ipcn)/4; - } - else // Iyz - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*16384 && - _spectrum>=2)) - cimg_forC(*this,c) { - CImg_3x3x3(I,Tfloat); - cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) hess(x,y,z,c) = (Icnn + Icpp - Icnp - Icpn)/4; - } - hess.move_to(res); - } - return res; - } - - //! Compute image Laplacian. - CImg& laplacian() { - return get_laplacian().move_to(*this); - } - - //! Compute image Laplacian \newinstance. - CImg get_laplacian() const { - if (is_empty()) return CImg(); - CImg res(_width,_height,_depth,_spectrum); - if (_depth>1) { // 3D - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*1048576 && - _spectrum>=2)) - cimg_forC(*this,c) { - Tfloat *ptrd = res.data(0,0,0,c); - CImg_3x3x3(I,Tfloat); - cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) *(ptrd++) = Incc + Ipcc + Icnc + Icpc + Iccn + Iccp - 6*Iccc; - } - } else if (_height>1) { // 2D - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*1048576 && - _depth*_spectrum>=2)) - cimg_forC(*this,c) { - Tfloat *ptrd = res.data(0,0,0,c); - CImg_3x3(I,Tfloat); - cimg_for3x3(*this,x,y,0,c,I,Tfloat) *(ptrd++) = Inc + Ipc + Icn + Icp - 4*Icc; - } - } else { // 1D - cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*1048576 && - _height*_depth*_spectrum>=2)) - cimg_forC(*this,c) { - Tfloat *ptrd = res.data(0,0,0,c); - CImg_3x3(I,Tfloat); - cimg_for3x3(*this,x,y,0,c,I,Tfloat) *(ptrd++) = Inc + Ipc - 2*Icc; - } - } - return res; - } - - //! Compute the structure tensor field of an image. - /** - \param is_fwbw_scheme scheme. Can be { false=centered | true=forward-backward } - **/ - CImg& structure_tensors(const bool is_fwbw_scheme=false) { - return get_structure_tensors(is_fwbw_scheme).move_to(*this); - } - - //! Compute the structure tensor field of an image \newinstance. - CImg get_structure_tensors(const bool is_fwbw_scheme=false) const { - if (is_empty()) return *this; - CImg res; - if (_depth>1) { // 3D - res.assign(_width,_height,_depth,6,0); - if (!is_fwbw_scheme) { // Classical central finite differences - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*1048576 && - _spectrum>=2)) - cimg_forC(*this,c) { - Tfloat - *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2), - *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5); - CImg_3x3x3(I,Tfloat); - cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { - const Tfloat - ix = (Incc - Ipcc)/2, - iy = (Icnc - Icpc)/2, - iz = (Iccn - Iccp)/2; - cimg_pragma_openmp(atomic) *(ptrd0++)+=ix*ix; - cimg_pragma_openmp(atomic) *(ptrd1++)+=ix*iy; - cimg_pragma_openmp(atomic) *(ptrd2++)+=ix*iz; - cimg_pragma_openmp(atomic) *(ptrd3++)+=iy*iy; - cimg_pragma_openmp(atomic) *(ptrd4++)+=iy*iz; - cimg_pragma_openmp(atomic) *(ptrd5++)+=iz*iz; - } - } - } else { // Forward/backward finite differences - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*1048576 && - _spectrum>=2)) - cimg_forC(*this,c) { - Tfloat - *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2), - *ptrd3 = res.data(0,0,0,3), *ptrd4 = res.data(0,0,0,4), *ptrd5 = res.data(0,0,0,5); - CImg_3x3x3(I,Tfloat); - cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) { - const Tfloat - ixf = Incc - Iccc, ixb = Iccc - Ipcc, ixc = (Incc - Ipcc)/2, - iyf = Icnc - Iccc, iyb = Iccc - Icpc, iyc = (Icnc - Icpc)/2, - izf = Iccn - Iccc, izb = Iccc - Iccp, izc = (Iccn - Iccp)/2; - cimg_pragma_openmp(atomic) *(ptrd0++)+=(ixf*ixf + ixb*ixb)/2; - cimg_pragma_openmp(atomic) *(ptrd1++)+=ixc*iyc; - cimg_pragma_openmp(atomic) *(ptrd2++)+=ixc*izc; - cimg_pragma_openmp(atomic) *(ptrd3++)+=(iyf*iyf + iyb*iyb)/2; - cimg_pragma_openmp(atomic) *(ptrd4++)+=iyc*izc; - cimg_pragma_openmp(atomic) *(ptrd5++)+=(izf*izf + izb*izb)/2; - } - } - } - } else { // 2D - res.assign(_width,_height,_depth,3,0); - if (!is_fwbw_scheme) { // Classical central finite differences - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*1048576 && - _depth*_spectrum>=2)) - cimg_forC(*this,c) { - Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); - CImg_3x3(I,Tfloat); - cimg_for3x3(*this,x,y,0,c,I,Tfloat) { - const Tfloat - ix = (Inc - Ipc)/2, - iy = (Icn - Icp)/2; - cimg_pragma_openmp(atomic) *(ptrd0++)+=ix*ix; - cimg_pragma_openmp(atomic) *(ptrd1++)+=ix*iy; - cimg_pragma_openmp(atomic) *(ptrd2++)+=iy*iy; - } - } - } else { // Forward/backward finite differences (version 2) - cimg_pragma_openmp(parallel for cimg_openmp_if(_width*_height>=(cimg_openmp_sizefactor)*1048576 && - _depth*_spectrum>=2)) - cimg_forC(*this,c) { - Tfloat *ptrd0 = res.data(0,0,0,0), *ptrd1 = res.data(0,0,0,1), *ptrd2 = res.data(0,0,0,2); - CImg_3x3(I,Tfloat); - cimg_for3x3(*this,x,y,0,c,I,Tfloat) { - const Tfloat - ixf = Inc - Icc, ixb = Icc - Ipc, ixc = (Inc - Ipc)/2, - iyf = Icn - Icc, iyb = Icc - Icp, iyc = (Icn - Icp)/2; - cimg_pragma_openmp(atomic) *(ptrd0++)+=(ixf*ixf + ixb*ixb)/2; - cimg_pragma_openmp(atomic) *(ptrd1++)+=ixc*iyc; - cimg_pragma_openmp(atomic) *(ptrd2++)+=(iyf*iyf + iyb*iyb)/2; - } - } - } - } - return res; - } - - //! Compute field of diffusion tensors for edge-preserving smoothing. - /** - \param sharpness Sharpness - \param anisotropy Anisotropy - \param alpha Standard deviation of the gradient blur. - \param sigma Standard deviation of the structure tensor blur. - \param is_sqrt Tells if the square root of the tensor field is computed instead. - **/ - CImg& diffusion_tensors(const float sharpness=0.7f, const float anisotropy=0.6f, - const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false) { - CImg res; - const float - nsharpness = std::max(sharpness,1e-5f), - power1 = (is_sqrt?0.5f:1)*nsharpness, - power2 = power1/(1e-7f + 1 - anisotropy); - blur(alpha).normalize(0,(T)255); - - if (_depth>1) { // 3D - get_structure_tensors().move_to(res).blur(sigma); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height*_depth>=(cimg_openmp_sizefactor)*256)) - cimg_forYZ(*this,y,z) { - Tfloat - *ptrd0 = res.data(0,y,z,0), *ptrd1 = res.data(0,y,z,1), *ptrd2 = res.data(0,y,z,2), - *ptrd3 = res.data(0,y,z,3), *ptrd4 = res.data(0,y,z,4), *ptrd5 = res.data(0,y,z,5); - CImg val(3), vec(3,3); - cimg_forX(*this,x) { - res.get_tensor_at(x,y,z).symmetric_eigen(val,vec); - const float - _l1 = val[2], _l2 = val[1], _l3 = val[0], - l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0, l3 = _l3>0?_l3:0, - ux = vec(0,0), uy = vec(0,1), uz = vec(0,2), - vx = vec(1,0), vy = vec(1,1), vz = vec(1,2), - wx = vec(2,0), wy = vec(2,1), wz = vec(2,2), - n1 = (float)std::pow(1 + l1 + l2 + l3,-power1), - n2 = (float)std::pow(1 + l1 + l2 + l3,-power2); - *(ptrd0++) = n1*(ux*ux + vx*vx) + n2*wx*wx; - *(ptrd1++) = n1*(ux*uy + vx*vy) + n2*wx*wy; - *(ptrd2++) = n1*(ux*uz + vx*vz) + n2*wx*wz; - *(ptrd3++) = n1*(uy*uy + vy*vy) + n2*wy*wy; - *(ptrd4++) = n1*(uy*uz + vy*vz) + n2*wy*wz; - *(ptrd5++) = n1*(uz*uz + vz*vz) + n2*wz*wz; - } - } - } else { // for 2D images - get_structure_tensors().move_to(res).blur(sigma); - cimg_pragma_openmp(parallel for cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*256 && - _height>=(cimg_openmp_sizefactor)*256)) - cimg_forY(*this,y) { - Tfloat *ptrd0 = res.data(0,y,0,0), *ptrd1 = res.data(0,y,0,1), *ptrd2 = res.data(0,y,0,2); - CImg val(2), vec(2,2); - cimg_forX(*this,x) { - res.get_tensor_at(x,y).symmetric_eigen(val,vec); - const float - _l1 = val[1], _l2 = val[0], - l1 = _l1>0?_l1:0, l2 = _l2>0?_l2:0, - ux = vec(1,0), uy = vec(1,1), - vx = vec(0,0), vy = vec(0,1), - n1 = (float)std::pow(1 + l1 + l2,-power1), - n2 = (float)std::pow(1 + l1 + l2,-power2); - *(ptrd0++) = n1*ux*ux + n2*vx*vx; - *(ptrd1++) = n1*ux*uy + n2*vx*vy; - *(ptrd2++) = n1*uy*uy + n2*vy*vy; - } - } - } - return res.move_to(*this); - } - - //! Compute field of diffusion tensors for edge-preserving smoothing \newinstance. - CImg get_diffusion_tensors(const float sharpness=0.7f, const float anisotropy=0.6f, - const float alpha=0.6f, const float sigma=1.1f, const bool is_sqrt=false) const { - return CImg(*this,false).diffusion_tensors(sharpness,anisotropy,alpha,sigma,is_sqrt); - } - - //! Estimate displacement field between two images. - /** - \param source Reference image. - \param smoothness Smoothness of estimated displacement field. - \param precision Precision required for algorithm convergence. - \param nb_scales Number of scales used to estimate the displacement field. - \param iteration_max Maximum number of iterations allowed for one scale. - \param is_backward If false, match I2(X + U(X)) = I1(X), else match I2(X) = I1(X - U(X)). - \param guide Image used as the initial correspondence estimate for the algorithm. - 'guide' may have a last channel with boolean values (0=false | other=true) that - tells for each pixel if its correspondence vector is constrained to its initial value (constraint mask). - **/ - CImg& displacement(const CImg& source, const float smoothness=0.1f, const float precision=5.f, - const unsigned int nb_scales=0, const unsigned int iteration_max=10000, - const bool is_backward=false, - const CImg& guide=CImg::const_empty()) { - return get_displacement(source,smoothness,precision,nb_scales,iteration_max,is_backward,guide). - move_to(*this); - } - - //! Estimate displacement field between two images \newinstance. - CImg get_displacement(const CImg& source, - const float smoothness=0.1f, const float precision=5.f, - const unsigned int nb_scales=0, const unsigned int iteration_max=10000, - const bool is_backward=false, - const CImg& guide=CImg::const_empty()) const { - if (is_empty() || !source) return +*this; - if (!is_sameXYZC(source)) - throw CImgArgumentException(_cimg_instance - "displacement(): Instance and source image (%u,%u,%u,%u,%p) have " - "different dimensions.", - cimg_instance, - source._width,source._height,source._depth,source._spectrum,source._data); - if (precision<0) - throw CImgArgumentException(_cimg_instance - "displacement(): Invalid specified precision %g " - "(should be >=0)", - cimg_instance, - precision); - - const bool is_3d = source._depth>1; - const unsigned int constraint = is_3d?3:2; - - if (guide && - (guide._width!=_width || guide._height!=_height || guide._depth!=_depth || guide._spectrum0?nb_scales: - (unsigned int)cimg::round(std::log(mins/8.)/std::log(1.5),1,1); - - const float _precision = (float)std::pow(10.,-(double)precision); - float sm, sM = source.max_min(sm), tm, tM = max_min(tm); - const float sdelta = sm==sM?1:(sM - sm), tdelta = tm==tM?1:(tM - tm); - - CImg U, V; - floatT bound = 0; - for (int scale = (int)_nb_scales - 1; scale>=0; --scale) { - const float factor = (float)std::pow(1.5,(double)scale); - const unsigned int - _sw = (unsigned int)(_width/factor), sw = _sw?_sw:1, - _sh = (unsigned int)(_height/factor), sh = _sh?_sh:1, - _sd = (unsigned int)(_depth/factor), sd = _sd?_sd:1; - if (sw<5 && sh<5 && (!is_3d || sd<5)) continue; // Skip too small scales - const CImg - I1 = (source.get_resize(sw,sh,sd,-100,2)-=sm)/=sdelta, - I2 = (get_resize(I1,2)-=tm)/=tdelta; - if (guide._spectrum>constraint) guide.get_resize(I2._width,I2._height,I2._depth,-100,1).move_to(V); - if (U) (U*=1.5f).resize(I2._width,I2._height,I2._depth,-100,3); - else { - if (guide) - guide.get_shared_channels(0,is_3d?2:1).get_resize(I2._width,I2._height,I2._depth,-100,2).move_to(U); - else U.assign(I2._width,I2._height,I2._depth,is_3d?3:2,0); - } - - float dt = 2, energy = cimg::type::max(); - const CImgList dI = is_backward?I1.get_gradient():I2.get_gradient(); - cimg_abort_init; - - for (unsigned int iteration = 0; iteration=0) // Isotropic regularization - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(_height*_depth>=(cimg_openmp_sizefactor)*8 && - _width>=(cimg_openmp_sizefactor)*16) - reduction(+:_energy)) - cimg_forYZ(U,y,z) { - const int - _p1y = y?y - 1:0, _n1y = yx) U(x,y,z,0) = (float)x; - if (U(x,y,z,1)>y) U(x,y,z,1) = (float)y; - if (U(x,y,z,2)>z) U(x,y,z,2) = (float)z; - bound = (float)x - _width; if (U(x,y,z,0)<=bound) U(x,y,z,0) = bound; - bound = (float)y - _height; if (U(x,y,z,1)<=bound) U(x,y,z,1) = bound; - bound = (float)z - _depth; if (U(x,y,z,2)<=bound) U(x,y,z,2) = bound; - } else { - if (U(x,y,z,0)<-x) U(x,y,z,0) = -(float)x; - if (U(x,y,z,1)<-y) U(x,y,z,1) = -(float)y; - if (U(x,y,z,2)<-z) U(x,y,z,2) = -(float)z; - bound = (float)_width - x; if (U(x,y,z,0)>=bound) U(x,y,z,0) = bound; - bound = (float)_height - y; if (U(x,y,z,1)>=bound) U(x,y,z,1) = bound; - bound = (float)_depth - z; if (U(x,y,z,2)>=bound) U(x,y,z,2) = bound; - } - _energy+=delta_I*delta_I + smoothness*_energy_regul; - } - if (V) cimg_forXYZ(V,_x,_y,_z) if (V(_x,_y,_z,3)) { // Apply constraints - U(_x,_y,_z,0) = V(_x,_y,_z,0)/factor; - U(_x,_y,_z,1) = V(_x,_y,_z,1)/factor; - U(_x,_y,_z,2) = V(_x,_y,_z,2)/factor; - } - } else { // Anisotropic regularization - const float nsmoothness = -smoothness; - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(_height*_depth>=(cimg_openmp_sizefactor)*8 && - _width>=(cimg_openmp_sizefactor)*16) - reduction(+:_energy)) - cimg_forYZ(U,y,z) { - const int - _p1y = y?y - 1:0, _n1y = yx) U(x,y,z,0) = (float)x; - if (U(x,y,z,1)>y) U(x,y,z,1) = (float)y; - if (U(x,y,z,2)>z) U(x,y,z,2) = (float)z; - bound = (float)x - _width; if (U(x,y,z,0)<=bound) U(x,y,z,0) = bound; - bound = (float)y - _height; if (U(x,y,z,1)<=bound) U(x,y,z,1) = bound; - bound = (float)z - _depth; if (U(x,y,z,2)<=bound) U(x,y,z,2) = bound; - } else { - if (U(x,y,z,0)<-x) U(x,y,z,0) = -(float)x; - if (U(x,y,z,1)<-y) U(x,y,z,1) = -(float)y; - if (U(x,y,z,2)<-z) U(x,y,z,2) = -(float)z; - bound = (float)_width - x; if (U(x,y,z,0)>=bound) U(x,y,z,0) = bound; - bound = (float)_height - y; if (U(x,y,z,1)>=bound) U(x,y,z,1) = bound; - bound = (float)_depth - z; if (U(x,y,z,2)>=bound) U(x,y,z,2) = bound; - } - _energy+=delta_I*delta_I + nsmoothness*_energy_regul; - } - if (V) cimg_forXYZ(V,_x,_y,_z) if (V(_x,_y,_z,3)) { // Apply constraints - U(_x,_y,_z,0) = V(_x,_y,_z,0)/factor; - U(_x,_y,_z,1) = V(_x,_y,_z,1)/factor; - U(_x,_y,_z,2) = V(_x,_y,_z,2)/factor; - } - } - } - } else { // 2D version - if (smoothness>=0) // Isotropic regularization - cimg_pragma_openmp(parallel for cimg_openmp_if(_height>=(cimg_openmp_sizefactor)*8 && - _width>=(cimg_openmp_sizefactor)*16) reduction(+:_energy)) - cimg_forY(U,y) { - const int _p1y = y?y - 1:0, _n1y = yx) U(x,y,0) = (float)x; - if (U(x,y,1)>y) U(x,y,1) = (float)y; - bound = (float)x - _width; if (U(x,y,0)<=bound) U(x,y,0) = bound; - bound = (float)y - _height; if (U(x,y,1)<=bound) U(x,y,1) = bound; - } else { - if (U(x,y,0)<-x) U(x,y,0) = -(float)x; - if (U(x,y,1)<-y) U(x,y,1) = -(float)y; - bound = (float)_width - x; if (U(x,y,0)>=bound) U(x,y,0) = bound; - bound = (float)_height - y; if (U(x,y,1)>=bound) U(x,y,1) = bound; - } - _energy+=delta_I*delta_I + smoothness*_energy_regul; - } - if (V) cimg_forXY(V,_x,_y) if (V(_x,_y,2)) { // Apply constraints - U(_x,_y,0) = V(_x,_y,0)/factor; - U(_x,_y,1) = V(_x,_y,1)/factor; - } - } else { // Anisotropic regularization - const float nsmoothness = -smoothness; - cimg_pragma_openmp(parallel for cimg_openmp_if(_height>=(cimg_openmp_sizefactor)*8 && - _width>=(cimg_openmp_sizefactor)*16) reduction(+:_energy)) - cimg_forY(U,y) { - const int _p1y = y?y - 1:0, _n1y = yx) U(x,y,0) = (float)x; - if (U(x,y,1)>y) U(x,y,1) = (float)y; - bound = (float)x - _width; if (U(x,y,0)<=bound) U(x,y,0) = bound; - bound = (float)y - _height; if (U(x,y,1)<=bound) U(x,y,1) = bound; - } else { - if (U(x,y,0)<-x) U(x,y,0) = -(float)x; - if (U(x,y,1)<-y) U(x,y,1) = -(float)y; - bound = (float)_width - x; if (U(x,y,0)>=bound) U(x,y,0) = bound; - bound = (float)_height - y; if (U(x,y,1)>=bound) U(x,y,1) = bound; - } - _energy+=delta_I*delta_I + nsmoothness*_energy_regul; - } - if (V) cimg_forXY(V,_x,_y) if (V(_x,_y,2)) { // Apply constraints - U(_x,_y,0) = V(_x,_y,0)/factor; - U(_x,_y,1) = V(_x,_y,1)/factor; - } - } - } - } - const float d_energy = (_energy - energy)/(sw*sh*sd); - if (d_energy<=0 && -d_energy<_precision) break; - if (d_energy>0) dt*=0.5f; - energy = _energy; - } - } - return U; - } - - //! Compute correspondence map between two images, using a patch-matching algorithm. - /** - \param patch_image The image containing the reference patches to match with the instance image. - \param patch_width Width of the patch used for matching. - \param patch_height Height of the patch used for matching. - \param patch_depth Depth of the patch used for matching. - \param nb_iterations Number of patch-match iterations. - \param nb_randoms Number of randomization attempts (per pixel). - \param patch_penalization Penalization factor in score related patch occurrences. - if negative, also tells that identity result is not avoided. - \param guide Image used as the initial correspondence estimate for the algorithm. - 'guide' may have a last channel with boolean values (0=false | other=true) that - tells for each pixel if its correspondence vector is constrained to its initial value (constraint mask). - \param[out] matching_score Returned as the image of matching scores. - **/ - template - CImg& matchpatch(const CImg& patch_image, - const unsigned int patch_width, - const unsigned int patch_height, - const unsigned int patch_depth, - const unsigned int nb_iterations, - const unsigned int nb_randoms, - const float patch_penalization, - const CImg &guide, - CImg &matching_score) { - return get_matchpatch(patch_image,patch_width,patch_height,patch_depth, - nb_iterations,nb_randoms,patch_penalization,guide,matching_score).move_to(*this); - } - - //! Compute correspondence map between two images, using the patch-match algorithm \newinstance. - template - CImg get_matchpatch(const CImg& patch_image, - const unsigned int patch_width, - const unsigned int patch_height, - const unsigned int patch_depth, - const unsigned int nb_iterations, - const unsigned int nb_randoms, - const float patch_penalization, - const CImg &guide, - CImg &matching_score) const { - return _matchpatch(patch_image,patch_width,patch_height,patch_depth, - nb_iterations,nb_randoms,patch_penalization, - guide,true,matching_score); - } - - //! Compute correspondence map between two images, using the patch-match algorithm \overloading. - template - CImg& matchpatch(const CImg& patch_image, - const unsigned int patch_width, - const unsigned int patch_height, - const unsigned int patch_depth, - const unsigned int nb_iterations=5, - const unsigned int nb_randoms=5, - const float patch_penalization=0, - const CImg &guide=CImg::const_empty()) { - return get_matchpatch(patch_image,patch_width,patch_height,patch_depth, - nb_iterations,nb_randoms,patch_penalization,guide).move_to(*this); - } - - //! Compute correspondence map between two images, using the patch-match algorithm \overloading. - template - CImg get_matchpatch(const CImg& patch_image, - const unsigned int patch_width, - const unsigned int patch_height, - const unsigned int patch_depth, - const unsigned int nb_iterations=5, - const unsigned int nb_randoms=5, - const float patch_penalization=0, - const CImg &guide=CImg::const_empty()) const { - CImg matching_score; - return _matchpatch(patch_image,patch_width,patch_height,patch_depth, - nb_iterations,nb_randoms,patch_penalization,guide,false,matching_score); - } - - template - CImg _matchpatch(const CImg& patch_image, - const unsigned int patch_width, - const unsigned int patch_height, - const unsigned int patch_depth, - const unsigned int nb_iterations, - const unsigned int nb_randoms, - const float patch_penalization, - const CImg &guide, - const bool is_matching_score, - CImg &matching_score) const { - if (is_empty()) return CImg::const_empty(); - if (patch_image._spectrum!=_spectrum) - throw CImgArgumentException(_cimg_instance - "matchpatch(): Instance image and specified patch image (%u,%u,%u,%u,%p) " - "have different spectrums.", - cimg_instance, - patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum, - patch_image._data); - if (patch_width>_width || patch_height>_height || patch_depth>_depth) - throw CImgArgumentException(_cimg_instance - "matchpatch(): Specified patch size %ux%ux%u is bigger than the dimensions " - "of the instance image.", - cimg_instance,patch_width,patch_height,patch_depth); - if (patch_width>patch_image._width || patch_height>patch_image._height || patch_depth>patch_image._depth) - throw CImgArgumentException(_cimg_instance - "matchpatch(): Specified patch size %ux%ux%u is bigger than the dimensions " - "of the patch image image (%u,%u,%u,%u,%p).", - cimg_instance,patch_width,patch_height,patch_depth, - patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum, - patch_image._data); - const unsigned int - _constraint = patch_image._depth>1?3:2, - constraint = guide._spectrum>_constraint?_constraint:0; - - if (guide && - (guide._width!=_width || guide._height!=_height || guide._depth!=_depth || guide._spectrum<_constraint)) - throw CImgArgumentException(_cimg_instance - "matchpatch(): Specified guide (%u,%u,%u,%u,%p) has invalid dimensions " - "considering instance and patch image (%u,%u,%u,%u,%p).", - cimg_instance, - guide._width,guide._height,guide._depth,guide._spectrum,guide._data, - patch_image._width,patch_image._height,patch_image._depth,patch_image._spectrum, - patch_image._data); - - CImg a_map(_width,_height,_depth,patch_image._depth>1?3:2); - CImg is_updated(_width,_height,_depth,1,3); - CImg score(_width,_height,_depth), penalty; - const float _patch_penalization = cimg::abs(patch_penalization); - const bool allow_identity = patch_penalization>=0; - if (_patch_penalization!=0) - penalty.assign(patch_image._width,patch_image._height,patch_image._depth,1,0); - - const int - psizew = (int)patch_width, psizew1 = psizew/2, psizew2 = psizew - psizew1 - 1, - psizeh = (int)patch_height, psizeh1 = psizeh/2, psizeh2 = psizeh - psizeh1 - 1, - psized = (int)patch_depth, psized1 = psized/2, psized2 = psized - psized1 - 1; - - // Interleave image buffers to speed up patch comparison (more cache-friendly). - CImg in_this = get_permute_axes("cxyz"); - in_this._width = _width*_spectrum; - in_this._height = _height; - in_this._depth = _depth; - in_this._spectrum = 1; - CImg in_patch = patch_image.get_permute_axes("cxyz"); - in_patch._width = patch_image._width*patch_image._spectrum; - in_patch._height = patch_image._height; - in_patch._depth = patch_image._depth; - in_patch._spectrum = 1; - - if (_depth>1 || patch_image._depth>1) { // 3D version - - // Initialize correspondence map. - if (guide) - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if_size(_width,64)) - cimg_forXYZ(*this,x,y,z) { // User-defined initialization - const int - cx1 = x<=psizew1?x:(x::inf()); - } else cimg_pragma_openmp(parallel cimg_openmp_if_size(_width,64)) { - cimg_uint64 rng = (cimg::_rand(),cimg::rng()); -#if cimg_use_openmp!=0 - rng+=omp_get_thread_num(); -#endif - cimg_pragma_openmp(for cimg_openmp_collapse(2)) - cimg_forXYZ(*this,x,y,z) { // Random initialization - const int - cx1 = x<=psizew1?x:(x::inf()); - } - cimg::srand(rng); - } - - // Start iteration loop. - cimg_abort_init; - for (unsigned int iter = 0; iter=(cimg_openmp_sizefactor)*64)) { - cimg_uint64 rng = (cimg::_rand(),cimg::rng()); - -#if cimg_use_openmp!=0 - rng+=omp_get_thread_num(); -#endif - cimg_pragma_openmp(for cimg_openmp_collapse(2)) - cimg_forXYZ(*this,X,Y,Z) { - const int - x = is_backward?width() - 1 - X:X, - y = is_backward?height() - 1 - Y:Y, - z = is_backward?depth() - 1 - Z:Z; - if (score(x,y,z)<=1e-5 || (constraint && guide(x,y,z,constraint)!=0)) continue; - const int - cx1 = x<=psizew1?x:(x0 && (is_updated(x - 1,y,z)&cmask)) { // Compare with left neighbor - u = a_map(x - 1,y,z,0); - v = a_map(x - 1,y,z,1); - w = a_map(x - 1,y,z,2); - if (u>=cx1 - 1 && u=cy1 && v=cz1 && w0 && (is_updated(x,y - 1,z)&cmask)) { // Compare with up neighbor - u = a_map(x,y - 1,z,0); - v = a_map(x,y - 1,z,1); - w = a_map(x,y - 1,z,2); - if (u>=cx1 && u=cy1 - 1 && v=cz1 && w0 && (is_updated(x,y,z - 1)&cmask)) { // Compare with backward neighbor - u = a_map(x,y,z - 1,0); - v = a_map(x,y,z - 1,1); - w = a_map(x,y,z - 1,2); - if (u>=cx1 && u=cy1 && v=cz1 - 1 && w=cx1 + 1 && u=cy1 && v=cz1 && w=cx1 && u=cy1 + 1 && v=cz1 && w=cx1 && u=cy1 && v=cz1 + 1 && w=(cimg_openmp_sizefactor)*64)) - cimg_forXYZ(score,x,y,z) { - const float p_score = score(x,y,z); - const int - cx1 = x<=psizew1?x:(x::inf()); - if (n_score!=p_score) { score(x,y,z) = n_score; is_updated(x,y) = 3; } - } - } - - } else { // 2D version - - // Initialize correspondence map. - if (guide) - cimg_pragma_openmp(parallel for cimg_openmp_if_size(_width,64)) - cimg_forXY(*this,x,y) { // User-defined initialization - const int - cx1 = x<=psizew1?x:(x::inf()); - } else cimg_pragma_openmp(parallel cimg_openmp_if_size(_width,64)) { - cimg_uint64 rng = (cimg::_rand(),cimg::rng()); - -#if cimg_use_openmp!=0 - rng+=omp_get_thread_num(); -#endif - cimg_pragma_openmp(for) - cimg_forXY(*this,x,y) { // Random initialization - const int - cx1 = x<=psizew1?x:(x::inf()); - } - cimg::srand(rng); - } - - // Start iteration loop. - cimg_abort_init; - for (unsigned int iter = 0; iter=(cimg_openmp_sizefactor)*64)) { - cimg_uint64 rng = (cimg::_rand(),cimg::rng()); - -#if cimg_use_openmp!=0 - rng+=omp_get_thread_num(); -#endif - cimg_pragma_openmp(for) - cimg_forXY(*this,X,Y) { - const int - x = is_backward?width() - 1 - X:X, - y = is_backward?height() - 1 - Y:Y; - if (score(x,y)<=1e-5 || (constraint && guide(x,y,constraint)!=0)) continue; - const int - cx1 = x<=psizew1?x:(x0 && (is_updated(x - 1,y)&cmask)) { // Compare with left neighbor - u = a_map(x - 1,y,0); - v = a_map(x - 1,y,1); - if (u>=cx1 - 1 && u=cy1 && v0 && (is_updated(x,y - 1)&cmask)) { // Compare with up neighbor - u = a_map(x,y - 1,0); - v = a_map(x,y - 1,1); - if (u>=cx1 && u=cy1 - 1 && v=cx1 + 1 && u=cy1 && v=cx1 && u=cy1 + 1 && v=(cimg_openmp_sizefactor)*64)) - cimg_forXY(score,x,y) { - const float p_score = score(x,y); - const int - cx1 = x<=psizew1?x:(x::inf()); - if (n_score!=p_score) { score(x,y) = n_score; is_updated(x,y) = 3; } - } - } - } - - if (is_matching_score) score.move_to(matching_score); - return a_map; - } - - // Compute SSD between two patches in different images. - static float _matchpatch(const CImg& img1, const CImg& img2, const CImg& penalty, - const unsigned int psizew, const unsigned int psizeh, - const unsigned int psized, const unsigned int psizec, - const int x1, const int y1, const int z1, - const int x2, const int y2, const int z2, - const int xc, const int yc, const int zc, - const float patch_penalization, - const bool allow_identity, - const float max_score) { // 3D version - if (!allow_identity && cimg::hypot((float)x1 - x2,(float)y1 - y2,(float)z1 - z2)::inf(); - const T *p1 = img1.data(x1*psizec,y1,z1), *p2 = img2.data(x2*psizec,y2,z2); - const unsigned int psizewc = psizew*psizec; - const ulongT - offx1 = (ulongT)img1._width - psizewc, - offx2 = (ulongT)img2._width - psizewc, - offy1 = (ulongT)img1._width*img1._height - (ulongT)psizeh*img1._width, - offy2 = (ulongT)img2._width*img2._height - (ulongT)psizeh*img2._width; - float ssd = 0; - for (unsigned int k = 0; kmax_score) return max_score; - p1+=offx1; p2+=offx2; - } - p1+=offy1; p2+=offy2; - } - return patch_penalization==0?ssd:cimg::sqr(std::sqrt(ssd) + - patch_penalization*psizewc*psizeh*psized*penalty(xc,yc,zc)/100); - } - - static float _matchpatch(const CImg& img1, const CImg& img2, const CImg& penalty, - const unsigned int psizew, const unsigned int psizeh, const unsigned int psizec, - const int x1, const int y1, - const int x2, const int y2, - const int xc, const int yc, - const float patch_penalization, - const bool allow_identity, - const float max_score) { // 2D version - if (!allow_identity && cimg::hypot((float)x1-x2,(float)y1-y2)::inf(); - const T *p1 = img1.data(x1*psizec,y1), *p2 = img2.data(x2*psizec,y2); - const unsigned int psizewc = psizew*psizec; - const ulongT - offx1 = (ulongT)img1._width - psizewc, - offx2 = (ulongT)img2._width - psizewc; - float ssd = 0; - for (unsigned int j = 0; jmax_score) return max_score; - p1+=offx1; p2+=offx2; - } - return patch_penalization==0?ssd:cimg::sqr(std::sqrt(ssd) + - patch_penalization*psizewc*psizeh*penalty(xc,yc)/100); - } - - //! Compute Euclidean distance function to a specified value. - /** - \param value Reference value. - \param metric Type of metric. Can be { 0=Chebyshev | 1=Manhattan | 2=Euclidean | 3=Squared-euclidean }. - \note - The distance transform implementation has been submitted by A. Meijster, and implements - the article 'W.H. Hesselink, A. Meijster, J.B.T.M. Roerdink, - "A general algorithm for computing distance transforms in linear time.", - In: Mathematical Morphology and its Applications to Image and Signal Processing, - J. Goutsias, L. Vincent, and D.S. Bloomberg (eds.), Kluwer, 2000, pp. 331-340.' - The submitted code has then been modified to fit CImg coding style and constraints. - **/ - CImg& distance(const T& value, const unsigned int metric=2) { - if (is_empty()) return *this; - if (cimg::type::string()!=pixel_type()) // For datatype < int - return CImg(*this,false).distance((Tint)value,metric). - cut((Tint)cimg::type::min(),(Tint)cimg::type::max()).move_to(*this); - bool is_value = false; - cimg_for(*this,ptr,T) *ptr = *ptr==value?is_value=true,(T)0:(T)std::max(0,99999999); // (avoid VC++ warning) - if (!is_value) return fill(cimg::type::max()); - switch (metric) { - case 0 : return _distance_core(_distance_sep_cdt,_distance_dist_cdt); // Chebyshev - case 1 : return _distance_core(_distance_sep_mdt,_distance_dist_mdt); // Manhattan - case 3 : return _distance_core(_distance_sep_edt,_distance_dist_edt); // Squared Euclidean - default : return _distance_core(_distance_sep_edt,_distance_dist_edt).sqrt(); // Euclidean - } - return *this; - } - - //! Compute distance to a specified value \newinstance. - CImg get_distance(const T& value, const unsigned int metric=2) const { - return CImg(*this,false).distance((Tfloat)value,metric); - } - - static longT _distance_sep_edt(const longT i, const longT u, const longT *const g) { - return (u*u - i*i + g[u] - g[i])/(2*(u - i)); - } - - static longT _distance_dist_edt(const longT x, const longT i, const longT *const g) { - return (x - i)*(x - i) + g[i]; - } - - static longT _distance_sep_mdt(const longT i, const longT u, const longT *const g) { - return (u - i<=g[u] - g[i]?999999999:(g[u] - g[i] + u + i)/2); - } - - static longT _distance_dist_mdt(const longT x, const longT i, const longT *const g) { - return (x=0) && f(t[q],s[q],g)>f(t[q],u,g)) { --q; } - if (q<0) { q = 0; s[0] = u; } - else { const longT w = 1 + sep(s[q], u, g); if (w<(longT)len) { ++q; s[q] = u; t[q] = w; }} - } - for (int u = (int)len - 1; u>=0; --u) { dt[u] = f(u,s[q],g); if (u==t[q]) --q; } // Backward scan - } - - CImg& _distance_core(longT (*const sep)(const longT, const longT, const longT *const), - longT (*const f)(const longT, const longT, const longT *const)) { - // Check for g++ 4.9.X, as OpenMP seems to crash for this particular function. I have no clues why. -#define cimg_is_gcc49x (__GNUC__==4 && __GNUC_MINOR__==9) - - const ulongT wh = (ulongT)_width*_height; -#if cimg_use_openmp!=0 && !cimg_is_gcc49x - cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2)) -#endif - cimg_forC(*this,c) { - CImg g(_width), dt(_width), s(_width), t(_width); - CImg img = get_shared_channel(c); -#if cimg_use_openmp!=0 && !cimg_is_gcc49x - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) cimg_openmp_if(_width>=(cimg_openmp_sizefactor)*512 && - _height*_depth>=16) - firstprivate(g,dt,s,t)) -#endif - cimg_forYZ(*this,y,z) { // Over X-direction - cimg_forX(*this,x) g[x] = (longT)img(x,y,z,0,wh); - _distance_scan(_width,g,sep,f,s,t,dt); - cimg_forX(*this,x) img(x,y,z,0,wh) = (T)dt[x]; - } - if (_height>1) { - g.assign(_height); dt.assign(_height); s.assign(_height); t.assign(_height); -#if cimg_use_openmp!=0 && !cimg_is_gcc49x - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(_height>=(cimg_openmp_sizefactor)*512 && _width*_depth>=16) - firstprivate(g,dt,s,t)) -#endif - cimg_forXZ(*this,x,z) { // Over Y-direction - cimg_forY(*this,y) g[y] = (longT)img(x,y,z,0,wh); - _distance_scan(_height,g,sep,f,s,t,dt); - cimg_forY(*this,y) img(x,y,z,0,wh) = (T)dt[y]; - } - } - if (_depth>1) { - g.assign(_depth); dt.assign(_depth); s.assign(_depth); t.assign(_depth); -#if cimg_use_openmp!=0 && !cimg_is_gcc49x - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if(_depth>=(cimg_openmp_sizefactor)*512 && _width*_height>=16) - firstprivate(g,dt,s,t)) -#endif - cimg_forXY(*this,x,y) { // Over Z-direction - cimg_forZ(*this,z) g[z] = (longT)img(x,y,z,0,wh); - _distance_scan(_depth,g,sep,f,s,t,dt); - cimg_forZ(*this,z) img(x,y,z,0,wh) = (T)dt[z]; - } - } - } - return *this; - } - - //! Compute chamfer distance to a specified value, with a custom metric. - /** - \param value Reference value. - \param metric_mask Metric mask. - \note The algorithm code has been initially proposed by A. Meijster, and modified by D. TschumperlĂ©. - **/ - template - CImg& distance(const T& value, const CImg& metric_mask) { - if (is_empty()) return *this; - bool is_value = false; - cimg_for(*this,ptr,T) *ptr = *ptr==value?is_value=true,0:(T)999999999; - if (!is_value) return fill(cimg::type::max()); - const ulongT wh = (ulongT)_width*_height; - cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2)) - cimg_forC(*this,c) { - CImg img = get_shared_channel(c); - cimg_pragma_openmp(parallel for cimg_openmp_collapse(3) - cimg_openmp_if(_width*_height*_depth>=(cimg_openmp_sizefactor)*1024)) - cimg_forXYZ(metric_mask,dx,dy,dz) { - const t weight = metric_mask(dx,dy,dz); - if (weight) { - for (int z = dz, nz = 0; z=0; --z,--nz) { // Backward scan - for (int y = height() - 1 - dy, ny = height() - 1; y>=0; --y,--ny) { - for (int x = width() - 1 - dx, nx = width() - 1; x>=0; --x,--nx) { - const T dd = img(nx,ny,nz,0,wh) + weight; - if (dd - CImg get_distance(const T& value, const CImg& metric_mask) const { - return CImg(*this,false).distance(value,metric_mask); - } - - //! Compute distance to a specified value, according to a custom metric (use dijkstra algorithm). - /** - \param value Reference value. - \param metric Field of distance potentials. - \param is_high_connectivity Tells if the algorithm uses low or high connectivity. - \param[out] return_path An image containing the nodes of the minimal path. - **/ - template - CImg& distance_dijkstra(const T& value, const CImg& metric, const bool is_high_connectivity, - CImg& return_path) { - return get_distance_dijkstra(value,metric,is_high_connectivity,return_path).move_to(*this); - } - - //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm) \newinstance. - template - CImg::type> - get_distance_dijkstra(const T& value, const CImg& metric, const bool is_high_connectivity, - CImg& return_path) const { - if (is_empty()) return return_path.assign(); - if (!is_sameXYZ(metric)) - throw CImgArgumentException(_cimg_instance - "distance_dijkstra(): image instance and metric map (%u,%u,%u,%u) " - "have incompatible dimensions.", - cimg_instance, - metric._width,metric._height,metric._depth,metric._spectrum); - typedef typename cimg::superset::type td; // Type used for computing cumulative distances - CImg result(_width,_height,_depth,_spectrum), Q; - CImg is_queued(_width,_height,_depth,1); - if (return_path) return_path.assign(_width,_height,_depth,_spectrum); - - cimg_forC(*this,c) { - const CImg img = get_shared_channel(c); - const CImg met = metric.get_shared_channel(c%metric._spectrum); - CImg res = result.get_shared_channel(c); - CImg path = return_path?return_path.get_shared_channel(c):CImg(); - unsigned int sizeQ = 0; - - // Detect initial seeds. - is_queued.fill(0); - cimg_forXYZ(img,x,y,z) if (img(x,y,z)==value) { - Q._priority_queue_insert(is_queued,sizeQ,0,x,y,z); - res(x,y,z) = 0; - if (path) path(x,y,z) = (to)0; - } - - // Start distance propagation. - while (sizeQ) { - - // Get and remove point with minimal potential from the queue. - const int x = (int)Q(0,1), y = (int)Q(0,2), z = (int)Q(0,3); - const td P = (td)-Q(0,0); - Q._priority_queue_remove(sizeQ); - - // Update neighbors. - td npot = 0; - if (x - 1>=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x - 1,y,z) + P),x - 1,y,z)) { - res(x - 1,y,z) = npot; if (path) path(x - 1,y,z) = (to)2; - } - if (x + 1=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y - 1,z) + P),x,y - 1,z)) { - res(x,y - 1,z) = npot; if (path) path(x,y - 1,z) = (to)8; - } - if (y + 1=0 && Q._priority_queue_insert(is_queued,sizeQ,-(npot=met(x,y,z - 1) + P),x,y,z - 1)) { - res(x,y,z - 1) = npot; if (path) path(x,y,z - 1) = (to)32; - } - if (z + 1=0 && y - 1>=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y - 1,z) + P)),x - 1,y - 1,z)) { - res(x - 1,y - 1,z) = npot; if (path) path(x - 1,y - 1,z) = (to)10; - } - if (x + 1=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x + 1,y - 1,z) + P)),x + 1,y - 1,z)) { - res(x + 1,y - 1,z) = npot; if (path) path(x + 1,y - 1,z) = (to)9; - } - if (x - 1>=0 && y + 1=0) { // Diagonal neighbors on slice z - 1 - if (x - 1>=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y,z - 1) + P)),x - 1,y,z - 1)) { - res(x - 1,y,z - 1) = npot; if (path) path(x - 1,y,z - 1) = (to)34; - } - if (x + 1=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y - 1,z - 1) + P)),x,y - 1,z - 1)) { - res(x,y - 1,z - 1) = npot; if (path) path(x,y - 1,z - 1) = (to)40; - } - if (y + 1=0 && y - 1>=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y - 1,z - 1) + P)), - x - 1,y - 1,z - 1)) { - res(x - 1,y - 1,z - 1) = npot; if (path) path(x - 1,y - 1,z - 1) = (to)42; - } - if (x + 1=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y - 1,z - 1) + P)), - x + 1,y - 1,z - 1)) { - res(x + 1,y - 1,z - 1) = npot; if (path) path(x + 1,y - 1,z - 1) = (to)41; - } - if (x - 1>=0 && y + 1=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x - 1,y,z + 1) + P)),x - 1,y,z + 1)) { - res(x - 1,y,z + 1) = npot; if (path) path(x - 1,y,z + 1) = (to)18; - } - if (x + 1=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt2*met(x,y - 1,z + 1) + P)),x,y - 1,z + 1)) { - res(x,y - 1,z + 1) = npot; if (path) path(x,y - 1,z + 1) = (to)24; - } - if (y + 1=0 && y - 1>=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x - 1,y - 1,z + 1) + P)), - x - 1,y - 1,z + 1)) { - res(x - 1,y - 1,z + 1) = npot; if (path) path(x - 1,y - 1,z + 1) = (to)26; - } - if (x + 1=0 && - Q._priority_queue_insert(is_queued,sizeQ,-(npot=(td)(sqrt3*met(x + 1,y - 1,z + 1) + P)), - x + 1,y - 1,z + 1)) { - res(x + 1,y - 1,z + 1) = npot; if (path) path(x + 1,y - 1,z + 1) = (to)25; - } - if (x - 1>=0 && y + 1 - CImg& distance_dijkstra(const T& value, const CImg& metric, - const bool is_high_connectivity=false) { - return get_distance_dijkstra(value,metric,is_high_connectivity).move_to(*this); - } - - //! Compute distance map to a specified value, according to a custom metric (use dijkstra algorithm). \newinstance. - template - CImg get_distance_dijkstra(const T& value, const CImg& metric, - const bool is_high_connectivity=false) const { - CImg return_path; - return get_distance_dijkstra(value,metric,is_high_connectivity,return_path); - } - - //! Compute distance map to one source point, according to a custom metric (use fast marching algorithm). - /** - \param value Reference value. - \param metric Field of distance potentials. - **/ - template - CImg& distance_eikonal(const T& value, const CImg& metric) { - return get_distance_eikonal(value,metric).move_to(*this); - } - - //! Compute distance map to one source point, according to a custom metric (use fast marching algorithm). - template - CImg get_distance_eikonal(const T& value, const CImg& metric) const { - if (is_empty()) return *this; - if (!is_sameXYZ(metric)) - throw CImgArgumentException(_cimg_instance - "distance_eikonal(): image instance and metric map (%u,%u,%u,%u) have " - "incompatible dimensions.", - cimg_instance, - metric._width,metric._height,metric._depth,metric._spectrum); - CImg result(_width,_height,_depth,_spectrum,cimg::type::max()), Q; - CImg state(_width,_height,_depth); // -1=far away, 0=narrow, 1=frozen - - cimg_pragma_openmp(parallel for cimg_openmp_if(_spectrum>=2) firstprivate(Q,state)) - cimg_forC(*this,c) { - const CImg img = get_shared_channel(c); - const CImg met = metric.get_shared_channel(c%metric._spectrum); - CImg res = result.get_shared_channel(c); - unsigned int sizeQ = 0; - state.fill(-1); - - // Detect initial seeds. - Tfloat *ptr1 = res._data; char *ptr2 = state._data; - cimg_for(img,ptr0,T) { if (*ptr0==value) { *ptr1 = 0; *ptr2 = 1; } ++ptr1; ++ptr2; } - - // Initialize seeds neighbors. - ptr2 = state._data; - cimg_forXYZ(img,x,y,z) if (*(ptr2++)==1) { - if (x - 1>=0 && state(x - 1,y,z)==-1) { - const Tfloat dist = res(x - 1,y,z) = __distance_eikonal(res,met(x - 1,y,z),x - 1,y,z); - Q._eik_priority_queue_insert(state,sizeQ,-dist,x - 1,y,z); - } - if (x + 1=0 && state(x,y - 1,z)==-1) { - const Tfloat dist = res(x,y - 1,z) = __distance_eikonal(res,met(x,y - 1,z),x,y - 1,z); - Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y - 1,z); - } - if (y + 1=0 && state(x,y,z - 1)==-1) { - const Tfloat dist = res(x,y,z - 1) = __distance_eikonal(res,met(x,y,z - 1),x,y,z - 1); - Q._eik_priority_queue_insert(state,sizeQ,-dist,x,y,z - 1); - } - if (z + 1=0) { - if (x - 1>=0 && state(x - 1,y,z)!=1) { - const Tfloat dist = __distance_eikonal(res,met(x - 1,y,z),x - 1,y,z); - if (dist=0 && state(x,y - 1,z)!=1) { - const Tfloat dist = __distance_eikonal(res,met(x,y - 1,z),x,y - 1,z); - if (dist=0 && state(x,y,z - 1)!=1) { - const Tfloat dist = __distance_eikonal(res,met(x,y,z - 1),x,y,z - 1); - if (dist& res, const Tfloat P, - const int x=0, const int y=0, const int z=0) const { - const Tfloat M = (Tfloat)cimg::type::max(); - T T1 = (T)std::min(x - 1>=0?res(x - 1,y,z):M,x + 11) { // 3D - T - T2 = (T)std::min(y - 1>=0?res(x,y - 1,z):M,y + 1=0?res(x,y,z - 1):M,z + 1T2) cimg::swap(T1,T2); - if (T2>T3) cimg::swap(T2,T3); - if (T1>T2) cimg::swap(T1,T2); - if (P<=0) return (Tfloat)T1; - if (T31) { // 2D - T T2 = (T)std::min(y - 1>=0?res(x,y - 1,z):M,y + 1T2) cimg::swap(T1,T2); - if (P<=0) return (Tfloat)T1; - if (T2 - void _eik_priority_queue_insert(CImg& state, unsigned int& siz, const t value, - const unsigned int x, const unsigned int y, const unsigned int z) { - if (state(x,y,z)>0) return; - state(x,y,z) = 0; - if (++siz>=_width) { if (!is_empty()) resize(_width*2,4,1,1,0); else assign(64,4); } - (*this)(siz - 1,0) = (T)value; (*this)(siz - 1,1) = (T)x; (*this)(siz - 1,2) = (T)y; (*this)(siz - 1,3) = (T)z; - for (unsigned int pos = siz - 1, par = 0; pos && value>(t)(*this)(par=(pos + 1)/2 - 1,0); pos = par) { - cimg::swap((*this)(pos,0),(*this)(par,0)); cimg::swap((*this)(pos,1),(*this)(par,1)); - cimg::swap((*this)(pos,2),(*this)(par,2)); cimg::swap((*this)(pos,3),(*this)(par,3)); - } - } - - //! Compute distance function to 0-valued isophotes, using the Eikonal PDE. - /** - \param nb_iterations Number of PDE iterations. - \param band_size Size of the narrow band. - \param time_step Time step of the PDE iterations. - **/ - CImg& distance_eikonal(const unsigned int nb_iterations, const float band_size=0, const float time_step=0.5f) { - if (is_empty()) return *this; - CImg velocity(*this,false); - for (unsigned int iteration = 0; iteration1) { // 3D - CImg_3x3x3(I,Tfloat); - cimg_forC(*this,c) cimg_for3x3x3(*this,x,y,z,c,I,Tfloat) if (band_size<=0 || cimg::abs(Iccc)0?(Incc - Iccc):(Iccc - Ipcc), - iy = gy*sgn>0?(Icnc - Iccc):(Iccc - Icpc), - iz = gz*sgn>0?(Iccn - Iccc):(Iccc - Iccp), - ng = 1e-5f + cimg::hypot(gx,gy,gz), - ngx = gx/ng, - ngy = gy/ng, - ngz = gz/ng, - veloc = sgn*(ngx*ix + ngy*iy + ngz*iz - 1); - *(ptrd++) = veloc; - if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; - } else *(ptrd++) = 0; - } else { // 2D version - CImg_3x3(I,Tfloat); - cimg_forC(*this,c) cimg_for3x3(*this,x,y,0,c,I,Tfloat) if (band_size<=0 || cimg::abs(Icc)0?(Inc - Icc):(Icc - Ipc), - iy = gy*sgn>0?(Icn - Icc):(Icc - Icp), - ng = std::max((Tfloat)1e-5,cimg::hypot(gx,gy)), - ngx = gx/ng, - ngy = gy/ng, - veloc = sgn*(ngx*ix + ngy*iy - 1); - *(ptrd++) = veloc; - if (veloc>veloc_max) veloc_max = veloc; else if (-veloc>veloc_max) veloc_max = -veloc; - } else *(ptrd++) = 0; - } - if (veloc_max>0) *this+=(velocity*=time_step/veloc_max); - } - return *this; - } - - //! Compute distance function to 0-valued isophotes, using the Eikonal PDE \newinstance. - CImg get_distance_eikonal(const unsigned int nb_iterations, const float band_size=0, - const float time_step=0.5f) const { - return CImg(*this,false).distance_eikonal(nb_iterations,band_size,time_step); - } - - //! Compute Haar multiscale wavelet transform. - /** - \param axis Axis considered for the transform. - \param invert Set inverse of direct transform. - \param nb_scales Number of scales used for the transform. - **/ - CImg& haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) { - return get_haar(axis,invert,nb_scales).move_to(*this); - } - - //! Compute Haar multiscale wavelet transform \newinstance. - CImg get_haar(const char axis, const bool invert=false, const unsigned int nb_scales=1) const { - if (is_empty() || !nb_scales) return +*this; - CImg res; - const Tfloat sqrt2 = std::sqrt(2.f); - if (nb_scales==1) { - switch (cimg::lowercase(axis)) { // Single scale transform - case 'x' : { - const unsigned int w = _width/2; - if (w) { - if ((w%2) && w!=1) - throw CImgInstanceException(_cimg_instance - "haar(): Sub-image width %u is not even.", - cimg_instance, - w); - - res.assign(_width,_height,_depth,_spectrum); - if (invert) cimg_forYZC(*this,y,z,c) { // Inverse transform along X - for (unsigned int x = 0, xw = w, x2 = 0; x& haar(const bool invert=false, const unsigned int nb_scales=1) { - return get_haar(invert,nb_scales).move_to(*this); - } - - //! Compute Haar multiscale wavelet transform \newinstance. - CImg get_haar(const bool invert=false, const unsigned int nb_scales=1) const { - CImg res; - if (nb_scales==1) { // Single scale transform - if (_width>1) get_haar('x',invert,1).move_to(res); - if (_height>1) { if (res) res.haar('y',invert,1); else get_haar('y',invert,1).move_to(res); } - if (_depth>1) { if (res) res.haar('z',invert,1); else get_haar('z',invert,1).move_to(res); } - if (res) return res; - } else { // Multi-scale transform - if (invert) { // Inverse transform - res.assign(*this,false); - if (_width>1) { - if (_height>1) { - if (_depth>1) { - unsigned int w = _width, h = _height, d = _depth; - for (unsigned int s = 1; w && h && d && s1) { - unsigned int w = _width, d = _depth; - for (unsigned int s = 1; w && d && s1) { - if (_depth>1) { - unsigned int h = _height, d = _depth; - for (unsigned int s = 1; h && d && s1) { - unsigned int d = _depth; - for (unsigned int s = 1; d && s1) { - if (_height>1) { - if (_depth>1) - for (unsigned int s = 1, w = _width/2, h = _height/2, d = _depth/2; w && h && d && s1) for (unsigned int s = 1, w = _width/2, d = _depth/2; w && d && s1) { - if (_depth>1) - for (unsigned int s = 1, h = _height/2, d = _depth/2; h && d && s1) for (unsigned int s = 1, d = _depth/2; d && s get_FFT(const char axis, const bool is_inverse=false) const { - CImgList res(*this,CImg()); - CImg::FFT(res[0],res[1],axis,is_inverse); - return res; - } - - //! Compute n-D Fast Fourier Transform. - /* - \param is_inverse Tells if the forward (\c false) or inverse (\c true) FFT is computed. - **/ - CImgList get_FFT(const bool is_inverse=false) const { - CImgList res(*this,CImg()); - CImg::FFT(res[0],res[1],is_inverse); - return res; - } - - //! Compute 1D Fast Fourier Transform, along a specified axis. - /** - \param[in,out] real Real part of the pixel values. - \param[in,out] imag Imaginary part of the pixel values. - \param axis Axis along which the FFT is computed. - \param is_inverse Tells if the forward (\c false) or inverse (\c true) FFT is computed. - **/ - static void FFT(CImg& real, CImg& imag, const char axis, const bool is_inverse=false, - const unsigned int nb_threads=0) { - if (!real) - throw CImgInstanceException("CImg<%s>::FFT(): Specified real part is empty.", - pixel_type()); - if (!imag) imag.assign(real._width,real._height,real._depth,real._spectrum,(T)0); - if (!real.is_sameXYZC(imag)) - throw CImgInstanceException("CImg<%s>::FFT(): Specified real part (%u,%u,%u,%u,%p) and " - "imaginary part (%u,%u,%u,%u,%p) have different dimensions.", - pixel_type(), - real._width,real._height,real._depth,real._spectrum,real._data, - imag._width,imag._height,imag._depth,imag._spectrum,imag._data); - const char _axis = cimg::lowercase(axis); - if (_axis!='x' && _axis!='y' && _axis!='z') - throw CImgArgumentException("CImgList<%s>::FFT(): Invalid specified axis '%c' for real and imaginary parts " - "(%u,%u,%u,%u) " - "(should be { x | y | z }).", - pixel_type(),axis, - real._width,real._height,real._depth,real._spectrum); - cimg::unused(nb_threads); -#ifdef cimg_use_fftw3 - cimg::mutex(12); -#ifndef cimg_use_fftw3_singlethread - fftw_plan_with_nthreads(nb_threads?nb_threads:cimg::nb_cpus()); -#endif - fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real._width*real._height*real._depth); - if (!data_in) - throw CImgInstanceException("CImgList<%s>::FFT(): Failed to allocate memory (%s) " - "for computing FFT of image (%u,%u,%u,%u) along the X-axis.", - pixel_type(), - cimg::strbuffersize(sizeof(fftw_complex)*real._width*real._height*real._depth), - real._width,real._height,real._depth,real._spectrum); - double *const ptrf = (double*)data_in; - fftw_plan data_plan = - _axis=='x'?fftw_plan_many_dft(1,(int*)&real._width,real.height()*real.depth(), - data_in,0,1,real.width(), - data_in,0,1,real.width(), - is_inverse?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE): - _axis=='y'?fftw_plan_many_dft(1,(int*)&real._height,real.width()*real.depth(), - data_in,0,1,real.height(), - data_in,0,1,real.height(), - is_inverse?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE): - fftw_plan_many_dft(1,(int*)&real._depth,real.width()*real.height(), - data_in,0,1,real.depth(), - data_in,0,1,real.depth(), - is_inverse?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE); - cimg_forC(real,c) { - CImg realc = real.get_shared_channel(c), imagc = imag.get_shared_channel(c); - switch (_axis) { - case 'x' : - cimg_pragma_openmp(parallel for cimg_openmp_if_size(real.width()*real.height()*real.depth(),125000)) - cimg_forXYZ(realc,x,y,z) { - const ulongT - i = realc.offset(x,y,z), - j = 2*(x + (ulongT)y*realc._width + (ulongT)z*realc._width*realc._height); - ptrf[j] = (double)realc[i]; - ptrf[j + 1] = (double)imagc[i]; - } - break; - case 'y' : - cimg_pragma_openmp(parallel for cimg_openmp_if_size(real.width()*real.height()*real.depth(),125000)) - cimg_forXYZ(realc,x,y,z) { - const ulongT - i = realc.offset(x,y,z), - j = 2*(y + (ulongT)x*realc._height + (ulongT)z*realc._width*realc._height); - ptrf[j] = (double)realc[i]; - ptrf[j + 1] = (double)imagc[i]; - } - break; - default : - cimg_pragma_openmp(parallel for cimg_openmp_if_size(real.width()*real.height()*real.depth(),125000)) - cimg_forXYZ(realc,x,y,z) { - const ulongT - i = realc.offset(x,y,z), - j = 2*(z + (ulongT)x*realc._depth + (ulongT)y*realc._width*realc._depth); - ptrf[j] = (double)realc[i]; - ptrf[j + 1] = (double)imagc[i]; - } - } - - fftw_execute(data_plan); - - const double a = is_inverse?1.0/(_axis=='x'?real.width():_axis=='y'?real.height():real.depth()):1.0; - switch (_axis) { - case 'x' : - cimg_pragma_openmp(parallel for cimg_openmp_if_size(real.width()*real.height()*real.depth(),125000)) - cimg_forXYZ(realc,x,y,z) { - const ulongT - i = 2*(x + (ulongT)y*realc._width + (ulongT)z*realc._width*realc._height), - j = realc.offset(x,y,z); - realc[j] = (T)(a*ptrf[i]); - imagc[j] = (T)(a*ptrf[i + 1]); - } - break; - case 'y' : - cimg_pragma_openmp(parallel for cimg_openmp_if_size(real.width()*real.height()*real.depth(),125000)) - cimg_forXYZ(realc,x,y,z) { - const ulongT - i = 2*(y + (ulongT)x*realc._height + (ulongT)z*realc._width*realc._height), - j = realc.offset(x,y,z); - realc[j] = (T)(a*ptrf[i]); - imagc[j] = (T)(a*ptrf[i + 1]); - } - break; - default : - cimg_pragma_openmp(parallel for cimg_openmp_if_size(real.width()*real.height()*real.depth(),125000)) - cimg_forXYZ(realc,x,y,z) { - const ulongT - i = 2*(z + (ulongT)x*realc._depth + (ulongT)y*realc._width*realc._depth), - j = realc.offset(x,y,z); - realc[j] = (T)(a*ptrf[i]); - imagc[j] = (T)(a*ptrf[i + 1]); - } - } - } - - fftw_destroy_plan(data_plan); - fftw_free(data_in); -#ifndef cimg_use_fftw3_singlethread - fftw_cleanup_threads(); -#endif - cimg::mutex(12,0); -#else - switch (_axis) { - case 'x' : { // Fourier along X, using built-in functions - const unsigned int N = real._width, N2 = N>>1; - if (((N - 1)&N) && N!=1) - throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) " - "have non 2^N dimension along the X-axis.", - pixel_type(), - real._width,real._height,real._depth,real._spectrum); - - for (unsigned int i = 0, j = 0; ii) cimg_forYZC(real,y,z,c) { - cimg::swap(real(i,y,z,c),real(j,y,z,c)); - cimg::swap(imag(i,y,z,c),imag(j,y,z,c)); - if (j=m; j-=m, m = n, n>>=1) {} - } - for (unsigned int delta = 2; delta<=N; delta<<=1) { - const unsigned int delta2 = delta>>1; - for (unsigned int i = 0; i>1; - if (((N - 1)&N) && N!=1) - throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) " - "have non 2^N dimension along the Y-axis.", - pixel_type(), - real._width,real._height,real._depth,real._spectrum); - - for (unsigned int i = 0, j = 0; ii) cimg_forXZC(real,x,z,c) { - cimg::swap(real(x,i,z,c),real(x,j,z,c)); - cimg::swap(imag(x,i,z,c),imag(x,j,z,c)); - if (j=m; j-=m, m = n, n>>=1) {} - } - for (unsigned int delta = 2; delta<=N; delta<<=1) { - const unsigned int delta2 = (delta>>1); - for (unsigned int i = 0; i>1; - if (((N - 1)&N) && N!=1) - throw CImgInstanceException("CImgList<%s>::FFT(): Specified real and imaginary parts (%u,%u,%u,%u) " - "have non 2^N dimension along the Z-axis.", - pixel_type(), - real._width,real._height,real._depth,real._spectrum); - - for (unsigned int i = 0, j = 0; ii) cimg_forXYC(real,x,y,c) { - cimg::swap(real(x,y,i,c),real(x,y,j,c)); - cimg::swap(imag(x,y,i,c),imag(x,y,j,c)); - if (j=m; j-=m, m = n, n>>=1) {} - } - for (unsigned int delta = 2; delta<=N; delta<<=1) { - const unsigned int delta2 = (delta>>1); - for (unsigned int i = 0; i& real, CImg& imag, const bool is_inverse=false, - const unsigned int nb_threads=0) { - if (!real) - throw CImgInstanceException("CImgList<%s>::FFT(): Empty specified real part.", - pixel_type()); - if (!imag) imag.assign(real._width,real._height,real._depth,real._spectrum,(T)0); - if (!real.is_sameXYZC(imag)) - throw CImgInstanceException("CImgList<%s>::FFT(): Specified real part (%u,%u,%u,%u,%p) and " - "imaginary part (%u,%u,%u,%u,%p) have different dimensions.", - pixel_type(), - real._width,real._height,real._depth,real._spectrum,real._data, - imag._width,imag._height,imag._depth,imag._spectrum,imag._data); - cimg::unused(nb_threads); -#ifdef cimg_use_fftw3 - cimg::mutex(12); -#ifndef cimg_use_fftw3_singlethread - fftw_plan_with_nthreads(nb_threads?nb_threads:cimg::nb_cpus()); -#endif - fftw_complex *data_in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*real._width*real._height*real._depth); - if (!data_in) - throw CImgInstanceException("CImgList<%s>::FFT(): Failed to allocate memory (%s) " - "for computing FFT of image (%u,%u,%u,%u).", - pixel_type(), - cimg::strbuffersize(sizeof(fftw_complex)*real._width* - real._height*real._depth*real._spectrum), - real._width,real._height,real._depth,real._spectrum); - double *const ptrf = (double*)data_in; - fftw_plan data_plan = - real._depth>1?fftw_plan_dft_3d(real._depth,real._height,real._width,data_in,data_in, - is_inverse?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE): - real._height>1?fftw_plan_dft_2d(real._height,real._width,data_in,data_in, - is_inverse?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE): - fftw_plan_dft_1d(real._width,data_in,data_in, - is_inverse?FFTW_BACKWARD:FFTW_FORWARD,FFTW_ESTIMATE); - cimg_forC(real,c) { - CImg realc = real.get_shared_channel(c), imagc = imag.get_shared_channel(c); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(real.width()*real.height()*real.depth(),125000)) - cimg_rofoff(realc,i) { const ulongT i2 = 2*i; ptrf[i2] = (double)realc[i]; ptrf[i2 + 1] = (double)imagc[i]; } - fftw_execute(data_plan); - if (is_inverse) { - const double a = 1.0/(real.width()*real.height()*real.depth()); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(real.width()*real.height()*real.depth(),125000)) - cimg_rofoff(realc,i) { const ulongT i2 = 2*i; realc[i] = (T)(a*ptrf[i2]); imagc[i] = (T)(a*ptrf[i2 + 1]); } - } else - cimg_pragma_openmp(parallel for cimg_openmp_if_size(real.width()*real.height()*real.depth(),125000)) - cimg_rofoff(realc,i) { const ulongT i2 = 2*i; realc[i] = (T)ptrf[i2]; imagc[i] = (T)ptrf[i2 + 1]; } - } - fftw_destroy_plan(data_plan); - fftw_free(data_in); -#ifndef cimg_use_fftw3_singlethread - fftw_cleanup_threads(); -#endif - cimg::mutex(12,0); -#else - if (real._depth>1) FFT(real,imag,'z',is_inverse); - if (real._height>1) FFT(real,imag,'y',is_inverse); - if (real._width>1) FFT(real,imag,'x',is_inverse); -#endif - } - - //@} - //------------------------------------- - // - //! \name 3D Objects Management - //@{ - //------------------------------------- - - //! Rotate 3D object's vertices. - /** - \param x X-coordinate of the rotation axis, or first quaternion coordinate. - \param y Y-coordinate of the rotation axis, or second quaternion coordinate. - \param z Z-coordinate of the rotation axis, or second quaternion coordinate. - \param w Angle of the rotation axis (in degree), or fourth quaternion coordinate. - \param is_quaternion Tell is the four arguments denotes a set { axis + angle } or a quaternion (x,y,z,w). - **/ - CImg& rotate_object3d(const float x, const float y, const float z, const float w, - const bool is_quaternion=false) { - return get_rotate_object3d(x,y,z,w,is_quaternion).move_to(*this); - } - - CImg get_rotate_object3d(const float x, const float y, const float z, const float w, - const bool is_quaternion=false) const { - if (_height!=3 || _depth>1 || _spectrum>1) - throw CImgInstanceException(_cimg_instance - "rotate_object3d(): Instance is not a set of 3D vertices.", - cimg_instance); - return CImg::rotation_matrix(x,y,z,w,is_quaternion)**this; - } - - //! Shift 3D object's vertices. - /** - \param tx X-coordinate of the 3D displacement vector. - \param ty Y-coordinate of the 3D displacement vector. - \param tz Z-coordinate of the 3D displacement vector. - **/ - CImg& shift_object3d(const float tx, const float ty=0, const float tz=0) { - if (_height!=3 || _depth>1 || _spectrum>1) - throw CImgInstanceException(_cimg_instance - "shift_object3d(): Instance is not a set of 3D vertices.", - cimg_instance); - - get_shared_row(0)+=tx; get_shared_row(1)+=ty; get_shared_row(2)+=tz; - return *this; - } - - //! Shift 3D object's vertices \newinstance. - CImg get_shift_object3d(const float tx, const float ty=0, const float tz=0) const { - return CImg(*this,false).shift_object3d(tx,ty,tz); - } - - //! Shift 3D object's vertices, so that it becomes centered. - /** - \note The object center is computed as its barycenter. - **/ - CImg& shift_object3d() { - if (_height!=3 || _depth>1 || _spectrum>1) - throw CImgInstanceException(_cimg_instance - "shift_object3d(): Instance is not a set of 3D vertices.", - cimg_instance); - - CImg xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2); - float - xm, xM = (float)xcoords.max_min(xm), - ym, yM = (float)ycoords.max_min(ym), - zm, zM = (float)zcoords.max_min(zm); - xcoords-=(xm + xM)/2; ycoords-=(ym + yM)/2; zcoords-=(zm + zM)/2; - return *this; - } - - //! Shift 3D object's vertices, so that it becomes centered \newinstance. - CImg get_shift_object3d() const { - return CImg(*this,false).shift_object3d(); - } - - //! Resize 3D object. - /** - \param sx Width of the 3D object's bounding box. - \param sy Height of the 3D object's bounding box. - \param sz Depth of the 3D object's bounding box. - **/ - CImg& resize_object3d(const float sx, const float sy=-100, const float sz=-100) { - if (_height!=3 || _depth>1 || _spectrum>1) - throw CImgInstanceException(_cimg_instance - "resize_object3d(): Instance is not a set of 3D vertices.", - cimg_instance); - - CImg xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2); - float - xm, xM = (float)xcoords.max_min(xm), - ym, yM = (float)ycoords.max_min(ym), - zm, zM = (float)zcoords.max_min(zm); - if (xm0) xcoords*=sx/(xM-xm); else xcoords*=-sx/100; } - if (ym0) ycoords*=sy/(yM-ym); else ycoords*=-sy/100; } - if (zm0) zcoords*=sz/(zM-zm); else zcoords*=-sz/100; } - return *this; - } - - //! Resize 3D object \newinstance. - CImg get_resize_object3d(const float sx, const float sy=-100, const float sz=-100) const { - return CImg(*this,false).resize_object3d(sx,sy,sz); - } - - //! Resize 3D object to unit size. - CImg resize_object3d() { - if (_height!=3 || _depth>1 || _spectrum>1) - throw CImgInstanceException(_cimg_instance - "resize_object3d(): Instance is not a set of 3D vertices.", - cimg_instance); - - CImg xcoords = get_shared_row(0), ycoords = get_shared_row(1), zcoords = get_shared_row(2); - float - xm, xM = (float)xcoords.max_min(xm), - ym, yM = (float)ycoords.max_min(ym), - zm, zM = (float)zcoords.max_min(zm); - const float dx = xM - xm, dy = yM - ym, dz = zM - zm, dmax = cimg::max(dx,dy,dz); - if (dmax>0) { xcoords/=dmax; ycoords/=dmax; zcoords/=dmax; } - return *this; - } - - //! Resize 3D object to unit size \newinstance. - CImg get_resize_object3d() const { - return CImg(*this,false).resize_object3d(); - } - - //! Merge two 3D objects together. - /** - \param[in,out] primitives Primitives data of the current 3D object. - \param obj_vertices Vertices data of the additional 3D object. - \param obj_primitives Primitives data of the additional 3D object. - **/ - template - CImg& append_object3d(CImgList& primitives, const CImg& obj_vertices, - const CImgList& obj_primitives) { - if (!obj_vertices || !obj_primitives) return *this; - if (obj_vertices._height!=3 || obj_vertices._depth>1 || obj_vertices._spectrum>1) - throw CImgInstanceException(_cimg_instance - "append_object3d(): Specified vertice image (%u,%u,%u,%u,%p) is not a " - "set of 3D vertices.", - cimg_instance, - obj_vertices._width,obj_vertices._height, - obj_vertices._depth,obj_vertices._spectrum,obj_vertices._data); - - if (is_empty()) { primitives.assign(obj_primitives); return assign(obj_vertices); } - if (_height!=3 || _depth>1 || _spectrum>1) - throw CImgInstanceException(_cimg_instance - "append_object3d(): Instance is not a set of 3D vertices.", - cimg_instance); - - const unsigned int P = _width; - append(obj_vertices,'x'); - const unsigned int N = primitives._width; - primitives.insert(obj_primitives); - for (unsigned int i = N; i &p = primitives[i]; - switch (p.size()) { - case 1 : p[0]+=P; break; // Point - case 5 : p[0]+=P; p[1]+=P; break; // Sphere - case 2 : case 6 : p[0]+=P; p[1]+=P; break; // Segment - case 3 : case 9 : p[0]+=P; p[1]+=P; p[2]+=P; break; // Triangle - case 4 : case 12 : p[0]+=P; p[1]+=P; p[2]+=P; p[3]+=P; break; // Rectangle - } - } - return *this; - } - - //! Texturize primitives of a 3D object. - /** - \param[in,out] primitives Primitives data of the 3D object. - \param[in,out] colors Colors data of the 3D object. - \param texture Texture image to map to 3D object. - \param coords Texture-mapping coordinates. - **/ - template - const CImg& texturize_object3d(CImgList& primitives, CImgList& colors, - const CImg& texture, const CImg& coords=CImg::const_empty()) const { - if (is_empty()) return *this; - if (_height!=3) - throw CImgInstanceException(_cimg_instance - "texturize_object3d(): image instance is not a set of 3D points.", - cimg_instance); - if (coords && (coords._width!=_width || coords._height!=2)) - throw CImgArgumentException(_cimg_instance - "texturize_object3d(): Invalid specified texture coordinates (%u,%u,%u,%u,%p).", - cimg_instance, - coords._width,coords._height,coords._depth,coords._spectrum,coords._data); - CImg _coords; - if (!coords) { // If no texture coordinates specified, do a default XY-projection - _coords.assign(_width,2); - float - xmin, xmax = (float)get_shared_row(0).max_min(xmin), - ymin, ymax = (float)get_shared_row(1).max_min(ymin), - dx = xmax>xmin?xmax-xmin:1, - dy = ymax>ymin?ymax-ymin:1; - cimg_forX(*this,p) { - _coords(p,0) = (int)(((*this)(p,0) - xmin)*texture._width/dx); - _coords(p,1) = (int)(((*this)(p,1) - ymin)*texture._height/dy); - } - } else _coords = coords; - - int texture_ind = -1; - cimglist_for(primitives,l) { - CImg &p = primitives[l]; - const unsigned int siz = p.size(); - switch (siz) { - case 1 : { // Point - const unsigned int i0 = (unsigned int)p[0]; - const int x0 = _coords(i0,0), y0 = _coords(i0,1); - texture.get_vector_at(x0<=0?0:x0>=texture.width()?texture.width() - 1:x0, - y0<=0?0:y0>=texture.height()?texture.height() - 1:y0).move_to(colors[l]); - } break; - case 2 : case 6 : { // Line - const unsigned int i0 = (unsigned int)p[0], i1 = (unsigned int)p[1]; - const int - x0 = _coords(i0,0), y0 = _coords(i0,1), - x1 = _coords(i1,0), y1 = _coords(i1,1); - if (texture_ind<0) colors[texture_ind=l].assign(texture,false); - else colors[l].assign(colors[texture_ind],true); - CImg::vector(i0,i1,x0,y0,x1,y1).move_to(p); - } break; - case 3 : case 9 : { // Triangle - const unsigned int i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], i2 = (unsigned int)p[2]; - const int - x0 = _coords(i0,0), y0 = _coords(i0,1), - x1 = _coords(i1,0), y1 = _coords(i1,1), - x2 = _coords(i2,0), y2 = _coords(i2,1); - if (texture_ind<0) colors[texture_ind=l].assign(texture,false); - else colors[l].assign(colors[texture_ind],true); - CImg::vector(i0,i1,i2,x0,y0,x1,y1,x2,y2).move_to(p); - } break; - case 4 : case 12 : { // Quadrangle - const unsigned int - i0 = (unsigned int)p[0], i1 = (unsigned int)p[1], i2 = (unsigned int)p[2], i3 = (unsigned int)p[3]; - const int - x0 = _coords(i0,0), y0 = _coords(i0,1), - x1 = _coords(i1,0), y1 = _coords(i1,1), - x2 = _coords(i2,0), y2 = _coords(i2,1), - x3 = _coords(i3,0), y3 = _coords(i3,1); - if (texture_ind<0) colors[texture_ind=l].assign(texture,false); - else colors[l].assign(colors[texture_ind],true); - CImg::vector(i0,i1,i2,i3,x0,y0,x1,y1,x2,y2,x3,y3).move_to(p); - } break; - } - } - return *this; - } - - //! Generate a 3D elevation of the image instance. - /** - \param[out] primitives The returned list of the 3D object primitives - (template type \e tf should be at least \e unsigned \e int). - \param[out] colors The returned list of the 3D object colors. - \param elevation The input elevation map. - \return The N vertices (xi,yi,zi) of the 3D object as a Nx3 CImg image (0<=i<=N - 1). - \par Example - \code - const CImg img("reference.jpg"); - CImgList faces3d; - CImgList colors3d; - const CImg points3d = img.get_elevation3d(faces3d,colors3d,img.get_norm()*0.2); - CImg().display_object3d("Elevation3d",points3d,faces3d,colors3d); - \endcode - \image html ref_elevation3d.jpg - **/ - template - CImg get_elevation3d(CImgList& primitives, CImgList& colors, const CImg& elevation) const { - if (!is_sameXY(elevation) || elevation._depth>1 || elevation._spectrum>1) - throw CImgArgumentException(_cimg_instance - "get_elevation3d(): Instance and specified elevation (%u,%u,%u,%u,%p) " - "have incompatible dimensions.", - cimg_instance, - elevation._width,elevation._height,elevation._depth, - elevation._spectrum,elevation._data); - if (is_empty()) return *this; - float m, M = (float)max_min(m); - if (M==m) ++M; - colors.assign(); - const unsigned int size_x1 = _width - 1, size_y1 = _height - 1; - for (unsigned int y = 0; y1?((*this)(x,y,1) - m)*255/(M-m):r), - b = (unsigned char)(_spectrum>2?((*this)(x,y,2) - m)*255/(M-m):_spectrum>1?0:r); - CImg::vector((tc)r,(tc)g,(tc)b).move_to(colors); - } - const typename CImg::_functor2d_int func(elevation); - return elevation3d(primitives,func,0,0,_width - 1.f,_height - 1.f,_width,_height); - } - - //! Generate the 3D projection planes of the image instance. - /** - \param[out] primitives Primitives data of the returned 3D object. - \param[out] colors Colors data of the returned 3D object. - \param x0 X-coordinate of the projection point. - \param y0 Y-coordinate of the projection point. - \param z0 Z-coordinate of the projection point. - \param normalize_colors Tells if the created textures have normalized colors. - **/ - template - CImg get_projections3d(CImgList& primitives, CImgList& colors, - const unsigned int x0, const unsigned int y0, const unsigned int z0, - const bool normalize_colors=false) const { - float m = 0, M = 0, delta = 1; - if (normalize_colors) { m = (float)min_max(M); delta = 255/(m==M?1:M-m); } - const unsigned int - _x0 = (x0>=_width)?_width - 1:x0, - _y0 = (y0>=_height)?_height - 1:y0, - _z0 = (z0>=_depth)?_depth - 1:z0; - CImg img_xy, img_xz, img_yz; - if (normalize_colors) { - ((get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1)-=m)*=delta).move_to(img_xy); - ((get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1)-=m)*=delta).resize(_width,_depth,1,-100,-1). - move_to(img_xz); - ((get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1)-=m)*=delta).resize(_height,_depth,1,-100,-1). - move_to(img_yz); - } else { - get_crop(0,0,_z0,0,_width - 1,_height - 1,_z0,_spectrum - 1).move_to(img_xy); - get_crop(0,_y0,0,0,_width - 1,_y0,_depth - 1,_spectrum - 1).resize(_width,_depth,1,-100,-1).move_to(img_xz); - get_crop(_x0,0,0,0,_x0,_height - 1,_depth - 1,_spectrum - 1).resize(_height,_depth,1,-100,-1).move_to(img_yz); - } - CImg points(12,3,1,1, - 0,_width - 1,_width - 1,0, 0,_width - 1,_width - 1,0, _x0,_x0,_x0,_x0, - 0,0,_height - 1,_height - 1, _y0,_y0,_y0,_y0, 0,_height - 1,_height - 1,0, - _z0,_z0,_z0,_z0, 0,0,_depth - 1,_depth - 1, 0,0,_depth - 1,_depth - 1); - primitives.assign(); - CImg::vector(0,1,2,3,0,0,img_xy._width - 1,0,img_xy._width - 1,img_xy._height - 1,0,img_xy._height - 1). - move_to(primitives); - CImg::vector(4,5,6,7,0,0,img_xz._width - 1,0,img_xz._width - 1,img_xz._height - 1,0,img_xz._height - 1). - move_to(primitives); - CImg::vector(8,9,10,11,0,0,img_yz._width - 1,0,img_yz._width - 1,img_yz._height - 1,0,img_yz._height - 1). - move_to(primitives); - colors.assign(); - img_xy.move_to(colors); - img_xz.move_to(colors); - img_yz.move_to(colors); - return points; - } - - //! Generate a isoline of the image instance as a 3D object. - /** - \param[out] primitives The returned list of the 3D object primitives - (template type \e tf should be at least \e unsigned \e int). - \param isovalue The returned list of the 3D object colors. - \param size_x The number of subdivisions along the X-axis. - \param size_y The number of subdisivions along the Y-axis. - \return The N vertices (xi,yi,zi) of the 3D object as a Nx3 CImg image (0<=i<=N - 1). - \par Example - \code - const CImg img("reference.jpg"); - CImgList faces3d; - const CImg points3d = img.get_isoline3d(faces3d,100); - CImg().display_object3d("Isoline3d",points3d,faces3d,colors3d); - \endcode - \image html ref_isoline3d.jpg - **/ - template - CImg get_isoline3d(CImgList& primitives, const float isovalue, - const int size_x=-100, const int size_y=-100) const { - if (_spectrum>1) - throw CImgInstanceException(_cimg_instance - "get_isoline3d(): Instance is not a scalar image.", - cimg_instance); - if (_depth>1) - throw CImgInstanceException(_cimg_instance - "get_isoline3d(): Instance is not a 2D image.", - cimg_instance); - primitives.assign(); - if (is_empty()) return *this; - CImg vertices; - if ((size_x==-100 && size_y==-100) || (size_x==width() && size_y==height())) { - const _functor2d_int func(*this); - vertices = isoline3d(primitives,func,isovalue,0,0,width() - 1.f,height() - 1.f,width(),height()); - } else { - const _functor2d_float func(*this); - vertices = isoline3d(primitives,func,isovalue,0,0,width() - 1.f,height() - 1.f,size_x,size_y); - } - return vertices; - } - - //! Compute isolines of a function, as a 3D object. - /** - \param[out] primitives Primitives data of the resulting 3D object. - \param func Elevation functor. Must have operator()(x,y) defined. - \param isovalue Isovalue to extract from function. - \param x0 X-coordinate of the starting point. - \param y0 Y-coordinate of the starting point. - \param x1 X-coordinate of the ending point. - \param y1 Y-coordinate of the ending point. - \param size_x Resolution of the function along the X-axis. - \param size_y Resolution of the function along the Y-axis. - \note Use the marching squares algorithm for extracting the isolines. - **/ - template - static CImg isoline3d(CImgList& primitives, const tfunc& func, const float isovalue, - const float x0, const float y0, const float x1, const float y1, - const int size_x=256, const int size_y=256) { - CImgList vertices; - primitives.assign(); - typename CImg::_functor_isoline3d add_vertex(vertices); - typename CImg::_functor_isoline3d add_segment(primitives); - isoline3d(add_vertex,add_segment,func,isovalue,x0,y0,x1,y1,size_x,size_y); - return vertices>'x'; - } - - //! Compute isolines of a function, as a 3D object. - /** - \param[out] add_vertex : Functor with operator()(x,y,z) defined for adding new vertex. - \param[out] add_segment : Functor with operator()(i,j) defined for adding new segment. - \param func Elevation function. Is of type float (*func)(const float x,const float y). - \param isovalue Isovalue to extract from function. - \param x0 X-coordinate of the starting point. - \param y0 Y-coordinate of the starting point. - \param x1 X-coordinate of the ending point. - \param y1 Y-coordinate of the ending point. - \param size_x Resolution of the function along the X-axis. - \param size_y Resolution of the function along the Y-axis. - \note Use the marching squares algorithm for extracting the isolines. - **/ - template - static void isoline3d(tv& add_vertex, tf& add_segment, const tfunc& func, const float isovalue, - const float x0, const float y0, const float x1, const float y1, - const int size_x, const int size_y) { - static const unsigned int edges[16] = { 0x0, 0x9, 0x3, 0xa, 0x6, 0xf, 0x5, 0xc, 0xc, - 0x5, 0xf, 0x6, 0xa, 0x3, 0x9, 0x0 }; - static const int segments[16][4] = { { -1,-1,-1,-1 }, { 0,3,-1,-1 }, { 0,1,-1,-1 }, { 1,3,-1,-1 }, - { 1,2,-1,-1 }, { 0,1,2,3 }, { 0,2,-1,-1 }, { 2,3,-1,-1 }, - { 2,3,-1,-1 }, { 0,2,-1,-1}, { 0,3,1,2 }, { 1,2,-1,-1 }, - { 1,3,-1,-1 }, { 0,1,-1,-1}, { 0,3,-1,-1}, { -1,-1,-1,-1 } }; - const unsigned int - _nx = (unsigned int)(size_x>=0?size_x:cimg::round((x1-x0)*-size_x/100 + 1)), - _ny = (unsigned int)(size_y>=0?size_y:cimg::round((y1-y0)*-size_y/100 + 1)), - nx = _nx?_nx:1, - ny = _ny?_ny:1, - nxm1 = nx - 1, - nym1 = ny - 1; - - if (!nxm1 || !nym1) return; - const float dx = (x1 - x0)/nxm1, dy = (y1 - y0)/nym1; - CImg indices1(nx,1,1,2,-1), indices2(nx,1,1,2); - CImg values1(nx), values2(nx); - float X = x0, Y = y0, nX = X + dx, nY = Y + dy; - int nb_vertices = 0; - - // Fill first line with values - cimg_forX(values1,x) { values1(x) = (float)func(X,Y); X+=dx; } - - // Run the marching squares algorithm - for (unsigned int yi = 0, nyi = 1; yi - static CImg isoline3d(CImgList& primitives, const char *const expression, const float isovalue, - const float x0, const float y0, const float x1, const float y1, - const int size_x=256, const int size_y=256) { - const _functor2d_expr func(expression); - return isoline3d(primitives,func,isovalue,x0,y0,x1,y1,size_x,size_y); - } - - template - static int _isoline3d_index(const unsigned int edge, const CImg& indices1, const CImg& indices2, - const unsigned int x, const unsigned int nx) { - switch (edge) { - case 0 : return (int)indices1(x,0); - case 1 : return (int)indices1(nx,1); - case 2 : return (int)indices2(x,0); - case 3 : return (int)indices1(x,1); - } - return 0; - } - - //! Generate an isosurface of the image instance as a 3D object. - /** - \param[out] primitives The returned list of the 3D object primitives - (template type \e tf should be at least \e unsigned \e int). - \param isovalue The returned list of the 3D object colors. - \param size_x Number of subdivisions along the X-axis. - \param size_y Number of subdisivions along the Y-axis. - \param size_z Number of subdisivions along the Z-axis. - \return The N vertices (xi,yi,zi) of the 3D object as a Nx3 CImg image (0<=i<=N - 1). - \par Example - \code - const CImg img = CImg("reference.jpg").resize(-100,-100,20); - CImgList faces3d; - const CImg points3d = img.get_isosurface3d(faces3d,100); - CImg().display_object3d("Isosurface3d",points3d,faces3d,colors3d); - \endcode - \image html ref_isosurface3d.jpg - **/ - template - CImg get_isosurface3d(CImgList& primitives, const float isovalue, - const int size_x=-100, const int size_y=-100, const int size_z=-100) const { - if (_spectrum>1) - throw CImgInstanceException(_cimg_instance - "get_isosurface3d(): Instance is not a scalar image.", - cimg_instance); - primitives.assign(); - if (is_empty()) return *this; - CImg vertices; - if ((size_x==-100 && size_y==-100 && size_z==-100) || (size_x==width() && size_y==height() && size_z==depth())) { - const _functor3d_int func(*this); - vertices = isosurface3d(primitives,func,isovalue,0,0,0,width() - 1.f,height() - 1.f,depth() - 1.f, - width(),height(),depth()); - } else { - const _functor3d_float func(*this); - vertices = isosurface3d(primitives,func,isovalue,0,0,0,width() - 1.f,height() - 1.f,depth() - 1.f, - size_x,size_y,size_z); - } - return vertices; - } - - //! Compute isosurface of a function, as a 3D object. - /** - \param[out] primitives Primitives data of the resulting 3D object. - \param func Implicit function. Is of type float (*func)(const float x, const float y, const float z). - \param isovalue Isovalue to extract. - \param x0 X-coordinate of the starting point. - \param y0 Y-coordinate of the starting point. - \param z0 Z-coordinate of the starting point. - \param x1 X-coordinate of the ending point. - \param y1 Y-coordinate of the ending point. - \param z1 Z-coordinate of the ending point. - \param size_x Resolution of the elevation function along the X-axis. - \param size_y Resolution of the elevation function along the Y-axis. - \param size_z Resolution of the elevation function along the Z-axis. - \note Use the marching cubes algorithm for extracting the isosurface. - **/ - template - static CImg isosurface3d(CImgList& primitives, const tfunc& func, const float isovalue, - const float x0, const float y0, const float z0, - const float x1, const float y1, const float z1, - const int size_x=32, const int size_y=32, const int size_z=32) { - CImgList vertices; - primitives.assign(); - typename CImg::_functor_isosurface3d add_vertex(vertices); - typename CImg::_functor_isosurface3d add_triangle(primitives); - isosurface3d(add_vertex,add_triangle,func,isovalue,x0,y0,z0,x1,y1,z1,size_x,size_y,size_z); - return vertices>'x'; - } - - //! Compute isosurface of a function, as a 3D object. - /** - \param[out] add_vertex : Functor with operator()(x,y,z) defined for adding new vertex. - \param[out] add_triangle : Functor with operator()(i,j) defined for adding new segment. - \param func Implicit function. Is of type float (*func)(const float x, const float y, const float z). - \param isovalue Isovalue to extract. - \param x0 X-coordinate of the starting point. - \param y0 Y-coordinate of the starting point. - \param z0 Z-coordinate of the starting point. - \param x1 X-coordinate of the ending point. - \param y1 Y-coordinate of the ending point. - \param z1 Z-coordinate of the ending point. - \param size_x Resolution of the elevation function along the X-axis. - \param size_y Resolution of the elevation function along the Y-axis. - \param size_z Resolution of the elevation function along the Z-axis. - \note Use the marching cubes algorithm for extracting the isosurface. - **/ - template - static void isosurface3d(tv& add_vertex, tf& add_triangle, const tfunc& func, const float isovalue, - const float x0, const float y0, const float z0, - const float x1, const float y1, const float z1, - const int size_x, const int size_y, const int size_z) { - static const unsigned int edges[256] = { - 0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, - 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, - 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, - 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, - 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, - 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, - 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, - 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc , 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, - 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, - 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, - 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, - 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460, - 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0, - 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230, - 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190, - 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000 - }; - - static const int triangles[256][16] = { - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, - { 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, - { 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1 }, - { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1 }, - { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, - { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, - { 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, - { 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 }, - { 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1 }, - { 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1 }, - { 10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1 }, - { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1 }, - { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1 }, - { 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 }, - { 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 }, - { 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, - { 7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, - { 2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1 }, - { 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1 }, - { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1 }, - { 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1 }, - { 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, - { 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 }, - { 2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, - { 5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1 }, - { 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, - { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1 }, - { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, - { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1 }, - { 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, - { 6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1 }, - { 8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1 }, - { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1 }, - { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, - { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, - { 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 }, - { 9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 }, - { 8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, - { 5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1 }, - { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1 }, - { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1 }, - { 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1 }, - { 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, - { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, - { 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 }, - { 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, - { 10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1 }, - { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, - { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1 }, - { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1 }, - { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 }, - { 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, - { 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 }, - { 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 }, - { 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, - { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1 }, - { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, - { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1 }, - { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 }, - { 1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 }, - { 11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 }, - { 8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 }, - { 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1 }, - { 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 }, - { 10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, - { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1 }, - { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1 }, - { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, - { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 }, - { 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, - { 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 }, - { 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1 }, - { 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, - { 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, - { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1 }, - { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1 }, - { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1 }, - { 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 }, - { 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 }, - { 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, - { 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1 }, - { 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1 }, - { 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1 }, - { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, - { 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1 }, - { 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, - { 6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 }, - { 7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 }, - { 3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1 }, - { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1 }, - { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1 }, - { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 }, - { 9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 }, - { 1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 }, - { 4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 }, - { 7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1 }, - { 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1 }, - { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1 }, - { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1 }, - { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1 }, - { 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 }, - { 6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 }, - { 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 }, - { 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1 }, - { 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1 }, - { 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1 }, - { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1 }, - { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1 }, - { 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1 }, - { 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 }, - { 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 }, - { 7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1 }, - { 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, - { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1 }, - { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1 }, - { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1 }, - { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, - { 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 }, - { 0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 }, - { 10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 }, - { 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1 }, - { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1 }, - { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1 }, - { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1 }, - { 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 }, - { 5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1 }, - { 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1 }, - { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1 }, - { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1 }, - { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1 }, - { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 }, - { 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 }, - { 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, - { 11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 }, - { 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1 }, - { 9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1 }, - { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1 }, - { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1 }, - { 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 }, - { 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, - { 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 }, - { 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, - { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } - }; - - const unsigned int - _nx = (unsigned int)(size_x>=0?size_x:cimg::round((x1-x0)*-size_x/100 + 1)), - _ny = (unsigned int)(size_y>=0?size_y:cimg::round((y1-y0)*-size_y/100 + 1)), - _nz = (unsigned int)(size_z>=0?size_z:cimg::round((z1-z0)*-size_z/100 + 1)), - nx = _nx?_nx:1, - ny = _ny?_ny:1, - nz = _nz?_nz:1, - nxm1 = nx - 1, - nym1 = ny - 1, - nzm1 = nz - 1; - if (!nxm1 || !nym1 || !nzm1) return; - const float dx = (x1 - x0)/nxm1, dy = (y1 - y0)/nym1, dz = (z1 - z0)/nzm1; - CImg indices1(nx,ny,1,3,-1), indices2(indices1); - CImg values1(nx,ny), values2(nx,ny); - float X = 0, Y = 0, Z = 0, nX = 0, nY = 0, nZ = 0; - int nb_vertices = 0; - - // Fill the first plane with function values - Y = y0; - cimg_forY(values1,y) { - X = x0; - cimg_forX(values1,x) { values1(x,y) = (float)func(X,Y,z0); X+=dx; } - Y+=dy; - } - - // Run Marching Cubes algorithm - Z = z0; nZ = Z + dz; - for (unsigned int zi = 0; zi - static CImg isosurface3d(CImgList& primitives, const char *const expression, const float isovalue, - const float x0, const float y0, const float z0, - const float x1, const float y1, const float z1, - const int dx=32, const int dy=32, const int dz=32) { - const _functor3d_expr func(expression); - return isosurface3d(primitives,func,isovalue,x0,y0,z0,x1,y1,z1,dx,dy,dz); - } - - template - static int _isosurface3d_index(const unsigned int edge, const CImg& indices1, const CImg& indices2, - const unsigned int x, const unsigned int y, - const unsigned int nx, const unsigned int ny) { - switch (edge) { - case 0 : return indices1(x,y,0); - case 1 : return indices1(nx,y,1); - case 2 : return indices1(x,ny,0); - case 3 : return indices1(x,y,1); - case 4 : return indices2(x,y,0); - case 5 : return indices2(nx,y,1); - case 6 : return indices2(x,ny,0); - case 7 : return indices2(x,y,1); - case 8 : return indices1(x,y,2); - case 9 : return indices1(nx,y,2); - case 10 : return indices1(nx,ny,2); - case 11 : return indices1(x,ny,2); - } - return 0; - } - - // Define functors for accessing image values (used in previous functions). - struct _functor2d_int { - const CImg& ref; - _functor2d_int(const CImg& pref):ref(pref) {} - float operator()(const float x, const float y) const { - return (float)ref((int)x,(int)y); - } - }; - - struct _functor2d_float { - const CImg& ref; - _functor2d_float(const CImg& pref):ref(pref) {} - float operator()(const float x, const float y) const { - return (float)ref._linear_atXY(x,y); - } - }; - - struct _functor2d_expr { - _cimg_math_parser *mp; - ~_functor2d_expr() { mp->end(); delete mp; } - _functor2d_expr(const char *const expr):mp(0) { - mp = new _cimg_math_parser(expr,0,CImg::const_empty(),0); - } - float operator()(const float x, const float y) const { - return (float)(*mp)(x,y,0,0); - } - }; - - struct _functor3d_int { - const CImg& ref; - _functor3d_int(const CImg& pref):ref(pref) {} - float operator()(const float x, const float y, const float z) const { - return (float)ref((int)x,(int)y,(int)z); - } - }; - - struct _functor3d_float { - const CImg& ref; - _functor3d_float(const CImg& pref):ref(pref) {} - float operator()(const float x, const float y, const float z) const { - return (float)ref._linear_atXYZ(x,y,z); - } - }; - - struct _functor3d_expr { - _cimg_math_parser *mp; - ~_functor3d_expr() { mp->end(); delete mp; } - _functor3d_expr(const char *const expr):mp(0) { - mp = new _cimg_math_parser(expr,0,CImg::const_empty(),0); - } - float operator()(const float x, const float y, const float z) const { - return (float)(*mp)(x,y,z,0); - } - }; - - struct _functor4d_int { - const CImg& ref; - _functor4d_int(const CImg& pref):ref(pref) {} - float operator()(const float x, const float y, const float z, const unsigned int c) const { - return (float)ref((int)x,(int)y,(int)z,c); - } - }; - - struct _functor_isoline3d { - CImgList& list; - _functor_isoline3d(CImgList& _list):list(_list) {} - template - void operator()(const t x, const t y, const t z) { CImg::vector((T)x,(T)y,(T)z).move_to(list); } - template - void operator()(const t i, const t j) { CImg::vector((T)i,(T)j).move_to(list); } - }; - - struct _functor_isosurface3d { - CImgList& list; - _functor_isosurface3d(CImgList& _list):list(_list) {} - template - void operator()(const t x, const t y, const t z) { CImg::vector((T)x,(T)y,(T)z).move_to(list); } - }; - - //! Compute 3D elevation of a function as a 3D object. - /** - \param[out] primitives Primitives data of the resulting 3D object. - \param func Elevation function. Is of type float (*func)(const float x,const float y). - \param x0 X-coordinate of the starting point. - \param y0 Y-coordinate of the starting point. - \param x1 X-coordinate of the ending point. - \param y1 Y-coordinate of the ending point. - \param size_x Resolution of the function along the X-axis. - \param size_y Resolution of the function along the Y-axis. - **/ - template - static CImg elevation3d(CImgList& primitives, const tfunc& func, - const float x0, const float y0, const float x1, const float y1, - const int size_x=256, const int size_y=256) { - const float - nx0 = x0=0?size_x:(nx1-nx0)*-size_x/100), - nsize_x = _nsize_x?_nsize_x:1, nsize_x1 = nsize_x - 1, - _nsize_y = (unsigned int)(size_y>=0?size_y:(ny1-ny0)*-size_y/100), - nsize_y = _nsize_y?_nsize_y:1, nsize_y1 = nsize_y - 1; - if (nsize_x<2 || nsize_y<2) - throw CImgArgumentException("CImg<%s>::elevation3d(): Invalid specified size (%d,%d).", - pixel_type(), - nsize_x,nsize_y); - - CImg vertices(nsize_x*nsize_y,3); - floatT *ptr_x = vertices.data(0,0), *ptr_y = vertices.data(0,1), *ptr_z = vertices.data(0,2); - for (unsigned int y = 0; y - static CImg elevation3d(CImgList& primitives, const char *const expression, - const float x0, const float y0, const float x1, const float y1, - const int size_x=256, const int size_y=256) { - const _functor2d_expr func(expression); - return elevation3d(primitives,func,x0,y0,x1,y1,size_x,size_y); - } - - //! Generate a 3D box object. - /** - \param[out] primitives The returned list of the 3D object primitives - (template type \e tf should be at least \e unsigned \e int). - \param size_x The width of the box (dimension along the X-axis). - \param size_y The height of the box (dimension along the Y-axis). - \param size_z The depth of the box (dimension along the Z-axis). - \return The N vertices (xi,yi,zi) of the 3D object as a Nx3 CImg image (0<=i<=N - 1). - \par Example - \code - CImgList faces3d; - const CImg points3d = CImg::box3d(faces3d,10,20,30); - CImg().display_object3d("Box3d",points3d,faces3d); - \endcode - \image html ref_box3d.jpg - **/ - template - static CImg box3d(CImgList& primitives, - const float size_x=200, const float size_y=100, const float size_z=100) { - primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 0,1,5,4, 3,7,6,2, 0,4,7,3, 1,2,6,5); - return CImg(8,3,1,1, - 0.,size_x,size_x, 0., 0.,size_x,size_x, 0., - 0., 0.,size_y,size_y, 0., 0.,size_y,size_y, - 0., 0., 0., 0.,size_z,size_z,size_z,size_z); - } - - //! Generate a 3D cone. - /** - \param[out] primitives The returned list of the 3D object primitives - (template type \e tf should be at least \e unsigned \e int). - \param radius The radius of the cone basis. - \param size_z The cone's height. - \param subdivisions The number of basis angular subdivisions. - \return The N vertices (xi,yi,zi) of the 3D object as a Nx3 CImg image (0<=i<=N - 1). - \par Example - \code - CImgList faces3d; - const CImg points3d = CImg::cone3d(faces3d,50); - CImg().display_object3d("Cone3d",points3d,faces3d); - \endcode - \image html ref_cone3d.jpg - **/ - template - static CImg cone3d(CImgList& primitives, - const float radius=50, const float size_z=100, const unsigned int subdivisions=24) { - primitives.assign(); - if (!subdivisions) return CImg(); - CImgList vertices(2,1,3,1,1, - 0.,0.,size_z, - 0.,0.,0.); - for (float delta = 360.f/subdivisions, angle = 0; angle<360; angle+=delta) { - const float a = (float)(angle*cimg::PI/180); - CImg::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),0).move_to(vertices); - } - const unsigned int nbr = vertices._width - 2; - for (unsigned int p = 0; p::vector(1,next,curr).move_to(primitives); - CImg::vector(0,curr,next).move_to(primitives); - } - return vertices>'x'; - } - - //! Generate a 3D cylinder. - /** - \param[out] primitives The returned list of the 3D object primitives - (template type \e tf should be at least \e unsigned \e int). - \param radius The radius of the cylinder basis. - \param size_z The cylinder's height. - \param subdivisions The number of basis angular subdivisions. - \return The N vertices (xi,yi,zi) of the 3D object as a Nx3 CImg image (0<=i<=N - 1). - \par Example - \code - CImgList faces3d; - const CImg points3d = CImg::cylinder3d(faces3d,50); - CImg().display_object3d("Cylinder3d",points3d,faces3d); - \endcode - \image html ref_cylinder3d.jpg - **/ - template - static CImg cylinder3d(CImgList& primitives, - const float radius=50, const float size_z=100, const unsigned int subdivisions=24) { - primitives.assign(); - if (!subdivisions) return CImg(); - CImgList vertices(2,1,3,1,1, - 0.,0.,0., - 0.,0.,size_z); - for (float delta = 360.f/subdivisions, angle = 0; angle<360; angle+=delta) { - const float a = (float)(angle*cimg::PI/180); - CImg::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),0.f).move_to(vertices); - CImg::vector((float)(radius*std::cos(a)),(float)(radius*std::sin(a)),size_z).move_to(vertices); - } - const unsigned int nbr = (vertices._width - 2)/2; - for (unsigned int p = 0; p::vector(0,next,curr).move_to(primitives); - CImg::vector(1,curr + 1,next + 1).move_to(primitives); - CImg::vector(curr,next,next + 1,curr + 1).move_to(primitives); - } - return vertices>'x'; - } - - //! Generate a 3D torus. - /** - \param[out] primitives The returned list of the 3D object primitives - (template type \e tf should be at least \e unsigned \e int). - \param radius1 The large radius. - \param radius2 The small radius. - \param subdivisions1 The number of angular subdivisions for the large radius. - \param subdivisions2 The number of angular subdivisions for the small radius. - \return The N vertices (xi,yi,zi) of the 3D object as a Nx3 CImg image (0<=i<=N - 1). - \par Example - \code - CImgList faces3d; - const CImg points3d = CImg::torus3d(faces3d,20,4); - CImg().display_object3d("Torus3d",points3d,faces3d); - \endcode - \image html ref_torus3d.jpg - **/ - template - static CImg torus3d(CImgList& primitives, - const float radius1=100, const float radius2=30, - const unsigned int subdivisions1=24, const unsigned int subdivisions2=12) { - primitives.assign(); - if (!subdivisions1 || !subdivisions2) return CImg(); - CImgList vertices; - for (unsigned int v = 0; v::vector(x,y,z).move_to(vertices); - } - } - for (unsigned int vv = 0; vv::vector(svv + nu,svv + uu,snv + uu,snv + nu).move_to(primitives); - } - } - return vertices>'x'; - } - - //! Generate a 3D XY-plane. - /** - \param[out] primitives The returned list of the 3D object primitives - (template type \e tf should be at least \e unsigned \e int). - \param size_x The width of the plane (dimension along the X-axis). - \param size_y The height of the plane (dimensions along the Y-axis). - \param subdivisions_x The number of planar subdivisions along the X-axis. - \param subdivisions_y The number of planar subdivisions along the Y-axis. - \return The N vertices (xi,yi,zi) of the 3D object as a Nx3 CImg image (0<=i<=N - 1). - \par Example - \code - CImgList faces3d; - const CImg points3d = CImg::plane3d(faces3d,100,50); - CImg().display_object3d("Plane3d",points3d,faces3d); - \endcode - \image html ref_plane3d.jpg - **/ - template - static CImg plane3d(CImgList& primitives, - const float size_x=100, const float size_y=100, - const unsigned int subdivisions_x=10, const unsigned int subdivisions_y=10) { - primitives.assign(); - if (!subdivisions_x || !subdivisions_y) return CImg(); - CImgList vertices; - const unsigned int w = subdivisions_x + 1, h = subdivisions_y + 1; - const float fx = (float)size_x/w, fy = (float)size_y/h; - for (unsigned int y = 0; y::vector(fx*x,fy*y,0).move_to(vertices); - for (unsigned int y = 0; y::vector(off1,off4,off3,off2).move_to(primitives); - } - return vertices>'x'; - } - - //! Generate a 3D sphere. - /** - \param[out] primitives The returned list of the 3D object primitives - (template type \e tf should be at least \e unsigned \e int). - \param radius The radius of the sphere (dimension along the X-axis). - \param subdivisions The number of recursive subdivisions from an initial icosahedron. - \return The N vertices (xi,yi,zi) of the 3D object as a Nx3 CImg image (0<=i<=N - 1). - \par Example - \code - CImgList faces3d; - const CImg points3d = CImg::sphere3d(faces3d,100,4); - CImg().display_object3d("Sphere3d",points3d,faces3d); - \endcode - \image html ref_sphere3d.jpg - **/ - template - static CImg sphere3d(CImgList& primitives, - const float radius=50, const unsigned int subdivisions=3) { - - // Create initial icosahedron - primitives.assign(); - const double tmp = (1 + std::sqrt(5.f))/2, a = 1./std::sqrt(1 + tmp*tmp), b = tmp*a; - CImgList vertices(12,1,3,1,1, b,a,0., -b,a,0., -b,-a,0., b,-a,0., a,0.,b, a,0.,-b, - -a,0.,-b, -a,0.,b, 0.,b,a, 0.,-b,a, 0.,-b,-a, 0.,b,-a); - primitives.assign(20,1,3,1,1, 4,8,7, 4,7,9, 5,6,11, 5,10,6, 0,4,3, 0,3,5, 2,7,1, 2,1,6, - 8,0,11, 8,11,1, 9,10,3, 9,2,10, 8,4,0, 11,0,5, 4,9,3, - 5,3,10, 7,8,1, 6,1,11, 7,2,9, 6,10,2); - // edge - length/2 - float he = (float)a; - - // Recurse subdivisions - for (unsigned int i = 0; i::vector(nx0,ny0,nz0).move_to(vertices); i0 = vertices.width() - 1; } - if (i1<0) { CImg::vector(nx1,ny1,nz1).move_to(vertices); i1 = vertices.width() - 1; } - if (i2<0) { CImg::vector(nx2,ny2,nz2).move_to(vertices); i2 = vertices.width() - 1; } - primitives.remove(0); - CImg::vector(p0,i0,i1).move_to(primitives); - CImg::vector((tf)i0,(tf)p1,(tf)i2).move_to(primitives); - CImg::vector((tf)i1,(tf)i2,(tf)p2).move_to(primitives); - CImg::vector((tf)i1,(tf)i0,(tf)i2).move_to(primitives); - } - } - return (vertices>'x')*=radius; - } - - //! Generate a 3D ellipsoid. - /** - \param[out] primitives The returned list of the 3D object primitives - (template type \e tf should be at least \e unsigned \e int). - \param tensor The tensor which gives the shape and size of the ellipsoid. - \param subdivisions The number of recursive subdivisions from an initial stretched icosahedron. - \return The N vertices (xi,yi,zi) of the 3D object as a Nx3 CImg image (0<=i<=N - 1). - \par Example - \code - CImgList faces3d; - const CImg tensor = CImg::diagonal(10,7,3), - points3d = CImg::ellipsoid3d(faces3d,tensor,4); - CImg().display_object3d("Ellipsoid3d",points3d,faces3d); - \endcode - \image html ref_ellipsoid3d.jpg - **/ - template - static CImg ellipsoid3d(CImgList& primitives, - const CImg& tensor, const unsigned int subdivisions=3) { - primitives.assign(); - if (!subdivisions) return CImg(); - CImg S, V; - tensor.symmetric_eigen(S,V); - const float orient = - (V(0,1)*V(1,2) - V(0,2)*V(1,1))*V(2,0) + - (V(0,2)*V(1,0) - V(0,0)*V(1,2))*V(2,1) + - (V(0,0)*V(1,1) - V(0,1)*V(1,0))*V(2,2); - if (orient<0) { V(2,0) = -V(2,0); V(2,1) = -V(2,1); V(2,2) = -V(2,2); } - const float l0 = S[0], l1 = S[1], l2 = S[2]; - CImg vertices = sphere3d(primitives,1.,subdivisions); - vertices.get_shared_row(0)*=l0; - vertices.get_shared_row(1)*=l1; - vertices.get_shared_row(2)*=l2; - return V*vertices; - } - - //! Convert 3D object into a CImg3d representation. - /** - \param primitives Primitives data of the 3D object. - \param colors Colors data of the 3D object. - \param opacities Opacities data of the 3D object. - \param full_check Tells if full checking of the 3D object must be performed. - **/ - template - CImg& object3dtoCImg3d(const CImgList& primitives, - const CImgList& colors, - const to& opacities, - const bool full_check=true) { - return get_object3dtoCImg3d(primitives,colors,opacities,full_check).move_to(*this); - } - - //! Convert 3D object into a CImg3d representation \overloading. - template - CImg& object3dtoCImg3d(const CImgList& primitives, - const CImgList& colors, - const bool full_check=true) { - return get_object3dtoCImg3d(primitives,colors,full_check).move_to(*this); - } - - //! Convert 3D object into a CImg3d representation \overloading. - template - CImg& object3dtoCImg3d(const CImgList& primitives, - const bool full_check=true) { - return get_object3dtoCImg3d(primitives,full_check).move_to(*this); - } - - //! Convert 3D object into a CImg3d representation \overloading. - CImg& object3dtoCImg3d(const bool full_check=true) { - return get_object3dtoCImg3d(full_check).move_to(*this); - } - - //! Convert 3D object into a CImg3d representation \newinstance. - template - CImg get_object3dtoCImg3d(const CImgList& primitives, - const CImgList& colors, - const to& opacities, - const bool full_check=true) const { - CImg error_message(1024); - if (!is_object3d(primitives,colors,opacities,full_check,error_message)) - throw CImgInstanceException(_cimg_instance - "object3dtoCImg3d(): Invalid specified 3D object (%u,%u) (%s).", - cimg_instance,_width,primitives._width,error_message.data()); - CImg res(1,_size_object3dtoCImg3d(primitives,colors,opacities)); - float *ptrd = res._data; - - // Put magick number. - *(ptrd++) = 'C' + 0.5f; *(ptrd++) = 'I' + 0.5f; *(ptrd++) = 'm' + 0.5f; - *(ptrd++) = 'g' + 0.5f; *(ptrd++) = '3' + 0.5f; *(ptrd++) = 'd' + 0.5f; - - // Put number of vertices and primitives. - *(ptrd++) = cimg::uint2float(_width); - *(ptrd++) = cimg::uint2float(primitives._width); - - // Put vertex data. - if (is_empty() || !primitives) return res; - const T *ptrx = data(0,0), *ptry = data(0,1), *ptrz = data(0,2); - cimg_forX(*this,p) { - *(ptrd++) = (float)*(ptrx++); - *(ptrd++) = (float)*(ptry++); - *(ptrd++) = (float)*(ptrz++); - } - - // Put primitive data. - cimglist_for(primitives,p) { - *(ptrd++) = (float)primitives[p].size(); - const tp *ptrp = primitives[p]._data; - cimg_foroff(primitives[p],i) *(ptrd++) = cimg::uint2float((unsigned int)*(ptrp++)); - } - - // Put color/texture data. - const unsigned int csiz = std::min(colors._width,primitives._width); - for (int c = 0; c<(int)csiz; ++c) { - const CImg& color = colors[c]; - const tc *ptrc = color._data; - if (color.size()==3) { *(ptrd++) = (float)*(ptrc++); *(ptrd++) = (float)*(ptrc++); *(ptrd++) = (float)*ptrc; } - else { - *(ptrd++) = -128.f; - int shared_ind = -1; - if (color.is_shared()) for (int i = 0; i - float* _object3dtoCImg3d(const CImgList& opacities, float *ptrd) const { - cimglist_for(opacities,o) { - const CImg& opacity = opacities[o]; - const to *ptro = opacity._data; - if (opacity.size()==1) *(ptrd++) = (float)*ptro; - else { - *(ptrd++) = -128.f; - int shared_ind = -1; - if (opacity.is_shared()) for (int i = 0; i - float* _object3dtoCImg3d(const CImg& opacities, float *ptrd) const { - const to *ptro = opacities._data; - cimg_foroff(opacities,o) *(ptrd++) = (float)*(ptro++); - return ptrd; - } - - template - unsigned int _size_object3dtoCImg3d(const CImgList& primitives, - const CImgList& colors, - const CImgList& opacities) const { - unsigned int siz = 8U + 3*_width; - cimglist_for(primitives,p) siz+=primitives[p].size() + 1; - for (int c = std::min(primitives.width(),colors.width()) - 1; c>=0; --c) { - if (colors[c].is_shared()) siz+=4; - else { const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4 + csiz:3; } - } - if (colors._width - unsigned int _size_object3dtoCImg3d(const CImgList& primitives, - const CImgList& colors, - const CImg& opacities) const { - unsigned int siz = 8U + 3*_width; - cimglist_for(primitives,p) siz+=primitives[p].size() + 1; - for (int c = std::min(primitives.width(),colors.width()) - 1; c>=0; --c) { - const unsigned int csiz = colors[c].size(); siz+=(csiz!=3)?4 + csiz:3; - } - if (colors._width - CImg get_object3dtoCImg3d(const CImgList& primitives, - const CImgList& colors, - const bool full_check=true) const { - CImgList opacities; - return get_object3dtoCImg3d(primitives,colors,opacities,full_check); - } - - //! Convert 3D object into a CImg3d representation \overloading. - template - CImg get_object3dtoCImg3d(const CImgList& primitives, - const bool full_check=true) const { - CImgList colors, opacities; - return get_object3dtoCImg3d(primitives,colors,opacities,full_check); - } - - //! Convert 3D object into a CImg3d representation \overloading. - CImg get_object3dtoCImg3d(const bool full_check=true) const { - CImgList opacities, colors; - CImgList primitives(width(),1,1,1,1); - cimglist_for(primitives,p) primitives(p,0) = p; - return get_object3dtoCImg3d(primitives,colors,opacities,full_check); - } - - //! Convert CImg3d representation into a 3D object. - /** - \param[out] primitives Primitives data of the 3D object. - \param[out] colors Colors data of the 3D object. - \param[out] opacities Opacities data of the 3D object. - \param full_check Tells if full checking of the 3D object must be performed. - **/ - template - CImg& CImg3dtoobject3d(CImgList& primitives, - CImgList& colors, - CImgList& opacities, - const bool full_check=true) { - return get_CImg3dtoobject3d(primitives,colors,opacities,full_check).move_to(*this); - } - - //! Convert CImg3d representation into a 3D object \newinstance. - template - CImg get_CImg3dtoobject3d(CImgList& primitives, - CImgList& colors, - CImgList& opacities, - const bool full_check=true) const { - CImg error_message(1024); - if (!is_CImg3d(full_check,error_message)) - throw CImgInstanceException(_cimg_instance - "CImg3dtoobject3d(): image instance is not a CImg3d (%s).", - cimg_instance,error_message.data()); - const T *ptrs = _data + 6; - const unsigned int - nb_points = cimg::float2uint((float)*(ptrs++)), - nb_primitives = cimg::float2uint((float)*(ptrs++)); - const CImg points = CImg(ptrs,3,nb_points,1,1,true).get_transpose(); - ptrs+=3*nb_points; - primitives.assign(nb_primitives); - cimglist_for(primitives,p) { - const unsigned int nb_inds = (unsigned int)*(ptrs++); - primitives[p].assign(1,nb_inds); - tp *ptrp = primitives[p]._data; - for (unsigned int i = 0; i::max(),(T)cimg::type::max()); \ - const float _sc_nopacity = cimg::abs((float)opacity), _sc_copacity = 1 - std::max((float)opacity,0.f); \ - const ulongT _sc_whd = (ulongT)_width*_height*_depth; \ - cimg::unused(_sc_maxval); - -#define cimg_draw_scanline(x0,x1,y,color,opacity,brightness) \ - _draw_scanline(x0,x1,y,color,opacity,brightness,_sc_nopacity,_sc_copacity,_sc_whd,_sc_maxval) - - // [internal] The following _draw_scanline() routines are *non user-friendly functions*, - // used only for internal purpose. - // Pre-requisites: x0<=x1, y-coordinate is valid, col is valid. - template - CImg& _draw_scanline(const int x0, const int x1, const int y, - const tc *const color, const float opacity, - const float brightness, - const float nopacity, const float copacity, const ulongT whd, const T _sc_maxval) { - const int nx0 = x0>0?x0:0, nx1 = x1=0) { - const tc *col = color; - const ulongT off = whd - dx - 1; - T *ptrd = data(nx0,y); - if (opacity>=1) { // ** Opaque drawing ** - if (brightness==1) { // Brightness==1 - if (sizeof(T)!=1) cimg_forC(*this,c) { - const T val = (T)*(col++); - for (int x = dx; x>=0; --x) *(ptrd++) = val; - ptrd+=off; - } else cimg_forC(*this,c) { - const T val = (T)*(col++); - std::memset(ptrd,(int)val,dx + 1); - ptrd+=whd; - } - } else if (brightness<1) { // Brightness<1 - if (sizeof(T)!=1) cimg_forC(*this,c) { - const T val = (T)(*(col++)*brightness); - for (int x = dx; x>=0; --x) *(ptrd++) = val; - ptrd+=off; - } else cimg_forC(*this,c) { - const T val = (T)(*(col++)*brightness); - std::memset(ptrd,(int)val,dx + 1); - ptrd+=whd; - } - } else { // Brightness>1 - if (sizeof(T)!=1) cimg_forC(*this,c) { - const T val = (T)((2-brightness)**(col++) + (brightness - 1)*_sc_maxval); - for (int x = dx; x>=0; --x) *(ptrd++) = val; - ptrd+=off; - } else cimg_forC(*this,c) { - const T val = (T)((2-brightness)**(col++) + (brightness - 1)*_sc_maxval); - std::memset(ptrd,(int)val,dx + 1); - ptrd+=whd; - } - } - } else { // ** Transparent drawing ** - if (brightness==1) { // Brightness==1 - cimg_forC(*this,c) { - const Tfloat val = *(col++)*nopacity; - for (int x = dx; x>=0; --x) { *ptrd = (T)(val + *ptrd*copacity); ++ptrd; } - ptrd+=off; - } - } else if (brightness<=1) { // Brightness<1 - cimg_forC(*this,c) { - const Tfloat val = *(col++)*brightness*nopacity; - for (int x = dx; x>=0; --x) { *ptrd = (T)(val + *ptrd*copacity); ++ptrd; } - ptrd+=off; - } - } else { // Brightness>1 - cimg_forC(*this,c) { - const Tfloat val = ((2-brightness)**(col++) + (brightness - 1)*_sc_maxval)*nopacity; - for (int x = dx; x>=0; --x) { *ptrd = (T)(val + *ptrd*copacity); ++ptrd; } - ptrd+=off; - } - } - } - } - return *this; - } - - //! Draw a 3D point. - /** - \param x0 X-coordinate of the point. - \param y0 Y-coordinate of the point. - \param z0 Z-coordinate of the point. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - \note - - To set pixel values without clipping needs, you should use the faster CImg::operator()() function. - \par Example: - \code - CImg img(100,100,1,3,0); - const unsigned char color[] = { 255,128,64 }; - img.draw_point(50,50,color); - \endcode - **/ - template - CImg& draw_point(const int x0, const int y0, const int z0, - const tc *const color, const float opacity=1) { - if (is_empty()) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_point(): Specified color is (null).", - cimg_instance); - if (x0>=0 && y0>=0 && z0>=0 && x0=1) cimg_forC(*this,c) { *ptrd = (T)*(col++); ptrd+=whd; } - else cimg_forC(*this,c) { *ptrd = (T)(*(col++)*nopacity + *ptrd*copacity); ptrd+=whd; } - } - return *this; - } - - //! Draw a 2D point \simplification. - template - CImg& draw_point(const int x0, const int y0, - const tc *const color, const float opacity=1) { - return draw_point(x0,y0,0,color,opacity); - } - - // Draw a points cloud. - /** - \param points Image of vertices coordinates. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - **/ - template - CImg& draw_point(const CImg& points, - const tc *const color, const float opacity=1) { - if (is_empty() || !points) return *this; - switch (points._height) { - case 0 : case 1 : - throw CImgArgumentException(_cimg_instance - "draw_point(): Invalid specified point set (%u,%u,%u,%u,%p).", - cimg_instance, - points._width,points._height,points._depth,points._spectrum,points._data); - case 2 : { - cimg_forX(points,i) draw_point((int)points(i,0),(int)points(i,1),color,opacity); - } break; - default : { - cimg_forX(points,i) draw_point((int)points(i,0),(int)points(i,1),(int)points(i,2),color,opacity); - } - } - return *this; - } - - //! Draw a 2D line. - /** - \param x0 X-coordinate of the starting line point. - \param y0 Y-coordinate of the starting line point. - \param x1 X-coordinate of the ending line point. - \param y1 Y-coordinate of the ending line point. - \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. - \param opacity Drawing opacity. - \param pattern An integer whose bits describe the line pattern. - \param init_hatch Tells if a reinitialization of the hash state must be done. - \note - - Line routine uses Bresenham's algorithm. - - Set \p init_hatch = false to draw consecutive hatched segments without breaking the line pattern. - \par Example: - \code - CImg img(100,100,1,3,0); - const unsigned char color[] = { 255,128,64 }; - img.draw_line(40,40,80,70,color); - \endcode - **/ - template - CImg& draw_line(int x0, int y0, - int x1, int y1, - const tc *const color, const float opacity=1, - const unsigned int pattern=~0U, const bool init_hatch=true) { - if (is_empty() || !opacity || !pattern || - std::min(y0,y1)>=height() || std::max(y0,y1)<0 || - std::min(x0,x1)>=width() || std::max(x0,x1)<0) return *this; - - int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dy01 = y1 - y0; - - const bool is_horizontal = cimg::abs(dx01)>cimg::abs(dy01); - if (is_horizontal) cimg::swap(x0,y0,x1,y1,w1,h1,dx01,dy01); - if (pattern==~0U && y0>y1) { - cimg::swap(x0,x1,y0,y1); - dx01*=-1; dy01*=-1; - } - - static unsigned int hatch = ~0U - (~0U>>1); - if (init_hatch) hatch = ~0U - (~0U>>1); - cimg_init_scanline(opacity); - const int - step = y0<=y1?1:-1,hdy01 = dy01*cimg::sign(dx01)/2, - cy0 = cimg::cut(y0,0,h1), cy1 = cimg::cut(y1,0,h1) + step; - dy01+=dy01?0:1; - - for (int y = cy0; y!=cy1; y+=step) { - const int - yy0 = y - y0, - x = x0 + (dx01*yy0 + hdy01)/dy01; - if (x>=0 && x<=w1 && pattern&hatch) { - T *const ptrd = is_horizontal?data(y,x):data(x,y); - cimg_forC(*this,c) { - const T val = color[c]; - ptrd[c*_sc_whd] = opacity>=1?val:(T)(val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - } - if (!(hatch>>=1)) hatch = ~0U - (~0U>>1); - } - return *this; - } - - //! Draw a 2D line, with z-buffering. - /** - \param zbuffer Zbuffer image. - \param x0 X-coordinate of the starting point. - \param y0 Y-coordinate of the starting point. - \param z0 Z-coordinate of the starting point - \param x1 X-coordinate of the ending point. - \param y1 Y-coordinate of the ending point. - \param z1 Z-coordinate of the ending point. - \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. - \param opacity Drawing opacity. - \param pattern An integer whose bits describe the line pattern. - \param init_hatch Tells if a reinitialization of the hash state must be done. - **/ - template - CImg& draw_line(CImg& zbuffer, - int x0, int y0, const float z0, - int x1, int y1, const float z1, - const tc *const color, const float opacity=1, - const unsigned int pattern=~0U, const bool init_hatch=true) { - if (is_empty() || z0<=0 || z1<=0 || !opacity || !pattern) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_line(): Specified color is (null).", - cimg_instance); - if (!is_sameXY(zbuffer)) - throw CImgArgumentException(_cimg_instance - "draw_line(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " - "different dimensions.", - cimg_instance, - zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); - - if (std::min(y0,y1)>=height() || std::max(y0,y1)<0 || std::min(x0,x1)>=width() || std::max(x0,x1)<0) return *this; - - float iz0 = 1/z0, iz1 = 1/z1; - int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dy01 = y1 - y0; - float diz01 = iz1 - iz0; - - const bool is_horizontal = cimg::abs(dx01)>cimg::abs(dy01); - if (is_horizontal) cimg::swap(x0,y0,x1,y1,w1,h1,dx01,dy01); - if (pattern==~0U && y0>y1) { - cimg::swap(x0,x1,y0,y1,iz0,iz1); - dx01*=-1; dy01*=-1; diz01*=-1; - } - - static unsigned int hatch = ~0U - (~0U>>1); - if (init_hatch) hatch = ~0U - (~0U>>1); - cimg_init_scanline(opacity); - - const int - step = y0<=y1?1:-1, hdy01 = dy01*cimg::sign(dx01)/2, - cy0 = cimg::cut(y0,0,h1), cy1 = cimg::cut(y1,0,h1) + step; - dy01+=dy01?0:1; - - for (int y = cy0; y!=cy1; y+=step) { - const int - yy0 = y - y0, - x = x0 + (dx01*yy0 + hdy01)/dy01; - const float iz = iz0 + diz01*yy0/dy01; - tz *const ptrz = is_horizontal?zbuffer.data(y,x):zbuffer.data(x,y); - - if (x>=0 && x<=w1 && pattern&hatch && iz>=*ptrz) { - *ptrz = (tz)iz; - T *const ptrd = is_horizontal?data(y,x):data(x,y); - cimg_forC(*this,c) { - const T val = color[c]; - ptrd[c*_sc_whd] = opacity>=1?val:(T)(val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - } - if (!(hatch>>=1)) hatch = ~0U - (~0U>>1); - } - return *this; - } - - //! Draw a textured 2D line. - /** - \param x0 X-coordinate of the starting line point. - \param y0 Y-coordinate of the starting line point. - \param x1 X-coordinate of the ending line point. - \param y1 Y-coordinate of the ending line point. - \param texture Texture image defining the pixel colors. - \param tx0 X-coordinate of the starting texture point. - \param ty0 Y-coordinate of the starting texture point. - \param tx1 X-coordinate of the ending texture point. - \param ty1 Y-coordinate of the ending texture point. - \param opacity Drawing opacity. - \param pattern An integer whose bits describe the line pattern. - \param init_hatch Tells if the hash variable must be reinitialized. - \note - - Line routine uses the well known Bresenham's algorithm. - \par Example: - \code - CImg img(100,100,1,3,0), texture("texture256x256.ppm"); - const unsigned char color[] = { 255,128,64 }; - img.draw_line(40,40,80,70,texture,0,0,255,255); - \endcode - **/ - template - CImg& draw_line(int x0, int y0, - int x1, int y1, - const CImg& texture, - int tx0, int ty0, - int tx1, int ty1, - const float opacity=1, - const unsigned int pattern=~0U, const bool init_hatch=true) { - - if (is_empty() || !opacity || !pattern) return *this; - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_line(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (is_overlapped(texture)) return draw_line(x0,y0,x1,y1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch); - - if (std::min(y0,y1)>=height() || std::max(y0,y1)<0 || std::min(x0,x1)>=width() || std::max(x0,x1)<0) return *this; - - int w1 = width() - 1, h1 = height() - 1; - longT - dx01 = (longT)x1 - x0, dy01 = (longT)y1 - y0, - dtx01 = (longT)tx1 - tx0, dty01 = (longT)ty1 - ty0; - - const bool is_horizontal = cimg::abs(dx01)>cimg::abs(dy01); - if (is_horizontal) cimg::swap(x0,y0,x1,y1,w1,h1,dx01,dy01); - if (pattern==~0U && y0>y1) { - cimg::swap(x0,x1,y0,y1,tx0,tx1,ty0,ty1); - dx01*=-1; dy01*=-1; dtx01*=-1; dty01*=-1; - } - - const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth; - static unsigned int hatch = ~0U - (~0U>>1); - if (init_hatch) hatch = ~0U - (~0U>>1); - cimg_init_scanline(opacity); - - const int step = y0<=y1?1:-1, cy0 = cimg::cut(y0,0,h1), cy1 = cimg::cut(y1,0,h1) + step; - const longT - hdy01 = dy01*cimg::sign(dx01)/2, - hdy01tx = dy01*cimg::sign(dtx01)/2, - hdy01ty = dy01*cimg::sign(dty01)/2; - - dy01+=dy01?0:1; - - for (int y = cy0; y!=cy1; y+=step) { - const longT - yy0 = (longT)y - y0, - x = x0 + (dx01*yy0 + hdy01)/dy01, - tx = tx0 + (dtx01*yy0 + hdy01tx)/dy01, - ty = ty0 + (dty01*yy0 + hdy01ty)/dy01; - if (x>=0 && x<=w1 && pattern&hatch) { - T *const ptrd = is_horizontal?data(y,x):data(x,y); - const tc *const color = &texture._atXY(tx,ty); - cimg_forC(*this,c) { - const T val = color[c*twhd]; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - } - if (!(hatch>>=1)) hatch = ~0U - (~0U>>1); - } - return *this; - } - - //! Draw a textured 2D line, with perspective correction. - /** - \param x0 X-coordinate of the starting point. - \param y0 Y-coordinate of the starting point. - \param z0 Z-coordinate of the starting point - \param x1 X-coordinate of the ending point. - \param y1 Y-coordinate of the ending point. - \param z1 Z-coordinate of the ending point. - \param texture Texture image defining the pixel colors. - \param tx0 X-coordinate of the starting texture point. - \param ty0 Y-coordinate of the starting texture point. - \param tx1 X-coordinate of the ending texture point. - \param ty1 Y-coordinate of the ending texture point. - \param opacity Drawing opacity. - \param pattern An integer whose bits describe the line pattern. - \param init_hatch Tells if the hash variable must be reinitialized. - **/ - template - CImg& draw_line(int x0, int y0, const float z0, - int x1, int y1, const float z1, - const CImg& texture, - const int tx0, const int ty0, - const int tx1, const int ty1, - const float opacity=1, - const unsigned int pattern=~0U, const bool init_hatch=true) { - if (is_empty() || z0<=0 || z1<=0 || !opacity || !pattern) return *this; - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_line(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (is_overlapped(texture)) - return draw_line(x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch); - - if (std::min(y0,y1)>=height() || std::max(y0,y1)<0 || std::min(x0,x1)>=width() || std::max(x0,x1)<0) return *this; - - float iz0 = 1/z0, iz1 = 1/z1; - int w1 = width() - 1, h1 = height() - 1; - longT dx01 = (longT)x1 - x0, dy01 = (longT)y1 - y0; - float - diz01 = iz1 - iz0, - txz0 = tx0*iz0, txz1 = tx1*iz1, - tyz0 = ty0*iz0, tyz1 = ty1*iz1, - dtxz01 = txz1 - txz0, dtyz01 = tyz1 - tyz0; - - const bool is_horizontal = cimg::abs(dx01)>cimg::abs(dy01); - if (is_horizontal) cimg::swap(x0,y0,x1,y1,w1,h1,dx01,dy01); - if (pattern==~0U && y0>y1) { - cimg::swap(x0,x1,y0,y1,iz0,iz1,txz0,txz1,tyz0,tyz1); - dx01*=-1; dy01*=-1; diz01*=-1; dtxz01*=-1; dtyz01*=-1; - } - - const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth; - static unsigned int hatch = ~0U - (~0U>>1); - if (init_hatch) hatch = ~0U - (~0U>>1); - cimg_init_scanline(opacity); - - const int step = y0<=y1?1:-1, cy0 = cimg::cut(y0,0,h1), cy1 = cimg::cut(y1,0,h1) + step; - const longT hdy01 = dy01*cimg::sign(dx01)/2; - - dy01+=dy01?0:1; - - for (int y = cy0; y!=cy1; y+=step) { - const longT - yy0 = (longT)y - y0, - x = x0 + (dx01*yy0 + hdy01)/dy01; - const float - iz = iz0 + diz01*yy0/dy01, - txz = txz0 + dtxz01*yy0/dy01, - tyz = tyz0 + dtyz01*yy0/dy01; - if (x>=0 && x<=w1 && pattern&hatch) { - const int - tx = (int)cimg::round(txz/iz), - ty = (int)cimg::round(tyz/iz); - T *const ptrd = is_horizontal?data(y,x):data(x,y); - const tc *const color = &texture._atXY(tx,ty); - cimg_forC(*this,c) { - const T val = color[c*twhd]; - ptrd[c*_sc_whd] = opacity>=1?val:(T)(val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - } - if (!(hatch>>=1)) hatch = ~0U - (~0U>>1); - } - return *this; - } - - //! Draw a textured 2D line, with perspective correction and z-buffering. - /** - \param zbuffer Z-buffer image. - \param x0 X-coordinate of the starting point. - \param y0 Y-coordinate of the starting point. - \param z0 Z-coordinate of the starting point - \param x1 X-coordinate of the ending point. - \param y1 Y-coordinate of the ending point. - \param z1 Z-coordinate of the ending point. - \param texture Texture image defining the pixel colors. - \param tx0 X-coordinate of the starting texture point. - \param ty0 Y-coordinate of the starting texture point. - \param tx1 X-coordinate of the ending texture point. - \param ty1 Y-coordinate of the ending texture point. - \param opacity Drawing opacity. - \param pattern An integer whose bits describe the line pattern. - \param init_hatch Tells if the hash variable must be reinitialized. - **/ - template - CImg& draw_line(CImg& zbuffer, - int x0, int y0, const float z0, - int x1, int y1, const float z1, - const CImg& texture, - const int tx0, const int ty0, - const int tx1, const int ty1, - const float opacity=1, - const unsigned int pattern=~0U, const bool init_hatch=true) { - if (is_empty() || z0<=0 || z1<=0 || !opacity || !pattern) return *this; - if (!is_sameXY(zbuffer)) - throw CImgArgumentException(_cimg_instance - "draw_line(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " - "different dimensions.", - cimg_instance, - zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_line(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (is_overlapped(texture)) - return draw_line(zbuffer,x0,y0,z0,x1,y1,z1,+texture,tx0,ty0,tx1,ty1,opacity,pattern,init_hatch); - - if (std::min(y0,y1)>=height() || std::max(y0,y1)<0 || std::min(x0,x1)>=width() || std::max(x0,x1)<0) return *this; - - float iz0 = 1/z0, iz1 = 1/z1; - int w1 = width() - 1, h1 = height() - 1; - longT dx01 = (longT)x1 - x0, dy01 = (longT)y1 - y0; - float - diz01 = iz1 - iz0, - txz0 = tx0*iz0, txz1 = tx1*iz1, - tyz0 = ty0*iz0, tyz1 = ty1*iz1, - dtxz01 = txz1 - txz0, dtyz01 = tyz1 - tyz0; - - const bool is_horizontal = cimg::abs(dx01)>cimg::abs(dy01); - if (is_horizontal) cimg::swap(x0,y0,x1,y1,w1,h1,dx01,dy01); - if (pattern==~0U && y0>y1) { - cimg::swap(x0,x1,y0,y1,iz0,iz1,txz0,txz1,tyz0,tyz1); - dx01*=-1; dy01*=-1; diz01*=-1; dtxz01*=-1; dtyz01*=-1; - } - - const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth; - static unsigned int hatch = ~0U - (~0U>>1); - if (init_hatch) hatch = ~0U - (~0U>>1); - cimg_init_scanline(opacity); - - const int step = y0<=y1?1:-1, cy0 = cimg::cut(y0,0,h1), cy1 = cimg::cut(y1,0,h1) + step; - const longT hdy01 = dy01*cimg::sign(dx01)/2; - - dy01+=dy01?0:1; - - for (int y = cy0; y!=cy1; y+=step) { - const longT - yy0 = (longT)y - y0, - x = x0 + (dx01*yy0 + hdy01)/dy01; - const float - iz = iz0 + diz01*yy0/dy01, - txz = txz0 + dtxz01*yy0/dy01, - tyz = tyz0 + dtyz01*yy0/dy01; - tz *const ptrz = is_horizontal?zbuffer.data(y,x):zbuffer.data(x,y); - - if (x>=0 && x<=w1 && pattern&hatch && iz>=*ptrz) { - *ptrz = (tz)iz; - const int - tx = (int)cimg::round(txz/iz), - ty = (int)cimg::round(tyz/iz); - T *const ptrd = is_horizontal?data(y,x):data(x,y); - const tc *const color = &texture._atXY(tx,ty); - cimg_forC(*this,c) { - const T val = color[c*twhd]; - ptrd[c*_sc_whd] = opacity>=1?val:(T)(val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - } - if (!(hatch>>=1)) hatch = ~0U - (~0U>>1); - } - return *this; - } - - //! Draw a set of consecutive lines. - /** - \param points Coordinates of vertices, stored as a list of vectors. - \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. - \param opacity Drawing opacity. - \param pattern An integer whose bits describe the line pattern. - \param init_hatch If set to true, init hatch motif. - \note - - This function uses several call to the single CImg::draw_line() procedure, - depending on the vectors size in \p points. - **/ - template - CImg& draw_line(const CImg& points, - const tc *const color, const float opacity=1, - const unsigned int pattern=~0U, const bool init_hatch=true) { - if (is_empty() || !points || points._width<2) return *this; - bool ninit_hatch = init_hatch; - switch (points._height) { - case 0 : case 1 : - throw CImgArgumentException(_cimg_instance - "draw_line(): Invalid specified point set (%u,%u,%u,%u,%p).", - cimg_instance, - points._width,points._height,points._depth,points._spectrum,points._data); - - default : { - const int x0 = (int)points(0,0), y0 = (int)points(0,1); - int ox = x0, oy = y0; - for (unsigned int i = 1; i - CImg& draw_arrow(const int x0, const int y0, - const int x1, const int y1, - const tc *const color, const float opacity=1, - const float angle=30, const float length=-10, - const unsigned int pattern=~0U) { - if (is_empty()) return *this; - const float u = (float)(x0 - x1), v = (float)(y0 - y1), sq = u*u + v*v, - deg = (float)(angle*cimg::PI/180), ang = (sq>0)?(float)std::atan2(v,u):0.f, - l = (length>=0)?length:-length*(float)std::sqrt(sq)/100; - if (sq>0) { - const float - cl = (float)std::cos(ang - deg), sl = (float)std::sin(ang - deg), - cr = (float)std::cos(ang + deg), sr = (float)std::sin(ang + deg); - const int - xl = x1 + (int)(l*cl), yl = y1 + (int)(l*sl), - xr = x1 + (int)(l*cr), yr = y1 + (int)(l*sr), - xc = x1 + (int)((l + 1)*(cl + cr))/2, yc = y1 + (int)((l + 1)*(sl + sr))/2; - draw_line(x0,y0,xc,yc,color,opacity,pattern).draw_triangle(x1,y1,xl,yl,xr,yr,color,opacity); - } else draw_point(x0,y0,color,opacity); - return *this; - } - - //! Draw a 2D spline. - /** - \param x0 X-coordinate of the starting curve point - \param y0 Y-coordinate of the starting curve point - \param u0 X-coordinate of the starting velocity - \param v0 Y-coordinate of the starting velocity - \param x1 X-coordinate of the ending curve point - \param y1 Y-coordinate of the ending curve point - \param u1 X-coordinate of the ending velocity - \param v1 Y-coordinate of the ending velocity - \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. - \param precision Curve drawing precision. - \param opacity Drawing opacity. - \param pattern An integer whose bits describe the line pattern. - \param init_hatch If \c true, init hatch motif. - \note - - The curve is a 2D cubic Bezier spline, from the set of specified starting/ending points - and corresponding velocity vectors. - - The spline is drawn as a sequence of connected segments. The \p precision parameter sets the - average number of pixels in each drawn segment. - - A cubic Bezier curve is sometimes defined by a set of 4 points { (\p x0,\p y0), (\p xa,\p ya), - (\p xb,\p yb), (\p x1,\p y1) } where (\p x0,\p y0) is the starting point, (\p x1,\p y1) is the ending point - and (\p xa,\p ya), (\p xb,\p yb) are two - \e control points. - The starting and ending velocities (\p u0,\p v0) and (\p u1,\p v1) can be deduced easily from - the control points as - \p u0 = (\p xa - \p x0), \p v0 = (\p ya - \p y0), \p u1 = (\p x1 - \p xb) and \p v1 = (\p y1 - \p yb). - \par Example: - \code - CImg img(100,100,1,3,0); - const unsigned char color[] = { 255,255,255 }; - img.draw_spline(30,30,0,100,90,40,0,-100,color); - \endcode - **/ - template - CImg& draw_spline(const int x0, const int y0, const float u0, const float v0, - const int x1, const int y1, const float u1, const float v1, - const tc *const color, const float opacity=1, - const float precision=0.25, const unsigned int pattern=~0U, - const bool init_hatch=true) { - if (is_empty()) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_spline(): Specified color is (null).", - cimg_instance); - if (x0==x1 && y0==y1) return draw_point(x0,y0,color,opacity); - bool ninit_hatch = init_hatch; - const float - ax = u0 + u1 + 2*(x0 - x1), - bx = 3*(x1 - x0) - 2*u0 - u1, - ay = v0 + v1 + 2*(y0 - y1), - by = 3*(y1 - y0) - 2*v0 - v1, - _precision = 1/(cimg::hypot((float)x0 - x1,(float)y0 - y1)*(precision>0?precision:1)); - int ox = x0, oy = y0; - for (float t = 0; t<1; t+=_precision) { - const float t2 = t*t, t3 = t2*t; - const int - nx = (int)(ax*t3 + bx*t2 + u0*t + x0), - ny = (int)(ay*t3 + by*t2 + v0*t + y0); - draw_line(ox,oy,nx,ny,color,opacity,pattern,ninit_hatch); - ninit_hatch = false; - ox = nx; oy = ny; - } - return draw_line(ox,oy,x1,y1,color,opacity,pattern,false); - } - - //! Draw a textured 2D spline. - /** - \param x0 X-coordinate of the starting curve point - \param y0 Y-coordinate of the starting curve point - \param u0 X-coordinate of the starting velocity - \param v0 Y-coordinate of the starting velocity - \param x1 X-coordinate of the ending curve point - \param y1 Y-coordinate of the ending curve point - \param u1 X-coordinate of the ending velocity - \param v1 Y-coordinate of the ending velocity - \param texture Texture image defining line pixel colors. - \param tx0 X-coordinate of the starting texture point. - \param ty0 Y-coordinate of the starting texture point. - \param tx1 X-coordinate of the ending texture point. - \param ty1 Y-coordinate of the ending texture point. - \param precision Curve drawing precision. - \param opacity Drawing opacity. - \param pattern An integer whose bits describe the line pattern. - \param init_hatch if \c true, reinit hatch motif. - **/ - template - CImg& draw_spline(const int x0, const int y0, const float u0, const float v0, - const int x1, const int y1, const float u1, const float v1, - const CImg& texture, - const int tx0, const int ty0, const int tx1, const int ty1, - const float opacity=1, - const float precision=4, const unsigned int pattern=~0U, - const bool init_hatch=true) { - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_spline(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (is_empty()) return *this; - if (is_overlapped(texture)) - return draw_spline(x0,y0,u0,v0,x1,y1,u1,v1,+texture,tx0,ty0,tx1,ty1,precision,opacity,pattern,init_hatch); - if (x0==x1 && y0==y1) - return draw_point(x0,y0,texture.get_vector_at(x0<=0?0:x0>=texture.width()?texture.width() - 1:x0, - y0<=0?0:y0>=texture.height()?texture.height() - 1:y0).data(), - opacity); - bool ninit_hatch = init_hatch; - const float - ax = u0 + u1 + 2*(x0 - x1), - bx = 3*(x1 - x0) - 2*u0 - u1, - ay = v0 + v1 + 2*(y0 - y1), - by = 3*(y1 - y0) - 2*v0 - v1, - _precision = 1/(cimg::hypot((float)x0 - x1,(float)y0 - y1)*(precision>0?precision:1)); - int ox = x0, oy = y0, otx = tx0, oty = ty0; - for (float t1 = 0; t1<1; t1+=_precision) { - const float t2 = t1*t1, t3 = t2*t1; - const int - nx = (int)(ax*t3 + bx*t2 + u0*t1 + x0), - ny = (int)(ay*t3 + by*t2 + v0*t1 + y0), - ntx = tx0 + (int)((tx1 - tx0)*t1), - nty = ty0 + (int)((ty1 - ty0)*t1); - draw_line(ox,oy,nx,ny,texture,otx,oty,ntx,nty,opacity,pattern,ninit_hatch); - ninit_hatch = false; - ox = nx; oy = ny; otx = ntx; oty = nty; - } - return draw_line(ox,oy,x1,y1,texture,otx,oty,tx1,ty1,opacity,pattern,false); - } - - //! Draw a set of consecutive splines. - /** - \param points Vertices data. - \param tangents Tangents data. - \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. - \param opacity Drawing opacity. - \param is_closed_set Tells if the drawn spline set is closed. - \param precision Precision of the drawing. - \param pattern An integer whose bits describe the line pattern. - \param init_hatch If \c true, init hatch motif. - **/ - template - CImg& draw_spline(const CImg& points, const CImg& tangents, - const tc *const color, const float opacity=1, - const bool is_closed_set=false, const float precision=4, - const unsigned int pattern=~0U, const bool init_hatch=true) { - if (is_empty() || !points || !tangents || points._width<2 || tangents._width<2) return *this; - bool ninit_hatch = init_hatch; - switch (points._height) { - case 0 : case 1 : - throw CImgArgumentException(_cimg_instance - "draw_spline(): Invalid specified point set (%u,%u,%u,%u,%p).", - cimg_instance, - points._width,points._height,points._depth,points._spectrum,points._data); - - default : { - const int x0 = (int)points(0,0), y0 = (int)points(0,1); - const float u0 = (float)tangents(0,0), v0 = (float)tangents(0,1); - int ox = x0, oy = y0; - float ou = u0, ov = v0; - for (unsigned int i = 1; i - CImg& draw_spline(const CImg& points, - const tc *const color, const float opacity=1, - const bool is_closed_set=false, const float precision=4, - const unsigned int pattern=~0U, const bool init_hatch=true) { - if (is_empty() || !points || points._width<2) return *this; - CImg tangents; - switch (points._height) { - case 0 : case 1 : - throw CImgArgumentException(_cimg_instance - "draw_spline(): Invalid specified point set (%u,%u,%u,%u,%p).", - cimg_instance, - points._width,points._height,points._depth,points._spectrum,points._data); - case 2 : { - tangents.assign(points._width,points._height); - cimg_forX(points,p) { - const unsigned int - p0 = is_closed_set?(p + points.width() - 1)%points.width():(p?p - 1:0), - p1 = is_closed_set?(p + 1)%points.width():(p + 1 - CImg& _draw_triangle(int x0, int y0, - int x1, int y1, - int x2, int y2, - const tc *const color, const float opacity, - const float brightness) { - if (y0>y1) cimg::swap(x0,x1,y0,y1); - if (y0>y2) cimg::swap(x0,x2,y0,y2); - if (y1>y2) cimg::swap(x1,x2,y1,y2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - h1 = height() - 1, - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1); - const longT - dx01 = (longT)x1 - x0, dx02 = (longT)x2 - x0, dx12 = (longT)x2 - x1, - dy01 = std::max((longT)1,(longT)y1 - y0), - dy02 = std::max((longT)1,(longT)y2 - y0), - dy12 = std::max((longT)1,(longT)y2 - y1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2; - const float cbs = cimg::cut(brightness,0,2); - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const longT yy0 = (longT)y - y0, yy1 = (longT)y - y1; - longT - xm = yxM) cimg::swap(xm,xM); - cimg_draw_scanline(xm,xM,y,color,opacity,cbs); - } - return *this; - } - - //! Draw a filled 2D triangle. - /** - \param x0 X-coordinate of the first vertex. - \param y0 Y-coordinate of the first vertex. - \param x1 X-coordinate of the second vertex. - \param y1 Y-coordinate of the second vertex. - \param x2 X-coordinate of the third vertex. - \param y2 Y-coordinate of the third vertex. - \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. - \param opacity Drawing opacity. - **/ - template - CImg& draw_triangle(const int x0, const int y0, - const int x1, const int y1, - const int x2, const int y2, - const tc *const color, const float opacity=1) { - if (is_empty()) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Specified color is (null).", - cimg_instance); - _draw_triangle(x0,y0,x1,y1,x2,y2,color,opacity,1); - return *this; - } - - //! Draw a outlined 2D triangle. - /** - \param x0 X-coordinate of the first vertex. - \param y0 Y-coordinate of the first vertex. - \param x1 X-coordinate of the second vertex. - \param y1 Y-coordinate of the second vertex. - \param x2 X-coordinate of the third vertex. - \param y2 Y-coordinate of the third vertex. - \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. - \param opacity Drawing opacity. - \param pattern An integer whose bits describe the outline pattern. - **/ - template - CImg& draw_triangle(const int x0, const int y0, - const int x1, const int y1, - const int x2, const int y2, - const tc *const color, const float opacity, - const unsigned int pattern) { - if (is_empty()) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Specified color is (null).", - cimg_instance); - draw_line(x0,y0,x1,y1,color,opacity,pattern,true). - draw_line(x1,y1,x2,y2,color,opacity,pattern,false). - draw_line(x2,y2,x0,y0,color,opacity,pattern,false); - return *this; - } - - //! Draw a filled 2D triangle, with z-buffering. - /** - \param zbuffer Z-buffer image. - \param x0 X-coordinate of the first vertex. - \param y0 Y-coordinate of the first vertex. - \param z0 Z-coordinate of the first vertex. - \param x1 X-coordinate of the second vertex. - \param y1 Y-coordinate of the second vertex. - \param z1 Z-coordinate of the second vertex. - \param x2 X-coordinate of the third vertex. - \param y2 Y-coordinate of the third vertex. - \param z2 Z-coordinate of the third vertex. - \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. - \param opacity Drawing opacity. - \param brightness Brightness factor. - **/ - template - CImg& draw_triangle(CImg& zbuffer, - int x0, int y0, const float z0, - int x1, int y1, const float z1, - int x2, int y2, const float z2, - const tc *const color, const float opacity=1, - const float brightness=1) { - if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Specified color is (null).", - cimg_instance); - if (!is_sameXY(zbuffer)) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " - "different dimensions.", - cimg_instance, - zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); - - float iz0 = 1/z0, iz1 = 1/z1, iz2 = 1/z2; - if (y0>y1) cimg::swap(x0,x1,y0,y1,iz0,iz1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,iz0,iz2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,iz1,iz2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int w1 = width() - 1, h1 = height() - 1, cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1); - const longT - dx01 = (longT)x1 - x0, dx02 = (longT)x2 - x0, dx12 = (longT)x2 - x1, - dy01 = std::max((longT)1,(longT)y1 - y0), - dy02 = std::max((longT)1,(longT)y2 - y0), - dy12 = std::max((longT)1,(longT)y2 - y1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2; - const float diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1; - - const float cbs = cimg::cut(brightness,0,2); - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const longT yy0 = (longT)y - y0, yy1 = (longT)y - y1; - longT - xm = yxM) cimg::swap(xm,xM,izm,izM); - if (xM>=0 && xm<=w1) { - const int - cxm = (int)cimg::cut(xm,(longT)0,(longT)w1), - cxM = (int)cimg::cut(xM,(longT)0,(longT)w1); - T *ptrd = data(cxm,y); - tz *ptrz = zbuffer.data(cxm,y); - const longT dxmM = std::max((longT)1,xM - xm); - const float dizmM = izM - izm; - - for (int x = cxm; x<=cxM; ++x) { - const longT xxm = x - xm; - const float iz = izm + dizmM*xxm/dxmM; - if (iz>=*ptrz) { - *ptrz = (tz)iz; - cimg_forC(*this,c) { - const Tfloat val = cbs<=1?color[c]*cbs:(2 - cbs)*color[c] + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - } - ++ptrd; ++ptrz; - } - } - } - return *this; - } - - //! Draw a Gouraud-shaded 2D triangle. - /** - \param x0 X-coordinate of the first vertex in the image instance. - \param y0 Y-coordinate of the first vertex in the image instance. - \param x1 X-coordinate of the second vertex in the image instance. - \param y1 Y-coordinate of the second vertex in the image instance. - \param x2 X-coordinate of the third vertex in the image instance. - \param y2 Y-coordinate of the third vertex in the image instance. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param bs0 Brightness factor of the first vertex (in [0,2]). - \param bs1 brightness factor of the second vertex (in [0,2]). - \param bs2 brightness factor of the third vertex (in [0,2]). - \param opacity Drawing opacity. - **/ - template - CImg& draw_triangle(int x0, int y0, - int x1, int y1, - int x2, int y2, - const tc *const color, - float bs0, - float bs1, - float bs2, - const float opacity=1) { - if (is_empty()) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Specified color is (null).", - cimg_instance); - - if (y0>y1) cimg::swap(x0,x1,y0,y1,bs0,bs1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,bs0,bs2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,bs1,bs2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int w1 = width() - 1, h1 = height() - 1, cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1); - const longT - dx01 = (longT)x1 - x0, dx02 = (longT)x2 - x0, dx12 = (longT)x2 - x1, - dy01 = std::max((longT)1,(longT)y1 - y0), - dy02 = std::max((longT)1,(longT)y2 - y0), - dy12 = std::max((longT)1,(longT)y2 - y1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2; - const float dbs01 = bs1 - bs0, dbs02 = bs2 - bs0, dbs12 = bs2 - bs1; - - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const longT yy0 = (longT)y - y0, yy1 = (longT)y - y1; - longT - xm = yxM) cimg::swap(xm,xM,bsm,bsM); - if (xM>=0 && xm<=w1) { - const int - cxm = (int)cimg::cut(xm,(longT)0,(longT)w1), - cxM = (int)cimg::cut(xM,(longT)0,(longT)w1); - T *ptrd = data(cxm,y); - const longT dxmM = std::max((longT)1,xM - xm); - const float dbsmM = bsM - bsm; - - for (int x = cxm; x<=cxM; ++x) { - const longT xxm = (longT)x - xm; - const float cbs = cimg::cut(bsm + dbsmM*xxm/dxmM,0,2); - cimg_forC(*this,c) { - const Tfloat val = cbs<=1?color[c]*cbs:(2 - cbs)*color[c] + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - ++ptrd; - } - } - } - return *this; - } - - //! Draw a Gouraud-shaded 2D triangle, with z-buffering \overloading. - template - CImg& draw_triangle(CImg& zbuffer, - int x0, int y0, const float z0, - int x1, int y1, const float z1, - int x2, int y2, const float z2, - const tc *const color, - float bs0, - float bs1, - float bs2, - float opacity=1) { - if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Specified color is (null).", - cimg_instance); - if (!is_sameXY(zbuffer)) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " - "different dimensions.", - cimg_instance, - zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); - - float iz0 = 1/z0, iz1 = 1/z1, iz2 = 1/z2; - if (y0>y1) cimg::swap(x0,x1,y0,y1,iz0,iz1,bs0,bs1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,iz0,iz2,bs0,bs2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,iz1,iz2,bs1,bs2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1, - dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1), - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2; - const float - diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1, - dbs01 = bs1 - bs0, dbs02 = bs2 - bs0, dbs12 = bs2 - bs1; - - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const int yy0 = y - y0, yy1 = y - y1; - int - xm = yxM) cimg::swap(xm,xM,izm,izM,bsm,bsM); - if (xM>=0 && xm<=w1) { - const int - cxm = cimg::cut(xm,0,w1), - cxM = cimg::cut(xM,0,w1); - T *ptrd = data(cxm,y); - tz *ptrz = zbuffer.data(cxm,y); - const int dxmM = std::max(1,xM - xm); - const float dizmM = izM - izm, dbsmM = bsM - bsm; - - for (int x = cxm; x<=cxM; ++x) { - const int xxm = x - xm; - const float iz = izm + dizmM*xxm/dxmM; - if (iz>=*ptrz) { - *ptrz = (tz)iz; - const float cbs = cimg::cut(bsm + dbsmM*xxm/dxmM,0,2); - cimg_forC(*this,c) { - const Tfloat val = cbs<=1?color[c]*cbs:(2 - cbs)*color[c] + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - } - ++ptrd; ++ptrz; - } - } - } - return *this; - } - - //! Draw a color-interpolated 2D triangle. - /** - \param x0 X-coordinate of the first vertex in the image instance. - \param y0 Y-coordinate of the first vertex in the image instance. - \param x1 X-coordinate of the second vertex in the image instance. - \param y1 Y-coordinate of the second vertex in the image instance. - \param x2 X-coordinate of the third vertex in the image instance. - \param y2 Y-coordinate of the third vertex in the image instance. - \param color1 Pointer to \c spectrum() consecutive values of type \c T, defining the color of the first vertex. - \param color2 Pointer to \c spectrum() consecutive values of type \c T, defining the color of the second vertex. - \param color3 Pointer to \c spectrum() consecutive values of type \c T, defining the color of the third vertex. - \param opacity Drawing opacity. - **/ - template - CImg& draw_triangle(int x0, int y0, - int x1, int y1, - int x2, int y2, - const tc *color0, - const tc *color1, - const tc *color2, - const float opacity=1) { - typedef typename cimg::superset::type stc; - if (is_empty()) return *this; - if (!color0 || !color1 || !color2) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): One of the specified color is (null).", - cimg_instance); - - if (y0>y1) cimg::swap(x0,x1,y0,y1,color0,color1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,color0,color2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,color1,color2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int w1 = width() - 1, h1 = height() - 1, cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1); - const longT - dx01 = (longT)x1 - x0, dx02 = (longT)x2 - x0, dx12 = (longT)x2 - x1, - dy01 = std::max((longT)1,(longT)y1 - y0), - dy02 = std::max((longT)1,(longT)y2 - y0), - dy12 = std::max((longT)1,(longT)y2 - y1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2; - cimg_init_scanline(opacity); - - cimg_forC(*this,c) { - const stc dcolor01 = color1[c] - color0[c], dcolor02 = color2[c] - color0[c], dcolor12 = color2[c] - color1[c]; - - for (int y = cy0; y<=cy2; ++y) { - const longT yy0 = (longT)y - y0, yy1 = (longT)y - y1; - longT - xm = yxM) cimg::swap(xm,xM,colorm,colorM); - if (xM>=0 && xm<=w1) { - const int - cxm = (int)cimg::cut(xm,(longT)0,(longT)w1), - cxM = (int)cimg::cut(xM,(longT)0,(longT)w1); - T *ptrd = data(cxm,y); - const longT dxmM = std::max((longT)1,xM - xm); - const stc dcolormM = colorM - colorm; - - for (int x = cxm; x<=cxM; ++x) { - const longT xxm = (longT)x - xm; - const stc col = colorm + dcolormM*xxm/dxmM; - ptrd[c*_sc_whd] = (T)(opacity>=1?col:col*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - ++ptrd; - } - } - } - } - return *this; - } - - //! Draw a textured 2D triangle. - /** - \param x0 X-coordinate of the first vertex in the image instance. - \param y0 Y-coordinate of the first vertex in the image instance. - \param x1 X-coordinate of the second vertex in the image instance. - \param y1 Y-coordinate of the second vertex in the image instance. - \param x2 X-coordinate of the third vertex in the image instance. - \param y2 Y-coordinate of the third vertex in the image instance. - \param texture Texture image used to fill the triangle. - \param tx0 X-coordinate of the first vertex in the texture image. - \param ty0 Y-coordinate of the first vertex in the texture image. - \param tx1 X-coordinate of the second vertex in the texture image. - \param ty1 Y-coordinate of the second vertex in the texture image. - \param tx2 X-coordinate of the third vertex in the texture image. - \param ty2 Y-coordinate of the third vertex in the texture image. - \param opacity Drawing opacity. - \param brightness Brightness factor of the drawing (in [0,2]). - **/ - template - CImg& draw_triangle(int x0, int y0, - int x1, int y1, - int x2, int y2, - const CImg& texture, - int tx0, int ty0, - int tx1, int ty1, - int tx2, int ty2, - const float opacity=1, - const float brightness=1) { - if (is_empty()) return *this; - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (is_overlapped(texture)) - return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness); - - if (y0>y1) cimg::swap(x0,x1,y0,y1,tx0,tx1,ty0,ty1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,tx0,tx2,ty0,ty2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,tx1,ty1,tx2,ty2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1, - dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1), - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2, - dtx01 = tx1 - tx0, dtx02 = tx2 - tx0, dtx12 = tx2 - tx1, - dty01 = ty1 - ty0, dty02 = ty2 - ty0, dty12 = ty2 - ty1, - hdy01tx = dy01*cimg::sign(dtx01)/2, hdy02tx = dy02*cimg::sign(dtx02)/2, hdy12tx = dy12*cimg::sign(dtx12)/2, - hdy01ty = dy01*cimg::sign(dty01)/2, hdy02ty = dy02*cimg::sign(dty02)/2, hdy12ty = dy12*cimg::sign(dty12)/2; - const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth; - const float cbs = cimg::cut(brightness,0,2); - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const int yy0 = y - y0, yy1 = y - y1; - int - xm = yxM) cimg::swap(xm,xM,txm,txM,tym,tyM); - if (xM>=0 && xm<=w1) { - const int - cxm = cimg::cut(xm,0,w1), - cxM = cimg::cut(xM,0,w1); - T *ptrd = data(cxm,y); - const int - dxmM = std::max(1,xM - xm), hdxmM = dxmM/2, - dtxmM = txM - txm, dtymM = tyM - tym; - - for (int x = cxm; x<=cxM; ++x) { - const int - xxm = x - xm, - tx = (txm*dxmM + dtxmM*xxm + hdxmM)/dxmM, - ty = (tym*dxmM + dtymM*xxm + hdxmM)/dxmM; - const tc *const color = &texture._atXY(tx,ty); - cimg_forC(*this,c) { - const Tfloat val = cbs<=1?color[c*twhd]*cbs:(2 - cbs)*color[c*twhd] + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - ++ptrd; - } - } - } - return *this; - } - - //! Draw a 2D textured triangle, with perspective correction. - template - CImg& draw_triangle(int x0, int y0, const float z0, - int x1, int y1, const float z1, - int x2, int y2, const float z2, - const CImg& texture, - int tx0, int ty0, - int tx1, int ty1, - int tx2, int ty2, - const float opacity=1, - const float brightness=1) { - if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (is_overlapped(texture)) - return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness); - - float iz0 = 1/z0, iz1 = 1/z1, iz2 = 1/z2; - if (y0>y1) cimg::swap(x0,x1,y0,y1,iz0,iz1,tx0,tx1,ty0,ty1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,iz0,iz2,tx0,tx2,ty0,ty2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,iz1,iz2,tx1,tx2,ty1,ty2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1, - dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1), - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2; - const float - diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1, - txz0 = tx0*iz0, txz1 = tx1*iz1, txz2 = tx2*iz2, - tyz0 = ty0*iz0, tyz1 = ty1*iz1, tyz2 = ty2*iz2, - dtxz01 = txz1 - txz0, dtxz02 = txz2 - txz0, dtxz12 = txz2 - txz1, - dtyz01 = tyz1 - tyz0, dtyz02 = tyz2 - tyz0, dtyz12 = tyz2 - tyz1; - - const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth; - const float cbs = cimg::cut(brightness,0,2); - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const int yy0 = y - y0, yy1 = y - y1; - int - xm = yxM) cimg::swap(xm,xM,txzm,txzM,tyzm,tyzM,izm,izM); - if (xM>=0 && xm<=w1) { - const int - cxm = cimg::cut(xm,0,w1), - cxM = cimg::cut(xM,0,w1); - T *ptrd = data(cxm,y); - const int dxmM = std::max(1,xM - xm); - const float dizmM = izM - izm, dtxzmM = txzM - txzm, dtyzmM = tyzM - tyzm; - - for (int x = cxm; x<=cxM; ++x) { - const int xxm = x - xm; - const float - iz = izm + dizmM*xxm/dxmM, - txz = txzm + dtxzmM*xxm/dxmM, - tyz = tyzm + dtyzmM*xxm/dxmM; - const int - tx = (int)cimg::round(txz/iz), - ty = (int)cimg::round(tyz/iz); - const tc *const color = &texture._atXY(tx,ty); - cimg_forC(*this,c) { - const Tfloat val = cbs<=1?color[c*twhd]*cbs:(2 - cbs)*color[c*twhd] + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - ++ptrd; - } - } - } - return *this; - } - - //! Draw a textured 2D triangle, with perspective correction and z-buffering. - template - CImg& draw_triangle(CImg& zbuffer, - int x0, int y0, const float z0, - int x1, int y1, const float z1, - int x2, int y2, const float z2, - const CImg& texture, - int tx0, int ty0, - int tx1, int ty1, - int tx2, int ty2, - const float opacity=1, - const float brightness=1) { - if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; - if (!is_sameXY(zbuffer)) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " - "different dimensions.", - cimg_instance, - zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); - - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (is_overlapped(texture)) - return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,opacity,brightness); - - float iz0 = 1/z0, iz1 = 1/z1, iz2 = 1/z2; - if (y0>y1) cimg::swap(x0,x1,y0,y1,iz0,iz1,tx0,tx1,ty0,ty1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,iz0,iz2,tx0,tx2,ty0,ty2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,iz1,iz2,tx1,tx2,ty1,ty2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1, - dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1), - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2; - const float - diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1, - txz0 = tx0*iz0, txz1 = tx1*iz1, txz2 = tx2*iz2, - tyz0 = ty0*iz0, tyz1 = ty1*iz1, tyz2 = ty2*iz2, - dtxz01 = txz1 - txz0, dtxz02 = txz2 - txz0, dtxz12 = txz2 - txz1, - dtyz01 = tyz1 - tyz0, dtyz02 = tyz2 - tyz0, dtyz12 = tyz2 - tyz1; - - const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth; - const float cbs = cimg::cut(brightness,0,2); - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const int yy0 = y - y0, yy1 = y - y1; - int - xm = yxM) cimg::swap(xm,xM,txzm,txzM,tyzm,tyzM,izm,izM); - if (xM>=0 && xm<=w1) { - const int - cxm = cimg::cut(xm,0,w1), - cxM = cimg::cut(xM,0,w1); - T *ptrd = data(cxm,y); - tz *ptrz = zbuffer.data(cxm,y); - const int dxmM = std::max(1,xM - xm); - const float dizmM = izM - izm, dtxzmM = txzM - txzm, dtyzmM = tyzM - tyzm; - - for (int x = cxm; x<=cxM; ++x) { - const int xxm = x - xm; - const float iz = izm + dizmM*xxm/dxmM; - if (iz>=*ptrz) { - *ptrz = (tz)iz; - const float - txz = txzm + dtxzmM*xxm/dxmM, - tyz = tyzm + dtyzmM*xxm/dxmM; - const int - tx = (int)cimg::round(txz/iz), - ty = (int)cimg::round(tyz/iz); - const tc *const color = &texture._atXY(tx,ty); - cimg_forC(*this,c) { - const Tfloat val = cbs<=1?color[c*twhd]*cbs:(2 - cbs)*color[c*twhd] + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - } - ++ptrd; ++ptrz; - } - } - } - return *this; - } - - //! Draw a Phong-shaded 2D triangle. - /** - \param x0 X-coordinate of the first vertex in the image instance. - \param y0 Y-coordinate of the first vertex in the image instance. - \param x1 X-coordinate of the second vertex in the image instance. - \param y1 Y-coordinate of the second vertex in the image instance. - \param x2 X-coordinate of the third vertex in the image instance. - \param y2 Y-coordinate of the third vertex in the image instance. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param light Light image. - \param lx0 X-coordinate of the first vertex in the light image. - \param ly0 Y-coordinate of the first vertex in the light image. - \param lx1 X-coordinate of the second vertex in the light image. - \param ly1 Y-coordinate of the second vertex in the light image. - \param lx2 X-coordinate of the third vertex in the light image. - \param ly2 Y-coordinate of the third vertex in the light image. - \param opacity Drawing opacity. - **/ - template - CImg& draw_triangle(int x0, int y0, - int x1, int y1, - int x2, int y2, - const tc *const color, - const CImg& light, - int lx0, int ly0, - int lx1, int ly1, - int lx2, int ly2, - const float opacity=1) { - if (is_empty()) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Specified color is (null).", - cimg_instance); - if (light._depth>1 || light._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).", - cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); - - if (y0>y1) cimg::swap(x0,x1,y0,y1,lx0,lx1,ly0,ly1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,lx0,lx2,ly0,ly2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,lx1,lx2,ly1,ly2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1, - dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1), - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2, - dlx01 = lx1 - lx0, dlx02 = lx2 - lx0, dlx12 = lx2 - lx1, - dly01 = ly1 - ly0, dly02 = ly2 - ly0, dly12 = ly2 - ly1, - hdy01lx = dy01*cimg::sign(dlx01)/2, hdy02lx = dy02*cimg::sign(dlx02)/2, hdy12lx = dy12*cimg::sign(dlx12)/2, - hdy01ly = dy01*cimg::sign(dly01)/2, hdy02ly = dy02*cimg::sign(dly02)/2, hdy12ly = dy12*cimg::sign(dly12)/2; - - const ulongT lwhd = (ulongT)light._width*light._height*light._depth; - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const int yy0 = y - y0, yy1 = y - y1; - int - xm = yxM) cimg::swap(xm,xM,lxm,lxM,lym,lyM); - if (xM>=0 && xm<=w1) { - const int - cxm = cimg::cut(xm,0,w1), - cxM = cimg::cut(xM,0,w1); - T *ptrd = data(cxm,y); - const int - dxmM = std::max(1,xM - xm), hdxmM = dxmM/2, - dlxmM = lxM - lxm, dlymM = lyM - lym; - - for (int x = cxm; x<=cxM; ++x) { - const int - xxm = x - xm, - lx = (lxm*dxmM + dlxmM*xxm + hdxmM)/dxmM, - ly = (lym*dxmM + dlymM*xxm + hdxmM)/dxmM; - const tl *const lig = &light._atXY(lx,ly); - cimg_forC(*this,c) { - const tc col = color[c]; - const float cbs = cimg::cut((float)lig[c*lwhd],0,2); - const Tfloat val = cbs<=1?cbs*col:(2 - cbs)*col + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - ++ptrd; - } - } - } - return *this; - } - - //! Draw a Phong-shaded 2D triangle, with z-buffering. - template - CImg& draw_triangle(CImg& zbuffer, - int x0, int y0, const float z0, - int x1, int y1, const float z1, - int x2, int y2, const float z2, - const tc *const color, - const CImg& light, - int lx0, int ly0, - int lx1, int ly1, - int lx2, int ly2, - const float opacity=1) { - if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Specified color is (null).", - cimg_instance); - if (light._depth>1 || light._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).", - cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); - if (!is_sameXY(zbuffer)) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " - "different dimensions.", - cimg_instance, - zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); - if (is_overlapped(light)) return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color, - +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); - - float iz0 = 1/z0, iz1 = 1/z1, iz2 = 1/z2; - if (y0>y1) cimg::swap(x0,x1,y0,y1,iz0,iz1,lx0,lx1,ly0,ly1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,iz0,iz2,lx0,lx2,ly0,ly2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,iz1,iz2,lx1,lx2,ly1,ly2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1, - dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1), - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2, - dlx01 = lx1 - lx0, dlx02 = lx2 - lx0, dlx12 = lx2 - lx1, - dly01 = ly1 - ly0, dly02 = ly2 - ly0, dly12 = ly2 - ly1, - hdy01lx = dy01*cimg::sign(dlx01)/2, hdy02lx = dy02*cimg::sign(dlx02)/2, hdy12lx = dy12*cimg::sign(dlx12)/2, - hdy01ly = dy01*cimg::sign(dly01)/2, hdy02ly = dy02*cimg::sign(dly02)/2, hdy12ly = dy12*cimg::sign(dly12)/2; - const float diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1; - - const ulongT lwhd = (ulongT)light._width*light._height*light._depth; - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const int yy0 = y - y0, yy1 = y - y1; - int - xm = yxM) cimg::swap(xm,xM,lxm,lxM,lym,lyM,izm,izM); - if (xM>=0 && xm<=w1) { - const int - cxm = cimg::cut(xm,0,w1), - cxM = cimg::cut(xM,0,w1); - T *ptrd = data(cxm,y); - tz *ptrz = zbuffer.data(cxm,y); - const int - dxmM = std::max(1,xM - xm), hdxmM = dxmM/2, - dlxmM = lxM - lxm, dlymM = lyM - lym; - const float dizmM = izM - izm; - - for (int x = cxm; x<=cxM; ++x) { - const int xxm = x - xm; - const float iz = izm + dizmM*xxm/dxmM; - if (iz>=*ptrz) { - *ptrz = (tz)iz; - const int - lx = (lxm*dxmM + dlxmM*xxm + hdxmM)/dxmM, - ly = (lym*dxmM + dlymM*xxm + hdxmM)/dxmM; - const tl *const lig = &light._atXY(lx,ly); - cimg_forC(*this,c) { - const float cbs = cimg::cut((float)lig[c*lwhd],0,2); - const tc col = color[c]; - const Tfloat val = cbs<=1?cbs*col:(2 - cbs)*col + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - } - ++ptrd; ++ptrz; - } - } - } - return *this; - } - - //! Draw a textured Gouraud-shaded 2D triangle. - /** - \param x0 X-coordinate of the first vertex in the image instance. - \param y0 Y-coordinate of the first vertex in the image instance. - \param x1 X-coordinate of the second vertex in the image instance. - \param y1 Y-coordinate of the second vertex in the image instance. - \param x2 X-coordinate of the third vertex in the image instance. - \param y2 Y-coordinate of the third vertex in the image instance. - \param texture Texture image used to fill the triangle. - \param tx0 X-coordinate of the first vertex in the texture image. - \param ty0 Y-coordinate of the first vertex in the texture image. - \param tx1 X-coordinate of the second vertex in the texture image. - \param ty1 Y-coordinate of the second vertex in the texture image. - \param tx2 X-coordinate of the third vertex in the texture image. - \param ty2 Y-coordinate of the third vertex in the texture image. - \param bs0 Brightness factor of the first vertex. - \param bs1 Brightness factor of the second vertex. - \param bs2 Brightness factor of the third vertex. - \param opacity Drawing opacity. - **/ - template - CImg& draw_triangle(int x0, int y0, - int x1, int y1, - int x2, int y2, - const CImg& texture, - int tx0, int ty0, - int tx1, int ty1, - int tx2, int ty2, - float bs0, - float bs1, - float bs2, - const float opacity=1) { - if (is_empty()) return *this; - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (is_overlapped(texture)) - return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2, - bs0,bs1,bs2,opacity); - - if (y0>y1) cimg::swap(x0,x1,y0,y1,tx0,tx1,ty0,ty1,bs0,bs1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,tx0,tx2,ty0,ty2,bs0,bs2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,tx1,tx2,ty1,ty2,bs1,bs2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1, - dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1), - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2, - dtx01 = tx1 - tx0, dtx02 = tx2 - tx0, dtx12 = tx2 - tx1, - dty01 = ty1 - ty0, dty02 = ty2 - ty0, dty12 = ty2 - ty1, - hdy01tx = dy01*cimg::sign(dtx01)/2, hdy02tx = dy02*cimg::sign(dtx02)/2, hdy12tx = dy12*cimg::sign(dtx12)/2, - hdy01ty = dy01*cimg::sign(dty01)/2, hdy02ty = dy02*cimg::sign(dty02)/2, hdy12ty = dy12*cimg::sign(dty12)/2; - const float dbs01 = bs1 - bs0, dbs02 = bs2 - bs0, dbs12 = bs2 - bs1; - - const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth; - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const int yy0 = y - y0, yy1 = y - y1; - int - xm = yxM) cimg::swap(xm,xM,txm,txM,tym,tyM,bsm,bsM); - if (xM>=0 && xm<=w1) { - const int - cxm = cimg::cut(xm,0,w1), - cxM = cimg::cut(xM,0,w1); - T *ptrd = data(cxm,y); - const int - dxmM = std::max(1,xM - xm), hdxmM = dxmM/2, - dtxmM = txM - txm, dtymM = tyM - tym; - const float dbsmM = bsM - bsm; - - for (int x = cxm; x<=cxM; ++x) { - const int - xxm = x - xm, - tx = (txm*dxmM + dtxmM*xxm + hdxmM)/dxmM, - ty = (tym*dxmM + dtymM*xxm + hdxmM)/dxmM; - const float cbs = cimg::cut(bsm + dbsmM*xxm/dxmM,0,2); - const tc *const color = &texture._atXY(tx,ty); - cimg_forC(*this,c) { - const tc col = color[c*twhd]; - const Tfloat val = cbs<=1?cbs*col:(2 - cbs)*col + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - ++ptrd; - } - } - } - return *this; - } - - //! Draw a textured Gouraud-shaded 2D triangle, with perspective correction \overloading. - template - CImg& draw_triangle(int x0, int y0, const float z0, - int x1, int y1, const float z1, - int x2, int y2, const float z2, - const CImg& texture, - int tx0, int ty0, - int tx1, int ty1, - int tx2, int ty2, - float bs0, - float bs1, - float bs2, - const float opacity=1) { - if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (is_overlapped(texture)) return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2, - bs0,bs1,bs2,opacity); - - float iz0 = 1/z0, iz1 = 1/z1, iz2 = 1/z2; - if (y0>y1) cimg::swap(x0,x1,y0,y1,iz0,iz1,tx0,tx1,ty0,ty1,bs0,bs1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,iz0,iz2,tx0,tx2,ty0,ty2,bs0,bs2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,iz1,iz2,tx1,tx2,ty1,ty2,bs1,bs2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1, - dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1), - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2; - const float - diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1, - txz0 = tx0*iz0, txz1 = tx1*iz1, txz2 = tx2*iz2, - tyz0 = ty0*iz0, tyz1 = ty1*iz1, tyz2 = ty2*iz2, - dtxz01 = txz1 - txz0, dtxz02 = txz2 - txz0, dtxz12 = txz2 - txz1, - dtyz01 = tyz1 - tyz0, dtyz02 = tyz2 - tyz0, dtyz12 = tyz2 - tyz1, - dbs01 = bs1 - bs0, dbs02 = bs2 - bs0, dbs12 = bs2 - bs1; - - const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth; - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const int yy0 = y - y0, yy1 = y - y1; - int - xm = yxM) cimg::swap(xm,xM,txzm,txzM,tyzm,tyzM,izm,izM,bsm,bsM); - if (xM>=0 && xm<=w1) { - const int - cxm = cimg::cut(xm,0,w1), - cxM = cimg::cut(xM,0,w1); - T *ptrd = data(cxm,y); - const int dxmM = std::max(1,xM - xm); - const float dizmM = izM - izm, dtxzmM = txzM - txzm, dtyzmM = tyzM - tyzm, dbsmM = bsM - bsm; - - for (int x = cxm; x<=cxM; ++x) { - const int xxm = x - xm; - const float - iz = izm + dizmM*xxm/dxmM, - txz = txzm + dtxzmM*xxm/dxmM, - tyz = tyzm + dtyzmM*xxm/dxmM, - cbs = cimg::cut(bsm + dbsmM*xxm/dxmM,0,2); - const int - tx = (int)cimg::round(txz/iz), - ty = (int)cimg::round(tyz/iz); - const tc *const color = &texture._atXY(tx,ty); - cimg_forC(*this,c) { - const tc col = color[c*twhd]; - const Tfloat val = cbs<=1?cbs*col:(2 - cbs)*col + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - ++ptrd; - } - } - } - return *this; - } - - //! Draw a textured Gouraud-shaded 2D triangle, with perspective correction and z-buffering \overloading. - template - CImg& draw_triangle(CImg& zbuffer, - int x0, int y0, const float z0, - int x1, int y1, const float z1, - int x2, int y2, const float z2, - const CImg& texture, - int tx0, int ty0, - int tx1, int ty1, - int tx2, int ty2, - float bs0, - float bs1, - float bs2, - const float opacity=1) { - if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; - if (!is_sameXY(zbuffer)) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " - "different dimensions.", - cimg_instance, - zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (is_overlapped(texture)) - return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,bs0,bs1,bs2,opacity); - - float iz0 = 1/z0, iz1 = 1/z1, iz2 = 1/z2; - if (y0>y1) cimg::swap(x0,x1,y0,y1,iz0,iz1,tx0,tx1,ty0,ty1,bs0,bs1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,iz0,iz2,tx0,tx2,ty0,ty2,bs0,bs2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,iz1,iz2,tx1,tx2,ty1,ty2,bs1,bs2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1, - dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1), - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2; - const float - diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1, - txz0 = tx0*iz0, txz1 = tx1*iz1, txz2 = tx2*iz2, - tyz0 = ty0*iz0, tyz1 = ty1*iz1, tyz2 = ty2*iz2, - dtxz01 = txz1 - txz0, dtxz02 = txz2 - txz0, dtxz12 = txz2 - txz1, - dtyz01 = tyz1 - tyz0, dtyz02 = tyz2 - tyz0, dtyz12 = tyz2 - tyz1, - dbs01 = bs1 - bs0, dbs02 = bs2 - bs0, dbs12 = bs2 - bs1; - - const ulongT twhd = (ulongT)texture._width*texture._height*texture._depth; - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const int yy0 = y - y0, yy1 = y - y1; - int - xm = yxM) cimg::swap(xm,xM,txzm,txzM,tyzm,tyzM,izm,izM,bsm,bsM); - if (xM>=0 && xm<=w1) { - const int - cxm = cimg::cut(xm,0,w1), - cxM = cimg::cut(xM,0,w1); - T *ptrd = data(cxm,y); - tz *ptrz = zbuffer.data(cxm,y); - const int dxmM = std::max(1,xM - xm); - const float dizmM = izM - izm, dtxzmM = txzM - txzm, dtyzmM = tyzM - tyzm, dbsmM = bsM - bsm; - - for (int x = cxm; x<=cxM; ++x) { - const int xxm = x - xm; - const float iz = izm + dizmM*xxm/dxmM; - if (iz>=*ptrz) { - *ptrz = (tz)iz; - const float - txz = txzm + dtxzmM*xxm/dxmM, - tyz = tyzm + dtyzmM*xxm/dxmM, - cbs = cimg::cut(bsm + dbsmM*xxm/dxmM,0,2); - const int - tx = (int)cimg::round(txz/iz), - ty = (int)cimg::round(tyz/iz); - const tc *const color = &texture._atXY(tx,ty); - cimg_forC(*this,c) { - const tc col = color[c*twhd]; - const Tfloat val = cbs<=1?cbs*col:(2 - cbs)*col + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - } - ++ptrd; ++ptrz; - } - } - } - return *this; - } - - //! Draw a textured Phong-shaded 2D triangle. - /** - \param x0 X-coordinate of the first vertex in the image instance. - \param y0 Y-coordinate of the first vertex in the image instance. - \param x1 X-coordinate of the second vertex in the image instance. - \param y1 Y-coordinate of the second vertex in the image instance. - \param x2 X-coordinate of the third vertex in the image instance. - \param y2 Y-coordinate of the third vertex in the image instance. - \param texture Texture image used to fill the triangle. - \param tx0 X-coordinate of the first vertex in the texture image. - \param ty0 Y-coordinate of the first vertex in the texture image. - \param tx1 X-coordinate of the second vertex in the texture image. - \param ty1 Y-coordinate of the second vertex in the texture image. - \param tx2 X-coordinate of the third vertex in the texture image. - \param ty2 Y-coordinate of the third vertex in the texture image. - \param light Light image. - \param lx0 X-coordinate of the first vertex in the light image. - \param ly0 Y-coordinate of the first vertex in the light image. - \param lx1 X-coordinate of the second vertex in the light image. - \param ly1 Y-coordinate of the second vertex in the light image. - \param lx2 X-coordinate of the third vertex in the light image. - \param ly2 Y-coordinate of the third vertex in the light image. - \param opacity Drawing opacity. - **/ - template - CImg& draw_triangle(int x0, int y0, - int x1, int y1, - int x2, int y2, - const CImg& texture, - int tx0, int ty0, - int tx1, int ty1, - int tx2, int ty2, - const CImg& light, - int lx0, int ly0, - int lx1, int ly1, - int lx2, int ly2, - const float opacity=1) { - if (is_empty()) return *this; - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (light._depth>1 || light._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).", - cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); - if (is_overlapped(texture)) - return draw_triangle(x0,y0,x1,y1,x2,y2,+texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); - if (is_overlapped(light)) - return draw_triangle(x0,y0,x1,y1,x2,y2,texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); - - if (y0>y1) cimg::swap(x0,x1,y0,y1,tx0,tx1,ty0,ty1,lx0,lx1,ly0,ly1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,tx0,tx2,ty0,ty2,lx0,lx2,ly0,ly2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,tx1,tx2,ty1,ty2,lx1,lx2,ly1,ly2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1, - dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1), - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2, - dtx01 = tx1 - tx0, dtx02 = tx2 - tx0, dtx12 = tx2 - tx1, - dty01 = ty1 - ty0, dty02 = ty2 - ty0, dty12 = ty2 - ty1, - hdy01tx = dy01*cimg::sign(dtx01)/2, hdy02tx = dy02*cimg::sign(dtx02)/2, hdy12tx = dy12*cimg::sign(dtx12)/2, - hdy01ty = dy01*cimg::sign(dty01)/2, hdy02ty = dy02*cimg::sign(dty02)/2, hdy12ty = dy12*cimg::sign(dty12)/2, - dlx01 = lx1 - lx0, dlx02 = lx2 - lx0, dlx12 = lx2 - lx1, - dly01 = ly1 - ly0, dly02 = ly2 - ly0, dly12 = ly2 - ly1, - hdy01lx = dy01*cimg::sign(dlx01)/2, hdy02lx = dy02*cimg::sign(dlx02)/2, hdy12lx = dy12*cimg::sign(dlx12)/2, - hdy01ly = dy01*cimg::sign(dly01)/2, hdy02ly = dy02*cimg::sign(dly02)/2, hdy12ly = dy12*cimg::sign(dly12)/2; - - const ulongT - twhd = (ulongT)texture._width*texture._height*texture._depth, - lwhd = (ulongT)light._width*light._height*light._depth; - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const int yy0 = y - y0, yy1 = y - y1; - int - xm = yxM) cimg::swap(xm,xM,txm,txM,tym,tyM,lxm,lxM,lym,lyM); - if (xM>=0 && xm<=w1) { - const int - cxm = cimg::cut(xm,0,w1), - cxM = cimg::cut(xM,0,w1); - T *ptrd = data(cxm,y); - const int - dxmM = std::max(1,xM - xm), hdxmM = dxmM/2, - dtxmM = txM - txm, dtymM = tyM - tym, - dlxmM = lxM - lxm, dlymM = lyM - lym; - - for (int x = cxm; x<=cxM; ++x) { - const int - xxm = x - xm, - tx = (txm*dxmM + dtxmM*xxm + hdxmM)/dxmM, - ty = (tym*dxmM + dtymM*xxm + hdxmM)/dxmM, - lx = (lxm*dxmM + dlxmM*xxm + hdxmM)/dxmM, - ly = (lym*dxmM + dlymM*xxm + hdxmM)/dxmM; - const tc *const color = &texture._atXY(tx,ty); - const tl *const lig = &light._atXY(lx,ly); - cimg_forC(*this,c) { - const tc col = color[c*twhd]; - const float cbs = cimg::cut((float)lig[c*lwhd],0,2); - const Tfloat val = cbs<=1?cbs*col:(2 - cbs)*col + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - ++ptrd; - } - } - } - return *this; - } - - //! Draw a textured Phong-shaded 2D triangle, with perspective correction. - template - CImg& draw_triangle(int x0, int y0, const float z0, - int x1, int y1, const float z1, - int x2, int y2, const float z2, - const CImg& texture, - int tx0, int ty0, - int tx1, int ty1, - int tx2, int ty2, - const CImg& light, - int lx0, int ly0, - int lx1, int ly1, - int lx2, int ly2, - const float opacity=1) { - if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (light._depth>1 || light._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).", - cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); - if (is_overlapped(texture)) - return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,+texture,tx0,ty0,tx1,ty1,tx2,ty2, - light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); - if (is_overlapped(light)) - return draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,texture,tx0,ty0,tx1,ty1,tx2,ty2, - +light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); - - float iz0 = 1/z0, iz1 = 1/z1, iz2 = 1/z2; - if (y0>y1) cimg::swap(x0,x1,y0,y1,iz0,iz1,tx0,tx1,ty0,ty1,lx0,lx1,ly0,ly1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,iz0,iz2,tx0,tx2,ty0,ty2,lx0,lx2,ly0,ly2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,iz1,iz2,tx1,tx2,ty1,ty2,lx1,lx2,ly1,ly2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1, - dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1), - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2; - const float - diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1, - txz0 = tx0*iz0, txz1 = tx1*iz1, txz2 = tx2*iz2, - tyz0 = ty0*iz0, tyz1 = ty1*iz1, tyz2 = ty2*iz2, - dtxz01 = txz1 - txz0, dtxz02 = txz2 - txz0, dtxz12 = txz2 - txz1, - dtyz01 = tyz1 - tyz0, dtyz02 = tyz2 - tyz0, dtyz12 = tyz2 - tyz1, - lxz0 = lx0*iz0, lxz1 = lx1*iz1, lxz2 = lx2*iz2, - lyz0 = ly0*iz0, lyz1 = ly1*iz1, lyz2 = ly2*iz2, - dlxz01 = lxz1 - lxz0, dlxz02 = lxz2 - lxz0, dlxz12 = lxz2 - lxz1, - dlyz01 = lyz1 - lyz0, dlyz02 = lyz2 - lyz0, dlyz12 = lyz2 - lyz1; - - const ulongT - twhd = (ulongT)texture._width*texture._height*texture._depth, - lwhd = (ulongT)light._width*light._height*light._depth; - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const int yy0 = y - y0, yy1 = y - y1; - int - xm = yxM) cimg::swap(xm,xM,izm,izM,txzm,txzM,tyzm,tyzM,lxzm,lxzM,lyzm,lyzM); - if (xM>=0 && xm<=w1) { - const int - cxm = cimg::cut(xm,0,w1), - cxM = cimg::cut(xM,0,w1); - T *ptrd = data(cxm,y); - const int dxmM = std::max(1,xM - xm); - const float - dizmM = izM - izm, - dtxzmM = txzM - txzm, dtyzmM = tyzM - tyzm, - dlxzmM = lxzM - lxzm, dlyzmM = lyzM - lyzm; - - for (int x = cxm; x<=cxM; ++x) { - const int xxm = x - xm; - const float - iz = izm + dizmM*xxm/dxmM, - txz = txzm + dtxzmM*xxm/dxmM, - tyz = tyzm + dtyzmM*xxm/dxmM, - lxz = lxzm + dlxzmM*xxm/dxmM, - lyz = lyzm + dlyzmM*xxm/dxmM; - const int - tx = (int)cimg::round(txz/iz), - ty = (int)cimg::round(tyz/iz), - lx = (int)cimg::round(lxz/iz), - ly = (int)cimg::round(lyz/iz); - const tc *const color = &texture._atXY(tx,ty); - const tl *const lig = &light._atXY(lx,ly); - cimg_forC(*this,c) { - const tc col = color[c*twhd]; - const float cbs = cimg::cut((float)lig[c*lwhd],0,2); - const Tfloat val = cbs<=1?cbs*col:(2 - cbs)*col + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - ++ptrd; - } - } - } - return *this; - } - - //! Draw a textured Phong-shaded 2D triangle, with perspective correction and z-buffering. - template - CImg& draw_triangle(CImg& zbuffer, - int x0, int y0, const float z0, - int x1, int y1, const float z1, - int x2, int y2, const float z2, - const CImg& texture, - int tx0, int ty0, - int tx1, int ty1, - int tx2, int ty2, - const CImg& light, - int lx0, int ly0, - int lx1, int ly1, - int lx2, int ly2, - const float opacity=1) { - if (is_empty() || z0<=0 || z1<=0 || z2<=0) return *this; - if (!is_sameXY(zbuffer)) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Instance and specified Z-buffer (%u,%u,%u,%u,%p) have " - "different dimensions.", - cimg_instance, - zbuffer._width,zbuffer._height,zbuffer._depth,zbuffer._spectrum,zbuffer._data); - if (texture._depth>1 || texture._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified texture (%u,%u,%u,%u,%p).", - cimg_instance, - texture._width,texture._height,texture._depth,texture._spectrum,texture._data); - if (light._depth>1 || light._spectrum<_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_triangle(): Invalid specified light texture (%u,%u,%u,%u,%p).", - cimg_instance,light._width,light._height,light._depth,light._spectrum,light._data); - if (is_overlapped(texture)) - return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2, - +texture,tx0,ty0,tx1,ty1,tx2,ty2,light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); - if (is_overlapped(light)) - return draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2, - texture,tx0,ty0,tx1,ty1,tx2,ty2,+light,lx0,ly0,lx1,ly1,lx2,ly2,opacity); - - float iz0 = 1/z0, iz1 = 1/z1, iz2 = 1/z2; - if (y0>y1) cimg::swap(x0,x1,y0,y1,iz0,iz1,tx0,tx1,ty0,ty1,lx0,lx1,ly0,ly1); - if (y0>y2) cimg::swap(x0,x2,y0,y2,iz0,iz2,tx0,tx2,ty0,ty2,lx0,lx2,ly0,ly2); - if (y1>y2) cimg::swap(x1,x2,y1,y2,iz1,iz2,tx1,tx2,ty1,ty2,lx1,lx2,ly1,ly2); - if (y2<0 || y0>=height() || cimg::min(x0,x1,x2)>=width() || cimg::max(x0,x1,x2)<0 || !opacity) return *this; - - const int - w1 = width() - 1, h1 = height() - 1, - dx01 = x1 - x0, dx02 = x2 - x0, dx12 = x2 - x1, - dy01 = std::max(1,y1 - y0), dy02 = std::max(1,y2 - y0), dy12 = std::max(1,y2 - y1), - cy0 = cimg::cut(y0,0,h1), cy2 = cimg::cut(y2,0,h1), - hdy01 = dy01*cimg::sign(dx01)/2, hdy02 = dy02*cimg::sign(dx02)/2, hdy12 = dy12*cimg::sign(dx12)/2; - const float - diz01 = iz1 - iz0, diz02 = iz2 - iz0, diz12 = iz2 - iz1, - txz0 = tx0*iz0, txz1 = tx1*iz1, txz2 = tx2*iz2, - tyz0 = ty0*iz0, tyz1 = ty1*iz1, tyz2 = ty2*iz2, - dtxz01 = txz1 - txz0, dtxz02 = txz2 - txz0, dtxz12 = txz2 - txz1, - dtyz01 = tyz1 - tyz0, dtyz02 = tyz2 - tyz0, dtyz12 = tyz2 - tyz1, - lxz0 = lx0*iz0, lxz1 = lx1*iz1, lxz2 = lx2*iz2, - lyz0 = ly0*iz0, lyz1 = ly1*iz1, lyz2 = ly2*iz2, - dlxz01 = lxz1 - lxz0, dlxz02 = lxz2 - lxz0, dlxz12 = lxz2 - lxz1, - dlyz01 = lyz1 - lyz0, dlyz02 = lyz2 - lyz0, dlyz12 = lyz2 - lyz1; - - const ulongT - twhd = (ulongT)texture._width*texture._height*texture._depth, - lwhd = (ulongT)light._width*light._height*light._depth; - cimg_init_scanline(opacity); - - for (int y = cy0; y<=cy2; ++y) { - const int yy0 = y - y0, yy1 = y - y1; - int - xm = yxM) cimg::swap(xm,xM,izm,izM,txzm,txzM,tyzm,tyzM,lxzm,lxzM,lyzm,lyzM); - if (xM>=0 && xm<=w1) { - const int - cxm = cimg::cut(xm,0,w1), - cxM = cimg::cut(xM,0,w1); - T *ptrd = data(cxm,y); - tz *ptrz = zbuffer.data(cxm,y); - const int dxmM = std::max(1,xM - xm); - const float - dizmM = izM - izm, - dtxzmM = txzM - txzm, dtyzmM = tyzM - tyzm, - dlxzmM = lxzM - lxzm, dlyzmM = lyzM - lyzm; - - for (int x = cxm; x<=cxM; ++x) { - const int xxm = x - xm; - const float iz = izm + dizmM*xxm/dxmM; - if (iz>=*ptrz) { - *ptrz = (tz)iz; - const float - txz = txzm + dtxzmM*xxm/dxmM, - tyz = tyzm + dtyzmM*xxm/dxmM, - lxz = lxzm + dlxzmM*xxm/dxmM, - lyz = lyzm + dlyzmM*xxm/dxmM; - const int - tx = (int)cimg::round(txz/iz), - ty = (int)cimg::round(tyz/iz), - lx = (int)cimg::round(lxz/iz), - ly = (int)cimg::round(lyz/iz); - const tc *const color = &texture._atXY(tx,ty); - const tl *const lig = &light._atXY(lx,ly); - cimg_forC(*this,c) { - const tc col = color[c*twhd]; - const float cbs = cimg::cut((float)lig[c*lwhd],0,2); - const Tfloat val = cbs<=1?cbs*col:(2 - cbs)*col + (cbs - 1)*_sc_maxval; - ptrd[c*_sc_whd] = (T)(opacity>=1?val:val*_sc_nopacity + ptrd[c*_sc_whd]*_sc_copacity); - } - } - ++ptrd; ++ptrz; - } - } - } - return *this; - } - - //! Draw a filled 4D rectangle. - /** - \param x0 X-coordinate of the upper-left rectangle corner. - \param y0 Y-coordinate of the upper-left rectangle corner. - \param z0 Z-coordinate of the upper-left rectangle corner. - \param c0 C-coordinate of the upper-left rectangle corner. - \param x1 X-coordinate of the lower-right rectangle corner. - \param y1 Y-coordinate of the lower-right rectangle corner. - \param z1 Z-coordinate of the lower-right rectangle corner. - \param c1 C-coordinate of the lower-right rectangle corner. - \param val Scalar value used to fill the rectangle area. - \param opacity Drawing opacity. - **/ - CImg& draw_rectangle(const int x0, const int y0, const int z0, const int c0, - const int x1, const int y1, const int z1, const int c1, - const T val, const float opacity=1) { - if (is_empty()) return *this; - const int - nx0 = x0=width()?width() - 1 - nx1:0) + (nx0<0?nx0:0), - ly = (1 + ny1 - ny0) + (ny1>=height()?height() - 1 - ny1:0) + (ny0<0?ny0:0), - lz = (1 + nz1 - nz0) + (nz1>=depth()?depth() - 1 - nz1:0) + (nz0<0?nz0:0), - lc = (1 + nc1 - nc0) + (nc1>=spectrum()?spectrum() - 1 - nc1:0) + (nc0<0?nc0:0); - const ulongT - offX = (ulongT)_width - lx, - offY = (ulongT)_width*(_height - ly), - offZ = (ulongT)_width*_height*(_depth - lz); - const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.f); - T *ptrd = data(nx0<0?0:nx0,ny0<0?0:ny0,nz0<0?0:nz0,nc0<0?0:nc0); - if (lx>0 && ly>0 && lz>0 && lc>0) - for (int v = 0; v=1) { - if (sizeof(T)!=1) { for (int x = 0; x - CImg& draw_rectangle(const int x0, const int y0, const int z0, - const int x1, const int y1, const int z1, - const tc *const color, const float opacity=1) { - if (is_empty()) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_rectangle(): Specified color is (null).", - cimg_instance); - cimg_forC(*this,c) draw_rectangle(x0,y0,z0,c,x1,y1,z1,c,(T)color[c],opacity); - return *this; - } - - //! Draw a filled 2D rectangle. - /** - \param x0 X-coordinate of the upper-left rectangle corner. - \param y0 Y-coordinate of the upper-left rectangle corner. - \param x1 X-coordinate of the lower-right rectangle corner. - \param y1 Y-coordinate of the lower-right rectangle corner. - \param color Pointer to \c spectrum() consecutive values of type \c T, defining the drawing color. - \param opacity Drawing opacity. - **/ - template - CImg& draw_rectangle(const int x0, const int y0, - const int x1, const int y1, - const tc *const color, const float opacity=1) { - return draw_rectangle(x0,y0,0,x1,y1,_depth - 1,color,opacity); - } - - //! Draw a outlined 2D rectangle \overloading. - template - CImg& draw_rectangle(const int x0, const int y0, - const int x1, const int y1, - const tc *const color, const float opacity, - const unsigned int pattern) { - if (is_empty()) return *this; - if (y0==y1) return draw_line(x0,y0,x1,y0,color,opacity,pattern,true); - if (x0==x1) return draw_line(x0,y0,x0,y1,color,opacity,pattern,true); - const int - nx0 = x0 - CImg& draw_polygon(const CImg& points, - const tc *const color, const float opacity=1) { - if (is_empty() || !points) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_polygon(): Specified color is (null).", - cimg_instance); - if (points.height()!=2) - throw CImgArgumentException(_cimg_instance - "draw_polygon(): Invalid specified point set (%u,%u,%u,%u).", - cimg_instance, - points._width,points._height,points._depth,points._spectrum); - if (points._width==1) return draw_point(cimg::uiround(points(0,0)),cimg::uiround(points(0,1)),color,opacity); - if (points._width==2) return draw_line(cimg::uiround(points(0,0)),cimg::uiround(points(0,1)), - cimg::uiround(points(1,0)),cimg::uiround(points(1,1)),color,opacity); - if (points._width==3) return draw_triangle(cimg::uiround(points(0,0)),cimg::uiround(points(0,1)), - cimg::uiround(points(1,0)),cimg::uiround(points(1,1)), - cimg::uiround(points(2,0)),cimg::uiround(points(2,1)),color,opacity); - cimg_init_scanline(opacity); - int - xmin = 0, ymin = 0, - xmax = points.get_shared_row(0).max_min(xmin), - ymax = points.get_shared_row(1).max_min(ymin); - if (xmax<0 || xmin>=width() || ymax<0 || ymin>=height()) return *this; - if (ymin==ymax) return draw_line(xmin,ymin,xmax,ymax,color,opacity); - - ymin = std::max(0,ymin); - ymax = std::min(height() - 1,ymax); - CImg Xs(points._width,ymax - ymin + 1); - CImg count(Xs._height,1,1,1,0); - unsigned int n = 0, nn = 1; - bool go_on = true; - - while (go_on) { - unsigned int an = (nn + 1)%points._width; - const int - x0 = cimg::uiround(points(n,0)), - y0 = cimg::uiround(points(n,1)); - if (points(nn,1)==y0) while (points(an,1)==y0) { nn = an; (an+=1)%=points._width; } - const int - x1 = cimg::uiround(points(nn,0)), - y1 = cimg::uiround(points(nn,1)); - unsigned int tn = an; - while (points(tn,1)==y1) (tn+=1)%=points._width; - - if (y0!=y1) { - const int - y2 = cimg::uiround(points(tn,1)), - x01 = x1 - x0, y01 = y1 - y0, y12 = y2 - y1, - step = cimg::sign(y01), - tmax = std::max(1,cimg::abs(y01)), htmax = tmax*cimg::sign(x01)/2, - tend = tmax - (step==cimg::sign(y12)); - unsigned int y = (unsigned int)y0 - ymin; - for (int t = 0; t<=tend; ++t, y+=step) - if (yn; - n = nn; - nn = an; - } - - cimg_pragma_openmp(parallel for cimg_openmp_if(Xs._height>=(cimg_openmp_sizefactor)*512)) - cimg_forY(Xs,y) { - const CImg Xsy = Xs.get_shared_points(0,count[y] - 1,y).sort(); - int px = width(); - for (unsigned int k = 0; k - CImg& draw_polygon(const CImg& points, - const tc *const color, const float opacity, const unsigned int pattern) { - if (is_empty() || !points) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_polygon(): Specified color is (null).", - cimg_instance); - if (points._width==1) return draw_point((int)points(0,0),(int)points(0,1),color,opacity); - if (points._width==2) return draw_line((int)points(0,0),(int)points(0,1), - (int)points(1,0),(int)points(1,1),color,opacity,pattern); - bool ninit_hatch = true; - switch (points._height) { - case 0 : case 1 : - throw CImgArgumentException(_cimg_instance - "draw_polygon(): Invalid specified point set (%u,%u,%u,%u).", - cimg_instance, - points._width,points._height,points._depth,points._spectrum); - default : { - CImg npoints(points._width,2); - int x = npoints(0,0) = (int)points(0,0), y = npoints(0,1) = (int)points(0,1); - unsigned int nb_points = 1; - for (unsigned int p = 1; p - CImg& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, - const tc *const color, const float opacity=1) { - return _draw_ellipse(x0,y0,r1,r2,angle,color,opacity,0U,true); - } - - //! Draw a filled 2D ellipse \overloading. - /** - \param x0 X-coordinate of the ellipse center. - \param y0 Y-coordinate of the ellipse center. - \param tensor Diffusion tensor describing the ellipse. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - **/ - template - CImg& draw_ellipse(const int x0, const int y0, const CImg &tensor, - const tc *const color, const float opacity=1) { - CImgList eig = tensor.get_symmetric_eigen(); - const CImg &val = eig[0], &vec = eig[1]; - return draw_ellipse(x0,y0,std::sqrt(val(0)),std::sqrt(val(1)), - std::atan2(vec(0,1),vec(0,0))*180/cimg::PI, - color,opacity); - } - - //! Draw an outlined 2D ellipse. - /** - \param x0 X-coordinate of the ellipse center. - \param y0 Y-coordinate of the ellipse center. - \param r1 First radius of the ellipse. - \param r2 Second radius of the ellipse. - \param angle Angle of the first radius. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - \param pattern An integer whose bits describe the outline pattern. - **/ - template - CImg& draw_ellipse(const int x0, const int y0, const float r1, const float r2, const float angle, - const tc *const color, const float opacity, const unsigned int pattern) { - if (pattern) _draw_ellipse(x0,y0,r1,r2,angle,color,opacity,pattern,false); - return *this; - } - - //! Draw an outlined 2D ellipse \overloading. - /** - \param x0 X-coordinate of the ellipse center. - \param y0 Y-coordinate of the ellipse center. - \param tensor Diffusion tensor describing the ellipse. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - \param pattern An integer whose bits describe the outline pattern. - **/ - template - CImg& draw_ellipse(const int x0, const int y0, const CImg &tensor, - const tc *const color, const float opacity, - const unsigned int pattern) { - CImgList eig = tensor.get_symmetric_eigen(); - const CImg &val = eig[0], &vec = eig[1]; - return draw_ellipse(x0,y0,std::sqrt(val(0)),std::sqrt(val(1)), - std::atan2(vec(0,1),vec(0,0))*180/cimg::PI, - color,opacity,pattern); - } - - template - CImg& _draw_ellipse(const int x0, const int y0, const float radius1, const float radius2, const float angle, - const tc *const color, const float opacity, - const unsigned int pattern, const bool is_filled) { - if (is_empty() || (!is_filled && !pattern)) return *this; - const float radiusM = std::max(radius1,radius2); - if (radius1<0 || radius2<0 || x0 - radiusM>=width() || y0 + radiusM<0 || y0 - radiusM>=height()) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_ellipse(): Specified color is (null).", - cimg_instance); - const int iradius1 = (int)cimg::round(radius1), iradius2 = (int)cimg::round(radius2); - if (!iradius1 && !iradius2) return draw_point(x0,y0,color,opacity); - if (iradius1==iradius2) { - if (is_filled) return draw_circle(x0,y0,iradius1,color,opacity); - else if (pattern==~0U) return draw_circle(x0,y0,iradius1,color,opacity,pattern); - } - const float ang = (float)(angle*cimg::PI/180); - - if (!is_filled) { // Outlined - const float ca = std::cos(ang), sa = std::sin(ang); - CImg points((unsigned int)cimg::round(6*radiusM),2); - cimg_forX(points,k) { - const float - _ang = (float)(2*cimg::PI*k/points._width), - X = (float)(radius1*std::cos(_ang)), - Y = (float)(radius2*std::sin(_ang)); - points(k,0) = (int)cimg::round(x0 + (X*ca - Y*sa)); - points(k,1) = (int)cimg::round(y0 + (X*sa + Y*ca)); - } - draw_polygon(points,color,opacity,pattern); - } else { // Filled - cimg_init_scanline(opacity); - const float - ca = std::cos(ang), - sa = -std::sin(ang), - ca2 = ca*ca, - sa2 = sa*sa, - casa = ca*sa, - i1 = 1/cimg::sqr(radius1), - i2 = 1/cimg::sqr(radius2), - t1 = i1*ca2 + i2*sa2, - t2 = (i2 - i1)*casa, - t3 = i2*ca2 + i1*sa2, - t12 = t1*2; - const int - _ymin = (int)std::floor(y0 - radiusM), - _ymax = (int)std::ceil(y0 + radiusM), - ymin = _ymin<0?0:_ymin, - ymax = _ymax>=height()?height() - 1:_ymax; - for (int y = ymin; y<=ymax; ++y) { - const float - Y = y - y0 + 0.5f, - B = 2*t2*Y, - C = t3*Y*Y - 1, - D = B*B - 4*t1*C; - if (D>=0) { - const float sD = std::sqrt(D); - const int - xmin = (int)(x0 + cimg::round((-B - sD)/t12)), - xmax = (int)(x0 + cimg::round((-B + sD)/t12)); - cimg_draw_scanline(xmin,xmax,y,color,opacity,1); - } - } - } - return *this; - } - - //! Draw a filled 2D circle. - /** - \param x0 X-coordinate of the circle center. - \param y0 Y-coordinate of the circle center. - \param radius Circle radius. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - \note - - Circle version of the Bresenham's algorithm is used. - **/ - template - CImg& draw_circle(const int x0, const int y0, int radius, - const tc *const color, const float opacity=1) { - if (is_empty()) return *this; - if (radius<0 || x0 - radius>=width() || y0 + radius<0 || y0 - radius>=height()) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_circle(): Specified color is (null).", - cimg_instance); - if (!radius) return draw_point(x0,y0,color,opacity); - cimg_init_scanline(opacity); - if (y0>=0 && y0=0) { - const int x1 = x0 - x, x2 = x0 + x, y1 = y0 - y, y2 = y0 + y; - if (y1>=0 && y1=0 && y2=0 && y1=0 && y2 - CImg& draw_circle(const int x0, const int y0, int radius, - const tc *const color, const float opacity, - const unsigned int pattern) { - if (pattern!=~0U) return draw_ellipse(x0,y0,radius,radius,0,color,opacity,pattern); - if (is_empty()) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_circle(): Specified color is (null).", - cimg_instance); - if (radius<0 || x0 - radius>=width() || y0 + radius<0 || y0 - radius>=height()) return *this; - if (!radius) return draw_point(x0,y0,color,opacity); - - draw_point(x0 - radius,y0,color,opacity).draw_point(x0 + radius,y0,color,opacity). - draw_point(x0,y0 - radius,color,opacity).draw_point(x0,y0 + radius,color,opacity); - if (radius==1) return *this; - for (int f = 1 - radius, ddFx = 0, ddFy = -(radius<<1), x = 0, y = radius; x=0) { f+=(ddFy+=2); --y; } - ++x; ++(f+=(ddFx+=2)); - if (x!=y + 1) { - const int x1 = x0 - y, x2 = x0 + y, y1 = y0 - x, y2 = y0 + x, - x3 = x0 - x, x4 = x0 + x, y3 = y0 - y, y4 = y0 + y; - draw_point(x1,y1,color,opacity).draw_point(x1,y2,color,opacity). - draw_point(x2,y1,color,opacity).draw_point(x2,y2,color,opacity); - if (x!=y) - draw_point(x3,y3,color,opacity).draw_point(x4,y4,color,opacity). - draw_point(x4,y3,color,opacity).draw_point(x3,y4,color,opacity); - } - } - return *this; - } - - //! Draw an image. - /** - \param sprite Sprite image. - \param x0 X-coordinate of the sprite position. - \param y0 Y-coordinate of the sprite position. - \param z0 Z-coordinate of the sprite position. - \param c0 C-coordinate of the sprite position. - \param opacity Drawing opacity. - **/ - template - CImg& draw_image(const int x0, const int y0, const int z0, const int c0, - const CImg& sprite, const float opacity=1) { - if (is_empty() || !sprite) return *this; - if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,opacity); - if (x0==0 && y0==0 && z0==0 && c0==0 && is_sameXYZC(sprite) && opacity>=1 && !is_shared()) - return assign(sprite,false); - const bool bx = x0<0, by = y0<0, bz = z0<0, bc = c0<0; - const int - dx0 = bx?0:x0, dy0 = by?0:y0, dz0 = bz?0:z0, dc0 = bc?0:c0, - sx0 = dx0 - x0, sy0 = dy0 - y0, sz0 = dz0 - z0, sc0 = dc0 - c0, - lx = sprite.width() - sx0 - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0), - ly = sprite.height() - sy0 - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0), - lz = sprite.depth() - sz0 - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0), - lc = sprite.spectrum() - sc0 - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0); - - const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.f); - if (lx>0 && ly>0 && lz>0 && lc>0) { - for (int c = 0; c=1) for (int x = 0; x& draw_image(const int x0, const int y0, const int z0, const int c0, - const CImg& sprite, const float opacity=1) { - if (is_empty() || !sprite) return *this; - if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,opacity); - if (x0==0 && y0==0 && z0==0 && c0==0 && is_sameXYZC(sprite) && opacity>=1 && !is_shared()) - return assign(sprite,false); - const bool bx = x0<0, by = y0<0, bz = z0<0, bc = c0<0; - const int - dx0 = bx?0:x0, dy0 = by?0:y0, dz0 = bz?0:z0, dc0 = bc?0:c0, - sx0 = dx0 - x0, sy0 = dy0 - y0, sz0 = dz0 - z0, sc0 = dc0 - c0, - lx = sprite.width() - sx0 - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0), - ly = sprite.height() - sy0 - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0), - lz = sprite.depth() - sz0 - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0), - lc = sprite.spectrum() - sc0 - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0); - const ulongT slx = lx*sizeof(T); - - const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.f); - if (lx>0 && ly>0 && lz>0 && lc>0) { - for (int c = 0; c=1) std::memcpy(ptrd,ptrs,slx); - else for (int x = 0; x - CImg& draw_image(const int x0, const int y0, const int z0, - const CImg& sprite, const float opacity=1) { - return draw_image(x0,y0,z0,0,sprite,opacity); - } - - //! Draw an image \overloading. - template - CImg& draw_image(const int x0, const int y0, - const CImg& sprite, const float opacity=1) { - return draw_image(x0,y0,0,sprite,opacity); - } - - //! Draw an image \overloading. - template - CImg& draw_image(const int x0, - const CImg& sprite, const float opacity=1) { - return draw_image(x0,0,sprite,opacity); - } - - //! Draw an image \overloading. - template - CImg& draw_image(const CImg& sprite, const float opacity=1) { - return draw_image(0,sprite,opacity); - } - - //! Draw a masked image. - /** - \param sprite Sprite image. - \param mask Mask image. - \param x0 X-coordinate of the sprite position in the image instance. - \param y0 Y-coordinate of the sprite position in the image instance. - \param z0 Z-coordinate of the sprite position in the image instance. - \param c0 C-coordinate of the sprite position in the image instance. - \param mask_max_value Maximum pixel value of the mask image \c mask. - \param opacity Drawing opacity. - \note - - Pixel values of \c mask set the opacity of the corresponding pixels in \c sprite. - - Dimensions along x,y and z of \p sprite and \p mask must be the same. - **/ - template - CImg& draw_image(const int x0, const int y0, const int z0, const int c0, - const CImg& sprite, const CImg& mask, const float opacity=1, - const float mask_max_value=1) { - if (is_empty() || !sprite || !mask) return *this; - if (is_overlapped(sprite)) return draw_image(x0,y0,z0,c0,+sprite,mask,opacity,mask_max_value); - if (is_overlapped(mask)) return draw_image(x0,y0,z0,c0,sprite,+mask,opacity,mask_max_value); - if (mask._width!=sprite._width || mask._height!=sprite._height || mask._depth!=sprite._depth) - throw CImgArgumentException(_cimg_instance - "draw_image(): Sprite (%u,%u,%u,%u,%p) and mask (%u,%u,%u,%u,%p) have " - "incompatible dimensions.", - cimg_instance, - sprite._width,sprite._height,sprite._depth,sprite._spectrum,sprite._data, - mask._width,mask._height,mask._depth,mask._spectrum,mask._data); - - const bool bx = x0<0, by = y0<0, bz = z0<0, bc = c0<0; - const int - dx0 = bx?0:x0, dy0 = by?0:y0, dz0 = bz?0:z0, dc0 = bc?0:c0, - sx0 = dx0 - x0, sy0 = dy0 - y0, sz0 = dz0 - z0, sc0 = dc0 - c0, - lx = sprite.width() - sx0 - (x0 + sprite.width()>width()?x0 + sprite.width() - width():0), - ly = sprite.height() - sy0 - (y0 + sprite.height()>height()?y0 + sprite.height() - height():0), - lz = sprite.depth() - sz0 - (z0 + sprite.depth()>depth()?z0 + sprite.depth() - depth():0), - lc = sprite.spectrum() - sc0 - (c0 + sprite.spectrum()>spectrum()?c0 + sprite.spectrum() - spectrum():0); - const ulongT msize = mask.size(); - - if (lx>0 && ly>0 && lz>0 && lc>0) { - for (int c = 0; c - CImg& draw_image(const int x0, const int y0, const int z0, - const CImg& sprite, const CImg& mask, const float opacity=1, - const float mask_max_value=1) { - return draw_image(x0,y0,z0,0,sprite,mask,opacity,mask_max_value); - } - - //! Draw a image \overloading. - template - CImg& draw_image(const int x0, const int y0, - const CImg& sprite, const CImg& mask, const float opacity=1, - const float mask_max_value=1) { - return draw_image(x0,y0,0,sprite,mask,opacity,mask_max_value); - } - - //! Draw a image \overloading. - template - CImg& draw_image(const int x0, - const CImg& sprite, const CImg& mask, const float opacity=1, - const float mask_max_value=1) { - return draw_image(x0,0,sprite,mask,opacity,mask_max_value); - } - - //! Draw an image. - template - CImg& draw_image(const CImg& sprite, const CImg& mask, const float opacity=1, - const float mask_max_value=1) { - return draw_image(0,sprite,mask,opacity,mask_max_value); - } - - //! Draw a text string. - /** - \param x0 X-coordinate of the text in the image instance. - \param y0 Y-coordinate of the text in the image instance. - \param text Format of the text ('printf'-style format string). - \param foreground_color Pointer to \c spectrum() consecutive values, defining the foreground drawing color. - \param background_color Pointer to \c spectrum() consecutive values, defining the background drawing color. - \param opacity Drawing opacity. - \param font Font used for drawing text. - **/ - template - CImg& draw_text(const int x0, const int y0, - const char *const text, - const tc1 *const foreground_color, const tc2 *const background_color, - const float opacity, const CImgList& font, ...) { - if (!font) return *this; - CImg tmp(2048); - std::va_list ap; va_start(ap,font); - cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); - return _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font,false); - } - - //! Draw a text string \overloading. - /** - \note A transparent background is used for the text. - **/ - template - CImg& draw_text(const int x0, const int y0, - const char *const text, - const tc *const foreground_color, const int, - const float opacity, const CImgList& font, ...) { - if (!font) return *this; - CImg tmp(2048); - std::va_list ap; va_start(ap,font); - cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); - return _draw_text(x0,y0,tmp,foreground_color,(tc*)0,opacity,font,false); - } - - //! Draw a text string \overloading. - /** - \note A transparent foreground is used for the text. - **/ - template - CImg& draw_text(const int x0, const int y0, - const char *const text, - const int, const tc *const background_color, - const float opacity, const CImgList& font, ...) { - if (!font) return *this; - CImg tmp(2048); - std::va_list ap; va_start(ap,font); - cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); - return _draw_text(x0,y0,tmp,(tc*)0,background_color,opacity,font,false); - } - - //! Draw a text string \overloading. - /** - \param x0 X-coordinate of the text in the image instance. - \param y0 Y-coordinate of the text in the image instance. - \param text Format of the text ('printf'-style format string). - \param foreground_color Array of spectrum() values of type \c T, - defining the foreground color (0 means 'transparent'). - \param background_color Array of spectrum() values of type \c T, - defining the background color (0 means 'transparent'). - \param opacity Drawing opacity. - \param font_height Height of the text font (exact match for 13,32,64,128, interpolated otherwise). - **/ - template - CImg& draw_text(const int x0, const int y0, - const char *const text, - const tc1 *const foreground_color, const tc2 *const background_color, - const float opacity=1, const unsigned int font_height=13, ...) { - if (!font_height) return *this; - CImg tmp(2048); - std::va_list ap; va_start(ap,font_height); - cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); - const CImgList& font = CImgList::font(font_height,true); - _draw_text(x0,y0,tmp,foreground_color,background_color,opacity,font,true); - return *this; - } - - //! Draw a text string \overloading. - template - CImg& draw_text(const int x0, const int y0, - const char *const text, - const tc *const foreground_color, const int background_color=0, - const float opacity=1, const unsigned int font_height=13, ...) { - if (!font_height) return *this; - cimg::unused(background_color); - CImg tmp(2048); - std::va_list ap; va_start(ap,font_height); - cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); - return draw_text(x0,y0,"%s",foreground_color,(const tc*)0,opacity,font_height,tmp._data); - } - - //! Draw a text string \overloading. - template - CImg& draw_text(const int x0, const int y0, - const char *const text, - const int, const tc *const background_color, - const float opacity=1, const unsigned int font_height=13, ...) { - if (!font_height) return *this; - CImg tmp(2048); - std::va_list ap; va_start(ap,font_height); - cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); - return draw_text(x0,y0,"%s",(tc*)0,background_color,opacity,font_height,tmp._data); - } - - template - CImg& _draw_text(const int x0, const int y0, - const char *const text, - const tc1 *const foreground_color, const tc2 *const background_color, - const float opacity, const CImgList& font, - const bool is_native_font) { - if (!text) return *this; - if (!font) - throw CImgArgumentException(_cimg_instance - "draw_text(): Empty specified font.", - cimg_instance); - - const unsigned int text_length = (unsigned int)std::strlen(text); - const int padding_x = font[0]._height<48?1:font[0]._height<128?(int)std::ceil(font[0]._height/51.0f + 0.745f):4; - unsigned char o_ch, ch = 0; - int x, y, w; - CImg left_paddings(text_length,1,1,1,0); - const CImg empty = CImg::empty(); - - if (is_empty() || is_native_font) { - // Pre-compute necessary size of the image as well as left paddings of each character. - x = y = w = 0; - o_ch = 0; - for (unsigned int i = 0; iw) w = x; x = 0; break; - case '\t' : x+=4*font[(int)' ']._width; break; - case ' ' : x+=font[(int)' ']._width; break; - default : if (ch'9')) || o_ch==';' || o_ch==':' || o_ch=='!') - left_padding = 4*padding_x; - else if (((o_ch=='i' || o_ch=='l' || o_ch=='I' || o_ch=='J' || o_ch=='M' || o_ch=='N') && - ((ch>='0' && ch<='9') || - (ch>='a' && ch<='z' && ch!='v' && ch!='x' && ch!='y') || - (ch>='B' && ch<='Z' && ch!='J' && ch!='T' && ch!='V' && ch!='X' && ch!='Y'))) || - o_ch=='.' || o_ch=='\'' || ch=='\'') - left_padding = padding_x; - else if ((o_ch<'0' || o_ch>'9') && ch!='-') { - const CImg &mask = ch + 256U' ' && o_ch>' ' && mask._height>13) { - const CImg &o_mask = o_ch + 256U13) { - const int w1 = mask.width()>0?o_mask.width() - 1:0, w2 = w1>1?w1 - 1:0, w3 = w2>1?w2 - 1:0; - left_padding = -10; - cimg_forY(mask,k) { - const int - lpad = o_mask(w1,k)>=8?0: - o_mask._width<=2 || o_mask(w2,k)>=8?-1: - o_mask._width<=3 || o_mask(w3,k)>=8?-2:-3, - rpad = mask(0,k)>=8?0: - mask._width<=2 || mask(1,k)>=8?-1: - mask._width<=3 || mask(2,k)>=8?-2:-3; - left_padding = std::max(left_padding,lpad + rpad); - } - } - } - } - left_paddings[i] = left_padding; - } - x+=left_padding + font[ch]._width + padding_x; - o_ch = ch; - } - } - } - if (x!=0 || ch=='\n') { if (x>w) w = x; y+=font[0]._height; } - if (is_empty()) assign(x0 + w,y0 + y,1,is_native_font?1:font[0]._spectrum,(T)0); - } - - // Draw font characters on image. - x = x0; y = y0; - for (unsigned int i = 0; i letter = font[ch]; - if (letter) { - const CImg &mask = ch + 256Uletter._spectrum) - letter.assign(letter.get_resize(-100,-100,1,_spectrum,0,2),false); - const unsigned int cmin = std::min(_spectrum,letter._spectrum); - if (foreground_color) - for (unsigned int c = 0; c& __draw_text(const char *const text, unsigned int &font_size, const int is_down, ...) { - CImg tmp(2048); - std::va_list ap; - va_start(ap,is_down); - cimg_vsnprintf(tmp,tmp._width,text,ap); va_end(ap); - CImg a_label, a_labelmask; - const unsigned char a_labelcolor = 255; - unsigned int ofs = font_size, fs = ofs; - do { // Determine best font size - a_label.assign().draw_text(0,0,"%s",&a_labelcolor,0,1,fs,tmp._data); - if (a_label._width<7*_width/10 && a_label._height>_height/20 && a_label._height<_height/5) { - font_size = fs; break; - } else if ((a_label._width>7*_width/10 || a_label._height>_height/5) && fs>13 && ofs>=fs) { - ofs = fs; fs = std::max(13U,(unsigned int)cimg::round(fs/1.25f)); - } else if (a_label._width<3*_width/10 && a_label._height<_height/20 && fs<64 && ofs<=fs) { - ofs = fs; fs = std::min(64U,(unsigned int)cimg::round(fs*1.25f)); - } else { font_size = fs; break; } - } while (true); - a_label.normalize(0,255); - a_label+=(255 - a_label.get_dilate(3)).normalize(0,80); - a_label.resize(-100,-100,1,3,1); - return draw_image(0,is_down?height() - a_label.height():0,a_label,0.85f); - } - - //! Draw a 2D vector field. - /** - \param flow Image of 2D vectors used as input data. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - \param sampling Length (in pixels) between each arrow. - \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length). - \param is_arrow Tells if arrows must be drawn, instead of oriented segments. - \param pattern Used pattern to draw lines. - \note Clipping is supported. - **/ - template - CImg& draw_quiver(const CImg& flow, - const t2 *const color, const float opacity=1, - const unsigned int sampling=25, const float factor=-20, - const bool is_arrow=true, const unsigned int pattern=~0U) { - return draw_quiver(flow,CImg(color,_spectrum,1,1,1,true),opacity,sampling,factor,is_arrow,pattern); - } - - //! Draw a 2D vector field, using a field of colors. - /** - \param flow Image of 2D vectors used as input data. - \param color Image of spectrum()-D vectors corresponding to the color of each arrow. - \param opacity Opacity of the drawing. - \param sampling Length (in pixels) between each arrow. - \param factor Length factor of each arrow (if <0, computed as a percentage of the maximum length). - \param is_arrow Tells if arrows must be drawn, instead of oriented segments. - \param pattern Used pattern to draw lines. - \note Clipping is supported. - **/ - template - CImg& draw_quiver(const CImg& flow, - const CImg& color, const float opacity=1, - const unsigned int sampling=25, const float factor=-20, - const bool is_arrow=true, const unsigned int pattern=~0U) { - if (is_empty()) return *this; - if (!flow || flow._spectrum!=2) - throw CImgArgumentException(_cimg_instance - "draw_quiver(): Invalid dimensions of specified flow (%u,%u,%u,%u,%p).", - cimg_instance, - flow._width,flow._height,flow._depth,flow._spectrum,flow._data); - if (sampling<=0) - throw CImgArgumentException(_cimg_instance - "draw_quiver(): Invalid sampling value %g " - "(should be >0)", - cimg_instance, - sampling); - const bool colorfield = (color._width==flow._width && color._height==flow._height && - color._depth==1 && color._spectrum==_spectrum); - if (is_overlapped(flow)) return draw_quiver(+flow,color,opacity,sampling,factor,is_arrow,pattern); - float vmax,fact; - if (factor<=0) { - float m, M = (float)flow.get_norm(2).max_min(m); - vmax = (float)std::max(cimg::abs(m),cimg::abs(M)); - if (!vmax) vmax = 1; - fact = -factor; - } else { fact = factor; vmax = 1; } - - for (unsigned int y = sampling/2; y<_height; y+=sampling) - for (unsigned int x = sampling/2; x<_width; x+=sampling) { - const unsigned int X = x*flow._width/_width, Y = y*flow._height/_height; - float u = (float)flow(X,Y,0,0)*fact/vmax, v = (float)flow(X,Y,0,1)*fact/vmax; - if (is_arrow) { - const int xx = (int)(x + u), yy = (int)(y + v); - if (colorfield) draw_arrow(x,y,xx,yy,color.get_vector_at(X,Y)._data,opacity,45,sampling/5.f,pattern); - else draw_arrow(x,y,xx,yy,color._data,opacity,45,sampling/5.f,pattern); - } else { - if (colorfield) - draw_line((int)(x - 0.5*u),(int)(y - 0.5*v),(int)(x + 0.5*u),(int)(y + 0.5*v), - color.get_vector_at(X,Y)._data,opacity,pattern); - else draw_line((int)(x - 0.5*u),(int)(y - 0.5*v),(int)(x + 0.5*u),(int)(y + 0.5*v), - color._data,opacity,pattern); - } - } - return *this; - } - - //! Draw a labeled horizontal axis. - /** - \param values_x Values along the horizontal axis. - \param y Y-coordinate of the horizontal axis in the image instance. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - \param pattern Drawing pattern. - \param font_height Height of the labels (exact match for 13,23,53,103, interpolated otherwise). - \param allow_zero Enable/disable the drawing of label '0' if found. - **/ - template - CImg& draw_axis(const CImg& values_x, const int y, - const tc *const color, const float opacity=1, - const unsigned int pattern=~0U, const unsigned int font_height=13, - const bool allow_zero=true, const float round_x=0) { - if (is_empty()) return *this; - const int yt = (y + 3 + font_height)<_height?y + 3:y - 2 - (int)font_height; - const int siz = (int)values_x.size() - 1; - CImg txt(32); - CImg a_label; - if (siz<=0) { // Degenerated case - draw_line(0,y,_width - 1,y,color,opacity,pattern); - if (!siz) { - cimg_snprintf(txt,txt._width,"%g",round_x?cimg::round((double)*values_x,round_x):(double)*values_x); - a_label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); - const int - _xt = (width() - a_label.width())/2, - xt = _xt<3?3:_xt + a_label.width()>=width() - 2?width() - 3 - a_label.width():_xt; - draw_point(width()/2,y - 1,color,opacity).draw_point(width()/2,y + 1,color,opacity); - if (allow_zero || *txt!='0' || txt[1]!=0) - draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); - } - } else { // Regular case - if (values_x[0]=width() - 2?width() - 3 - a_label.width():_xt; - draw_point(xi,y - 1,color,opacity).draw_point(xi,y + 1,color,opacity); - if (allow_zero || *txt!='0' || txt[1]!=0) - draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); - } - } - return *this; - } - - //! Draw a labeled vertical axis. - /** - \param x X-coordinate of the vertical axis in the image instance. - \param values_y Values along the Y-axis. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - \param pattern Drawing pattern. - \param font_height Height of the labels (exact match for 13,23,53,103, interpolated otherwise). - \param allow_zero Enable/disable the drawing of label '0' if found. - **/ - template - CImg& draw_axis(const int x, const CImg& values_y, - const tc *const color, const float opacity=1, - const unsigned int pattern=~0U, const unsigned int font_height=13, - const bool allow_zero=true, const float round_y=0) { - if (is_empty()) return *this; - int siz = (int)values_y.size() - 1; - CImg txt(32); - CImg a_label; - if (siz<=0) { // Degenerated case - draw_line(x,0,x,_height - 1,color,opacity,pattern); - if (!siz) { - cimg_snprintf(txt,txt._width,"%g",round_y?cimg::round((double)*values_y,round_y):(double)*values_y); - a_label.assign().draw_text(0,0,txt,color,(tc*)0,opacity,font_height); - const int - _yt = (height() - a_label.height())/2, - yt = _yt<0?0:_yt + a_label.height()>=height()?height() - 1 - a_label.height():_yt, - _xt = x - 2 - a_label.width(), - xt = _xt>=0?_xt:x + 3; - draw_point(x - 1,height()/2,color,opacity).draw_point(x + 1,height()/2,color,opacity); - if (allow_zero || *txt!='0' || txt[1]!=0) - draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); - } - } else { // Regular case - if (values_y[0]=height()?height() - 1 - a_label.height():_yt, - _xt = x - 2 - a_label.width(), - xt = _xt>=0?_xt:x + 3; - draw_point(x - 1,yi,color,opacity).draw_point(x + 1,yi,color,opacity); - if (allow_zero || *txt!='0' || txt[1]!=0) - draw_text(xt,yt,txt,color,(tc*)0,opacity,font_height); - } - } - return *this; - } - - //! Draw labeled horizontal and vertical axes. - /** - \param values_x Values along the X-axis. - \param values_y Values along the Y-axis. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - \param pattern_x Drawing pattern for the X-axis. - \param pattern_y Drawing pattern for the Y-axis. - \param font_height Height of the labels (exact match for 13,23,53,103, interpolated otherwise). - \param allow_zero Enable/disable the drawing of label '0' if found. - **/ - template - CImg& draw_axes(const CImg& values_x, const CImg& values_y, - const tc *const color, const float opacity=1, - const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U, - const unsigned int font_height=13, const bool allow_zero=true, - const float round_x=0, const float round_y=0) { - if (is_empty()) return *this; - const CImg nvalues_x(values_x._data,values_x.size(),1,1,1,true); - const int sizx = (int)values_x.size() - 1, wm1 = width() - 1; - if (sizx>=0) { - float ox = (float)*nvalues_x; - for (unsigned int x = sizx?1U:0U; x<_width; ++x) { - const float nx = (float)nvalues_x._linear_atX((float)x*sizx/wm1); - if (nx*ox<=0) { - draw_axis(nx==0?x:x - 1,values_y,color,opacity,pattern_y,font_height,allow_zero,round_y); - break; - } - ox = nx; - } - } - const CImg nvalues_y(values_y._data,values_y.size(),1,1,1,true); - const int sizy = (int)values_y.size() - 1, hm1 = height() - 1; - if (sizy>0) { - float oy = (float)nvalues_y[0]; - for (unsigned int y = sizy?1U:0U; y<_height; ++y) { - const float ny = (float)nvalues_y._linear_atX((float)y*sizy/hm1); - if (ny*oy<=0) { - draw_axis(values_x,ny==0?y:y - 1,color,opacity,pattern_x,font_height,allow_zero,round_x); - break; - } - oy = ny; - } - } - return *this; - } - - //! Draw labeled horizontal and vertical axes \overloading. - template - CImg& draw_axes(const float x0, const float x1, const float y0, const float y1, - const tc *const color, const float opacity=1, - const int subdivisionx=-60, const int subdivisiony=-60, - const float precisionx=0, const float precisiony=0, - const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U, - const unsigned int font_height=13) { - if (is_empty()) return *this; - const bool allow_zero = (x0*x1>0) || (y0*y1>0); - const float - dx = cimg::abs(x1 - x0), dy = cimg::abs(y1 - y0), - px = dx<=0?1:precisionx==0?(float)std::pow(10.,(int)std::log10(dx) - 2.):precisionx, - py = dy<=0?1:precisiony==0?(float)std::pow(10.,(int)std::log10(dy) - 2.):precisiony; - if (x0!=x1 && y0!=y1) - draw_axes(CImg::sequence(subdivisionx>0?subdivisionx:1-width()/subdivisionx,x0,x1), - CImg::sequence(subdivisiony>0?subdivisiony:1-height()/subdivisiony,y0,y1), - color,opacity,pattern_x,pattern_y,font_height,allow_zero,px,py); - else if (x0==x1 && y0!=y1) - draw_axis((int)x0,CImg::sequence(subdivisiony>0?subdivisiony:1-height()/subdivisiony,y0,y1), - color,opacity,pattern_y,font_height,py); - else if (x0!=x1 && y0==y1) - draw_axis(CImg::sequence(subdivisionx>0?subdivisionx:1-width()/subdivisionx,x0,x1),(int)y0, - color,opacity,pattern_x,font_height,px); - return *this; - } - - //! Draw 2D grid. - /** - \param values_x X-coordinates of the vertical lines. - \param values_y Y-coordinates of the horizontal lines. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - \param pattern_x Drawing pattern for vertical lines. - \param pattern_y Drawing pattern for horizontal lines. - **/ - template - CImg& draw_grid(const CImg& values_x, const CImg& values_y, - const tc *const color, const float opacity=1, - const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U) { - if (is_empty()) return *this; - if (values_x) cimg_foroff(values_x,x) { - const int xi = (int)values_x[x]; - if (xi>=0 && xi=0 && yi - CImg& draw_grid(const float delta_x, const float delta_y, - const float offsetx, const float offsety, - const bool invertx, const bool inverty, - const tc *const color, const float opacity=1, - const unsigned int pattern_x=~0U, const unsigned int pattern_y=~0U) { - if (is_empty()) return *this; - CImg seqx, seqy; - if (delta_x!=0) { - const float dx = delta_x>0?delta_x:_width*-delta_x/100; - const unsigned int nx = (unsigned int)(_width/dx); - seqx = CImg::sequence(1 + nx,0,(unsigned int)(dx*nx)); - if (offsetx) cimg_foroff(seqx,x) seqx(x) = (unsigned int)cimg::mod(seqx(x) + offsetx,(float)_width); - if (invertx) cimg_foroff(seqx,x) seqx(x) = _width - 1 - seqx(x); - } - if (delta_y!=0) { - const float dy = delta_y>0?delta_y:_height*-delta_y/100; - const unsigned int ny = (unsigned int)(_height/dy); - seqy = CImg::sequence(1 + ny,0,(unsigned int)(dy*ny)); - if (offsety) cimg_foroff(seqy,y) seqy(y) = (unsigned int)cimg::mod(seqy(y) + offsety,(float)_height); - if (inverty) cimg_foroff(seqy,y) seqy(y) = _height - 1 - seqy(y); - } - return draw_grid(seqx,seqy,color,opacity,pattern_x,pattern_y); - } - - //! Draw 1D graph. - /** - \param data Image containing the graph values I = f(x). - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - - \param plot_type Define the type of the plot: - - 0 = No plot. - - 1 = Plot using segments. - - 2 = Plot using cubic splines. - - 3 = Plot with bars. - \param vertex_type Define the type of points: - - 0 = No points. - - 1 = Point. - - 2 = Straight cross. - - 3 = Diagonal cross. - - 4 = Filled circle. - - 5 = Outlined circle. - - 6 = Square. - - 7 = Diamond. - \param ymin Lower bound of the y-range. - \param ymax Upper bound of the y-range. - \param pattern Drawing pattern. - \note - - if \c ymin==ymax==0, the y-range is computed automatically from the input samples. - **/ - template - CImg& draw_graph(const CImg& data, - const tc *const color, const float opacity=1, - const unsigned int plot_type=1, const int vertex_type=1, - const double ymin=0, const double ymax=0, const unsigned int pattern=~0U) { - if (is_empty() || _height<=1) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_graph(): Specified color is (null).", - cimg_instance); - - // Create shaded colors for displaying bar plots. - CImg color1, color2; - if (plot_type==3) { - color1.assign(_spectrum); color2.assign(_spectrum); - cimg_forC(*this,c) { - color1[c] = (tc)std::min((float)cimg::type::max(),(float)color[c]*1.2f); - color2[c] = (tc)(color[c]*0.4f); - } - } - - // Compute min/max and normalization factors. - const ulongT - siz = data.size(), - _siz1 = siz - (plot_type!=3), - siz1 = _siz1?_siz1:1; - const unsigned int - _width1 = _width - (plot_type!=3), - width1 = _width1?_width1:1; - double m = ymin, M = ymax; - if (ymin==ymax) m = (double)data.max_min(M); - if (m==M) { --m; ++M; } - const float ca = (float)(M-m)/(_height - 1); - bool init_hatch = true; - - // Draw graph edges - switch (plot_type%4) { - case 1 : { // Segments - int oX = 0, oY = (int)cimg::round((data[0] - m)/ca); - if (siz==1) { - const int Y = (int)cimg::round((*data - m)/ca); - draw_line(0,Y,width() - 1,Y,color,opacity,pattern); - } else { - const float fx = (float)_width/siz1; - for (ulongT off = 1; off ndata(data._data,siz,1,1,1,true); - int oY = (int)cimg::round((data[0] - m)/ca); - cimg_forX(*this,x) { - const int Y = (int)cimg::round((ndata._cubic_atX((float)x*siz1/width1)-m)/ca); - if (x>0) draw_line(x,oY,x + 1,Y,color,opacity,pattern,init_hatch); - init_hatch = false; - oY = Y; - } - } break; - case 3 : { // Bars - const int Y0 = (int)cimg::round(-m/ca); - const float fx = (float)_width/siz1; - int oX = 0; - cimg_foroff(data,off) { - const int - X = (int)cimg::round((off + 1)*fx) - 1, - Y = (int)cimg::round((data[off] - m)/ca); - draw_rectangle(oX,Y0,X,Y,color,opacity). - draw_line(oX,Y,oX,Y0,color2.data(),opacity). - draw_line(oX,Y0,X,Y0,Y<=Y0?color2.data():color1.data(),opacity). - draw_line(X,Y,X,Y0,color1.data(),opacity). - draw_line(oX,Y,X,Y,Y<=Y0?color1.data():color2.data(),opacity); - oX = X + 1; - } - } break; - default : break; // No edges - } - - // Draw graph points - const unsigned int wb2 = plot_type==3?_width1/(2*siz):0; - const float fx = (float)_width1/siz1; - switch (vertex_type%8) { - case 1 : { // Point - cimg_foroff(data,off) { - const int - X = (int)cimg::round(off*fx + wb2), - Y = (int)cimg::round((data[off]-m)/ca); - draw_point(X,Y,color,opacity); - } - } break; - case 2 : { // Straight Cross - cimg_foroff(data,off) { - const int - X = (int)cimg::round(off*fx + wb2), - Y = (int)cimg::round((data[off]-m)/ca); - draw_line(X - 3,Y,X + 3,Y,color,opacity).draw_line(X,Y - 3,X,Y + 3,color,opacity); - } - } break; - case 3 : { // Diagonal Cross - cimg_foroff(data,off) { - const int - X = (int)cimg::round(off*fx + wb2), - Y = (int)cimg::round((data[off]-m)/ca); - draw_line(X - 3,Y - 3,X + 3,Y + 3,color,opacity).draw_line(X - 3,Y + 3,X + 3,Y - 3,color,opacity); - } - } break; - case 4 : { // Filled Circle - cimg_foroff(data,off) { - const int - X = (int)cimg::round(off*fx + wb2), - Y = (int)cimg::round((data[off]-m)/ca); - draw_circle(X,Y,3,color,opacity); - } - } break; - case 5 : { // Outlined circle - cimg_foroff(data,off) { - const int - X = (int)cimg::round(off*fx + wb2), - Y = (int)cimg::round((data[off]-m)/ca); - draw_circle(X,Y,3,color,opacity,~0U); - } - } break; - case 6 : { // Square - cimg_foroff(data,off) { - const int - X = (int)cimg::round(off*fx + wb2), - Y = (int)cimg::round((data[off]-m)/ca); - draw_rectangle(X - 3,Y - 3,X + 3,Y + 3,color,opacity,~0U); - } - } break; - case 7 : { // Diamond - cimg_foroff(data,off) { - const int - X = (int)cimg::round(off*fx + wb2), - Y = (int)cimg::round((data[off]-m)/ca); - draw_line(X,Y - 4,X + 4,Y,color,opacity). - draw_line(X + 4,Y,X,Y + 4,color,opacity). - draw_line(X,Y + 4,X - 4,Y,color,opacity). - draw_line(X - 4,Y,X,Y - 4,color,opacity); - } - } break; - default : break; // No points - } - return *this; - } - - bool _draw_fill(const int x, const int y, const int z, - const CImg& ref, const float tolerance2) const { - const T *ptr1 = data(x,y,z), *ptr2 = ref._data; - const ulongT off = _width*_height*_depth; - float diff = 0; - cimg_forC(*this,c) { diff += cimg::sqr(*ptr1 - *(ptr2++)); ptr1+=off; } - return diff<=tolerance2; - } - - //! Draw filled 3D region with the flood fill algorithm. - /** - \param x0 X-coordinate of the starting point of the region to fill. - \param y0 Y-coordinate of the starting point of the region to fill. - \param z0 Z-coordinate of the starting point of the region to fill. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param[out] region Image that will contain the mask of the filled region mask, as an output. - \param tolerance Tolerance concerning neighborhood values. - \param opacity Opacity of the drawing. - \param is_high_connectivity Tells if 8-connexity must be used. - \return \c region is initialized with the binary mask of the filled region. - **/ - template - CImg& draw_fill(const int x0, const int y0, const int z0, - const tc *const color, const float opacity, - CImg ®ion, - const float tolerance = 0, - const bool is_high_connectivity = false) { -#define _draw_fill_push(x,y,z) if (N>=stack._width) stack.resize(2*N + 1,1,1,3,0); \ - stack[N] = x; stack(N,1) = y; stack(N++,2) = z -#define _draw_fill_pop(x,y,z) x = stack[--N]; y = stack(N,1); z = stack(N,2) -#define _draw_fill_is_inside(x,y,z) !_region(x,y,z) && _draw_fill(x,y,z,ref,tolerance2) - - if (!containsXYZC(x0,y0,z0,0)) return *this; - const float nopacity = cimg::abs((float)opacity), copacity = 1 - std::max((float)opacity,0.f); - const float tolerance2 = cimg::sqr(tolerance); - const CImg ref = get_vector_at(x0,y0,z0); - CImg stack(256,1,1,3); - CImg _region(_width,_height,_depth,1,0); - unsigned int N = 0; - int x, y, z; - - _draw_fill_push(x0,y0,z0); - while (N>0) { - _draw_fill_pop(x,y,z); - if (!_region(x,y,z)) { - const int yp = y - 1, yn = y + 1, zp = z - 1, zn = z + 1; - int xl = x, xr = x; - - // Using these booleans reduces the number of pushes drastically. - bool is_yp = false, is_yn = false, is_zp = false, is_zn = false; - for (int step = -1; step<2; step+=2) { - while (x>=0 && x=0 && _draw_fill_is_inside(x,yp,z)) { - if (!is_yp) { _draw_fill_push(x,yp,z); is_yp = true; } - } else is_yp = false; - if (yn1) { - if (zp>=0 && _draw_fill_is_inside(x,y,zp)) { - if (!is_zp) { _draw_fill_push(x,y,zp); is_zp = true; } - } else is_zp = false; - if (zn=0 && !is_yp) { - if (xp>=0 && _draw_fill_is_inside(xp,yp,z)) { - _draw_fill_push(xp,yp,z); if (step<0) is_yp = true; - } - if (xn0) is_yp = true; - } - } - if (yn=0 && _draw_fill_is_inside(xp,yn,z)) { - _draw_fill_push(xp,yn,z); if (step<0) is_yn = true; - } - if (xn0) is_yn = true; - } - } - if (depth()>1) { - if (zp>=0 && !is_zp) { - if (xp>=0 && _draw_fill_is_inside(xp,y,zp)) { - _draw_fill_push(xp,y,zp); if (step<0) is_zp = true; - } - if (xn0) is_zp = true; - } - - if (yp>=0 && !is_yp) { - if (_draw_fill_is_inside(x,yp,zp)) { _draw_fill_push(x,yp,zp); } - if (xp>=0 && _draw_fill_is_inside(xp,yp,zp)) { _draw_fill_push(xp,yp,zp); } - if (xn=0 && _draw_fill_is_inside(xp,yn,zp)) { _draw_fill_push(xp,yn,zp); } - if (xn=0 && _draw_fill_is_inside(xp,y,zn)) { - _draw_fill_push(xp,y,zn); if (step<0) is_zn = true; - } - if (xn0) is_zn = true; - } - - if (yp>=0 && !is_yp) { - if (_draw_fill_is_inside(x,yp,zn)) { _draw_fill_push(x,yp,zn); } - if (xp>=0 && _draw_fill_is_inside(xp,yp,zn)) { _draw_fill_push(xp,yp,zn); } - if (xn=0 && _draw_fill_is_inside(xp,yn,zn)) { _draw_fill_push(xp,yn,zn); } - if (xn - CImg& draw_fill(const int x0, const int y0, const int z0, - const tc *const color, const float opacity=1, - const float tolerance=0, const bool is_high_connexity=false) { - CImg tmp; - return draw_fill(x0,y0,z0,color,opacity,tmp,tolerance,is_high_connexity); - } - - //! Draw filled 2D region with the flood fill algorithm \simplification. - template - CImg& draw_fill(const int x0, const int y0, - const tc *const color, const float opacity=1, - const float tolerance=0, const bool is_high_connexity=false) { - CImg tmp; - return draw_fill(x0,y0,0,color,opacity,tmp,tolerance,is_high_connexity); - } - - //! Draw a random plasma texture. - /** - \param alpha Alpha-parameter. - \param beta Beta-parameter. - \param scale Scale-parameter. - \note Use the mid-point algorithm to render. - **/ - CImg& draw_plasma(const float alpha=1, const float beta=0, const unsigned int scale=8) { - if (is_empty()) return *this; - const int w = width(), h = height(); - const Tfloat m = (Tfloat)cimg::type::min(), M = (Tfloat)cimg::type::max(); - cimg_uint64 rng = (cimg::_rand(),cimg::rng()); - cimg_forZC(*this,z,c) { - CImg ref = get_shared_slice(z,c); - for (int delta = 1<1; delta>>=1) { - const int delta2 = delta>>1; - const float r = alpha*delta + beta; - - // Square step. - for (int y0 = 0; y0M?M:val); - } - - // Diamond steps. - for (int y = -delta2; yM?M:val); - } - for (int y0 = 0; y0M?M:val); - } - for (int y = -delta2; yM?M:val); - } - } - } - cimg::srand(rng); - return *this; - } - - //! Draw a quadratic Mandelbrot or Julia 2D fractal. - /** - \param x0 X-coordinate of the upper-left pixel. - \param y0 Y-coordinate of the upper-left pixel. - \param x1 X-coordinate of the lower-right pixel. - \param y1 Y-coordinate of the lower-right pixel. - \param colormap Colormap. - \param opacity Drawing opacity. - \param z0r Real part of the upper-left fractal vertex. - \param z0i Imaginary part of the upper-left fractal vertex. - \param z1r Real part of the lower-right fractal vertex. - \param z1i Imaginary part of the lower-right fractal vertex. - \param iteration_max Maximum number of iterations for each estimated point. - \param is_normalized_iteration Tells if iterations are normalized. - \param is_julia_set Tells if the Mandelbrot or Julia set is rendered. - \param param_r Real part of the Julia set parameter. - \param param_i Imaginary part of the Julia set parameter. - \note Fractal rendering is done by the Escape Time Algorithm. - **/ - template - CImg& draw_mandelbrot(const int x0, const int y0, const int x1, const int y1, - const CImg& colormap, const float opacity=1, - const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2, - const unsigned int iteration_max=255, - const bool is_normalized_iteration=false, - const bool is_julia_set=false, - const double param_r=0, const double param_i=0) { - if (is_empty()) return *this; - CImg palette; - if (colormap) palette.assign(colormap._data,colormap.size()/colormap._spectrum,1,1,colormap._spectrum,true); - if (palette && palette._spectrum!=_spectrum) - throw CImgArgumentException(_cimg_instance - "draw_mandelbrot(): Instance and specified colormap (%u,%u,%u,%u,%p) have " - "incompatible dimensions.", - cimg_instance, - colormap._width,colormap._height,colormap._depth,colormap._spectrum,colormap._data); - - const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.f), ln2 = (float)std::log(2.); - const int - _x0 = cimg::cut(x0,0,width() - 1), - _y0 = cimg::cut(y0,0,height() - 1), - _x1 = cimg::cut(x1,0,width() - 1), - _y1 = cimg::cut(y1,0,height() - 1); - - cimg_pragma_openmp(parallel for cimg_openmp_collapse(2) - cimg_openmp_if((1 + _x1 - _x0)*(1 + _y1 - _y0)>=(cimg_openmp_sizefactor)*2048)) - for (int q = _y0; q<=_y1; ++q) - for (int p = _x0; p<=_x1; ++p) { - unsigned int iteration = 0; - const double x = z0r + p*(z1r-z0r)/_width, y = z0i + q*(z1i-z0i)/_height; - double zr, zi, cr, ci; - if (is_julia_set) { zr = x; zi = y; cr = param_r; ci = param_i; } - else { zr = param_r; zi = param_i; cr = x; ci = y; } - for (iteration=1; zr*zr + zi*zi<=4 && iteration<=iteration_max; ++iteration) { - const double temp = zr*zr - zi*zi + cr; - zi = 2*zr*zi + ci; - zr = temp; - } - if (iteration>iteration_max) { - if (palette) { - if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette(0,c); - else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(palette(0,c)*nopacity + (*this)(p,q,0,c)*copacity); - } else { - if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)0; - else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)((*this)(p,q,0,c)*copacity); - } - } else if (is_normalized_iteration) { - const float - normz = (float)cimg::abs(zr*zr + zi*zi), - niteration = (float)(iteration + 1 - std::log(std::log(normz))/ln2); - if (palette) { - if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette._linear_atX(niteration,c); - else cimg_forC(*this,c) - (*this)(p,q,0,c) = (T)(palette._linear_atX(niteration,c)*nopacity + (*this)(p,q,0,c)*copacity); - } else { - if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)niteration; - else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(niteration*nopacity + (*this)(p,q,0,c)*copacity); - } - } else { - if (palette) { - if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)palette._atX(iteration,c); - else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(palette(iteration,c)*nopacity + (*this)(p,q,0,c)*copacity); - } else { - if (opacity>=1) cimg_forC(*this,c) (*this)(p,q,0,c) = (T)iteration; - else cimg_forC(*this,c) (*this)(p,q,0,c) = (T)(iteration*nopacity + (*this)(p,q,0,c)*copacity); - } - } - } - return *this; - } - - //! Draw a quadratic Mandelbrot or Julia 2D fractal \overloading. - template - CImg& draw_mandelbrot(const CImg& colormap, const float opacity=1, - const double z0r=-2, const double z0i=-2, const double z1r=2, const double z1i=2, - const unsigned int iteration_max=255, - const bool is_normalized_iteration=false, - const bool is_julia_set=false, - const double param_r=0, const double param_i=0) { - return draw_mandelbrot(0,0,_width - 1,_height - 1,colormap,opacity, - z0r,z0i,z1r,z1i,iteration_max,is_normalized_iteration,is_julia_set,param_r,param_i); - } - - //! Draw a 1D gaussian function. - /** - \param xc X-coordinate of the gaussian center. - \param sigma Standard variation of the gaussian distribution. - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - **/ - template - CImg& draw_gaussian(const float xc, const float sigma, - const tc *const color, const float opacity=1) { - if (is_empty()) return *this; - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_gaussian(): Specified color is (null).", - cimg_instance); - const float sigma2 = 2*sigma*sigma, nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.f); - const ulongT whd = (ulongT)_width*_height*_depth; - const tc *col = color; - cimg_forX(*this,x) { - const float dx = (x - xc), val = (float)std::exp(-dx*dx/sigma2); - T *ptrd = data(x,0,0,0); - if (opacity>=1) cimg_forC(*this,c) { *ptrd = (T)(val*(*col++)); ptrd+=whd; } - else cimg_forC(*this,c) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; } - col-=_spectrum; - } - return *this; - } - - //! Draw a 2D gaussian function. - /** - \param xc X-coordinate of the gaussian center. - \param yc Y-coordinate of the gaussian center. - \param tensor Covariance matrix (must be 2x2). - \param color Pointer to \c spectrum() consecutive values, defining the drawing color. - \param opacity Drawing opacity. - **/ - template - CImg& draw_gaussian(const float xc, const float yc, const CImg& tensor, - const tc *const color, const float opacity=1) { - if (is_empty()) return *this; - if (tensor._width!=2 || tensor._height!=2 || tensor._depth!=1 || tensor._spectrum!=1) - throw CImgArgumentException(_cimg_instance - "draw_gaussian(): Specified tensor (%u,%u,%u,%u,%p) is not a 2x2 matrix.", - cimg_instance, - tensor._width,tensor._height,tensor._depth,tensor._spectrum,tensor._data); - if (!color) - throw CImgArgumentException(_cimg_instance - "draw_gaussian(): Specified color is (null).", - cimg_instance); - typedef typename CImg::Tfloat tfloat; - const CImg invT = tensor.get_invert(), invT2 = (invT*invT)/=-2.; - const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = invT2(1,1); - const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.f); - const ulongT whd = (ulongT)_width*_height*_depth; - const tc *col = color; - float dy = -yc; - cimg_forY(*this,y) { - float dx = -xc; - cimg_forX(*this,x) { - const float val = (float)std::exp(a*dx*dx + b*dx*dy + c*dy*dy); - T *ptrd = data(x,y,0,0); - if (opacity>=1) cimg_forC(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whd; } - else cimg_forC(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; } - col-=_spectrum; - ++dx; - } - ++dy; - } - return *this; - } - - //! Draw a 2D gaussian function \overloading. - template - CImg& draw_gaussian(const int xc, const int yc, const float r1, const float r2, const float ru, const float rv, - const tc *const color, const float opacity=1) { - const double - a = r1*ru*ru + r2*rv*rv, - b = (r1-r2)*ru*rv, - c = r1*rv*rv + r2*ru*ru; - const CImg tensor(2,2,1,1, a,b,b,c); - return draw_gaussian(xc,yc,tensor,color,opacity); - } - - //! Draw a 2D gaussian function \overloading. - template - CImg& draw_gaussian(const float xc, const float yc, const float sigma, - const tc *const color, const float opacity=1) { - return draw_gaussian(xc,yc,CImg::diagonal(sigma,sigma),color,opacity); - } - - //! Draw a 3D gaussian function \overloading. - template - CImg& draw_gaussian(const float xc, const float yc, const float zc, const CImg& tensor, - const tc *const color, const float opacity=1) { - if (is_empty()) return *this; - typedef typename CImg::Tfloat tfloat; - if (tensor._width!=3 || tensor._height!=3 || tensor._depth!=1 || tensor._spectrum!=1) - throw CImgArgumentException(_cimg_instance - "draw_gaussian(): Specified tensor (%u,%u,%u,%u,%p) is not a 3x3 matrix.", - cimg_instance, - tensor._width,tensor._height,tensor._depth,tensor._spectrum,tensor._data); - - const CImg invT = tensor.get_invert(), invT2 = (invT*invT)/=-2.; - const tfloat a = invT2(0,0), b = 2*invT2(1,0), c = 2*invT2(2,0), d = invT2(1,1), e = 2*invT2(2,1), f = invT2(2,2); - const float nopacity = cimg::abs(opacity), copacity = 1 - std::max(opacity,0.f); - const ulongT whd = (ulongT)_width*_height*_depth; - const tc *col = color; - cimg_forXYZ(*this,x,y,z) { - const float - dx = (x - xc), dy = (y - yc), dz = (z - zc), - val = (float)std::exp(a*dx*dx + b*dx*dy + c*dx*dz + d*dy*dy + e*dy*dz + f*dz*dz); - T *ptrd = data(x,y,z,0); - if (opacity>=1) cimg_forC(*this,k) { *ptrd = (T)(val*(*col++)); ptrd+=whd; } - else cimg_forC(*this,k) { *ptrd = (T)(nopacity*val*(*col++) + *ptrd*copacity); ptrd+=whd; } - col-=_spectrum; - } - return *this; - } - - //! Draw a 3D gaussian function \overloading. - template - CImg& draw_gaussian(const float xc, const float yc, const float zc, const float sigma, - const tc *const color, const float opacity=1) { - return draw_gaussian(xc,yc,zc,CImg::diagonal(sigma,sigma,sigma),color,opacity); - } - - //! Draw a 3D object. - /** - \param x0 X-coordinate of the 3D object position - \param y0 Y-coordinate of the 3D object position - \param z0 Z-coordinate of the 3D object position - \param vertices Image Nx3 describing 3D point coordinates - \param primitives List of P primitives - \param colors List of P color (or textures) - \param opacities Image or list of P opacities - \param render_type d Render type (0=Points, 1=Lines, 2=Faces (no light), 3=Faces (flat), 4=Faces(Gouraud) - \param is_double_sided Tells if object faces have two sides or are oriented. - \param focale length of the focale (0 for parallel projection) - \param lightx X-coordinate of the light - \param lighty Y-coordinate of the light - \param lightz Z-coordinate of the light - \param specular_lightness Amount of specular light. - \param specular_shininess Shininess of the object - \param g_opacity Global opacity of the object. - **/ - template - CImg& draw_object3d(const float x0, const float y0, const float z0, - const CImg& vertices, const CImgList& primitives, - const CImgList& colors, const CImg& opacities, - const unsigned int render_type=4, - const bool is_double_sided=false, const float focale=700, - const float lightx=0, const float lighty=0, const float lightz=-5e8, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const float g_opacity=1) { - return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities,render_type, - is_double_sided,focale,lightx,lighty,lightz, - specular_lightness,specular_shininess,g_opacity,CImg::empty()); - } - - //! Draw a 3D object \simplification. - template - CImg& draw_object3d(const float x0, const float y0, const float z0, - const CImg& vertices, const CImgList& primitives, - const CImgList& colors, const CImg& opacities, - const unsigned int render_type, - const bool is_double_sided, const float focale, - const float lightx, const float lighty, const float lightz, - const float specular_lightness, const float specular_shininess, - const float g_opacity, CImg& zbuffer) { - return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities, - render_type,is_double_sided,focale,lightx,lighty,lightz, - specular_lightness,specular_shininess,g_opacity,1); - } - -#ifdef cimg_use_board - template - CImg& draw_object3d(LibBoard::Board& board, - const float x0, const float y0, const float z0, - const CImg& vertices, const CImgList& primitives, - const CImgList& colors, const CImg& opacities, - const unsigned int render_type=4, - const bool is_double_sided=false, const float focale=700, - const float lightx=0, const float lighty=0, const float lightz=-5e8, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const float g_opacity=1) { - return draw_object3d(board,x0,y0,z0,vertices,primitives,colors,opacities,render_type, - is_double_sided,focale,lightx,lighty,lightz, - specular_lightness,specular_shininess,g_opacity,CImg::empty()); - } - - template - CImg& draw_object3d(LibBoard::Board& board, - const float x0, const float y0, const float z0, - const CImg& vertices, const CImgList& primitives, - const CImgList& colors, const CImg& opacities, - const unsigned int render_type, - const bool is_double_sided, const float focale, - const float lightx, const float lighty, const float lightz, - const float specular_lightness, const float specular_shininess, - const float g_opacity, CImg& zbuffer) { - return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities, - render_type,is_double_sided,focale,lightx,lighty,lightz, - specular_lightness,specular_shininess,g_opacity,1); - } -#endif - - //! Draw a 3D object \simplification. - template - CImg& draw_object3d(const float x0, const float y0, const float z0, - const CImg& vertices, const CImgList& primitives, - const CImgList& colors, const CImgList& opacities, - const unsigned int render_type=4, - const bool is_double_sided=false, const float focale=700, - const float lightx=0, const float lighty=0, const float lightz=-5e8, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const float g_opacity=1) { - return draw_object3d(x0,y0,z0,vertices,primitives,colors,opacities,render_type, - is_double_sided,focale,lightx,lighty,lightz, - specular_lightness,specular_shininess,g_opacity,CImg::empty()); - } - - //! Draw a 3D object \simplification. - template - CImg& draw_object3d(const float x0, const float y0, const float z0, - const CImg& vertices, const CImgList& primitives, - const CImgList& colors, const CImgList& opacities, - const unsigned int render_type, - const bool is_double_sided, const float focale, - const float lightx, const float lighty, const float lightz, - const float specular_lightness, const float specular_shininess, - const float g_opacity, CImg& zbuffer) { - return _draw_object3d(0,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities, - render_type,is_double_sided,focale,lightx,lighty,lightz, - specular_lightness,specular_shininess,g_opacity,1); - } - -#ifdef cimg_use_board - template - CImg& draw_object3d(LibBoard::Board& board, - const float x0, const float y0, const float z0, - const CImg& vertices, const CImgList& primitives, - const CImgList& colors, const CImgList& opacities, - const unsigned int render_type=4, - const bool is_double_sided=false, const float focale=700, - const float lightx=0, const float lighty=0, const float lightz=-5e8, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const float g_opacity=1) { - return draw_object3d(board,x0,y0,z0,vertices,primitives,colors,opacities,render_type, - is_double_sided,focale,lightx,lighty,lightz, - specular_lightness,specular_shininess,g_opacity,CImg::empty()); - } - - template - CImg& draw_object3d(LibBoard::Board& board, - const float x0, const float y0, const float z0, - const CImg& vertices, const CImgList& primitives, - const CImgList& colors, const CImgList& opacities, - const unsigned int render_type, - const bool is_double_sided, const float focale, - const float lightx, const float lighty, const float lightz, - const float specular_lightness, const float specular_shininess, - const float g_opacity, CImg& zbuffer) { - return _draw_object3d((void*)&board,zbuffer,x0,y0,z0,vertices,primitives,colors,opacities, - render_type,is_double_sided,focale,lightx,lighty,lightz, - specular_lightness,specular_shininess,g_opacity,1); - } -#endif - - //! Draw a 3D object \simplification. - template - CImg& draw_object3d(const float x0, const float y0, const float z0, - const CImg& vertices, const CImgList& primitives, - const CImgList& colors, - const unsigned int render_type=4, - const bool is_double_sided=false, const float focale=700, - const float lightx=0, const float lighty=0, const float lightz=-5e8, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const float g_opacity=1) { - return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg::const_empty(), - render_type,is_double_sided,focale,lightx,lighty,lightz, - specular_lightness,specular_shininess,g_opacity,CImg::empty()); - } - - //! Draw a 3D object \simplification. - template - CImg& draw_object3d(const float x0, const float y0, const float z0, - const CImg& vertices, const CImgList& primitives, - const CImgList& colors, - const unsigned int render_type, - const bool is_double_sided, const float focale, - const float lightx, const float lighty, const float lightz, - const float specular_lightness, const float specular_shininess, - const float g_opacity, CImg& zbuffer) { - return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg::const_empty(), - render_type,is_double_sided,focale,lightx,lighty,lightz, - specular_lightness,specular_shininess,g_opacity,zbuffer); - } - -#ifdef cimg_use_board - template - CImg& draw_object3d(LibBoard::Board& board, - const float x0, const float y0, const float z0, - const CImg& vertices, const CImgList& primitives, - const CImgList& colors, - const unsigned int render_type=4, - const bool is_double_sided=false, const float focale=700, - const float lightx=0, const float lighty=0, const float lightz=-5e8, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const float g_opacity=1) { - return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg::const_empty(), - render_type,is_double_sided,focale,lightx,lighty,lightz, - specular_lightness,specular_shininess,g_opacity,CImg::empty()); - } - - template - CImg& draw_object3d(LibBoard::Board& board, - const float x0, const float y0, const float z0, - const CImg& vertices, const CImgList& primitives, - const CImgList& colors, - const unsigned int render_type, - const bool is_double_sided, const float focale, - const float lightx, const float lighty, const float lightz, - const float specular_lightness, const float specular_shininess, - const float g_opacity, CImg& zbuffer) { - return draw_object3d(x0,y0,z0,vertices,primitives,colors,CImg::const_empty(), - render_type,is_double_sided,focale,lightx,lighty,lightz, - specular_lightness,specular_shininess,g_opacity,zbuffer); - } -#endif - - template - static float __draw_object3d(const CImgList& opacities, const unsigned int n_primitive, CImg& opacity) { - if (n_primitive>=opacities._width || opacities[n_primitive].is_empty()) { opacity.assign(); return 1; } - if (opacities[n_primitive].size()==1) { opacity.assign(); return opacities(n_primitive,0); } - opacity.assign(opacities[n_primitive],true); - return 1.f; - } - - template - static float __draw_object3d(const CImg& opacities, const unsigned int n_primitive, CImg& opacity) { - opacity.assign(); - return n_primitive>=opacities._width?1.f:(float)opacities[n_primitive]; - } - - template - static float ___draw_object3d(const CImgList& opacities, const unsigned int n_primitive) { - return n_primitive - static float ___draw_object3d(const CImg& opacities, const unsigned int n_primitive) { - return n_primitive - CImg& _draw_object3d(void *const pboard, CImg& zbuffer, - const float X, const float Y, const float Z, - const CImg& vertices, - const CImgList& primitives, - const CImgList& colors, - const to& opacities, - const unsigned int render_type, - const bool is_double_sided, const float focale, - const float lightx, const float lighty, const float lightz, - const float specular_lightness, const float specular_shininess, - const float g_opacity, const float sprite_scale) { - typedef typename cimg::superset2::type tpfloat; - typedef typename to::value_type _to; - if (is_empty() || !vertices || !primitives) return *this; - CImg error_message(1024); - if (!vertices.is_object3d(primitives,colors,opacities,false,error_message)) - throw CImgArgumentException(_cimg_instance - "draw_object3d(): Invalid specified 3D object (%u,%u) (%s).", - cimg_instance,vertices._width,primitives._width,error_message.data()); -#ifndef cimg_use_board - if (pboard) return *this; -#endif - if (render_type==5) cimg::mutex(10); // Static variable used in this case, breaks thread-safety - - const float - nspec = 1 - (specular_lightness<0.f?0.f:(specular_lightness>1.f?1.f:specular_lightness)), - nspec2 = 1 + (specular_shininess<0.f?0.f:specular_shininess), - nsl1 = (nspec2 - 1)/cimg::sqr(nspec - 1), - nsl2 = 1 - 2*nsl1*nspec, - nsl3 = nspec2 - nsl1 - nsl2; - - // Create light texture for phong-like rendering. - CImg light_texture; - if (render_type==5) { - if (colors._width>primitives._width) { - static CImg default_light_texture; - static const tc *lptr = 0; - static tc ref_values[64] = { 0 }; - const CImg& img = colors.back(); - bool is_same_texture = (lptr==img._data); - if (is_same_texture) - for (unsigned int r = 0, j = 0; j<8; ++j) - for (unsigned int i = 0; i<8; ++i) - if (ref_values[r++]!=img(i*img._width/9,j*img._height/9,0,(i + j)%img._spectrum)) { - is_same_texture = false; break; - } - if (!is_same_texture || default_light_texture._spectrum<_spectrum) { - (default_light_texture.assign(img,false)/=255).resize(-100,-100,1,_spectrum); - lptr = colors.back().data(); - for (unsigned int r = 0, j = 0; j<8; ++j) - for (unsigned int i = 0; i<8; ++i) - ref_values[r++] = img(i*img._width/9,j*img._height/9,0,(i + j)%img._spectrum); - } - light_texture.assign(default_light_texture,true); - } else { - static CImg default_light_texture; - static float olightx = 0, olighty = 0, olightz = 0, ospecular_shininess = 0; - if (!default_light_texture || - lightx!=olightx || lighty!=olighty || lightz!=olightz || - specular_shininess!=ospecular_shininess || default_light_texture._spectrum<_spectrum) { - default_light_texture.assign(512,512); - const float - dlx = lightx - X, - dly = lighty - Y, - dlz = lightz - Z, - nl = cimg::hypot(dlx,dly,dlz), - nlx = (default_light_texture._width - 1)/2*(1 + dlx/nl), - nly = (default_light_texture._height - 1)/2*(1 + dly/nl), - white[] = { 1 }; - default_light_texture.draw_gaussian(nlx,nly,default_light_texture._width/3.f,white); - cimg_forXY(default_light_texture,x,y) { - const float factor = default_light_texture(x,y); - if (factor>nspec) default_light_texture(x,y) = std::min(2.f,nsl1*factor*factor + nsl2*factor + nsl3); - } - default_light_texture.resize(-100,-100,1,_spectrum); - olightx = lightx; olighty = lighty; olightz = lightz; ospecular_shininess = specular_shininess; - } - light_texture.assign(default_light_texture,true); - } - } - - // Compute 3D to 2D projection. - CImg projections(vertices._width,2); - tpfloat parallzmin = cimg::type::max(); - const float absfocale = focale?cimg::abs(focale):0; - if (absfocale) { - cimg_pragma_openmp(parallel for cimg_openmp_if_size(projections.size(),4096)) - cimg_forX(projections,l) { // Perspective projection - const tpfloat - x = (tpfloat)vertices(l,0), - y = (tpfloat)vertices(l,1), - z = (tpfloat)vertices(l,2); - const tpfloat projectedz = z + Z + absfocale; - projections(l,1) = Y + absfocale*y/projectedz; - projections(l,0) = X + absfocale*x/projectedz; - } - } else { - cimg_pragma_openmp(parallel for cimg_openmp_if_size(projections.size(),4096)) - cimg_forX(projections,l) { // Parallel projection - const tpfloat - x = (tpfloat)vertices(l,0), - y = (tpfloat)vertices(l,1), - z = (tpfloat)vertices(l,2); - if (z visibles(primitives._width,1,1,1,~0U); - CImg zrange(primitives._width); - const tpfloat zmin = absfocale?(tpfloat)(1.5f - absfocale):cimg::type::min(); - bool is_forward = zbuffer?true:false; - - cimg_pragma_openmp(parallel for cimg_openmp_if_size(primitives.size(),4096)) - cimglist_for(primitives,l) { - const CImg& primitive = primitives[l]; - switch (primitive.size()) { - case 1 : { // Point - CImg<_to> _opacity; - __draw_object3d(opacities,l,_opacity); - if (l<=colors.width() && (colors[l].size()!=_spectrum || _opacity)) is_forward = false; - const unsigned int i0 = (unsigned int)primitive(0); - const tpfloat z0 = Z + vertices(i0,2); - if (z0>zmin) { - visibles(l) = (unsigned int)l; - zrange(l) = z0; - } - } break; - case 5 : { // Sphere - const unsigned int - i0 = (unsigned int)primitive(0), - i1 = (unsigned int)primitive(1); - const tpfloat - Xc = 0.5f*((float)vertices(i0,0) + (float)vertices(i1,0)), - Yc = 0.5f*((float)vertices(i0,1) + (float)vertices(i1,1)), - Zc = 0.5f*((float)vertices(i0,2) + (float)vertices(i1,2)), - _zc = Z + Zc, - zc = _zc + _focale, - xc = X + Xc*(absfocale?absfocale/zc:1), - yc = Y + Yc*(absfocale?absfocale/zc:1), - radius = 0.5f*cimg::hypot(vertices(i1,0) - vertices(i0,0), - vertices(i1,1) - vertices(i0,1), - vertices(i1,2) - vertices(i0,2))*(absfocale?absfocale/zc:1), - xm = xc - radius, - ym = yc - radius, - xM = xc + radius, - yM = yc + radius; - if (xM>=0 && xm<_width && yM>=0 && ym<_height && _zc>zmin) { - visibles(l) = (unsigned int)l; - zrange(l) = _zc; - } - is_forward = false; - } break; - case 2 : case 6 : { // Segment - const unsigned int - i0 = (unsigned int)primitive(0), - i1 = (unsigned int)primitive(1); - const tpfloat - x0 = projections(i0,0), y0 = projections(i0,1), z0 = Z + vertices(i0,2), - x1 = projections(i1,0), y1 = projections(i1,1), z1 = Z + vertices(i1,2); - tpfloat xm, xM, ym, yM; - if (x0=0 && xm<_width && yM>=0 && ym<_height && z0>zmin && z1>zmin) { - visibles(l) = (unsigned int)l; - zrange(l) = (z0 + z1)/2; - } - } break; - case 3 : case 9 : { // Triangle - const unsigned int - i0 = (unsigned int)primitive(0), - i1 = (unsigned int)primitive(1), - i2 = (unsigned int)primitive(2); - const tpfloat - x0 = projections(i0,0), y0 = projections(i0,1), z0 = Z + vertices(i0,2), - x1 = projections(i1,0), y1 = projections(i1,1), z1 = Z + vertices(i1,2), - x2 = projections(i2,0), y2 = projections(i2,1), z2 = Z + vertices(i2,2); - tpfloat xm, xM, ym, yM; - if (x0xM) xM = x2; - if (y0yM) yM = y2; - if (xM>=0 && xm<_width && yM>=0 && ym<_height && z0>zmin && z1>zmin && z2>zmin) { - const tpfloat d = (x1-x0)*(y2-y0) - (x2-x0)*(y1-y0); - if (is_double_sided || d<0) { - visibles(l) = (unsigned int)l; - zrange(l) = (z0 + z1 + z2)/3; - } - } - } break; - case 4 : case 12 : { // Quadrangle - const unsigned int - i0 = (unsigned int)primitive(0), - i1 = (unsigned int)primitive(1), - i2 = (unsigned int)primitive(2), - i3 = (unsigned int)primitive(3); - const tpfloat - x0 = projections(i0,0), y0 = projections(i0,1), z0 = Z + vertices(i0,2), - x1 = projections(i1,0), y1 = projections(i1,1), z1 = Z + vertices(i1,2), - x2 = projections(i2,0), y2 = projections(i2,1), z2 = Z + vertices(i2,2), - x3 = projections(i3,0), y3 = projections(i3,1), z3 = Z + vertices(i3,2); - tpfloat xm, xM, ym, yM; - if (x0xM) xM = x2; - if (x3xM) xM = x3; - if (y0yM) yM = y2; - if (y3yM) yM = y3; - if (xM>=0 && xm<_width && yM>=0 && ym<_height && z0>zmin && z1>zmin && z2>zmin && z3>zmin) { - const float d = (x1 - x0)*(y2 - y0) - (x2 - x0)*(y1 - y0); - if (is_double_sided || d<0) { - visibles(l) = (unsigned int)l; - zrange(l) = (z0 + z1 + z2 + z3)/4; - } - } - } break; - default : - if (render_type==5) cimg::mutex(10,0); - throw CImgArgumentException(_cimg_instance - "draw_object3d(): Invalid primitive[%u] with size %u " - "(should have size 1,2,3,4,5,6,9 or 12).", - cimg_instance, - l,primitive.size()); - } - } - - // Force transparent primitives to be drawn last when zbuffer is activated - // (and if object contains no spheres or sprites). - if (is_forward) - cimglist_for(primitives,l) - if (___draw_object3d(opacities,l)!=1) zrange(l) = 2*zmax - zrange(l); - - // Sort only visibles primitives. - unsigned int *p_visibles = visibles._data; - tpfloat *p_zrange = zrange._data; - const tpfloat *ptrz = p_zrange; - cimg_for(visibles,ptr,unsigned int) { - if (*ptr!=~0U) { *(p_visibles++) = *ptr; *(p_zrange++) = *ptrz; } - ++ptrz; - } - const unsigned int nb_visibles = (unsigned int)(p_zrange - zrange._data); - if (!nb_visibles) { - if (render_type==5) cimg::mutex(10,0); - return *this; - } - CImg permutations; - CImg(zrange._data,nb_visibles,1,1,1,true).sort(permutations,is_forward); - - // Compute light properties - CImg lightprops; - switch (render_type) { - case 3 : { // Flat Shading - lightprops.assign(nb_visibles); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(nb_visibles,4096)) - cimg_forX(lightprops,l) { - const CImg& primitive = primitives(visibles(permutations(l))); - const unsigned int psize = (unsigned int)primitive.size(); - if (psize==3 || psize==4 || psize==9 || psize==12) { - const unsigned int - i0 = (unsigned int)primitive(0), - i1 = (unsigned int)primitive(1), - i2 = (unsigned int)primitive(2); - const tpfloat - x0 = (tpfloat)vertices(i0,0), y0 = (tpfloat)vertices(i0,1), z0 = (tpfloat)vertices(i0,2), - x1 = (tpfloat)vertices(i1,0), y1 = (tpfloat)vertices(i1,1), z1 = (tpfloat)vertices(i1,2), - x2 = (tpfloat)vertices(i2,0), y2 = (tpfloat)vertices(i2,1), z2 = (tpfloat)vertices(i2,2), - dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0, - dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0, - nx = dy1*dz2 - dz1*dy2, - ny = dz1*dx2 - dx1*dz2, - nz = dx1*dy2 - dy1*dx2, - norm = 1e-5f + cimg::hypot(nx,ny,nz), - lx = X + (x0 + x1 + x2)/3 - lightx, - ly = Y + (y0 + y1 + y2)/3 - lighty, - lz = Z + (z0 + z1 + z2)/3 - lightz, - nl = 1e-5f + cimg::hypot(lx,ly,lz), - factor = std::max(cimg::abs(-lx*nx - ly*ny - lz*nz)/(norm*nl),(tpfloat)0); - lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3); - } else lightprops[l] = 1; - } - } break; - - case 4 : // Gouraud Shading - case 5 : { // Phong-Shading - CImg vertices_normals(vertices._width,6,1,1,0); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(nb_visibles,4096)) - for (int l = 0; l<(int)nb_visibles; ++l) { - const CImg& primitive = primitives[visibles(l)]; - const unsigned int psize = (unsigned int)primitive.size(); - const bool - triangle_flag = (psize==3) || (psize==9), - quadrangle_flag = (psize==4) || (psize==12); - if (triangle_flag || quadrangle_flag) { - const unsigned int - i0 = (unsigned int)primitive(0), - i1 = (unsigned int)primitive(1), - i2 = (unsigned int)primitive(2), - i3 = quadrangle_flag?(unsigned int)primitive(3):0; - const tpfloat - x0 = (tpfloat)vertices(i0,0), y0 = (tpfloat)vertices(i0,1), z0 = (tpfloat)vertices(i0,2), - x1 = (tpfloat)vertices(i1,0), y1 = (tpfloat)vertices(i1,1), z1 = (tpfloat)vertices(i1,2), - x2 = (tpfloat)vertices(i2,0), y2 = (tpfloat)vertices(i2,1), z2 = (tpfloat)vertices(i2,2), - dx1 = x1 - x0, dy1 = y1 - y0, dz1 = z1 - z0, - dx2 = x2 - x0, dy2 = y2 - y0, dz2 = z2 - z0, - nnx = dy1*dz2 - dz1*dy2, - nny = dz1*dx2 - dx1*dz2, - nnz = dx1*dy2 - dy1*dx2, - norm = 1e-5f + cimg::hypot(nnx,nny,nnz), - nx = nnx/norm, - ny = nny/norm, - nz = nnz/norm; - unsigned int ix = 0, iy = 1, iz = 2; - if (is_double_sided && nz>0) { ix = 3; iy = 4; iz = 5; } - vertices_normals(i0,ix)+=nx; vertices_normals(i0,iy)+=ny; vertices_normals(i0,iz)+=nz; - vertices_normals(i1,ix)+=nx; vertices_normals(i1,iy)+=ny; vertices_normals(i1,iz)+=nz; - vertices_normals(i2,ix)+=nx; vertices_normals(i2,iy)+=ny; vertices_normals(i2,iz)+=nz; - if (quadrangle_flag) { - vertices_normals(i3,ix)+=nx; vertices_normals(i3,iy)+=ny; vertices_normals(i3,iz)+=nz; - } - } - } - - if (is_double_sided) cimg_forX(vertices_normals,p) { - const float - nx0 = vertices_normals(p,0), ny0 = vertices_normals(p,1), nz0 = vertices_normals(p,2), - nx1 = vertices_normals(p,3), ny1 = vertices_normals(p,4), nz1 = vertices_normals(p,5), - n0 = nx0*nx0 + ny0*ny0 + nz0*nz0, n1 = nx1*nx1 + ny1*ny1 + nz1*nz1; - if (n1>n0) { - vertices_normals(p,0) = -nx1; - vertices_normals(p,1) = -ny1; - vertices_normals(p,2) = -nz1; - } - } - - if (render_type==4) { - lightprops.assign(vertices._width); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(nb_visibles,4096)) - cimg_forX(lightprops,l) { - const tpfloat - nx = vertices_normals(l,0), - ny = vertices_normals(l,1), - nz = vertices_normals(l,2), - norm = 1e-5f + cimg::hypot(nx,ny,nz), - lx = X + vertices(l,0) - lightx, - ly = Y + vertices(l,1) - lighty, - lz = Z + vertices(l,2) - lightz, - nl = 1e-5f + cimg::hypot(lx,ly,lz), - factor = std::max((-lx*nx - ly*ny - lz*nz)/(norm*nl),(tpfloat)0); - lightprops[l] = factor<=nspec?factor:(nsl1*factor*factor + nsl2*factor + nsl3); - } - } else { - const unsigned int - lw2 = light_texture._width/2 - 1, - lh2 = light_texture._height/2 - 1; - lightprops.assign(vertices._width,2); - cimg_pragma_openmp(parallel for cimg_openmp_if_size(nb_visibles,4096)) - cimg_forX(lightprops,l) { - const tpfloat - nx = vertices_normals(l,0), - ny = vertices_normals(l,1), - nz = vertices_normals(l,2), - norm = 1e-5f + cimg::hypot(nx,ny,nz), - nnx = nx/norm, - nny = ny/norm; - lightprops(l,0) = lw2*(1 + nnx); - lightprops(l,1) = lh2*(1 + nny); - } - } - } break; - } - - // Draw visible primitives - const CImg default_color(1,_spectrum,1,1,(tc)200); - CImg<_to> _opacity; - - for (unsigned int l = 0; l& primitive = primitives[n_primitive]; - const CImg - &__color = n_primitive(), - _color = (__color && __color.size()!=_spectrum && __color._spectrum<_spectrum)? - __color.get_resize(-100,-100,-100,_spectrum,0):CImg(), - &color = _color?_color:(__color?__color:default_color); - const tc *const pcolor = color._data; - float opacity = __draw_object3d(opacities,n_primitive,_opacity); - if (_opacity.is_empty()) opacity*=g_opacity; - -#ifdef cimg_use_board - LibBoard::Board &board = *(LibBoard::Board*)pboard; -#endif - - switch (primitive.size()) { - case 1 : { // Colored point or sprite - const unsigned int n0 = (unsigned int)primitive[0]; - const int x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)); - - if (_opacity.is_empty()) { // Scalar opacity - - if (color.size()==_spectrum) { // Colored point - draw_point(x0,y0,pcolor,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawDot((float)x0,height()-(float)y0); - } -#endif - } else { // Sprite - const tpfloat z = Z + vertices(n0,2); - const float factor = focale<0?1:sprite_scale*(absfocale?absfocale/(z + absfocale):1); - const unsigned int - _sw = (unsigned int)(color._width*factor), - _sh = (unsigned int)(color._height*factor), - sw = _sw?_sw:1, sh = _sh?_sh:1; - const int nx0 = x0 - (int)sw/2, ny0 = y0 - (int)sh/2; - if (sw<=3*_width/2 && sh<=3*_height/2 && - (nx0 + (int)sw/2>=0 || nx0 - (int)sw/2=0 || ny0 - (int)sh/2 - _sprite = (sw!=color._width || sh!=color._height)? - color.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg(), - &sprite = _sprite?_sprite:color; - draw_image(nx0,ny0,sprite,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(128,128,128); - board.setFillColor(LibBoard::Color::Null); - board.drawRectangle((float)nx0,height() - (float)ny0,sw,sh); - } -#endif - } - } - } else { // Opacity mask - const tpfloat z = Z + vertices(n0,2); - const float factor = focale<0?1:sprite_scale*(absfocale?absfocale/(z + absfocale):1); - const unsigned int - _sw = (unsigned int)(std::max(color._width,_opacity._width)*factor), - _sh = (unsigned int)(std::max(color._height,_opacity._height)*factor), - sw = _sw?_sw:1, sh = _sh?_sh:1; - const int nx0 = x0 - (int)sw/2, ny0 = y0 - (int)sh/2; - if (sw<=3*_width/2 && sh<=3*_height/2 && - (nx0 + (int)sw/2>=0 || nx0 - (int)sw/2=0 || ny0 - (int)sh/2 - _sprite = (sw!=color._width || sh!=color._height)? - color.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg(), - &sprite = _sprite?_sprite:color; - const CImg<_to> - _nopacity = (sw!=_opacity._width || sh!=_opacity._height)? - _opacity.get_resize(sw,sh,1,-100,render_type<=3?1:3):CImg<_to>(), - &nopacity = _nopacity?_nopacity:_opacity; - draw_image(nx0,ny0,sprite,nopacity,g_opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(128,128,128); - board.setFillColor(LibBoard::Color::Null); - board.drawRectangle((float)nx0,height() - (float)ny0,sw,sh); - } -#endif - } - } - } break; - case 2 : { // Colored line - const unsigned int - n0 = (unsigned int)primitive[0], - n1 = (unsigned int)primitive[1]; - const int - x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)), - x1 = cimg::uiround(projections(n1,0)), y1 = cimg::uiround(projections(n1,1)); - const float - z0 = vertices(n0,2) + Z + _focale, - z1 = vertices(n1,2) + Z + _focale; - if (render_type) { - if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opacity); - else draw_line(x0,y0,x1,y1,pcolor,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawLine((float)x0,height() - (float)y0,x1,height() - (float)y1); - } -#endif - } else { - draw_point(x0,y0,pcolor,opacity).draw_point(x1,y1,pcolor,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawDot((float)x0,height() - (float)y0); - board.drawDot((float)x1,height() - (float)y1); - } -#endif - } - } break; - case 5 : { // Colored sphere - const unsigned int - n0 = (unsigned int)primitive[0], - n1 = (unsigned int)primitive[1], - is_wireframe = (unsigned int)primitive[2], - is_radius = (unsigned int)primitive[3]; - float Xc,Yc,Zc,radius; - if (is_radius) { - Xc = (float)vertices(n0,0); - Yc = (float)vertices(n0,1); - Zc = (float)vertices(n0,2); - radius = cimg::hypot(vertices(n1,0) - vertices(n0,0), - vertices(n1,1) - vertices(n0,1), - vertices(n1,2) - vertices(n0,2)); - } else { - Xc = 0.5f*((float)vertices(n0,0) + (float)vertices(n1,0)); - Yc = 0.5f*((float)vertices(n0,1) + (float)vertices(n1,1)); - Zc = 0.5f*((float)vertices(n0,2) + (float)vertices(n1,2)); - radius = 0.5f*cimg::hypot(vertices(n1,0) - vertices(n0,0), - vertices(n1,1) - vertices(n0,1), - vertices(n1,2) - vertices(n0,2)); - } - const float - zc = Z + Zc + _focale, - af = absfocale?absfocale/zc:1, - xc = X + Xc*af, - yc = Y + Yc*af; - radius*=af; - - switch (render_type) { - case 0 : - draw_point((int)xc,(int)yc,pcolor,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawDot(xc,height() - yc); - } -#endif - break; - case 1 : - draw_circle((int)xc,(int)yc,(int)radius,pcolor,opacity,~0U); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.setFillColor(LibBoard::Color::Null); - board.drawCircle(xc,height() - yc,radius); - } -#endif - break; - default : - if (is_wireframe) draw_circle((int)xc,(int)yc,(int)radius,pcolor,opacity,~0U); - else draw_circle((int)xc,(int)yc,(int)radius,pcolor,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - if (!is_wireframe) board.fillCircle(xc,height() - yc,radius); - else { - board.setFillColor(LibBoard::Color::Null); - board.drawCircle(xc,height() - yc,radius); - } - } -#endif - break; - } - } break; - case 6 : { // Textured line - if (!__color) { - if (render_type==5) cimg::mutex(10,0); - throw CImgArgumentException(_cimg_instance - "draw_object3d(): Undefined texture for line primitive [%u].", - cimg_instance,n_primitive); - } - const unsigned int - n0 = (unsigned int)primitive[0], - n1 = (unsigned int)primitive[1]; - const int - tx0 = (int)primitive[2], ty0 = (int)primitive[3], - tx1 = (int)primitive[4], ty1 = (int)primitive[5], - x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)), - x1 = cimg::uiround(projections(n1,0)), y1 = cimg::uiround(projections(n1,1)); - const float - z0 = vertices(n0,2) + Z + _focale, - z1 = vertices(n1,2) + Z + _focale; - if (render_type) { - if (zbuffer) draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity); - else draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); - } -#endif - } else { - draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0, - ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity). - draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1, - ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.drawDot((float)x0,height() - (float)y0); - board.drawDot((float)x1,height() - (float)y1); - } -#endif - } - } break; - case 3 : { // Colored triangle - const unsigned int - n0 = (unsigned int)primitive[0], - n1 = (unsigned int)primitive[1], - n2 = (unsigned int)primitive[2]; - const int - x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)), - x1 = cimg::uiround(projections(n1,0)), y1 = cimg::uiround(projections(n1,1)), - x2 = cimg::uiround(projections(n2,0)), y2 = cimg::uiround(projections(n2,1)); - const float - z0 = vertices(n0,2) + Z + _focale, - z1 = vertices(n1,2) + Z + _focale, - z2 = vertices(n2,2) + Z + _focale; - switch (render_type) { - case 0 : - draw_point(x0,y0,pcolor,opacity).draw_point(x1,y1,pcolor,opacity).draw_point(x2,y2,pcolor,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawDot((float)x0,height() - (float)y0); - board.drawDot((float)x1,height() - (float)y1); - board.drawDot((float)x2,height() - (float)y2); - } -#endif - break; - case 1 : - if (zbuffer) - draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opacity).draw_line(zbuffer,x0,y0,z0,x2,y2,z2,pcolor,opacity). - draw_line(zbuffer,x1,y1,z1,x2,y2,z2,pcolor,opacity); - else - draw_line(x0,y0,x1,y1,pcolor,opacity).draw_line(x0,y0,x2,y2,pcolor,opacity). - draw_line(x1,y1,x2,y2,pcolor,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); - board.drawLine((float)x0,height() - (float)y0,(float)x2,height() - (float)y2); - board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2); - } -#endif - break; - case 2 : - if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity); - else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height() - (float)y0, - (float)x1,height() - (float)y1, - (float)x2,height() - (float)y2); - } -#endif - break; - case 3 : - if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity,lightprops(l)); - else _draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity,lightprops(l)); - -#ifdef cimg_use_board - if (pboard) { - const float lp = std::min(lightprops(l),1.f); - board.setPenColorRGBi((unsigned char)(color[0]*lp), - (unsigned char)(color[1]*lp), - (unsigned char)(color[2]*lp), - (unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height() - (float)y0, - (float)x1,height() - (float)y1, - (float)x2,height() - (float)y2); - } -#endif - break; - case 4 : - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor, - lightprops(n0),lightprops(n1),lightprops(n2),opacity); - else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,lightprops(n0),lightprops(n1),lightprops(n2),opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi((unsigned char)(color[0]), - (unsigned char)(color[1]), - (unsigned char)(color[2]), - (unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprops(n0), - (float)x1,height() - (float)y1,lightprops(n1), - (float)x2,height() - (float)y2,lightprops(n2)); - } -#endif - break; - case 5 : { - const unsigned int - lx0 = (unsigned int)cimg::uiround(lightprops(n0,0)), ly0 = (unsigned int)cimg::uiround(lightprops(n0,1)), - lx1 = (unsigned int)cimg::uiround(lightprops(n1,0)), ly1 = (unsigned int)cimg::uiround(lightprops(n1,1)), - lx2 = (unsigned int)cimg::uiround(lightprops(n2,0)), ly2 = (unsigned int)cimg::uiround(lightprops(n2,1)); - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity); - else draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity); - -#ifdef cimg_use_board - if (pboard) { - const float - l0 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n0,0))), - (int)(light_texture.height()/2*(1 + lightprops(n0,1)))), - l1 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n1,0))), - (int)(light_texture.height()/2*(1 + lightprops(n1,1)))), - l2 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n2,0))), - (int)(light_texture.height()/2*(1 + lightprops(n2,1)))); - board.setPenColorRGBi((unsigned char)(color[0]), - (unsigned char)(color[1]), - (unsigned char)(color[2]), - (unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, - (float)x1,height() - (float)y1,l1, - (float)x2,height() - (float)y2,l2); - } -#endif - } break; - } - } break; - case 4 : { // Colored quadrangle - const unsigned int - n0 = (unsigned int)primitive[0], - n1 = (unsigned int)primitive[1], - n2 = (unsigned int)primitive[2], - n3 = (unsigned int)primitive[3]; - const int - x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)), - x1 = cimg::uiround(projections(n1,0)), y1 = cimg::uiround(projections(n1,1)), - x2 = cimg::uiround(projections(n2,0)), y2 = cimg::uiround(projections(n2,1)), - x3 = cimg::uiround(projections(n3,0)), y3 = cimg::uiround(projections(n3,1)), - xc = (x0 + x1 + x2 + x3)/4, yc = (y0 + y1 + y2 + y3)/4; - const float - z0 = vertices(n0,2) + Z + _focale, - z1 = vertices(n1,2) + Z + _focale, - z2 = vertices(n2,2) + Z + _focale, - z3 = vertices(n3,2) + Z + _focale, - zc = (z0 + z1 + z2 + z3)/4; - - switch (render_type) { - case 0 : - draw_point(x0,y0,pcolor,opacity).draw_point(x1,y1,pcolor,opacity). - draw_point(x2,y2,pcolor,opacity).draw_point(x3,y3,pcolor,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawDot((float)x0,height() - (float)y0); - board.drawDot((float)x1,height() - (float)y1); - board.drawDot((float)x2,height() - (float)y2); - board.drawDot((float)x3,height() - (float)y3); - } -#endif - break; - case 1 : - if (zbuffer) - draw_line(zbuffer,x0,y0,z0,x1,y1,z1,pcolor,opacity).draw_line(zbuffer,x1,y1,z1,x2,y2,z2,pcolor,opacity). - draw_line(zbuffer,x2,y2,z2,x3,y3,z3,pcolor,opacity).draw_line(zbuffer,x3,y3,z3,x0,y0,z0,pcolor,opacity); - else - draw_line(x0,y0,x1,y1,pcolor,opacity).draw_line(x1,y1,x2,y2,pcolor,opacity). - draw_line(x2,y2,x3,y3,pcolor,opacity).draw_line(x3,y3,x0,y0,pcolor,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); - board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2); - board.drawLine((float)x2,height() - (float)y2,(float)x3,height() - (float)y3); - board.drawLine((float)x3,height() - (float)y3,(float)x0,height() - (float)y0); - } -#endif - break; - case 2 : - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity). - draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,opacity); - else - draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity).draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(color[0],color[1],color[2],(unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height() - (float)y0, - (float)x1,height() - (float)y1, - (float)x2,height() - (float)y2); - board.fillTriangle((float)x0,height() - (float)y0, - (float)x2,height() - (float)y2, - (float)x3,height() - (float)y3); - } -#endif - break; - case 3 : - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,pcolor,opacity,lightprops(l)). - draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,pcolor,opacity,lightprops(l)); - else - _draw_triangle(x0,y0,x1,y1,x2,y2,pcolor,opacity,lightprops(l)). - _draw_triangle(x0,y0,x2,y2,x3,y3,pcolor,opacity,lightprops(l)); - -#ifdef cimg_use_board - if (pboard) { - const float lp = std::min(lightprops(l),1.f); - board.setPenColorRGBi((unsigned char)(color[0]*lp), - (unsigned char)(color[1]*lp), - (unsigned char)(color[2]*lp),(unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height() - (float)y0, - (float)x1,height() - (float)y1, - (float)x2,height() - (float)y2); - board.fillTriangle((float)x0,height() - (float)y0, - (float)x2,height() - (float)y2, - (float)x3,height() - (float)y3); - } -#endif - break; - case 4 : { - const float - lightprop0 = lightprops(n0), lightprop1 = lightprops(n1), - lightprop2 = lightprops(n2), lightprop3 = lightprops(n3), - lightpropc = (lightprop0 + lightprop1 + lightprop2 + lightprop2)/4; - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,xc,yc,zc,pcolor,lightprop0,lightprop1,lightpropc,opacity). - draw_triangle(zbuffer,x1,y1,z1,x2,y2,z2,xc,yc,zc,pcolor,lightprop1,lightprop2,lightpropc,opacity). - draw_triangle(zbuffer,x2,y2,z2,x3,y3,z3,xc,yc,zc,pcolor,lightprop2,lightprop3,lightpropc,opacity). - draw_triangle(zbuffer,x3,y3,z3,x0,y0,z0,xc,yc,zc,pcolor,lightprop3,lightprop0,lightpropc,opacity); - else - draw_triangle(x0,y0,x1,y1,xc,yc,pcolor,lightprop0,lightprop1,lightpropc,opacity). - draw_triangle(x1,y1,x2,y2,xc,yc,pcolor,lightprop1,lightprop2,lightpropc,opacity). - draw_triangle(x2,y2,x3,y3,xc,yc,pcolor,lightprop2,lightprop3,lightpropc,opacity). - draw_triangle(x3,y3,x0,y0,xc,yc,pcolor,lightprop3,lightprop0,lightpropc,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi((unsigned char)(color[0]), - (unsigned char)(color[1]), - (unsigned char)(color[2]), - (unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0, - (float)x1,height() - (float)y1,lightprop1, - (float)x2,height() - (float)y2,lightprop2); - board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0, - (float)x2,height() - (float)y2,lightprop2, - (float)x3,height() - (float)y3,lightprop3); - } -#endif - } break; - case 5 : { - const unsigned int - lx0 = (unsigned int)cimg::uiround(lightprops(n0,0)), ly0 = (unsigned int)cimg::uiround(lightprops(n0,1)), - lx1 = (unsigned int)cimg::uiround(lightprops(n1,0)), ly1 = (unsigned int)cimg::uiround(lightprops(n1,1)), - lx2 = (unsigned int)cimg::uiround(lightprops(n2,0)), ly2 = (unsigned int)cimg::uiround(lightprops(n2,1)), - lx3 = (unsigned int)cimg::uiround(lightprops(n3,0)), ly3 = (unsigned int)cimg::uiround(lightprops(n3,1)), - lxc = (lx0 + lx1 + lx2 + lx3)/4, lyc = (ly0 + ly1 + ly2 + ly3)/4; - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,xc,yc,zc,pcolor,light_texture,lx0,ly0,lx1,ly1,lxc,lyc,opacity). - draw_triangle(zbuffer,x1,y1,z1,x2,y2,z2,xc,yc,zc,pcolor,light_texture,lx1,ly1,lx2,ly2,lxc,lyc,opacity). - draw_triangle(zbuffer,x2,y2,z2,x3,y3,z3,xc,yc,zc,pcolor,light_texture,lx2,ly2,lx3,ly3,lxc,lyc,opacity). - draw_triangle(zbuffer,x3,y3,z3,x0,y0,z0,xc,yc,zc,pcolor,light_texture,lx3,ly3,lx0,ly0,lxc,lyc,opacity); - else - draw_triangle(x0,y0,x1,y1,xc,yc,pcolor,light_texture,lx0,ly0,lx1,ly1,lxc,lyc,opacity). - draw_triangle(x1,y1,x2,y2,xc,yc,pcolor,light_texture,lx1,ly1,lx2,ly2,lxc,lyc,opacity). - draw_triangle(x2,y2,x3,y3,xc,yc,pcolor,light_texture,lx2,ly2,lx3,ly3,lxc,lyc,opacity). - draw_triangle(x3,y3,x0,y0,xc,yc,pcolor,light_texture,lx3,ly3,lx0,ly0,lxc,lyc,opacity); - -#ifdef cimg_use_board - if (pboard) { - const float - l0 = light_texture((int)(light_texture.width()/2*(1 + lx0)), (int)(light_texture.height()/2*(1 + ly0))), - l1 = light_texture((int)(light_texture.width()/2*(1 + lx1)), (int)(light_texture.height()/2*(1 + ly1))), - l2 = light_texture((int)(light_texture.width()/2*(1 + lx2)), (int)(light_texture.height()/2*(1 + ly2))), - l3 = light_texture((int)(light_texture.width()/2*(1 + lx3)), (int)(light_texture.height()/2*(1 + ly3))); - board.setPenColorRGBi((unsigned char)(color[0]), - (unsigned char)(color[1]), - (unsigned char)(color[2]), - (unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, - (float)x1,height() - (float)y1,l1, - (float)x2,height() - (float)y2,l2); - board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, - (float)x2,height() - (float)y2,l2, - (float)x3,height() - (float)y3,l3); - } -#endif - } break; - } - } break; - case 9 : { // Textured triangle - if (!__color) { - if (render_type==5) cimg::mutex(10,0); - throw CImgArgumentException(_cimg_instance - "draw_object3d(): Undefined texture for triangle primitive [%u].", - cimg_instance,n_primitive); - } - const unsigned int - n0 = (unsigned int)primitive[0], - n1 = (unsigned int)primitive[1], - n2 = (unsigned int)primitive[2]; - const int - tx0 = (int)primitive[3], ty0 = (int)primitive[4], - tx1 = (int)primitive[5], ty1 = (int)primitive[6], - tx2 = (int)primitive[7], ty2 = (int)primitive[8], - x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)), - x1 = cimg::uiround(projections(n1,0)), y1 = cimg::uiround(projections(n1,1)), - x2 = cimg::uiround(projections(n2,0)), y2 = cimg::uiround(projections(n2,1)); - const float - z0 = vertices(n0,2) + Z + _focale, - z1 = vertices(n1,2) + Z + _focale, - z2 = vertices(n2,2) + Z + _focale; - switch (render_type) { - case 0 : - draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0, - ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity). - draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1, - ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity). - draw_point(x2,y2,color.get_vector_at(tx2<=0?0:tx2>=color.width()?color.width() - 1:tx2, - ty2<=0?0:ty2>=color.height()?color.height() - 1:ty2)._data,opacity); -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.drawDot((float)x0,height() - (float)y0); - board.drawDot((float)x1,height() - (float)y1); - board.drawDot((float)x2,height() - (float)y2); - } -#endif - break; - case 1 : - if (zbuffer) - draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity). - draw_line(zbuffer,x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opacity). - draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity); - else - draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity). - draw_line(x0,y0,z0,x2,y2,z2,color,tx0,ty0,tx2,ty2,opacity). - draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); - board.drawLine((float)x0,height() - (float)y0,(float)x2,height() - (float)y2); - board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2); - } -#endif - break; - case 2 : - if (zbuffer) draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity); - else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height() - (float)y0, - (float)x1,height() - (float)y1, - (float)x2,height() - (float)y2); - } -#endif - break; - case 3 : - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)); - else draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)); - -#ifdef cimg_use_board - if (pboard) { - const float lp = std::min(lightprops(l),1.f); - board.setPenColorRGBi((unsigned char)(128*lp), - (unsigned char)(128*lp), - (unsigned char)(128*lp), - (unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height() - (float)y0, - (float)x1,height() - (float)y1, - (float)x2,height() - (float)y2); - } -#endif - break; - case 4 : - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2, - lightprops(n0),lightprops(n1),lightprops(n2),opacity); - else - draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2, - lightprops(n0),lightprops(n1),lightprops(n2),opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprops(n0), - (float)x1,height() - (float)y1,lightprops(n1), - (float)x2,height() - (float)y2,lightprops(n2)); - } -#endif - break; - case 5 : - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture, - (unsigned int)lightprops(n0,0),(unsigned int)lightprops(n0,1), - (unsigned int)lightprops(n1,0),(unsigned int)lightprops(n1,1), - (unsigned int)lightprops(n2,0),(unsigned int)lightprops(n2,1), - opacity); - else - draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,light_texture, - (unsigned int)lightprops(n0,0),(unsigned int)lightprops(n0,1), - (unsigned int)lightprops(n1,0),(unsigned int)lightprops(n1,1), - (unsigned int)lightprops(n2,0),(unsigned int)lightprops(n2,1), - opacity); - -#ifdef cimg_use_board - if (pboard) { - const float - l0 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n0,0))), - (int)(light_texture.height()/2*(1 + lightprops(n0,1)))), - l1 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n1,0))), - (int)(light_texture.height()/2*(1 + lightprops(n1,1)))), - l2 = light_texture((int)(light_texture.width()/2*(1 + lightprops(n2,0))), - (int)(light_texture.height()/2*(1 + lightprops(n2,1)))); - board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, - (float)x1,height() - (float)y1,l1, - (float)x2,height() - (float)y2,l2); - } -#endif - break; - } - } break; - case 12 : { // Textured quadrangle - if (!__color) { - if (render_type==5) cimg::mutex(10,0); - throw CImgArgumentException(_cimg_instance - "draw_object3d(): Undefined texture for quadrangle primitive [%u].", - cimg_instance,n_primitive); - } - const unsigned int - n0 = (unsigned int)primitive[0], - n1 = (unsigned int)primitive[1], - n2 = (unsigned int)primitive[2], - n3 = (unsigned int)primitive[3]; - const int - tx0 = (int)primitive[4], ty0 = (int)primitive[5], - tx1 = (int)primitive[6], ty1 = (int)primitive[7], - tx2 = (int)primitive[8], ty2 = (int)primitive[9], - tx3 = (int)primitive[10], ty3 = (int)primitive[11], - x0 = cimg::uiround(projections(n0,0)), y0 = cimg::uiround(projections(n0,1)), - x1 = cimg::uiround(projections(n1,0)), y1 = cimg::uiround(projections(n1,1)), - x2 = cimg::uiround(projections(n2,0)), y2 = cimg::uiround(projections(n2,1)), - x3 = cimg::uiround(projections(n3,0)), y3 = cimg::uiround(projections(n3,1)); - const float - z0 = vertices(n0,2) + Z + _focale, - z1 = vertices(n1,2) + Z + _focale, - z2 = vertices(n2,2) + Z + _focale, - z3 = vertices(n3,2) + Z + _focale; - - switch (render_type) { - case 0 : - draw_point(x0,y0,color.get_vector_at(tx0<=0?0:tx0>=color.width()?color.width() - 1:tx0, - ty0<=0?0:ty0>=color.height()?color.height() - 1:ty0)._data,opacity). - draw_point(x1,y1,color.get_vector_at(tx1<=0?0:tx1>=color.width()?color.width() - 1:tx1, - ty1<=0?0:ty1>=color.height()?color.height() - 1:ty1)._data,opacity). - draw_point(x2,y2,color.get_vector_at(tx2<=0?0:tx2>=color.width()?color.width() - 1:tx2, - ty2<=0?0:ty2>=color.height()?color.height() - 1:ty2)._data,opacity). - draw_point(x3,y3,color.get_vector_at(tx3<=0?0:tx3>=color.width()?color.width() - 1:tx3, - ty3<=0?0:ty3>=color.height()?color.height() - 1:ty3)._data,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.drawDot((float)x0,height() - (float)y0); - board.drawDot((float)x1,height() - (float)y1); - board.drawDot((float)x2,height() - (float)y2); - board.drawDot((float)x3,height() - (float)y3); - } -#endif - break; - case 1 : - if (zbuffer) - draw_line(zbuffer,x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity). - draw_line(zbuffer,x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity). - draw_line(zbuffer,x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opacity). - draw_line(zbuffer,x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opacity); - else - draw_line(x0,y0,z0,x1,y1,z1,color,tx0,ty0,tx1,ty1,opacity). - draw_line(x1,y1,z1,x2,y2,z2,color,tx1,ty1,tx2,ty2,opacity). - draw_line(x2,y2,z2,x3,y3,z3,color,tx2,ty2,tx3,ty3,opacity). - draw_line(x3,y3,z3,x0,y0,z0,color,tx3,ty3,tx0,ty0,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.drawLine((float)x0,height() - (float)y0,(float)x1,height() - (float)y1); - board.drawLine((float)x1,height() - (float)y1,(float)x2,height() - (float)y2); - board.drawLine((float)x2,height() - (float)y2,(float)x3,height() - (float)y3); - board.drawLine((float)x3,height() - (float)y3,(float)x0,height() - (float)y0); - } -#endif - break; - case 2 : - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity). - draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity); - else - draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity). - draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height() - (float)y0, - (float)x1,height() - (float)y1, - (float)x2,height() - (float)y2); - board.fillTriangle((float)x0,height() - (float)y0, - (float)x2,height() - (float)y2, - (float)x3,height() - (float)y3); - } -#endif - break; - case 3 : - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)). - draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity,lightprops(l)); - else - draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2,opacity,lightprops(l)). - draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3,opacity,lightprops(l)); - -#ifdef cimg_use_board - if (pboard) { - const float lp = std::min(lightprops(l),1.f); - board.setPenColorRGBi((unsigned char)(128*lp), - (unsigned char)(128*lp), - (unsigned char)(128*lp), - (unsigned char)(opacity*255)); - board.fillTriangle((float)x0,height() - (float)y0, - (float)x1,height() - (float)y1, - (float)x2,height() - (float)y2); - board.fillTriangle((float)x0,height() - (float)y0, - (float)x2,height() - (float)y2, - (float)x3,height() - (float)y3); - } -#endif - break; - case 4 : { - const float - lightprop0 = lightprops(n0), lightprop1 = lightprops(n1), - lightprop2 = lightprops(n2), lightprop3 = lightprops(n3); - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2, - lightprop0,lightprop1,lightprop2,opacity). - draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3, - lightprop0,lightprop2,lightprop3,opacity); - else - draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2, - lightprop0,lightprop1,lightprop2,opacity). - draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3, - lightprop0,lightprop2,lightprop3,opacity); - -#ifdef cimg_use_board - if (pboard) { - board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height() - (float)y0,lightprop0, - (float)x1,height() - (float)y1,lightprop1, - (float)x2,height() - (float)y2,lightprop2); - board.fillGouraudTriangle((float)x0,height() -(float)y0,lightprop0, - (float)x2,height() - (float)y2,lightprop2, - (float)x3,height() - (float)y3,lightprop3); - } -#endif - } break; - case 5 : { - const unsigned int - lx0 = (unsigned int)cimg::uiround(lightprops(n0,0)), ly0 = (unsigned int)cimg::uiround(lightprops(n0,1)), - lx1 = (unsigned int)cimg::uiround(lightprops(n1,0)), ly1 = (unsigned int)cimg::uiround(lightprops(n1,1)), - lx2 = (unsigned int)cimg::uiround(lightprops(n2,0)), ly2 = (unsigned int)cimg::uiround(lightprops(n2,1)), - lx3 = (unsigned int)cimg::uiround(lightprops(n3,0)), ly3 = (unsigned int)cimg::uiround(lightprops(n3,1)); - if (zbuffer) - draw_triangle(zbuffer,x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2, - light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity). - draw_triangle(zbuffer,x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3, - light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity); - else - draw_triangle(x0,y0,z0,x1,y1,z1,x2,y2,z2,color,tx0,ty0,tx1,ty1,tx2,ty2, - light_texture,lx0,ly0,lx1,ly1,lx2,ly2,opacity). - draw_triangle(x0,y0,z0,x2,y2,z2,x3,y3,z3,color,tx0,ty0,tx2,ty2,tx3,ty3, - light_texture,lx0,ly0,lx2,ly2,lx3,ly3,opacity); -#ifdef cimg_use_board - if (pboard) { - const float - l0 = light_texture((int)(light_texture.width()/2*(1 + lx0)), (int)(light_texture.height()/2*(1 + ly0))), - l1 = light_texture((int)(light_texture.width()/2*(1 + lx1)), (int)(light_texture.height()/2*(1 + ly1))), - l2 = light_texture((int)(light_texture.width()/2*(1 + lx2)), (int)(light_texture.height()/2*(1 + ly2))), - l3 = light_texture((int)(light_texture.width()/2*(1 + lx3)), (int)(light_texture.height()/2*(1 + ly3))); - board.setPenColorRGBi(128,128,128,(unsigned char)(opacity*255)); - board.fillGouraudTriangle((float)x0,height() - (float)y0,l0, - (float)x1,height() - (float)y1,l1, - (float)x2,height() - (float)y2,l2); - board.fillGouraudTriangle((float)x0,height() -(float)y0,l0, - (float)x2,height() - (float)y2,l2, - (float)x3,height() - (float)y3,l3); - } -#endif - } break; - } - } break; - } - } - if (render_type==5) cimg::mutex(10,0); - return *this; - } - - //@} - //--------------------------- - // - //! \name Data Input - //@{ - //--------------------------- - - //! Launch simple interface to select a shape from an image. - /** - \param disp Display window to use. - \param feature_type Type of feature to select. Can be { 0=point | 1=line | 2=rectangle | 3=ellipse }. - \param XYZ Pointer to 3 values X,Y,Z which tells about the projection point coordinates, for volumetric images. - \param exit_on_anykey Exit function when any key is pressed. - **/ - CImg& select(CImgDisplay &disp, - const unsigned int feature_type=2, unsigned int *const XYZ=0, - const bool exit_on_anykey=false, - const bool is_deep_selection_default=false) { - return get_select(disp,feature_type,XYZ,exit_on_anykey,is_deep_selection_default).move_to(*this); - } - - //! Simple interface to select a shape from an image \overloading. - CImg& select(const char *const title, - const unsigned int feature_type=2, unsigned int *const XYZ=0, - const bool exit_on_anykey=false, - const bool is_deep_selection_default=false) { - return get_select(title,feature_type,XYZ,exit_on_anykey,is_deep_selection_default).move_to(*this); - } - - //! Simple interface to select a shape from an image \newinstance. - CImg get_select(CImgDisplay &disp, - const unsigned int feature_type=2, unsigned int *const XYZ=0, - const bool exit_on_anykey=false, - const bool is_deep_selection_default=false) const { - return _select(disp,0,feature_type,XYZ,0,0,0,exit_on_anykey,true,false,is_deep_selection_default); - } - - //! Simple interface to select a shape from an image \newinstance. - CImg get_select(const char *const title, - const unsigned int feature_type=2, unsigned int *const XYZ=0, - const bool exit_on_anykey=false, - const bool is_deep_selection_default=false) const { - CImgDisplay disp; - return _select(disp,title,feature_type,XYZ,0,0,0,exit_on_anykey,true,false,is_deep_selection_default); - } - - CImg _select(CImgDisplay &disp, const char *const title, - const unsigned int feature_type, unsigned int *const XYZ, - const int origX, const int origY, const int origZ, - const bool exit_on_anykey, - const bool reset_view3d, - const bool force_display_z_coord, - const bool is_deep_selection_default) const { - if (is_empty()) return CImg(1,feature_type==0?3:6,1,1,-1); - if (!disp) { - disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1); - if (!title) disp.set_title("CImg<%s> (%ux%ux%ux%u)",pixel_type(),_width,_height,_depth,_spectrum); - } else { - if (title) disp.set_title("%s",title); - disp.move_inside_screen(); - } - - CImg thumb; - if (width()>disp.screen_width() || height()>disp.screen_height()) - get_resize(cimg_fitscreen(width(),height(),depth()),depth(),-100).move_to(thumb); - - const unsigned int old_normalization = disp.normalization(); - bool old_is_resized = disp.is_resized(); - disp._normalization = 0; - disp.show().set_key(0).set_wheel().show_mouse(); - - static const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 }; - int area = 0, area_started = 0, area_clicked = 0, phase = 0, - X0 = (int)((XYZ?XYZ[0]:_width/2)%_width), - Y0 = (int)((XYZ?XYZ[1]:_height/2)%_height), - Z0 = (int)((XYZ?XYZ[2]:_depth/2)%_depth), - X1 =-1, Y1 = -1, Z1 = -1, - X3d = -1, Y3d = -1, - oX3d = X3d, oY3d = -1, - omx = -1, omy = -1; - float X = -1, Y = -1, Z = -1; - unsigned int key = 0, font_size = 32; - - bool is_deep_selection = is_deep_selection_default, - shape_selected = false, text_down = false, visible_cursor = true; - static CImg pose3d; - static bool is_view3d = false, is_axes = true; - if (reset_view3d) { pose3d.assign(); is_view3d = false; } - CImg points3d, opacities3d, sel_opacities3d; - CImgList primitives3d, sel_primitives3d; - CImgList colors3d, sel_colors3d; - CImg visu, visu0, view3d; - CImg text(1024); *text = 0; - - while (!key && !disp.is_closed() && !shape_selected) { - - // Handle mouse motion and selection - int - mx = disp.mouse_x(), - my = disp.mouse_y(); - - const float - mX = mx<0?-1.f:(float)mx*(width() + (depth()>1?depth():0))/disp.width(), - mY = my<0?-1.f:(float)my*(height() + (depth()>1?depth():0))/disp.height(); - - area = 0; - if (mX>=0 && mY>=0 && mX=0 && mX=height()) { area = 2; X = mX; Z = mY - _height; Y = (float)(phase?Y1:Y0); } - if (mY>=0 && mX>=width() && mY=width() && mY>=height()) area = 4; - if (disp.button()) { if (!area_clicked) area_clicked = area; } else area_clicked = 0; - - CImg filename(32); - - switch (key = disp.key()) { -#if cimg_OS!=2 - case cimg::keyCTRLRIGHT : -#endif - case 0 : case cimg::keyCTRLLEFT : key = 0; break; - case cimg::keyPAGEUP : - if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_wheel(1); key = 0; } break; - case cimg::keyPAGEDOWN : - if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { disp.set_wheel(-1); key = 0; } break; - case cimg::keyX : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - is_axes = !is_axes; disp.set_key(key,false); key = 0; visu0.assign(); - } break; - case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), - CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false). - _is_resized = true; - disp.set_key(key,false); key = 0; visu0.assign(); - } break; - case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true; - disp.set_key(key,false); key = 0; visu0.assign(); - } break; - case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false).resize(cimg_fitscreen(_width,_height,_depth),false)._is_resized = true; - disp.set_key(key,false); key = 0; visu0.assign(); - } break; - case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen()._is_resized = true; - disp.set_key(key,false); key = 0; visu0.assign(); - } break; - case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - is_view3d = !is_view3d; disp.set_key(key,false); key = 0; visu0.assign(); - } break; - case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - static unsigned int snap_number = 0; - std::FILE *file; - do { - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++); - if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file); - } while (file); - if (visu0) { - (+visu0).__draw_text(" Saving snapshot...",font_size,(int)text_down).display(disp); - visu0.save(filename); - (+visu0).__draw_text(" Snapshot '%s' saved. ",font_size,(int)text_down,filename._data).display(disp); - } - disp.set_key(key,false); key = 0; - } break; - case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - static unsigned int snap_number = 0; - std::FILE *file; - do { - -#ifdef cimg_use_zlib - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++); -#else - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++); -#endif - if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file); - } while (file); - (+visu0).__draw_text(" Saving instance... ",font_size,(int)text_down).display(disp); - save(filename); - (+visu0).__draw_text(" Instance '%s' saved. ",font_size,(int)text_down,filename._data).display(disp); - disp.set_key(key,false); key = 0; - } break; - } - - switch (area) { - - case 0 : // When mouse is out of image range - mx = my = -1; X = Y = Z = -1; - break; - - case 1 : case 2 : case 3 : { // When mouse is over the XY,XZ or YZ projections - const unsigned int but = disp.button(); - const bool b1 = (bool)(but&1), b2 = (bool)(but&2), b3 = (bool)(but&4); - - if (b1 && phase==1 && area_clicked==area) { // When selection has been started (1st step) - if (_depth>1 && (X1!=(int)X || Y1!=(int)Y || Z1!=(int)Z)) visu0.assign(); - X1 = (int)X; Y1 = (int)Y; Z1 = (int)Z; - } - if (!b1 && phase==2 && area_clicked!=area) { // When selection is at 2nd step (for volumes) - switch (area_started) { - case 1 : if (Z1!=(int)Z) visu0.assign(); Z1 = (int)Z; break; - case 2 : if (Y1!=(int)Y) visu0.assign(); Y1 = (int)Y; break; - case 3 : if (X1!=(int)X) visu0.assign(); X1 = (int)X; break; - } - } - if (b2 && area_clicked==area) { // When moving through the image/volume - if (phase) { - if (_depth>1 && (X1!=(int)X || Y1!=(int)Y || Z1!=(int)Z)) visu0.assign(); - X1 = (int)X; Y1 = (int)Y; Z1 = (int)Z; - } else { - if (_depth>1 && (X0!=(int)X || Y0!=(int)Y || Z0!=(int)Z)) visu0.assign(); - X0 = (int)X; Y0 = (int)Y; Z0 = (int)Z; - } - } - if (b3) { // Reset selection - X = (float)X0; Y = (float)Y0; Z = (float)Z0; phase = area = area_clicked = area_started = 0; - visu0.assign(); - } - if (disp.wheel()) { // When moving through the slices of the volume (with mouse wheel) - if (_depth>1 && !disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT() && - !disp.is_keySHIFTLEFT() && !disp.is_keySHIFTRIGHT()) { - switch (area) { - case 1 : - if (phase) Z = (float)(Z1+=disp.wheel()); else Z = (float)(Z0+=disp.wheel()); - visu0.assign(); break; - case 2 : - if (phase) Y = (float)(Y1+=disp.wheel()); else Y = (float)(Y0+=disp.wheel()); - visu0.assign(); break; - case 3 : - if (phase) X = (float)(X1+=disp.wheel()); else X = (float)(X0+=disp.wheel()); - visu0.assign(); break; - } - disp.set_wheel(); - } else key = ~0U; - } - - if ((phase==0 && b1) || - (phase==1 && !b1) || - (phase==2 && b1)) switch (phase) { // Detect change of phase - case 0 : - if (area==area_clicked) { - X0 = X1 = (int)X; Y0 = Y1 = (int)Y; Z0 = Z1 = (int)Z; area_started = area; ++phase; - } break; - case 1 : - if (area==area_started) { - X1 = (int)X; Y1 = (int)Y; Z1 = (int)Z; ++phase; - if (_depth>1) { - if (disp.is_keyCTRLLEFT()) is_deep_selection = !is_deep_selection_default; - if (is_deep_selection) ++phase; - } - } else if (!b1) { X = (float)X0; Y = (float)Y0; Z = (float)Z0; phase = 0; visu0.assign(); } - break; - case 2 : ++phase; break; - } - } break; - - case 4 : // When mouse is over the 3D view - if (is_view3d && points3d) { - X3d = mx - width()*disp.width()/(width() + (depth()>1?depth():0)); - Y3d = my - height()*disp.height()/(height() + (depth()>1?depth():0)); - if (oX3d<0) { oX3d = X3d; oY3d = Y3d; } - // Left + right buttons: reset. - if ((disp.button()&3)==3) { pose3d.assign(); view3d.assign(); oX3d = oY3d = X3d = Y3d = -1; } - else if (disp.button()&1 && pose3d && (oX3d!=X3d || oY3d!=Y3d)) { // Left button: rotate - const float - R = 0.45f*std::min(view3d._width,view3d._height), - R2 = R*R, - u0 = (float)(oX3d - view3d.width()/2), - v0 = (float)(oY3d - view3d.height()/2), - u1 = (float)(X3d - view3d.width()/2), - v1 = (float)(Y3d - view3d.height()/2), - n0 = cimg::hypot(u0,v0), - n1 = cimg::hypot(u1,v1), - nu0 = n0>R?(u0*R/n0):u0, - nv0 = n0>R?(v0*R/n0):v0, - nw0 = (float)std::sqrt(std::max(0.f,R2 - nu0*nu0 - nv0*nv0)), - nu1 = n1>R?(u1*R/n1):u1, - nv1 = n1>R?(v1*R/n1):v1, - nw1 = (float)std::sqrt(std::max(0.f,R2 - nu1*nu1 - nv1*nv1)), - u = nv0*nw1 - nw0*nv1, - v = nw0*nu1 - nu0*nw1, - w = nv0*nu1 - nu0*nv1, - n = cimg::hypot(u,v,w), - alpha = (float)std::asin(n/R2)*180/cimg::PI; - pose3d.draw_image(CImg::rotation_matrix(u,v,w,-alpha)*pose3d.get_crop(0,0,2,2)); - view3d.assign(); - } else if (disp.button()&2 && pose3d && oY3d!=Y3d) { // Right button: zoom - pose3d(3,2)+=(Y3d - oY3d)*1.5f; view3d.assign(); - } - if (disp.wheel()) { // Wheel: zoom - pose3d(3,2)-=disp.wheel()*15; view3d.assign(); disp.set_wheel(); - } - if (disp.button()&4 && pose3d && (oX3d!=X3d || oY3d!=Y3d)) { // Middle button: shift - pose3d(3,0)-=oX3d - X3d; pose3d(3,1)-=oY3d - Y3d; view3d.assign(); - } - oX3d = X3d; oY3d = Y3d; - } - mx = my = -1; X = Y = Z = -1; - break; - } - - if (phase) { - if (!feature_type) shape_selected = phase?true:false; - else { - if (_depth>1) shape_selected = (phase==3)?true:false; - else shape_selected = (phase==2)?true:false; - } - } - - if (X0<0) X0 = 0; - if (X0>=width()) X0 = width() - 1; - if (Y0<0) Y0 = 0; - if (Y0>=height()) Y0 = height() - 1; - if (Z0<0) Z0 = 0; - if (Z0>=depth()) Z0 = depth() - 1; - if (X1<1) X1 = 0; - if (X1>=width()) X1 = width() - 1; - if (Y1<0) Y1 = 0; - if (Y1>=height()) Y1 = height() - 1; - if (Z1<0) Z1 = 0; - if (Z1>=depth()) Z1 = depth() - 1; - - // Draw visualization image on the display - if (mx!=omx || my!=omy || !visu0 || (_depth>1 && !view3d)) { - - if (!visu0) { // Create image of projected planes - if (thumb) thumb._get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0); - else _get_select(disp,old_normalization,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0).move_to(visu0); - visu0.resize(disp); - view3d.assign(); - points3d.assign(); - } - - if (is_view3d && _depth>1 && !view3d) { // Create 3D view for volumetric images - const unsigned int - _x3d = (unsigned int)cimg::round((float)_width*visu0._width/(_width + _depth),1,1), - _y3d = (unsigned int)cimg::round((float)_height*visu0._height/(_height + _depth),1,1), - x3d = _x3d>=visu0._width?visu0._width - 1:_x3d, - y3d = _y3d>=visu0._height?visu0._height - 1:_y3d; - CImg(1,2,1,1,64,128).resize(visu0._width - x3d,visu0._height - y3d,1,visu0._spectrum,3). - move_to(view3d); - if (!points3d) { - get_projections3d(primitives3d,colors3d,phase?X1:X0,phase?Y1:Y0,phase?Z1:Z0,true).move_to(points3d); - points3d.append(CImg(8,3,1,1, - 0,_width - 1,_width - 1,0,0,_width - 1,_width - 1,0, - 0,0,_height - 1,_height - 1,0,0,_height - 1,_height - 1, - 0,0,0,0,_depth - 1,_depth - 1,_depth - 1,_depth - 1),'x'); - CImg::vector(12,13).move_to(primitives3d); CImg::vector(13,14).move_to(primitives3d); - CImg::vector(14,15).move_to(primitives3d); CImg::vector(15,12).move_to(primitives3d); - CImg::vector(16,17).move_to(primitives3d); CImg::vector(17,18).move_to(primitives3d); - CImg::vector(18,19).move_to(primitives3d); CImg::vector(19,16).move_to(primitives3d); - CImg::vector(12,16).move_to(primitives3d); CImg::vector(13,17).move_to(primitives3d); - CImg::vector(14,18).move_to(primitives3d); CImg::vector(15,19).move_to(primitives3d); - colors3d.insert(12,CImg::vector(255,255,255)); - opacities3d.assign(primitives3d.width(),1,1,1,0.5f); - if (!phase) { - opacities3d[0] = opacities3d[1] = opacities3d[2] = 0.8f; - sel_primitives3d.assign(); - sel_colors3d.assign(); - sel_opacities3d.assign(); - } else { - if (feature_type==2) { - points3d.append(CImg(8,3,1,1, - X0,X1,X1,X0,X0,X1,X1,X0, - Y0,Y0,Y1,Y1,Y0,Y0,Y1,Y1, - Z0,Z0,Z0,Z0,Z1,Z1,Z1,Z1),'x'); - sel_primitives3d.assign(); - CImg::vector(20,21).move_to(sel_primitives3d); - CImg::vector(21,22).move_to(sel_primitives3d); - CImg::vector(22,23).move_to(sel_primitives3d); - CImg::vector(23,20).move_to(sel_primitives3d); - CImg::vector(24,25).move_to(sel_primitives3d); - CImg::vector(25,26).move_to(sel_primitives3d); - CImg::vector(26,27).move_to(sel_primitives3d); - CImg::vector(27,24).move_to(sel_primitives3d); - CImg::vector(20,24).move_to(sel_primitives3d); - CImg::vector(21,25).move_to(sel_primitives3d); - CImg::vector(22,26).move_to(sel_primitives3d); - CImg::vector(23,27).move_to(sel_primitives3d); - } else { - points3d.append(CImg(2,3,1,1, - X0,X1, - Y0,Y1, - Z0,Z1),'x'); - sel_primitives3d.assign(CImg::vector(20,21)); - } - sel_colors3d.assign(sel_primitives3d._width,CImg::vector(255,255,255)); - sel_opacities3d.assign(sel_primitives3d._width,1,1,1,0.8f); - } - points3d.shift_object3d(-0.5f*(_width - 1),-0.5f*(_height - 1),-0.5f*(_depth - 1)).resize_object3d(); - points3d*=0.75f*std::min(view3d._width,view3d._height); - } - - if (!pose3d) CImg(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0).move_to(pose3d); - CImg zbuffer3d(view3d._width,view3d._height,1,1,0); - const CImg rotated_points3d = pose3d.get_crop(0,0,2,2)*points3d; - if (sel_primitives3d) - view3d.draw_object3d(pose3d(3,0) + 0.5f*view3d._width, - pose3d(3,1) + 0.5f*view3d._height, - pose3d(3,2), - rotated_points3d,sel_primitives3d,sel_colors3d,sel_opacities3d, - 2,true,500,0,0,0,0,0,1,zbuffer3d); - view3d.draw_object3d(pose3d(3,0) + 0.5f*view3d._width, - pose3d(3,1) + 0.5f*view3d._height, - pose3d(3,2), - rotated_points3d,primitives3d,colors3d,opacities3d, - 2,true,500,0,0,0,0,0,1,zbuffer3d); - visu0.draw_image(x3d,y3d,view3d); - } - visu = visu0; - - if (X<0 || Y<0 || Z<0) { if (!visible_cursor) { disp.show_mouse(); visible_cursor = true; }} - else { - if (is_axes) { if (visible_cursor) { disp.hide_mouse(); visible_cursor = false; }} - else { if (!visible_cursor) { disp.show_mouse(); visible_cursor = true; }} - const int d = (depth()>1)?depth():0; - int _vX = (int)X, _vY = (int)Y, _vZ = (int)Z; - if (phase>=2) { _vX = X1; _vY = Y1; _vZ = Z1; } - int - w = disp.width(), W = width() + d, - h = disp.height(), H = height() + d, - _xp = (int)(_vX*(float)w/W), xp = _xp + ((int)(_xp*(float)W/w)!=_vX), - _yp = (int)(_vY*(float)h/H), yp = _yp + ((int)(_yp*(float)H/h)!=_vY), - _xn = (int)((_vX + 1.f)*w/W - 1), xn = _xn + ((int)((_xn + 1.f)*W/w)!=_vX + 1), - _yn = (int)((_vY + 1.f)*h/H - 1), yn = _yn + ((int)((_yn + 1.f)*H/h)!=_vY + 1), - _zxp = (int)((_vZ + width())*(float)w/W), zxp = _zxp + ((int)(_zxp*(float)W/w)!=_vZ + width()), - _zyp = (int)((_vZ + height())*(float)h/H), zyp = _zyp + ((int)(_zyp*(float)H/h)!=_vZ + height()), - _zxn = (int)((_vZ + width() + 1.f)*w/W - 1), - zxn = _zxn + ((int)((_zxn + 1.f)*W/w)!=_vZ + width() + 1), - _zyn = (int)((_vZ + height() + 1.f)*h/H - 1), - zyn = _zyn + ((int)((_zyn + 1.f)*H/h)!=_vZ + height() + 1), - _xM = (int)(width()*(float)w/W - 1), xM = _xM + ((int)((_xM + 1.f)*W/w)!=width()), - _yM = (int)(height()*(float)h/H - 1), yM = _yM + ((int)((_yM + 1.f)*H/h)!=height()), - xc = (xp + xn)/2, - yc = (yp + yn)/2, - zxc = (zxp + zxn)/2, - zyc = (zyp + zyn)/2, - xf = (int)(X*w/W), - yf = (int)(Y*h/H), - zxf = (int)((Z + width())*w/W), - zyf = (int)((Z + height())*h/H); - - if (is_axes) { // Draw axes - visu.draw_line(0,yf,visu.width() - 1,yf,foreground_color,0.7f,0xFF00FF00). - draw_line(0,yf,visu.width() - 1,yf,background_color,0.7f,0x00FF00FF). - draw_line(xf,0,xf,visu.height() - 1,foreground_color,0.7f,0xFF00FF00). - draw_line(xf,0,xf,visu.height() - 1,background_color,0.7f,0x00FF00FF); - if (_depth>1) - visu.draw_line(zxf,0,zxf,yM,foreground_color,0.7f,0xFF00FF00). - draw_line(zxf,0,zxf,yM,background_color,0.7f,0x00FF00FF). - draw_line(0,zyf,xM,zyf,foreground_color,0.7f,0xFF00FF00). - draw_line(0,zyf,xM,zyf,background_color,0.7f,0x00FF00FF); - } - - // Draw box cursor. - if (xn - xp>=4 && yn - yp>=4) - visu.draw_rectangle(xp,yp,xn,yn,foreground_color,0.2f). - draw_rectangle(xp,yp,xn,yn,foreground_color,1,0xAAAAAAAA). - draw_rectangle(xp,yp,xn,yn,background_color,1,0x55555555); - if (_depth>1) { - if (yn - yp>=4 && zxn - zxp>=4) - visu.draw_rectangle(zxp,yp,zxn,yn,background_color,0.2f). - draw_rectangle(zxp,yp,zxn,yn,foreground_color,1,0xAAAAAAAA). - draw_rectangle(zxp,yp,zxn,yn,background_color,1,0x55555555); - if (xn - xp>=4 && zyn - zyp>=4) - visu.draw_rectangle(xp,zyp,xn,zyn,background_color,0.2f). - draw_rectangle(xp,zyp,xn,zyn,foreground_color,1,0xAAAAAAAA). - draw_rectangle(xp,zyp,xn,zyn,background_color,1,0x55555555); - } - - // Draw selection. - if (phase && (phase!=1 || area_started==area)) { - const int - _xp0 = (int)(X0*(float)w/W), xp0 = _xp0 + ((int)(_xp0*(float)W/w)!=X0), - _yp0 = (int)(Y0*(float)h/H), yp0 = _yp0 + ((int)(_yp0*(float)H/h)!=Y0), - _xn0 = (int)((X0 + 1.f)*w/W - 1), xn0 = _xn0 + ((int)((_xn0 + 1.f)*W/w)!=X0 + 1), - _yn0 = (int)((Y0 + 1.f)*h/H - 1), yn0 = _yn0 + ((int)((_yn0 + 1.f)*H/h)!=Y0 + 1), - _zxp0 = (int)((Z0 + width())*(float)w/W), zxp0 = _zxp0 + ((int)(_zxp0*(float)W/w)!=Z0 + width()), - _zyp0 = (int)((Z0 + height())*(float)h/H), zyp0 = _zyp0 + ((int)(_zyp0*(float)H/h)!=Z0 + height()), - _zxn0 = (int)((Z0 + width() + 1.f)*w/W - 1), - zxn0 = _zxn0 + ((int)((_zxn0 + 1.f)*W/w)!=Z0 + width() + 1), - _zyn0 = (int)((Z0 + height() + 1.f)*h/H - 1), - zyn0 = _zyn0 + ((int)((_zyn0 + 1.f)*H/h)!=Z0 + height() + 1), - xc0 = (xp0 + xn0)/2, - yc0 = (yp0 + yn0)/2, - zxc0 = (zxp0 + zxn0)/2, - zyc0 = (zyp0 + zyn0)/2; - - switch (feature_type) { - case 1 : { // Vector - visu.draw_arrow(xc0,yc0,xc,yc,background_color,0.9f,30,5,0x33333333). - draw_arrow(xc0,yc0,xc,yc,foreground_color,0.9f,30,5,0xCCCCCCCC); - if (d) { - visu.draw_arrow(zxc0,yc0,zxc,yc,background_color,0.9f,30,5,0x33333333). - draw_arrow(zxc0,yc0,zxc,yc,foreground_color,0.9f,30,5,0xCCCCCCCC). - draw_arrow(xc0,zyc0,xc,zyc,background_color,0.9f,30,5,0x33333333). - draw_arrow(xc0,zyc0,xc,zyc,foreground_color,0.9f,30,5,0xCCCCCCCC); - } - } break; - case 2 : { // Box - visu.draw_rectangle(X0=0 && my<13) text_down = true; else if (my>=visu.height() - 13) text_down = false; - if (!feature_type || !phase) { - if (X>=0 && Y>=0 && Z>=0 && X1 || force_display_z_coord) - cimg_snprintf(text,text._width," Point (%d,%d,%d) = [ ",origX + (int)X,origY + (int)Y,origZ + (int)Z); - else cimg_snprintf(text,text._width," Point (%d,%d) = [ ",origX + (int)X,origY + (int)Y); - CImg values = get_vector_at((int)X,(int)Y,(int)Z); - const bool is_large_spectrum = values._height>8; - if (is_large_spectrum) - values.draw_image(0,4,values.get_rows(values._height - 4,values._height - 1)).resize(1,8,1,1,0); - char *ctext = text._data + std::strlen(text), *const ltext = text._data + 512; - for (unsigned int c = 0; c::format_s(), - cimg::type::format(values[c])); - ctext += std::strlen(ctext); - if (c==3 && is_large_spectrum) { - cimg_snprintf(ctext,24," ..."); - ctext += std::strlen(ctext); - } - *(ctext++) = ' '; *ctext = 0; - } - std::strcpy(text._data + std::strlen(text),"] "); - } - } else switch (feature_type) { - case 1 : { - const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1), - length = cimg::round(cimg::hypot(dX,dY,dZ),0.1); - if (_depth>1 || force_display_z_coord) - cimg_snprintf(text,text._width," Vect (%d,%d,%d)-(%d,%d,%d), Length = %g ", - origX + X0,origY + Y0,origZ + Z0,origX + X1,origY + Y1,origZ + Z1,length); - else if (_width!=1 && _height!=1) - cimg_snprintf(text,text._width," Vect (%d,%d)-(%d,%d), Length = %g, Angle = %g\260 ", - origX + X0,origY + Y0,origX + X1,origY + Y1,length, - cimg::round(cimg::mod(180*std::atan2(-dY,-dX)/cimg::PI,360.),0.1)); - else - cimg_snprintf(text,text._width," Vect (%d,%d)-(%d,%d), Length = %g ", - origX + X0,origY + Y0,origX + X1,origY + Y1,length); - } break; - case 2 : { - const double dX = (double)(X0 - X1), dY = (double)(Y0 - Y1), dZ = (double)(Z0 - Z1), - length = cimg::round(cimg::hypot(dX,dY,dZ),0.1); - if (_depth>1 || force_display_z_coord) - cimg_snprintf(text,text._width, - " Box ( %d,%d,%d ) - ( %d,%d,%d )\n Size = ( %d,%d,%d ), Length = %g ", - origX + (X01 || force_display_z_coord) - cimg_snprintf(text,text._width," Ellipse ( %d,%d,%d ) - ( %d,%d,%d ), Radii = ( %d,%d,%d ) ", - origX + X0,origY + Y0,origZ + Z0,origX + X1,origY + Y1,origZ + Z1, - 1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1),1 + cimg::abs(Z0 - Z1)); - else cimg_snprintf(text,text._width," Ellipse ( %d,%d ) - ( %d,%d ), Radii = ( %d,%d ) ", - origX + X0,origY + Y0,origX + X1,origY + Y1, - 1 + cimg::abs(X0 - X1),1 + cimg::abs(Y0 - Y1)); - } - if (phase || (mx>=0 && my>=0)) visu.__draw_text("%s",font_size,(int)text_down,text._data); - } - - disp.display(visu); - } - if (!shape_selected) disp.wait(); - if (disp.is_resized()) { disp.resize(false)._is_resized = false; old_is_resized = true; visu0.assign(); } - omx = mx; omy = my; - if (!exit_on_anykey && key && key!=cimg::keyESC && - (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { - key = 0; - } - } - - // Return result. - CImg res(1,feature_type==0?3:6,1,1,-1); - if (XYZ) { XYZ[0] = (unsigned int)X0; XYZ[1] = (unsigned int)Y0; XYZ[2] = (unsigned int)Z0; } - if (shape_selected) { - if (feature_type==2) { - if (is_deep_selection) switch (area_started) { - case 1 : Z0 = 0; Z1 = _depth - 1; break; - case 2 : Y0 = 0; Y1 = _height - 1; break; - case 3 : X0 = 0; X1 = _width - 1; break; - } - if (X0>X1) cimg::swap(X0,X1); - if (Y0>Y1) cimg::swap(Y0,Y1); - if (Z0>Z1) cimg::swap(Z0,Z1); - } - if (X1<0 || Y1<0 || Z1<0) X0 = Y0 = Z0 = X1 = Y1 = Z1 = -1; - switch (feature_type) { - case 1 : case 2 : res[0] = X0; res[1] = Y0; res[2] = Z0; res[3] = X1; res[4] = Y1; res[5] = Z1; break; - case 3 : - res[3] = cimg::abs(X1 - X0); res[4] = cimg::abs(Y1 - Y0); res[5] = cimg::abs(Z1 - Z0); - res[0] = X0; res[1] = Y0; res[2] = Z0; - break; - default : res[0] = X0; res[1] = Y0; res[2] = Z0; - } - } - if (!exit_on_anykey || !(disp.button()&4)) disp.set_button(); - if (!visible_cursor) disp.show_mouse(); - disp._normalization = old_normalization; - disp._is_resized = old_is_resized; - if (key!=~0U) disp.set_key(key); - return res; - } - - // Return a visualizable uchar8 image for display routines. - CImg _get_select(const CImgDisplay& disp, const int normalization, - const int x, const int y, const int z) const { - if (is_empty()) return CImg(1,1,1,1,0); - const CImg crop = get_shared_channels(0,std::min(2,spectrum() - 1)); - CImg img2d; - if (_depth>1) { - const int mdisp = std::min(disp.screen_width(),disp.screen_height()); - if (depth()>mdisp) { - crop.get_resize(-100,-100,mdisp,-100,0).move_to(img2d); - img2d.projections2d(x,y,z*img2d._depth/_depth); - } else crop.get_projections2d(x,y,z).move_to(img2d); - } else CImg(crop,false).move_to(img2d); - - // Check for inf and NaN values. - if (cimg::type::is_float() && normalization) { - bool is_inf = false, is_nan = false; - cimg_for(img2d,ptr,Tuchar) - if (cimg::type::is_inf(*ptr)) { is_inf = true; break; } - else if (cimg::type::is_nan(*ptr)) { is_nan = true; break; } - if (is_inf || is_nan) { - Tint m0 = (Tint)cimg::type::max(), M0 = (Tint)cimg::type::min(); - if (!normalization) { m0 = 0; M0 = 255; } - else if (normalization==2) { m0 = (Tint)disp._min; M0 = (Tint)disp._max; } - else { - cimg_for(img2d,ptr,Tuchar) - if (!cimg::type::is_inf(*ptr) && !cimg::type::is_nan(*ptr)) { - if (*ptr<(Tuchar)m0) m0 = *ptr; - if (*ptr>(Tuchar)M0) M0 = *ptr; - } - } - const T - val_minf = (T)(normalization==1 || normalization==3?m0 - cimg::abs(m0):m0), - val_pinf = (T)(normalization==1 || normalization==3?M0 + cimg::abs(M0):M0); - if (is_nan) - cimg_for(img2d,ptr,Tuchar) - if (cimg::type::is_nan(*ptr)) *ptr = val_minf; // Replace NaN values - if (is_inf) - cimg_for(img2d,ptr,Tuchar) - if (cimg::type::is_inf(*ptr)) *ptr = (float)*ptr<0?val_minf:val_pinf; // Replace +-inf values - } - } - - switch (normalization) { - case 1 : img2d.normalize((ucharT)0,(ucharT)255); break; - case 2 : { - const float m = disp._min, M = disp._max; - (img2d-=m)*=255.f/(M - m>0?M - m:1); - } break; - case 3 : - if (cimg::type::is_float()) img2d.normalize((ucharT)0,(ucharT)255); - else { - const float - m = (float)cimg::type::min(), - M = (float)cimg::type::max(); - (img2d-=m)*=255.f/(M - m>0?M - m:1); - } break; - } - if (img2d.spectrum()==2) img2d.channels(0,2); - return img2d; - } - - //! Select sub-graph in a graph. - CImg get_select_graph(CImgDisplay &disp, - const unsigned int plot_type=1, const unsigned int vertex_type=1, - const char *const labelx=0, const double xmin=0, const double xmax=0, - const char *const labely=0, const double ymin=0, const double ymax=0, - const bool exit_on_anykey=false) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "select_graph(): Empty instance.", - cimg_instance); - if (!disp) disp.assign(cimg_fitscreen(CImgDisplay::screen_width()/2,CImgDisplay::screen_height()/2,1),0,0). - set_title("CImg<%s>",pixel_type()); - const ulongT siz = (ulongT)_width*_height*_depth; - const unsigned int old_normalization = disp.normalization(); - disp.show().set_button().set_wheel()._normalization = 0; - - double nymin = ymin, nymax = ymax, nxmin = xmin, nxmax = xmax; - if (nymin==nymax) { nymin = (Tfloat)min_max(nymax); const double dy = nymax - nymin; nymin-=dy/20; nymax+=dy/20; } - if (nymin==nymax) { --nymin; ++nymax; } - if (nxmin==nxmax && nxmin==0) { nxmin = 0; nxmax = siz - 1.; } - - static const unsigned char black[] = { 0, 0, 0 }, white[] = { 255, 255, 255 }, gray[] = { 220, 220, 220 }; - static const unsigned char gray2[] = { 110, 110, 110 }, ngray[] = { 35, 35, 35 }; - - CImg colormap(3,_spectrum); - if (_spectrum==1) { colormap[0] = colormap[1] = 120; colormap[2] = 200; } - else { - colormap(0,0) = 220; colormap(1,0) = 10; colormap(2,0) = 10; - if (_spectrum>1) { colormap(0,1) = 10; colormap(1,1) = 220; colormap(2,1) = 10; } - if (_spectrum>2) { colormap(0,2) = 10; colormap(1,2) = 10; colormap(2,2) = 220; } - if (_spectrum>3) { colormap(0,3) = 220; colormap(1,3) = 220; colormap(2,3) = 10; } - if (_spectrum>4) { colormap(0,4) = 220; colormap(1,4) = 10; colormap(2,4) = 220; } - if (_spectrum>5) { colormap(0,5) = 10; colormap(1,5) = 220; colormap(2,5) = 220; } - if (_spectrum>6) { - cimg_uint64 rng = 10; - cimg_for_inY(colormap,6,colormap.height()-1,k) { - colormap(0,k) = (unsigned char)(120 + cimg::rand(-100.f,100.f,&rng)); - colormap(1,k) = (unsigned char)(120 + cimg::rand(-100.f,100.f,&rng)); - colormap(2,k) = (unsigned char)(120 + cimg::rand(-100.f,100.f,&rng)); - } - } - } - - CImg visu0, visu, graph, text, axes; - int x0 = -1, x1 = -1, y0 = -1, y1 = -1, omouse_x = -2, omouse_y = -2; - const unsigned int one = plot_type==3?0U:1U; - unsigned int okey = 0, obutton = 0, font_size = 32; - CImg message(1024); - CImg_3x3(I,unsigned char); - - for (bool selected = false; !selected && !disp.is_closed() && !okey && !disp.wheel(); ) { - const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y(); - const unsigned int key = disp.key(), button = disp.button(); - - // Generate graph representation. - if (!visu0) { - visu0.assign(disp.width(),disp.height(),1,3,220); - const int gdimx = disp.width() - 32, gdimy = disp.height() - 32; - if (gdimx>0 && gdimy>0) { - graph.assign(gdimx,gdimy,1,3,255); - if (siz<32) { - if (siz>1) graph.draw_grid(gdimx/(float)(siz - one),gdimy/(float)(siz - one),0,0, - false,true,black,0.2f,0x33333333,0x33333333); - } else graph.draw_grid(-10,-10,0,0,false,true,black,0.2f,0x33333333,0x33333333); - cimg_forC(*this,c) - graph.draw_graph(get_shared_channel(c),&colormap(0,c),(plot_type!=3 || _spectrum==1)?1:0.6f, - plot_type,vertex_type,nymax,nymin); - - axes.assign(gdimx,gdimy,1,1,0); - const float - dx = (float)cimg::abs(nxmax - nxmin), dy = (float)cimg::abs(nymax - nymin), - px = (float)std::pow(10.,(int)std::log10(dx?dx:1) - 2.), - py = (float)std::pow(10.,(int)std::log10(dy?dy:1) - 2.); - const CImg - seqx = dx<=0?CImg::vector(nxmin): - CImg::sequence(1 + gdimx/60,nxmin,one?nxmax:nxmin + (nxmax - nxmin)*(siz + 1)/siz), - seqy = CImg::sequence(1 + gdimy/60,nymax,nymin); - - const bool allow_zero = (nxmin*nxmax>0) || (nymin*nymax>0); - axes.draw_axes(seqx,seqy,white,1,~0U,~0U,13,allow_zero,px,py); - if (nymin>0) axes.draw_axis(seqx,gdimy - 1,gray,1,~0U,13,allow_zero,px); - if (nymax<0) axes.draw_axis(seqx,0,gray,1,~0U,13,allow_zero,px); - if (nxmin>0) axes.draw_axis(0,seqy,gray,1,~0U,13,allow_zero,py); - if (nxmax<0) axes.draw_axis(gdimx - 1,seqy,gray,1,~0U,13,allow_zero,py); - - cimg_for3x3(axes,x,y,0,0,I,unsigned char) - if (Icc) { - if (Icc==255) cimg_forC(graph,c) graph(x,y,c) = 0; - else cimg_forC(graph,c) graph(x,y,c) = (unsigned char)(2*graph(x,y,c)/3); - } - else if (Ipc || Inc || Icp || Icn || Ipp || Inn || Ipn || Inp) - cimg_forC(graph,c) graph(x,y,c) = (unsigned char)((graph(x,y,c) + 511)/3); - - visu0.draw_image(16,16,graph); - visu0.draw_line(15,15,16 + gdimx,15,gray2).draw_line(16 + gdimx,15,16 + gdimx,16 + gdimy,gray2). - draw_line(16 + gdimx,16 + gdimy,15,16 + gdimy,white).draw_line(15,16 + gdimy,15,15,white); - } else graph.assign(); - text.assign().draw_text(0,0,labelx?labelx:"X-axis",white,ngray,1,13).resize(-100,-100,1,3); - visu0.draw_image((visu0.width() - text.width())/2,visu0.height() - 14,~text); - text.assign().draw_text(0,0,labely?labely:"Y-axis",white,ngray,1,13).rotate(-90).resize(-100,-100,1,3); - visu0.draw_image(1,(visu0.height() - text.height())/2,~text); - visu.assign(); - } - - // Generate and display current view. - if (!visu) { - visu.assign(visu0); - if (graph && x0>=0 && x1>=0) { - const int - nx0 = x0<=x1?x0:x1, - nx1 = x0<=x1?x1:x0, - ny0 = y0<=y1?y0:y1, - ny1 = y0<=y1?y1:y0, - sx0 = (int)(16 + nx0*(visu.width() - 32)/std::max((ulongT)1,siz - one)), - sx1 = (int)(15 + (nx1 + 1)*(visu.width() - 32)/std::max((ulongT)1,siz - one)), - sy0 = 16 + ny0, - sy1 = 16 + ny1; - if (y0>=0 && y1>=0) - visu.draw_rectangle(sx0,sy0,sx1,sy1,gray,0.5f).draw_rectangle(sx0,sy0,sx1,sy1,black,0.5f,0xCCCCCCCCU); - else visu.draw_rectangle(sx0,0,sx1,visu.height() - 17,gray,0.5f). - draw_line(sx0,16,sx0,visu.height() - 17,black,0.5f,0xCCCCCCCCU). - draw_line(sx1,16,sx1,visu.height() - 17,black,0.5f,0xCCCCCCCCU); - } - if (mouse_x>=16 && mouse_y>=16 && mouse_x=7) - cimg_snprintf(message,message._width,"Value[%u:%g] = ( %g %g %g ... %g %g %g )",x,cx, - (double)(*this)(x,0,0,0),(double)(*this)(x,0,0,1),(double)(*this)(x,0,0,2), - (double)(*this)(x,0,0,_spectrum - 4),(double)(*this)(x,0,0,_spectrum - 3), - (double)(*this)(x,0,0,_spectrum - 1)); - else { - cimg_snprintf(message,message._width,"Value[%u:%g] = ( ",x,cx); - cimg_forC(*this,c) cimg_sprintf(message._data + std::strlen(message),"%g ",(double)(*this)(x,0,0,c)); - cimg_sprintf(message._data + std::strlen(message),")"); - } - if (x0>=0 && x1>=0) { - const unsigned int - nx0 = (unsigned int)(x0<=x1?x0:x1), - nx1 = (unsigned int)(x0<=x1?x1:x0), - ny0 = (unsigned int)(y0<=y1?y0:y1), - ny1 = (unsigned int)(y0<=y1?y1:y0); - const double - cx0 = nxmin + nx0*(nxmax - nxmin)/std::max((ulongT)1,siz - 1), - cx1 = nxmin + (nx1 + one)*(nxmax - nxmin)/std::max((ulongT)1,siz - 1), - cy0 = nymax - ny0*(nymax - nymin)/(visu._height - 32), - cy1 = nymax - ny1*(nymax - nymin)/(visu._height - 32); - if (y0>=0 && y1>=0) - cimg_sprintf(message._data + std::strlen(message)," - Range ( %u:%g, %g ) - ( %u:%g, %g )", - x0,cx0,cy0,x1 + one,cx1,cy1); - else - cimg_sprintf(message._data + std::strlen(message)," - Range [ %u:%g - %u:%g ]", - x0,cx0,x1 + one,cx1); - } - text.assign().draw_text(0,0,message,white,ngray,1,13).resize(-100,-100,1,3); - visu.draw_image((visu.width() - text.width())/2,1,~text); - } - visu.display(disp); - } - - // Test keys. - CImg filename(32); - switch (okey = key) { -#if cimg_OS!=2 - case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT : -#endif - case cimg::keyCTRLLEFT : case cimg::keySHIFTLEFT : okey = 0; break; - case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), - CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false). - _is_resized = true; - disp.set_key(key,false); okey = 0; - } break; - case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true; - disp.set_key(key,false); okey = 0; - } break; - case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(cimg_fitscreen(CImgDisplay::screen_width()/2, - CImgDisplay::screen_height()/2,1),false)._is_resized = true; - disp.set_key(key,false); okey = 0; - } break; - case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen()._is_resized = true; - disp.set_key(key,false); okey = 0; - } break; - case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - static unsigned int snap_number = 0; - if (visu || visu0) { - CImg &screen = visu?visu:visu0; - std::FILE *file; - do { - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++); - if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file); - } while (file); - (+screen).__draw_text(" Saving snapshot... ",font_size,0).display(disp); - screen.save(filename); - (+screen).__draw_text(" Snapshot '%s' saved. ",font_size,0,filename._data).display(disp); - } - disp.set_key(key,false); okey = 0; - } break; - case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - static unsigned int snap_number = 0; - if (visu || visu0) { - CImg &screen = visu?visu:visu0; - std::FILE *file; - do { - -#ifdef cimg_use_zlib - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++); -#else - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++); -#endif - if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file); - } while (file); - (+screen).__draw_text(" Saving instance... ",font_size,0).display(disp); - save(filename); - (+screen).__draw_text(" Instance '%s' saved. ",font_size,0,filename._data).display(disp); - } - disp.set_key(key,false); okey = 0; - } break; - } - - // Handle mouse motion and mouse buttons. - if (obutton!=button || omouse_x!=mouse_x || omouse_y!=mouse_y) { - visu.assign(); - if (disp.mouse_x()>=0 && disp.mouse_y()>=0) { - const int - mx = (mouse_x - 16)*(int)(siz - one)/(disp.width() - 32), - cx = cimg::cut(mx,0,(int)(siz - 1 - one)), - my = mouse_y - 16, - cy = cimg::cut(my,0,disp.height() - 32); - if (button&1) { - if (!obutton) { x0 = cx; y0 = -1; } else { x1 = cx; y1 = -1; } - } - else if (button&2) { - if (!obutton) { x0 = cx; y0 = cy; } else { x1 = cx; y1 = cy; } - } - else if (obutton) { x1 = x1>=0?cx:-1; y1 = y1>=0?cy:-1; selected = true; } - } else if (!button && obutton) selected = true; - obutton = button; omouse_x = mouse_x; omouse_y = mouse_y; - } - if (disp.is_resized()) { disp.resize(false); visu0.assign(); } - if (visu && visu0) disp.wait(); - if (!exit_on_anykey && okey && okey!=cimg::keyESC && - (okey!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { - disp.set_key(key,false); - okey = 0; - } - } - - disp._normalization = old_normalization; - if (x1>=0 && x1(4,1,1,1,x0,y0,x1>=0?x1 + (int)one:-1,y1); - } - - //! Load image from a file. - /** - \param filename Filename, as a C-string. - \note The extension of \c filename defines the file format. If no filename - extension is provided, CImg::get_load() will try to load the file as a .cimg or .cimgz file. - **/ - CImg& load(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimg_instance - "load(): Specified filename is (null).", - cimg_instance); - - if (!cimg::strncasecmp(filename,"http://",7) || !cimg::strncasecmp(filename,"https://",8)) { - CImg filename_local(256); - load(cimg::load_network(filename,filename_local)); - std::remove(filename_local); - return *this; - } - - const char *const ext = cimg::split_filename(filename); - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - bool is_loaded = true; - try { -#ifdef cimg_load_plugin - cimg_load_plugin(filename); -#endif -#ifdef cimg_load_plugin1 - cimg_load_plugin1(filename); -#endif -#ifdef cimg_load_plugin2 - cimg_load_plugin2(filename); -#endif -#ifdef cimg_load_plugin3 - cimg_load_plugin3(filename); -#endif -#ifdef cimg_load_plugin4 - cimg_load_plugin4(filename); -#endif -#ifdef cimg_load_plugin5 - cimg_load_plugin5(filename); -#endif -#ifdef cimg_load_plugin6 - cimg_load_plugin6(filename); -#endif -#ifdef cimg_load_plugin7 - cimg_load_plugin7(filename); -#endif -#ifdef cimg_load_plugin8 - cimg_load_plugin8(filename); -#endif - // Text formats - if (!cimg::strcasecmp(ext,"asc")) load_ascii(filename); - else if (!cimg::strcasecmp(ext,"csv") || - !cimg::strcasecmp(ext,"dlm") || - !cimg::strcasecmp(ext,"txt")) load_dlm(filename); - else if (!cimg::strcasecmp(ext,"pdf")) load_pdf_external(filename); - - // 2D binary formats - else if (!cimg::strcasecmp(ext,"bmp")) load_bmp(filename); - else if (!cimg::strcasecmp(ext,"jpg") || - !cimg::strcasecmp(ext,"jpeg") || - !cimg::strcasecmp(ext,"jpe") || - !cimg::strcasecmp(ext,"jfif") || - !cimg::strcasecmp(ext,"jif")) load_jpeg(filename); - else if (!cimg::strcasecmp(ext,"png")) load_png(filename); - else if (!cimg::strcasecmp(ext,"ppm") || - !cimg::strcasecmp(ext,"pgm") || - !cimg::strcasecmp(ext,"pnm") || - !cimg::strcasecmp(ext,"pbm") || - !cimg::strcasecmp(ext,"pnk")) load_pnm(filename); - else if (!cimg::strcasecmp(ext,"pfm")) load_pfm(filename); - else if (!cimg::strcasecmp(ext,"tif") || - !cimg::strcasecmp(ext,"tiff")) load_tiff(filename); - else if (!cimg::strcasecmp(ext,"exr")) load_exr(filename); - else if (!cimg::strcasecmp(ext,"arw") || - !cimg::strcasecmp(ext,"cr2") || - !cimg::strcasecmp(ext,"crw") || - !cimg::strcasecmp(ext,"dcr") || - !cimg::strcasecmp(ext,"dng") || - !cimg::strcasecmp(ext,"mrw") || - !cimg::strcasecmp(ext,"nef") || - !cimg::strcasecmp(ext,"orf") || - !cimg::strcasecmp(ext,"pix") || - !cimg::strcasecmp(ext,"ptx") || - !cimg::strcasecmp(ext,"raf") || - !cimg::strcasecmp(ext,"srf")) load_dcraw_external(filename); - else if (!cimg::strcasecmp(ext,"gif")) load_gif_external(filename); - else if (!cimg::strcasecmp(ext,"heic") || - !cimg::strcasecmp(ext,"avif")) load_heif(filename); - - // 3D binary formats - else if (!cimg::strcasecmp(ext,"dcm") || - !cimg::strcasecmp(ext,"dicom")) load_medcon_external(filename); - else if (!cimg::strcasecmp(ext,"hdr") || - !cimg::strcasecmp(ext,"nii")) load_analyze(filename); - else if (!cimg::strcasecmp(ext,"par") || - !cimg::strcasecmp(ext,"rec")) load_parrec(filename); - else if (!cimg::strcasecmp(ext,"mnc")) load_minc2(filename); - else if (!cimg::strcasecmp(ext,"inr")) load_inr(filename); - else if (!cimg::strcasecmp(ext,"pan")) load_pandore(filename); - else if (!cimg::strcasecmp(ext,"cimg") || - !cimg::strcasecmp(ext,"cimgz") || - !*ext) return load_cimg(filename); - - // Archive files - else if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename); - - // Image sequences - else if (!cimg::strcasecmp(ext,"avi") || - !cimg::strcasecmp(ext,"mov") || - !cimg::strcasecmp(ext,"asf") || - !cimg::strcasecmp(ext,"divx") || - !cimg::strcasecmp(ext,"flv") || - !cimg::strcasecmp(ext,"mpg") || - !cimg::strcasecmp(ext,"m1v") || - !cimg::strcasecmp(ext,"m2v") || - !cimg::strcasecmp(ext,"m4v") || - !cimg::strcasecmp(ext,"mjp") || - !cimg::strcasecmp(ext,"mp4") || - !cimg::strcasecmp(ext,"mkv") || - !cimg::strcasecmp(ext,"mpe") || - !cimg::strcasecmp(ext,"movie") || - !cimg::strcasecmp(ext,"ogm") || - !cimg::strcasecmp(ext,"ogg") || - !cimg::strcasecmp(ext,"ogv") || - !cimg::strcasecmp(ext,"qt") || - !cimg::strcasecmp(ext,"rm") || - !cimg::strcasecmp(ext,"vob") || - !cimg::strcasecmp(ext,"webm") || - !cimg::strcasecmp(ext,"wmv") || - !cimg::strcasecmp(ext,"xvid") || - !cimg::strcasecmp(ext,"mpeg")) load_video(filename); - else is_loaded = false; - } catch (CImgIOException&) { is_loaded = false; } - - // If nothing loaded, try to guess file format from magic number in file. - if (!is_loaded) { - std::FILE *file = cimg::std_fopen(filename,"rb"); - if (!file) { - cimg::exception_mode(omode); - throw CImgIOException(_cimg_instance - "load(): Failed to open file '%s'.", - cimg_instance, - filename); - } - - const char *const f_type = cimg::ftype(file,filename); - cimg::fclose(file); - is_loaded = true; - try { - if (!cimg::strcasecmp(f_type,"pnm")) load_pnm(filename); - else if (!cimg::strcasecmp(f_type,"pfm")) load_pfm(filename); - else if (!cimg::strcasecmp(f_type,"bmp")) load_bmp(filename); - else if (!cimg::strcasecmp(f_type,"inr")) load_inr(filename); - else if (!cimg::strcasecmp(f_type,"jpg")) load_jpeg(filename); - else if (!cimg::strcasecmp(f_type,"pan")) load_pandore(filename); - else if (!cimg::strcasecmp(f_type,"png")) load_png(filename); - else if (!cimg::strcasecmp(f_type,"tif")) load_tiff(filename); - else if (!cimg::strcasecmp(f_type,"gif")) load_gif_external(filename); - else if (!cimg::strcasecmp(f_type,"dcm")) load_medcon_external(filename); - else is_loaded = false; - } catch (CImgIOException&) { is_loaded = false; } - } - - // If nothing loaded, try to load file with other means. - if (!is_loaded) { - try { - load_other(filename); - } catch (CImgIOException&) { - cimg::exception_mode(omode); - throw CImgIOException(_cimg_instance - "load(): Failed to recognize format of file '%s'.", - cimg_instance, - filename); - } - } - cimg::exception_mode(omode); - return *this; - } - - //! Load image from a file \newinstance. - static CImg get_load(const char *const filename) { - return CImg().load(filename); - } - - //! Load image from an ascii file. - /** - \param filename Filename, as a C -string. - **/ - CImg& load_ascii(const char *const filename) { - return _load_ascii(0,filename); - } - - //! Load image from an ascii file \inplace. - static CImg get_load_ascii(const char *const filename) { - return CImg().load_ascii(filename); - } - - //! Load image from an ascii file \overloading. - CImg& load_ascii(std::FILE *const file) { - return _load_ascii(file,0); - } - - //! Loadimage from an ascii file \newinstance. - static CImg get_load_ascii(std::FILE *const file) { - return CImg().load_ascii(file); - } - - CImg& _load_ascii(std::FILE *const file, const char *const filename) { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_ascii(): Specified filename is (null).", - cimg_instance); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - CImg line(256); *line = 0; - int err = std::fscanf(nfile,"%255[^\n]",line._data); - unsigned int dx = 0, dy = 1, dz = 1, dc = 1; - cimg_sscanf(line,"%u%*c%u%*c%u%*c%u",&dx,&dy,&dz,&dc); - err = std::fscanf(nfile,"%*[^0-9.eEinfa+-]"); - if (!dx || !dy || !dz || !dc) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_ascii(): Invalid ascii header in file '%s', image dimensions are set " - "to (%u,%u,%u,%u).", - cimg_instance, - filename?filename:"(FILE*)",dx,dy,dz,dc); - } - assign(dx,dy,dz,dc); - const ulongT siz = size(); - ulongT off = 0; - double val; - T *ptr = _data; - for (err = 1, off = 0; off& load_dlm(const char *const filename) { - return _load_dlm(0,filename); - } - - //! Load image from a DLM file \newinstance. - static CImg get_load_dlm(const char *const filename) { - return CImg().load_dlm(filename); - } - - //! Load image from a DLM file \overloading. - CImg& load_dlm(std::FILE *const file) { - return _load_dlm(file,0); - } - - //! Load image from a DLM file \newinstance. - static CImg get_load_dlm(std::FILE *const file) { - return CImg().load_dlm(file); - } - - CImg& _load_dlm(std::FILE *const file, const char *const filename) { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_dlm(): Specified filename is (null).", - cimg_instance); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"r"); - CImg delimiter(256), tmp(256); *delimiter = *tmp = 0; - unsigned int cdx = 0, dx = 0, dy = 0; - int err = 0; - double val; - assign(256,256,1,1,(T)0); - while ((err = std::fscanf(nfile,"%lf%255[^0-9eEinfa.+-]",&val,delimiter._data))>0) { - if (err>0) (*this)(cdx++,dy) = (T)val; - if (cdx>=_width) resize(3*_width/2,_height,1,1,0); - char c = 0; - if (!cimg_sscanf(delimiter,"%255[^\n]%c",tmp._data,&c) || c=='\n') { - dx = std::max(cdx,dx); - if (++dy>=_height) resize(_width,3*_height/2,1,1,0); - cdx = 0; - } - } - if (cdx && err==1) { dx = cdx; ++dy; } - if (!dx || !dy) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_dlm(): Invalid DLM file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - } - resize(dx,dy,1,1,0); - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Load image from a BMP file. - /** - \param filename Filename, as a C-string. - **/ - CImg& load_bmp(const char *const filename) { - return _load_bmp(0,filename); - } - - //! Load image from a BMP file \newinstance. - static CImg get_load_bmp(const char *const filename) { - return CImg().load_bmp(filename); - } - - //! Load image from a BMP file \overloading. - CImg& load_bmp(std::FILE *const file) { - return _load_bmp(file,0); - } - - //! Load image from a BMP file \newinstance. - static CImg get_load_bmp(std::FILE *const file) { - return CImg().load_bmp(file); - } - - CImg& _load_bmp(std::FILE *const file, const char *const filename) { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_bmp(): Specified filename is (null).", - cimg_instance); - - const ulongT fsiz = file?(ulongT)cimg_max_buf_size:(ulongT)cimg::fsize(filename); - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - CImg header(54); - cimg::fread(header._data,54,nfile); - if (*header!='B' || header[1]!='M') { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_bmp(): Invalid BMP file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - } - - // Read header and pixel buffer - int - file_size = header[0x02] + (header[0x03]<<8) + (header[0x04]<<16) + (header[0x05]<<24), - offset = header[0x0A] + (header[0x0B]<<8) + (header[0x0C]<<16) + (header[0x0D]<<24), - header_size = header[0x0E] + (header[0x0F]<<8) + (header[0x10]<<16) + (header[0x11]<<24), - dx = header[0x12] + (header[0x13]<<8) + (header[0x14]<<16) + (header[0x15]<<24), - dy = header[0x16] + (header[0x17]<<8) + (header[0x18]<<16) + (header[0x19]<<24), - compression = header[0x1E] + (header[0x1F]<<8) + (header[0x20]<<16) + (header[0x21]<<24), - nb_colors = header[0x2E] + (header[0x2F]<<8) + (header[0x30]<<16) + (header[0x31]<<24), - bpp = header[0x1C] + (header[0x1D]<<8); - - if (!file_size || file_size==offset) { - cimg::fseek(nfile,0,SEEK_END); - file_size = (int)cimg::ftell(nfile); - cimg::fseek(nfile,54,SEEK_SET); - } - if (header_size>40) cimg::fseek(nfile,header_size - 40,SEEK_CUR); - - const int - dx_bytes = (bpp==1)?(dx/8 + (dx%8?1:0)):((bpp==4)?(dx/2 + (dx%2)):(int)((longT)dx*bpp/8)), - align_bytes = (4 - dx_bytes%4)%4; - const ulongT - cimg_iobuffer = (ulongT)24*1024*1024, - buf_size = (ulongT)cimg::abs(dy)*(dx_bytes + align_bytes); - - if (buf_size>fsiz) - throw CImgIOException(_cimg_instance - "load_bmp(): File size %lu for filename '%s' does not match " - "encoded image dimensions (%d,%d).", - cimg_instance, - (long)fsiz,filename?filename:"(FILE*)",dx,dy); - - CImg colormap; - if (bpp<16) { if (!nb_colors) nb_colors = 1<0) cimg::fseek(nfile,xoffset,SEEK_CUR); - - CImg buffer; - if (buf_size=2) for (int y = height() - 1; y>=0; --y) { - if (buf_size>=cimg_iobuffer) { - if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break; - cimg::fseek(nfile,align_bytes,SEEK_CUR); - } - unsigned char mask = 0x80, val = 0; - cimg_forX(*this,x) { - if (mask==0x80) val = *(ptrs++); - const unsigned char *col = (unsigned char*)(colormap._data + (val&mask?1:0)); - (*this)(x,y,2) = (T)*(col++); - (*this)(x,y,1) = (T)*(col++); - (*this)(x,y,0) = (T)*(col++); - mask = cimg::ror(mask); - } - ptrs+=align_bytes; - } - } break; - case 4 : { // 16 colors - if (colormap._width>=16) for (int y = height() - 1; y>=0; --y) { - if (buf_size>=cimg_iobuffer) { - if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break; - cimg::fseek(nfile,align_bytes,SEEK_CUR); - } - unsigned char mask = 0xF0, val = 0; - cimg_forX(*this,x) { - if (mask==0xF0) val = *(ptrs++); - const unsigned char color = (unsigned char)((mask<16)?(val&mask):((val&mask)>>4)); - const unsigned char *col = (unsigned char*)(colormap._data + color); - (*this)(x,y,2) = (T)*(col++); - (*this)(x,y,1) = (T)*(col++); - (*this)(x,y,0) = (T)*(col++); - mask = cimg::ror(mask,4); - } - ptrs+=align_bytes; - } - } break; - case 8 : { // 256 colors - if (colormap._width>=256) for (int y = height() - 1; y>=0; --y) { - if (buf_size>=cimg_iobuffer) { - if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break; - cimg::fseek(nfile,align_bytes,SEEK_CUR); - } - cimg_forX(*this,x) { - const unsigned char *col = (unsigned char*)(colormap._data + *(ptrs++)); - (*this)(x,y,2) = (T)*(col++); - (*this)(x,y,1) = (T)*(col++); - (*this)(x,y,0) = (T)*(col++); - } - ptrs+=align_bytes; - } - } break; - case 16 : { // 16 bits colors (RGB565) - for (int y = height() - 1; y>=0; --y) { - if (buf_size>=cimg_iobuffer) { - if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break; - cimg::fseek(nfile,align_bytes,SEEK_CUR); - } - cimg_forX(*this,x) { - const unsigned char c1 = *(ptrs++), c2 = *(ptrs++); - const unsigned short col = (unsigned short)c2<<8 | c1; - (*this)(x,y,2) = (T)((col&0x1F)<<3); - (*this)(x,y,1) = (T)(((col>>5)&0x3F)<<3); - (*this)(x,y,0) = (T)(((col>>11)&0x1F)<<3); - } - ptrs+=align_bytes; - } - } break; - case 24 : { // 24 bits colors - for (int y = height() - 1; y>=0; --y) { - if (buf_size>=cimg_iobuffer) { - if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break; - cimg::fseek(nfile,align_bytes,SEEK_CUR); - } - cimg_forX(*this,x) { - (*this)(x,y,2) = (T)*(ptrs++); - (*this)(x,y,1) = (T)*(ptrs++); - (*this)(x,y,0) = (T)*(ptrs++); - } - ptrs+=align_bytes; - } - } break; - case 32 : { // 32 bits colors - for (int y = height() - 1; y>=0; --y) { - if (buf_size>=cimg_iobuffer) { - if (!cimg::fread(ptrs=buffer._data,dx_bytes,nfile)) break; - cimg::fseek(nfile,align_bytes,SEEK_CUR); - } - cimg_forX(*this,x) { - (*this)(x,y,2) = (T)*(ptrs++); - (*this)(x,y,1) = (T)*(ptrs++); - (*this)(x,y,0) = (T)*(ptrs++); - ++ptrs; - } - ptrs+=align_bytes; - } - } break; - } - if (dy<0) mirror('y'); - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Load image from a JPEG file. - /** - \param filename Filename, as a C-string. - **/ - CImg& load_jpeg(const char *const filename) { - return _load_jpeg(0,filename); - } - - //! Load image from a JPEG file \newinstance. - static CImg get_load_jpeg(const char *const filename) { - return CImg().load_jpeg(filename); - } - - //! Load image from a JPEG file \overloading. - CImg& load_jpeg(std::FILE *const file) { - return _load_jpeg(file,0); - } - - //! Load image from a JPEG file \newinstance. - static CImg get_load_jpeg(std::FILE *const file) { - return CImg().load_jpeg(file); - } - - // Custom error handler for libjpeg. -#ifdef cimg_use_jpeg - struct _cimg_error_mgr { - struct jpeg_error_mgr original; - jmp_buf setjmp_buffer; - char message[JMSG_LENGTH_MAX]; - }; - - typedef struct _cimg_error_mgr *_cimg_error_ptr; - - METHODDEF(void) _cimg_jpeg_error_exit(j_common_ptr cinfo) { - _cimg_error_ptr c_err = (_cimg_error_ptr) cinfo->err; // Return control to the setjmp point - (*cinfo->err->format_message)(cinfo,c_err->message); - jpeg_destroy(cinfo); // Clean memory and temp files - longjmp(c_err->setjmp_buffer,1); - } -#endif - - CImg& _load_jpeg(std::FILE *const file, const char *const filename) { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_jpeg(): Specified filename is (null).", - cimg_instance); - -#ifndef cimg_use_jpeg - if (file) - throw CImgIOException(_cimg_instance - "load_jpeg(): Unable to load data from '(FILE*)' unless libjpeg is enabled.", - cimg_instance); - else return load_other(filename); -#else - - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - struct jpeg_decompress_struct cinfo; - struct _cimg_error_mgr jerr; - cinfo.err = jpeg_std_error(&jerr.original); - jerr.original.error_exit = _cimg_jpeg_error_exit; - if (setjmp(jerr.setjmp_buffer)) { // JPEG error - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_jpeg(): Error message returned by libjpeg: %s.", - cimg_instance,jerr.message); - } - - jpeg_create_decompress(&cinfo); - jpeg_stdio_src(&cinfo,nfile); - jpeg_read_header(&cinfo,TRUE); - jpeg_start_decompress(&cinfo); - - if (cinfo.output_components!=1 && cinfo.output_components!=3 && cinfo.output_components!=4) { - if (!file) { - cimg::fclose(nfile); - return load_other(filename); - } else - throw CImgIOException(_cimg_instance - "load_jpeg(): Failed to load JPEG data from file '%s'.", - cimg_instance,filename?filename:"(FILE*)"); - } - CImg buffer(cinfo.output_width*cinfo.output_components); - JSAMPROW row_pointer[1]; - try { assign(cinfo.output_width,cinfo.output_height,1,cinfo.output_components); } - catch (...) { if (!file) cimg::fclose(nfile); throw; } - T *ptr_r = _data, *ptr_g = _data + 1UL*_width*_height, *ptr_b = _data + 2UL*_width*_height, - *ptr_a = _data + 3UL*_width*_height; - while (cinfo.output_scanline - // This is experimental code, not much tested, use with care. - CImg& load_magick(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimg_instance - "load_magick(): Specified filename is (null).", - cimg_instance); - -#ifdef cimg_use_magick - Magick::Image image(filename); - const unsigned int W = image.size().width(), H = image.size().height(); - switch (image.type()) { - case Magick::PaletteMatteType : - case Magick::TrueColorMatteType : - case Magick::ColorSeparationType : { - assign(W,H,1,4); - T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3); - Magick::PixelPacket *pixels = image.getPixels(0,0,W,H); - for (ulongT off = (ulongT)W*H; off; --off) { - *(ptr_r++) = (T)(pixels->red); - *(ptr_g++) = (T)(pixels->green); - *(ptr_b++) = (T)(pixels->blue); - *(ptr_a++) = (T)(pixels->opacity); - ++pixels; - } - } break; - case Magick::PaletteType : - case Magick::TrueColorType : { - assign(W,H,1,3); - T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); - Magick::PixelPacket *pixels = image.getPixels(0,0,W,H); - for (ulongT off = (ulongT)W*H; off; --off) { - *(ptr_r++) = (T)(pixels->red); - *(ptr_g++) = (T)(pixels->green); - *(ptr_b++) = (T)(pixels->blue); - ++pixels; - } - } break; - case Magick::GrayscaleMatteType : { - assign(W,H,1,2); - T *ptr_r = data(0,0,0,0), *ptr_a = data(0,0,0,1); - Magick::PixelPacket *pixels = image.getPixels(0,0,W,H); - for (ulongT off = (ulongT)W*H; off; --off) { - *(ptr_r++) = (T)(pixels->red); - *(ptr_a++) = (T)(pixels->opacity); - ++pixels; - } - } break; - default : { - assign(W,H,1,1); - T *ptr_r = data(0,0,0,0); - Magick::PixelPacket *pixels = image.getPixels(0,0,W,H); - for (ulongT off = (ulongT)W*H; off; --off) { - *(ptr_r++) = (T)(pixels->red); - ++pixels; - } - } - } - return *this; -#else - throw CImgIOException(_cimg_instance - "load_magick(): Unable to load file '%s' unless libMagick++ is enabled.", - cimg_instance, - filename); -#endif - } - - //! Load image from a file, using Magick++ library \newinstance. - static CImg get_load_magick(const char *const filename) { - return CImg().load_magick(filename); - } - - //! Load image from a PNG file. - /** - \param filename Filename, as a C-string. - \param[out] bits_per_value Number of bits used to store a scalar value in the image file. - **/ - CImg& load_png(const char *const filename, unsigned int *const bits_per_value=0) { - return _load_png(0,filename,bits_per_value); - } - - //! Load image from a PNG file \newinstance. - static CImg get_load_png(const char *const filename, unsigned int *const bits_per_value=0) { - return CImg().load_png(filename,bits_per_value); - } - - //! Load image from a PNG file \overloading. - CImg& load_png(std::FILE *const file, unsigned int *const bits_per_value=0) { - return _load_png(file,0,bits_per_value); - } - - //! Load image from a PNG file \newinstance. - static CImg get_load_png(std::FILE *const file, unsigned int *const bits_per_value=0) { - return CImg().load_png(file,bits_per_value); - } - - // (Note: Most of this function has been written by Eric Fausett) - CImg& _load_png(std::FILE *const file, const char *const filename, unsigned int *const bits_per_value) { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_png(): Specified filename is (null).", - cimg_instance); - -#ifndef cimg_use_png - cimg::unused(bits_per_value); - if (file) - throw CImgIOException(_cimg_instance - "load_png(): Unable to load data from '(FILE*)' unless libpng is enabled.", - cimg_instance); - - else return load_other(filename); -#else - // Open file and check for PNG validity -#if defined __GNUC__ - const char *volatile nfilename = filename; // Use 'volatile' to avoid (wrong) g++ warning - std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"rb"); -#else - const char *nfilename = filename; - std::FILE *nfile = file?file:cimg::fopen(nfilename,"rb"); -#endif - unsigned char pngCheck[8] = { 0 }; - cimg::fread(pngCheck,8,(std::FILE*)nfile); - if (png_sig_cmp(pngCheck,0,8)) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_png(): Invalid PNG file '%s'.", - cimg_instance, - nfilename?nfilename:"(FILE*)"); - } - - // Setup PNG structures for read - png_voidp user_error_ptr = 0; - png_error_ptr user_error_fn = 0, user_warning_fn = 0; - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,user_error_ptr,user_error_fn,user_warning_fn); - if (!png_ptr) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_png(): Failed to initialize 'png_ptr' structure for file '%s'.", - cimg_instance, - nfilename?nfilename:"(FILE*)"); - } - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - if (!file) cimg::fclose(nfile); - png_destroy_read_struct(&png_ptr,(png_infopp)0,(png_infopp)0); - throw CImgIOException(_cimg_instance - "load_png(): Failed to initialize 'info_ptr' structure for file '%s'.", - cimg_instance, - nfilename?nfilename:"(FILE*)"); - } - png_infop end_info = png_create_info_struct(png_ptr); - if (!end_info) { - if (!file) cimg::fclose(nfile); - png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)0); - throw CImgIOException(_cimg_instance - "load_png(): Failed to initialize 'end_info' structure for file '%s'.", - cimg_instance, - nfilename?nfilename:"(FILE*)"); - } - - // Error handling callback for png file reading - if (setjmp(png_jmpbuf(png_ptr))) { - if (!file) cimg::fclose((std::FILE*)nfile); - png_destroy_read_struct(&png_ptr, &end_info, (png_infopp)0); - throw CImgIOException(_cimg_instance - "load_png(): Encountered unknown fatal error in libpng for file '%s'.", - cimg_instance, - nfilename?nfilename:"(FILE*)"); - } - png_init_io(png_ptr, nfile); - png_set_sig_bytes(png_ptr, 8); - - // Get PNG Header Info up to data block - png_read_info(png_ptr,info_ptr); - png_uint_32 W, H; - int bit_depth, color_type, interlace_type; - bool is_gray = false; - png_get_IHDR(png_ptr,info_ptr,&W,&H,&bit_depth,&color_type,&interlace_type,(int*)0,(int*)0); - png_set_interlace_handling(png_ptr); - if (bits_per_value) *bits_per_value = (unsigned int)bit_depth; - - // Transforms to unify image data - if (color_type==PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png_ptr); - color_type = PNG_COLOR_TYPE_RGB; - bit_depth = 8; - } - if (color_type==PNG_COLOR_TYPE_GRAY && bit_depth<8) { - png_set_expand_gray_1_2_4_to_8(png_ptr); - is_gray = true; - bit_depth = 8; - } - if (png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) { - png_set_tRNS_to_alpha(png_ptr); - color_type |= PNG_COLOR_MASK_ALPHA; - } - if (color_type==PNG_COLOR_TYPE_GRAY || color_type==PNG_COLOR_TYPE_GRAY_ALPHA) { - png_set_gray_to_rgb(png_ptr); - color_type |= PNG_COLOR_MASK_COLOR; - is_gray = true; - } - if (color_type==PNG_COLOR_TYPE_RGB) - png_set_filler(png_ptr,0xffffU,PNG_FILLER_AFTER); - - png_read_update_info(png_ptr,info_ptr); - if (bit_depth!=8 && bit_depth!=16) { - if (!file) cimg::fclose(nfile); - png_destroy_read_struct(&png_ptr,&end_info,(png_infopp)0); - throw CImgIOException(_cimg_instance - "load_png(): Invalid bit depth %u in file '%s'.", - cimg_instance, - bit_depth,nfilename?nfilename:"(FILE*)"); - } - const int byte_depth = bit_depth>>3; - - // Allocate memory for image reading - png_bytep *const imgData = new png_bytep[H]; - for (unsigned int row = 0; row& load_pnm(const char *const filename) { - return _load_pnm(0,filename); - } - - //! Load image from a PNM file \newinstance. - static CImg get_load_pnm(const char *const filename) { - return CImg().load_pnm(filename); - } - - //! Load image from a PNM file \overloading. - CImg& load_pnm(std::FILE *const file) { - return _load_pnm(file,0); - } - - //! Load image from a PNM file \newinstance. - static CImg get_load_pnm(std::FILE *const file) { - return CImg().load_pnm(file); - } - - CImg& _load_pnm(std::FILE *const file, const char *const filename) { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_pnm(): Specified filename is (null).", - cimg_instance); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - unsigned int ppm_type, W, H, D = 1, colormax = 255; - CImg item(16384,1,1,1,0); - int err, rval, gval, bval; - const longT cimg_iobuffer = (longT)24*1024*1024; - while ((err=std::fscanf(nfile,"%16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); - if (cimg_sscanf(item," P%u",&ppm_type)!=1) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_pnm(): PNM header not found in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - } - while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); - if ((err=cimg_sscanf(item," %u %u %u %u",&W,&H,&D,&colormax))<2) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_pnm(): WIDTH and HEIGHT fields undefined in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - } - if (ppm_type!=1 && ppm_type!=4) { - if (err==2 || (err==3 && (ppm_type==5 || ppm_type==7 || ppm_type==8 || ppm_type==9))) { - while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); - if (cimg_sscanf(item,"%u",&colormax)!=1) - cimg::warn(_cimg_instance - "load_pnm(): COLORMAX field is undefined in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - } else { colormax = D; D = 1; } - } - std::fgetc(nfile); - - if (filename) { // Check that dimensions specified in file does not exceed the buffer dimension - const cimg_int64 siz = cimg::fsize(filename); - if (W*H*D>siz) - throw CImgIOException(_cimg_instance - "load_pnm(): Specified image dimensions in file '%s' exceed file size.", - cimg_instance, - filename); - } - - switch (ppm_type) { - case 1 : { // 2D B&W ascii - assign(W,H,1,1); - T* ptrd = _data; - cimg_foroff(*this,off) { if (std::fscanf(nfile,"%d",&rval)>0) *(ptrd++) = (T)(rval?0:255); else break; } - } break; - case 2 : { // 2D grey ascii - assign(W,H,1,1); - T* ptrd = _data; - cimg_foroff(*this,off) { if (std::fscanf(nfile,"%d",&rval)>0) *(ptrd++) = (T)rval; else break; } - } break; - case 3 : { // 2D color ascii - assign(W,H,1,3); - T *ptrd = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); - cimg_forXY(*this,x,y) { - if (std::fscanf(nfile,"%d %d %d",&rval,&gval,&bval)==3) { - *(ptrd++) = (T)rval; *(ptr_g++) = (T)gval; *(ptr_b++) = (T)bval; - } else break; - } - } break; - case 4 : { // 2D b&w binary (support 3D PINK extension) - CImg raw; - assign(W,H,D,1); - T *ptrd = data(0,0,0,0); - unsigned int w = 0, h = 0, d = 0; - for (longT to_read = (longT)((W/8 + (W%8?1:0))*H*D); to_read>0; ) { - raw.assign(std::min(to_read,cimg_iobuffer)); - cimg::fread(raw._data,raw._width,nfile); - to_read-=raw._width; - const unsigned char *ptrs = raw._data; - unsigned char mask = 0, val = 0; - for (ulongT off = (ulongT)raw._width; off || mask; mask>>=1) { - if (!mask) { if (off--) val = *(ptrs++); mask = 128; } - *(ptrd++) = (T)((val&mask)?0:255); - if (++w==W) { w = 0; mask = 0; if (++h==H) { h = 0; if (++d==D) break; }} - } - } - } break; - case 5 : case 7 : { // 2D/3D grey binary (support 3D PINK extension) - if (colormax<256) { // 8 bits - CImg raw; - assign(W,H,D,1); - T *ptrd = data(0,0,0,0); - for (longT to_read = (longT)size(); to_read>0; ) { - raw.assign(std::min(to_read,cimg_iobuffer)); - cimg::fread(raw._data,raw._width,nfile); - to_read-=raw._width; - const unsigned char *ptrs = raw._data; - for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); - } - } else { // 16 bits - CImg raw; - assign(W,H,D,1); - T *ptrd = data(0,0,0,0); - for (longT to_read = (longT)size(); to_read>0; ) { - raw.assign(std::min(to_read,cimg_iobuffer/2)); - cimg::fread(raw._data,raw._width,nfile); - if (!cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); - to_read-=raw._width; - const unsigned short *ptrs = raw._data; - for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); - } - } - } break; - case 6 : { // 2D color binary - if (colormax<256) { // 8 bits - CImg raw; - assign(W,H,1,3); - T - *ptr_r = data(0,0,0,0), - *ptr_g = data(0,0,0,1), - *ptr_b = data(0,0,0,2); - for (longT to_read = (longT)size(); to_read>0; ) { - raw.assign(std::min(to_read,cimg_iobuffer)); - cimg::fread(raw._data,raw._width,nfile); - to_read-=raw._width; - const unsigned char *ptrs = raw._data; - for (ulongT off = (ulongT)raw._width/3; off; --off) { - *(ptr_r++) = (T)*(ptrs++); - *(ptr_g++) = (T)*(ptrs++); - *(ptr_b++) = (T)*(ptrs++); - } - } - } else { // 16 bits - CImg raw; - assign(W,H,1,3); - T - *ptr_r = data(0,0,0,0), - *ptr_g = data(0,0,0,1), - *ptr_b = data(0,0,0,2); - for (longT to_read = (longT)size(); to_read>0; ) { - raw.assign(std::min(to_read,cimg_iobuffer/2)); - cimg::fread(raw._data,raw._width,nfile); - if (!cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); - to_read-=raw._width; - const unsigned short *ptrs = raw._data; - for (ulongT off = (ulongT)raw._width/3; off; --off) { - *(ptr_r++) = (T)*(ptrs++); - *(ptr_g++) = (T)*(ptrs++); - *(ptr_b++) = (T)*(ptrs++); - } - } - } - } break; - case 8 : { // 2D/3D grey binary with int32 integers (PINK extension) - CImg raw; - assign(W,H,D,1); - T *ptrd = data(0,0,0,0); - for (longT to_read = (longT)size(); to_read>0; ) { - raw.assign(std::min(to_read,cimg_iobuffer)); - cimg::fread(raw._data,raw._width,nfile); - to_read-=raw._width; - const int *ptrs = raw._data; - for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); - } - } break; - case 9 : { // 2D/3D grey binary with float values (PINK extension) - CImg raw; - assign(W,H,D,1); - T *ptrd = data(0,0,0,0); - for (longT to_read = (longT)size(); to_read>0; ) { - raw.assign(std::min(to_read,cimg_iobuffer)); - cimg::fread(raw._data,raw._width,nfile); - to_read-=raw._width; - const float *ptrs = raw._data; - for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); - } - } break; - default : - assign(); - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_pnm(): PNM type 'P%d' found, but type is not supported.", - cimg_instance, - filename?filename:"(FILE*)",ppm_type); - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Load image from a PFM file. - /** - \param filename Filename, as a C-string. - **/ - CImg& load_pfm(const char *const filename) { - return _load_pfm(0,filename); - } - - //! Load image from a PFM file \newinstance. - static CImg get_load_pfm(const char *const filename) { - return CImg().load_pfm(filename); - } - - //! Load image from a PFM file \overloading. - CImg& load_pfm(std::FILE *const file) { - return _load_pfm(file,0); - } - - //! Load image from a PFM file \newinstance. - static CImg get_load_pfm(std::FILE *const file) { - return CImg().load_pfm(file); - } - - CImg& _load_pfm(std::FILE *const file, const char *const filename) { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_pfm(): Specified filename is (null).", - cimg_instance); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - char pfm_type; - CImg item(16384,1,1,1,0); - int W = 0, H = 0, err = 0; - double scale = 0; - while ((err=std::fscanf(nfile,"%16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); - if (cimg_sscanf(item," P%c",&pfm_type)!=1) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_pfm(): PFM header not found in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - } - while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); - if ((err=cimg_sscanf(item," %d %d",&W,&H))<2) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_pfm(): WIDTH and HEIGHT fields are undefined in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - } else if (W<=0 || H<=0) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_pfm(): WIDTH (%d) and HEIGHT (%d) fields are invalid in file '%s'.", - cimg_instance,W,H, - filename?filename:"(FILE*)"); - } - if (err==2) { - while ((err=std::fscanf(nfile," %16383[^\n]",item.data()))!=EOF && (*item=='#' || !err)) std::fgetc(nfile); - if (cimg_sscanf(item,"%lf",&scale)!=1) - cimg::warn(_cimg_instance - "load_pfm(): SCALE field is undefined in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - } - std::fgetc(nfile); - const bool is_color = (pfm_type=='F'), is_inverted = (scale>0)!=cimg::endianness(); - if (is_color) { - assign(W,H,1,3,(T)0); - CImg buf(3*W); - T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2); - cimg_forY(*this,y) { - cimg::fread(buf._data,3*W,nfile); - if (is_inverted) cimg::invert_endianness(buf._data,3*W); - const float *ptrs = buf._data; - cimg_forX(*this,x) { - *(ptr_r++) = (T)*(ptrs++); - *(ptr_g++) = (T)*(ptrs++); - *(ptr_b++) = (T)*(ptrs++); - } - } - } else { - assign(W,H,1,1,(T)0); - CImg buf(W); - T *ptrd = data(0,0,0,0); - cimg_forY(*this,y) { - cimg::fread(buf._data,W,nfile); - if (is_inverted) cimg::invert_endianness(buf._data,W); - const float *ptrs = buf._data; - cimg_forX(*this,x) *(ptrd++) = (T)*(ptrs++); - } - } - if (!file) cimg::fclose(nfile); - return mirror('y'); // Most of the .pfm files are flipped along the y-axis - } - - //! Load image from a RGB file. - /** - \param filename Filename, as a C-string. - \param dimw Width of the image buffer. - \param dimh Height of the image buffer. - **/ - CImg& load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) { - return _load_rgb(0,filename,dimw,dimh); - } - - //! Load image from a RGB file \newinstance. - static CImg get_load_rgb(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) { - return CImg().load_rgb(filename,dimw,dimh); - } - - //! Load image from a RGB file \overloading. - CImg& load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) { - return _load_rgb(file,0,dimw,dimh); - } - - //! Load image from a RGB file \newinstance. - static CImg get_load_rgb(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) { - return CImg().load_rgb(file,dimw,dimh); - } - - CImg& _load_rgb(std::FILE *const file, const char *const filename, - const unsigned int dimw, const unsigned int dimh) { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_rgb(): Specified filename is (null).", - cimg_instance); - - if (!dimw || !dimh) return assign(); - const longT cimg_iobuffer = (longT)24*1024*1024; - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - CImg raw; - assign(dimw,dimh,1,3); - T - *ptr_r = data(0,0,0,0), - *ptr_g = data(0,0,0,1), - *ptr_b = data(0,0,0,2); - for (longT to_read = (longT)size(); to_read>0; ) { - raw.assign(std::min(to_read,cimg_iobuffer)); - cimg::fread(raw._data,raw._width,nfile); - to_read-=raw._width; - const unsigned char *ptrs = raw._data; - for (ulongT off = raw._width/3UL; off; --off) { - *(ptr_r++) = (T)*(ptrs++); - *(ptr_g++) = (T)*(ptrs++); - *(ptr_b++) = (T)*(ptrs++); - } - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Load image from a RGBA file. - /** - \param filename Filename, as a C-string. - \param dimw Width of the image buffer. - \param dimh Height of the image buffer. - **/ - CImg& load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) { - return _load_rgba(0,filename,dimw,dimh); - } - - //! Load image from a RGBA file \newinstance. - static CImg get_load_rgba(const char *const filename, const unsigned int dimw, const unsigned int dimh=1) { - return CImg().load_rgba(filename,dimw,dimh); - } - - //! Load image from a RGBA file \overloading. - CImg& load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) { - return _load_rgba(file,0,dimw,dimh); - } - - //! Load image from a RGBA file \newinstance. - static CImg get_load_rgba(std::FILE *const file, const unsigned int dimw, const unsigned int dimh=1) { - return CImg().load_rgba(file,dimw,dimh); - } - - CImg& _load_rgba(std::FILE *const file, const char *const filename, - const unsigned int dimw, const unsigned int dimh) { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_rgba(): Specified filename is (null).", - cimg_instance); - - if (!dimw || !dimh) return assign(); - const longT cimg_iobuffer = (longT)24*1024*1024; - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - CImg raw; - assign(dimw,dimh,1,4); - T - *ptr_r = data(0,0,0,0), - *ptr_g = data(0,0,0,1), - *ptr_b = data(0,0,0,2), - *ptr_a = data(0,0,0,3); - for (longT to_read = (longT)size(); to_read>0; ) { - raw.assign(std::min(to_read,cimg_iobuffer)); - cimg::fread(raw._data,raw._width,nfile); - to_read-=raw._width; - const unsigned char *ptrs = raw._data; - for (ulongT off = raw._width/4UL; off; --off) { - *(ptr_r++) = (T)*(ptrs++); - *(ptr_g++) = (T)*(ptrs++); - *(ptr_b++) = (T)*(ptrs++); - *(ptr_a++) = (T)*(ptrs++); - } - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Load image from a TIFF file. - /** - \param filename Filename, as a C-string. - \param first_frame First frame to read (for multi-pages tiff). - \param last_frame Last frame to read (for multi-pages tiff). - \param step_frame Step value of frame reading. - \param[out] bits_per_value Number of bits used to store a scalar value in the image file. - \param[out] voxel_size Voxel size, as stored in the filename. - \param[out] description Description, as stored in the filename. - \note - - libtiff support is enabled by defining the precompilation - directive \c cimg_use_tif. - - When libtiff is enabled, 2D and 3D (multipage) several - channel per pixel are supported for - char,uchar,short,ushort,float and \c double pixel types. - - If \c cimg_use_tiff is not defined at compile time the - function uses CImg& load_other(const char*). - **/ - CImg& load_tiff(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, unsigned int *const bits_per_value=0, - float *const voxel_size=0, CImg *const description=0) { - if (!filename) - throw CImgArgumentException(_cimg_instance - "load_tiff(): Specified filename is (null).", - cimg_instance); - - const unsigned int - nfirst_frame = first_frame1) - throw CImgArgumentException(_cimg_instance - "load_tiff(): Unable to read sub-images from file '%s' unless libtiff is enabled.", - cimg_instance, - filename); - return load_other(filename); -#else -#if cimg_verbosity<3 - TIFFSetWarningHandler(0); - TIFFSetErrorHandler(0); -#endif - TIFF *tif = TIFFOpen(filename,"r"); - if (tif) { - unsigned int nb_images = 0; - do ++nb_images; while (TIFFReadDirectory(tif)); - if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images)) - cimg::warn(_cimg_instance - "load_tiff(): File '%s' contains %u image(s) while specified frame range is [%u,%u] (step %u).", - cimg_instance, - filename,nb_images,nfirst_frame,nlast_frame,nstep_frame); - - if (nfirst_frame>=nb_images) return assign(); - if (nlast_frame>=nb_images) nlast_frame = nb_images - 1; - TIFFSetDirectory(tif,0); - CImg frame; - for (unsigned int l = nfirst_frame; l<=nlast_frame; l+=nstep_frame) { - frame._load_tiff(tif,l,bits_per_value,voxel_size,description); - if (l==nfirst_frame) - assign(frame._width,frame._height,1 + (nlast_frame - nfirst_frame)/nstep_frame,frame._spectrum); - if (frame._width>_width || frame._height>_height || frame._spectrum>_spectrum) - resize(std::max(frame._width,_width), - std::max(frame._height,_height),-100, - std::max(frame._spectrum,_spectrum),0); - draw_image(0,0,(l - nfirst_frame)/nstep_frame,frame); - } - TIFFClose(tif); - } else throw CImgIOException(_cimg_instance - "load_tiff(): Failed to open file '%s'.", - cimg_instance, - filename); - return *this; -#endif - } - - //! Load image from a TIFF file \newinstance. - static CImg get_load_tiff(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, unsigned int *const bits_per_value=0, - float *const voxel_size=0, CImg *const description=0) { - return CImg().load_tiff(filename,first_frame,last_frame,step_frame,bits_per_value,voxel_size,description); - } - - // (Original contribution by Jerome Boulanger). -#ifdef cimg_use_tiff - template - void _load_tiff_tiled_contig(TIFF *const tif, const cimg_uint16 samplesperpixel, - const cimg_uint32 nx, const cimg_uint32 ny, - const cimg_uint32 tw, const cimg_uint32 th) { - t *const buf = (t*)_TIFFmalloc(TIFFTileSize(tif)); - if (buf) { - for (unsigned int row = 0; row - void _load_tiff_tiled_separate(TIFF *const tif, const cimg_uint16 samplesperpixel, - const cimg_uint32 nx, const cimg_uint32 ny, - const cimg_uint32 tw, const cimg_uint32 th) { - t *const buf = (t*)_TIFFmalloc(TIFFTileSize(tif)); - if (buf) { - for (unsigned int vv = 0; vv - void _load_tiff_contig(TIFF *const tif, const cimg_uint16 samplesperpixel, - const cimg_uint32 nx, const cimg_uint32 ny) { - t *const buf = (t*)_TIFFmalloc(TIFFStripSize(tif)); - if (buf) { - cimg_uint32 row, rowsperstrip = (cimg_uint32)-1; - TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip); - for (row = 0; rowny?ny - row:rowsperstrip); - tstrip_t strip = TIFFComputeStrip(tif, row, 0); - if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { - _TIFFfree(buf); TIFFClose(tif); - throw CImgIOException(_cimg_instance - "load_tiff(): Invalid strip in file '%s'.", - cimg_instance, - TIFFFileName(tif)); - } - const t *ptr = buf; - for (unsigned int rr = 0; rr - void _load_tiff_separate(TIFF *const tif, const cimg_uint16 samplesperpixel, - const cimg_uint32 nx, const cimg_uint32 ny) { - t *buf = (t*)_TIFFmalloc(TIFFStripSize(tif)); - if (buf) { - cimg_uint32 row, rowsperstrip = (cimg_uint32)-1; - TIFFGetField(tif,TIFFTAG_ROWSPERSTRIP,&rowsperstrip); - for (unsigned int vv = 0; vvny?ny - row:rowsperstrip); - tstrip_t strip = TIFFComputeStrip(tif, row, vv); - if ((TIFFReadEncodedStrip(tif,strip,buf,-1))<0) { - _TIFFfree(buf); TIFFClose(tif); - throw CImgIOException(_cimg_instance - "load_tiff(): Invalid strip in file '%s'.", - cimg_instance, - TIFFFileName(tif)); - } - const t *ptr = buf; - for (unsigned int rr = 0;rr& _load_tiff(TIFF *const tif, const unsigned int directory, unsigned int *const bits_per_value, - float *const voxel_size, CImg *const description) { - if (!TIFFSetDirectory(tif,directory)) return assign(); - cimg_uint16 samplesperpixel = 1, bitspersample = 8, photo = 0; - cimg_uint16 sampleformat = 1; - cimg_uint32 nx = 1, ny = 1; - const char *const filename = TIFFFileName(tif); - const bool is_spp = (bool)TIFFGetField(tif,TIFFTAG_SAMPLESPERPIXEL,&samplesperpixel); - TIFFGetField(tif,TIFFTAG_IMAGEWIDTH,&nx); - TIFFGetField(tif,TIFFTAG_IMAGELENGTH,&ny); - TIFFGetField(tif, TIFFTAG_SAMPLEFORMAT, &sampleformat); - TIFFGetFieldDefaulted(tif,TIFFTAG_BITSPERSAMPLE,&bitspersample); - TIFFGetField(tif,TIFFTAG_PHOTOMETRIC,&photo); - if (bits_per_value) *bits_per_value = (unsigned int)bitspersample; - if (voxel_size) { - const char *s_description = 0; - float vx = 0, vy = 0, vz = 0; - if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description) { - const char *s_desc = std::strstr(s_description,"VX="); - if (s_desc && cimg_sscanf(s_desc,"VX=%f VY=%f VZ=%f",&vx,&vy,&vz)==3) { // CImg format - voxel_size[0] = vx; voxel_size[1] = vy; voxel_size[2] = vz; - } - s_desc = std::strstr(s_description,"spacing="); - if (s_desc && cimg_sscanf(s_desc,"spacing=%f",&vz)==1) { // Fiji format - voxel_size[2] = vz; - } - } - TIFFGetField(tif,TIFFTAG_XRESOLUTION,voxel_size); - TIFFGetField(tif,TIFFTAG_YRESOLUTION,voxel_size + 1); - voxel_size[0] = 1.f/voxel_size[0]; - voxel_size[1] = 1.f/voxel_size[1]; - } - if (description) { - const char *s_description = 0; - if (TIFFGetField(tif,TIFFTAG_IMAGEDESCRIPTION,&s_description) && s_description) - CImg::string(s_description).move_to(*description); - } - const unsigned int spectrum = !is_spp || photo>=3?(photo>1?3:1):samplesperpixel; - assign(nx,ny,1,spectrum); - - if ((photo>=3 && sampleformat==1 && - (bitspersample==4 || bitspersample==8) && - (samplesperpixel==1 || samplesperpixel==3 || samplesperpixel==4)) || - (bitspersample==1 && samplesperpixel==1)) { - // Special case for unsigned color images. - cimg_uint32 *const raster = (cimg_uint32*)_TIFFmalloc(nx*ny*sizeof(cimg_uint32)); - if (!raster) { - _TIFFfree(raster); TIFFClose(tif); - throw CImgException(_cimg_instance - "load_tiff(): Failed to allocate memory (%s) for file '%s'.", - cimg_instance, - cimg::strbuffersize(nx*ny*sizeof(cimg_uint32)),filename); - } - TIFFReadRGBAImage(tif,nx,ny,raster,0); - switch (spectrum) { - case 1 : - cimg_forXY(*this,x,y) - (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 -y) + x]); - break; - case 3 : - cimg_forXY(*this,x,y) { - (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 - y) + x]); - (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 - y) + x]); - (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 - y) + x]); - } - break; - case 4 : - cimg_forXY(*this,x,y) { - (*this)(x,y,0) = (T)(float)TIFFGetR(raster[nx*(ny - 1 - y) + x]); - (*this)(x,y,1) = (T)(float)TIFFGetG(raster[nx*(ny - 1 - y) + x]); - (*this)(x,y,2) = (T)(float)TIFFGetB(raster[nx*(ny - 1 - y) + x]); - (*this)(x,y,3) = (T)(float)TIFFGetA(raster[nx*(ny - 1 - y) + x]); - } - break; - } - _TIFFfree(raster); - } else { // Other cases - cimg_uint16 config; - TIFFGetField(tif,TIFFTAG_PLANARCONFIG,&config); - if (TIFFIsTiled(tif)) { - cimg_uint32 tw = 1, th = 1; - TIFFGetField(tif,TIFFTAG_TILEWIDTH,&tw); - TIFFGetField(tif,TIFFTAG_TILELENGTH,&th); - if (config==PLANARCONFIG_CONTIG) switch (bitspersample) { - case 8 : - if (sampleformat==SAMPLEFORMAT_UINT) - _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); - else _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); - break; - case 16 : - if (sampleformat==SAMPLEFORMAT_UINT) - _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); - else _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); - break; - case 32 : - if (sampleformat==SAMPLEFORMAT_UINT) - _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); - else if (sampleformat==SAMPLEFORMAT_INT) - _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); - else _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); - break; - case 64 : - if (sampleformat==SAMPLEFORMAT_UINT) - _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); - else if (sampleformat==SAMPLEFORMAT_INT) - _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); - else _load_tiff_tiled_contig(tif,samplesperpixel,nx,ny,tw,th); - break; - } else switch (bitspersample) { - case 8 : - if (sampleformat==SAMPLEFORMAT_UINT) - _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); - else _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); - break; - case 16 : - if (sampleformat==SAMPLEFORMAT_UINT) - _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); - else _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); - break; - case 32 : - if (sampleformat==SAMPLEFORMAT_UINT) - _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); - else if (sampleformat==SAMPLEFORMAT_INT) - _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); - else _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); - break; - case 64 : - if (sampleformat==SAMPLEFORMAT_UINT) - _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); - else if (sampleformat==SAMPLEFORMAT_INT) - _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); - else _load_tiff_tiled_separate(tif,samplesperpixel,nx,ny,tw,th); - break; - } - } else { - if (config==PLANARCONFIG_CONTIG) switch (bitspersample) { - case 8 : - if (sampleformat==SAMPLEFORMAT_UINT) - _load_tiff_contig(tif,samplesperpixel,nx,ny); - else _load_tiff_contig(tif,samplesperpixel,nx,ny); - break; - case 16 : - if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig(tif,samplesperpixel,nx,ny); - else _load_tiff_contig(tif,samplesperpixel,nx,ny); - break; - case 32 : - if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig(tif,samplesperpixel,nx,ny); - else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_contig(tif,samplesperpixel,nx,ny); - else _load_tiff_contig(tif,samplesperpixel,nx,ny); - break; - case 64 : - if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_contig(tif,samplesperpixel,nx,ny); - else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_contig(tif,samplesperpixel,nx,ny); - else _load_tiff_contig(tif,samplesperpixel,nx,ny); - break; - } else switch (bitspersample) { - case 8 : - if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate(tif,samplesperpixel,nx,ny); - else _load_tiff_separate(tif,samplesperpixel,nx,ny); - break; - case 16 : - if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate(tif,samplesperpixel,nx,ny); - else _load_tiff_separate(tif,samplesperpixel,nx,ny); - break; - case 32 : - if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate(tif,samplesperpixel,nx,ny); - else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_separate(tif,samplesperpixel,nx,ny); - else _load_tiff_separate(tif,samplesperpixel,nx,ny); - break; - case 64 : - if (sampleformat==SAMPLEFORMAT_UINT) _load_tiff_separate(tif,samplesperpixel,nx,ny); - else if (sampleformat==SAMPLEFORMAT_INT) _load_tiff_separate(tif,samplesperpixel,nx,ny); - else _load_tiff_separate(tif,samplesperpixel,nx,ny); - break; - } - } - } - return *this; - } -#endif - - //! Load image from a MINC2 file. - /** - \param filename Filename, as a C-string. - **/ - // (Original code by Haz-Edine Assemlal). - CImg& load_minc2(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimg_instance - "load_minc2(): Specified filename is (null).", - cimg_instance); -#ifndef cimg_use_minc2 - return load_other(filename); -#else - minc::minc_1_reader rdr; - rdr.open(filename); - assign(rdr.ndim(1)?rdr.ndim(1):1, - rdr.ndim(2)?rdr.ndim(2):1, - rdr.ndim(3)?rdr.ndim(3):1, - rdr.ndim(4)?rdr.ndim(4):1); - if (pixel_type()==cimg::type::string()) - rdr.setup_read_byte(); - else if (pixel_type()==cimg::type::string()) - rdr.setup_read_int(); - else if (pixel_type()==cimg::type::string()) - rdr.setup_read_double(); - else - rdr.setup_read_float(); - minc::load_standard_volume(rdr,this->_data); - return *this; -#endif - } - - //! Load image from a MINC2 file \newinstance. - static CImg get_load_minc2(const char *const filename) { - return CImg().load_analyze(filename); - } - - //! Load image from an ANALYZE7.5/NIFTI file. - /** - \param filename Filename, as a C-string. - \param[out] voxel_size Pointer to the three voxel sizes read from the file. - **/ - CImg& load_analyze(const char *const filename, float *const voxel_size=0) { - return _load_analyze(0,filename,voxel_size); - } - - //! Load image from an ANALYZE7.5/NIFTI file \newinstance. - static CImg get_load_analyze(const char *const filename, float *const voxel_size=0) { - return CImg().load_analyze(filename,voxel_size); - } - - //! Load image from an ANALYZE7.5/NIFTI file \overloading. - CImg& load_analyze(std::FILE *const file, float *const voxel_size=0) { - return _load_analyze(file,0,voxel_size); - } - - //! Load image from an ANALYZE7.5/NIFTI file \newinstance. - static CImg get_load_analyze(std::FILE *const file, float *const voxel_size=0) { - return CImg().load_analyze(file,voxel_size); - } - - CImg& _load_analyze(std::FILE *const file, const char *const filename, float *const voxel_size=0) { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_analyze(): Specified filename is (null).", - cimg_instance); - - std::FILE *nfile_header = 0, *nfile = 0; - if (!file) { - CImg body(1024); - const char *const ext = cimg::split_filename(filename,body); - if (!cimg::strcasecmp(ext,"hdr")) { // File is an Analyze header file - nfile_header = cimg::fopen(filename,"rb"); - cimg_sprintf(body._data + std::strlen(body),".img"); - nfile = cimg::fopen(body,"rb"); - } else if (!cimg::strcasecmp(ext,"img")) { // File is an Analyze data file - nfile = cimg::fopen(filename,"rb"); - cimg_sprintf(body._data + std::strlen(body),".hdr"); - nfile_header = cimg::fopen(body,"rb"); - } else nfile_header = nfile = cimg::fopen(filename,"rb"); // File is a Niftii file - } else nfile_header = nfile = file; // File is a Niftii file - if (!nfile || !nfile_header) - throw CImgIOException(_cimg_instance - "load_analyze(): Invalid Analyze7.5 or NIFTI header in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - - // Read header. - bool endian = false; - unsigned int header_size; - cimg::fread(&header_size,1,nfile_header); - if (!header_size) - throw CImgIOException(_cimg_instance - "load_analyze(): Invalid zero-size header in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - if (header_size>=4096) { endian = true; cimg::invert_endianness(header_size); } - - unsigned char *const header = new unsigned char[header_size]; - cimg::fread(header + 4,header_size - 4,nfile_header); - if (!file && nfile_header!=nfile) cimg::fclose(nfile_header); - if (endian) { - cimg::invert_endianness((short*)(header + 40),5); - cimg::invert_endianness((short*)(header + 70),1); - cimg::invert_endianness((short*)(header + 72),1); - cimg::invert_endianness((float*)(header + 76),4); - cimg::invert_endianness((float*)(header + 108),1); - cimg::invert_endianness((float*)(header + 112),1); - } - - if (nfile_header==nfile) { - const unsigned int vox_offset = (unsigned int)*(float*)(header + 108); - std::fseek(nfile,vox_offset,SEEK_SET); - } - - unsigned short *dim = (unsigned short*)(header + 40), dimx = 1, dimy = 1, dimz = 1, dimv = 1; - if (!dim[0]) - cimg::warn(_cimg_instance - "load_analyze(): File '%s' defines an image with zero dimensions.", - cimg_instance, - filename?filename:"(FILE*)"); - - if (dim[0]>4) - cimg::warn(_cimg_instance - "load_analyze(): File '%s' defines an image with %u dimensions, reading only the 4 first.", - cimg_instance, - filename?filename:"(FILE*)",dim[0]); - - if (dim[0]>=1) dimx = dim[1]; - if (dim[0]>=2) dimy = dim[2]; - if (dim[0]>=3) dimz = dim[3]; - if (dim[0]>=4) dimv = dim[4]; - float scalefactor = *(float*)(header + 112); if (scalefactor==0) scalefactor = 1; - const unsigned short datatype = *(unsigned short*)(header + 70); - if (voxel_size) { - const float *vsize = (float*)(header + 76); - voxel_size[0] = vsize[1]; voxel_size[1] = vsize[2]; voxel_size[2] = vsize[3]; - } - delete[] header; - - // Read pixel data. - assign(dimx,dimy,dimz,dimv); - const size_t pdim = (size_t)dimx*dimy*dimz*dimv; - switch (datatype) { - case 2 : { - unsigned char *const buffer = new unsigned char[pdim]; - cimg::fread(buffer,pdim,nfile); - cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); - delete[] buffer; - } break; - case 4 : { - short *const buffer = new short[pdim]; - cimg::fread(buffer,pdim,nfile); - if (endian) cimg::invert_endianness(buffer,pdim); - cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); - delete[] buffer; - } break; - case 8 : { - int *const buffer = new int[pdim]; - cimg::fread(buffer,pdim,nfile); - if (endian) cimg::invert_endianness(buffer,pdim); - cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); - delete[] buffer; - } break; - case 16 : { - float *const buffer = new float[pdim]; - cimg::fread(buffer,pdim,nfile); - if (endian) cimg::invert_endianness(buffer,pdim); - cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); - delete[] buffer; - } break; - case 64 : { - double *const buffer = new double[pdim]; - cimg::fread(buffer,pdim,nfile); - if (endian) cimg::invert_endianness(buffer,pdim); - cimg_foroff(*this,off) _data[off] = (T)(buffer[off]*scalefactor); - delete[] buffer; - } break; - default : - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_analyze(): Unable to load datatype %d in file '%s'", - cimg_instance, - datatype,filename?filename:"(FILE*)"); - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Load image from a .cimg[z] file. - /** - \param filename Filename, as a C-string. - \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. - \param align Appending alignment. - **/ - CImg& load_cimg(const char *const filename, const char axis='z', const float align=0) { - CImgList list; - list.load_cimg(filename); - if (list._width==1) return list[0].move_to(*this); - return assign(list.get_append(axis,align)); - } - - //! Load image from a .cimg[z] file \newinstance - static CImg get_load_cimg(const char *const filename, const char axis='z', const float align=0) { - return CImg().load_cimg(filename,axis,align); - } - - //! Load image from a .cimg[z] file \overloading. - CImg& load_cimg(std::FILE *const file, const char axis='z', const float align=0) { - CImgList list; - list.load_cimg(file); - if (list._width==1) return list[0].move_to(*this); - return assign(list.get_append(axis,align)); - } - - //! Load image from a .cimg[z] file \newinstance - static CImg get_load_cimg(std::FILE *const file, const char axis='z', const float align=0) { - return CImg().load_cimg(file,axis,align); - } - - //! Load sub-images of a .cimg file. - /** - \param filename Filename, as a C-string. - \param n0 Starting frame. - \param n1 Ending frame (~0U for max). - \param x0 X-coordinate of the starting sub-image vertex. - \param y0 Y-coordinate of the starting sub-image vertex. - \param z0 Z-coordinate of the starting sub-image vertex. - \param c0 C-coordinate of the starting sub-image vertex. - \param x1 X-coordinate of the ending sub-image vertex (~0U for max). - \param y1 Y-coordinate of the ending sub-image vertex (~0U for max). - \param z1 Z-coordinate of the ending sub-image vertex (~0U for max). - \param c1 C-coordinate of the ending sub-image vertex (~0U for max). - \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. - \param align Appending alignment. - **/ - CImg& load_cimg(const char *const filename, - const unsigned int n0, const unsigned int n1, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0, - const unsigned int x1, const unsigned int y1, - const unsigned int z1, const unsigned int c1, - const char axis='z', const float align=0) { - CImgList list; - list.load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); - if (list._width==1) return list[0].move_to(*this); - return assign(list.get_append(axis,align)); - } - - //! Load sub-images of a .cimg file \newinstance. - static CImg get_load_cimg(const char *const filename, - const unsigned int n0, const unsigned int n1, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0, - const unsigned int x1, const unsigned int y1, - const unsigned int z1, const unsigned int c1, - const char axis='z', const float align=0) { - return CImg().load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1,axis,align); - } - - //! Load sub-images of a .cimg file \overloading. - CImg& load_cimg(std::FILE *const file, - const unsigned int n0, const unsigned int n1, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0, - const unsigned int x1, const unsigned int y1, - const unsigned int z1, const unsigned int c1, - const char axis='z', const float align=0) { - CImgList list; - list.load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); - if (list._width==1) return list[0].move_to(*this); - return assign(list.get_append(axis,align)); - } - - //! Load sub-images of a .cimg file \newinstance. - static CImg get_load_cimg(std::FILE *const file, - const unsigned int n0, const unsigned int n1, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0, - const unsigned int x1, const unsigned int y1, - const unsigned int z1, const unsigned int c1, - const char axis='z', const float align=0) { - return CImg().load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1,axis,align); - } - - //! Load image from an INRIMAGE-4 file. - /** - \param filename Filename, as a C-string. - \param[out] voxel_size Pointer to the three voxel sizes read from the file. - **/ - CImg& load_inr(const char *const filename, float *const voxel_size=0) { - return _load_inr(0,filename,voxel_size); - } - - //! Load image from an INRIMAGE-4 file \newinstance. - static CImg get_load_inr(const char *const filename, float *const voxel_size=0) { - return CImg().load_inr(filename,voxel_size); - } - - //! Load image from an INRIMAGE-4 file \overloading. - CImg& load_inr(std::FILE *const file, float *const voxel_size=0) { - return _load_inr(file,0,voxel_size); - } - - //! Load image from an INRIMAGE-4 file \newinstance. - static CImg get_load_inr(std::FILE *const file, float *voxel_size=0) { - return CImg().load_inr(file,voxel_size); - } - - static void _load_inr_header(std::FILE *file, int out[8], float *const voxel_size) { - CImg item(1024), tmp1(64), tmp2(64); - *item = *tmp1 = *tmp2 = 0; - out[0] = std::fscanf(file,"%63s",item._data); - out[0] = out[1] = out[2] = out[3] = out[5] = 1; out[4] = out[6] = out[7] = -1; - if (cimg::strncasecmp(item,"#INRIMAGE-4#{",13)!=0) - throw CImgIOException("CImg<%s>::load_inr(): INRIMAGE-4 header not found.", - pixel_type()); - - while (std::fscanf(file," %63[^\n]%*c",item._data)!=EOF && std::strncmp(item,"##}",3)) { - cimg_sscanf(item," XDIM%*[^0-9]%d",out); - cimg_sscanf(item," YDIM%*[^0-9]%d",out + 1); - cimg_sscanf(item," ZDIM%*[^0-9]%d",out + 2); - cimg_sscanf(item," VDIM%*[^0-9]%d",out + 3); - cimg_sscanf(item," PIXSIZE%*[^0-9]%d",out + 6); - if (voxel_size) { - cimg_sscanf(item," VX%*[^0-9.+-]%f",voxel_size); - cimg_sscanf(item," VY%*[^0-9.+-]%f",voxel_size + 1); - cimg_sscanf(item," VZ%*[^0-9.+-]%f",voxel_size + 2); - } - if (cimg_sscanf(item," CPU%*[ =]%s",tmp1._data)) out[7] = cimg::strncasecmp(tmp1,"sun",3)?0:1; - switch (cimg_sscanf(item," TYPE%*[ =]%s %s",tmp1._data,tmp2._data)) { - case 0 : break; - case 2 : - out[5] = cimg::strncasecmp(tmp1,"unsigned",8)?1:0; - std::strncpy(tmp1,tmp2,tmp1._width - 1); // Fallthrough - case 1 : - if (!cimg::strncasecmp(tmp1,"int",3) || !cimg::strncasecmp(tmp1,"fixed",5)) out[4] = 0; - if (!cimg::strncasecmp(tmp1,"float",5) || !cimg::strncasecmp(tmp1,"double",6)) out[4] = 1; - if (!cimg::strncasecmp(tmp1,"packed",6)) out[4] = 2; - if (out[4]>=0) break; // Fallthrough - default : - throw CImgIOException("CImg<%s>::load_inr(): Invalid pixel type '%s' defined in header.", - pixel_type(), - tmp2._data); - } - } - if (out[0]<0 || out[1]<0 || out[2]<0 || out[3]<0) - throw CImgIOException("CImg<%s>::load_inr(): Invalid dimensions (%d,%d,%d,%d) defined in header.", - pixel_type(), - out[0],out[1],out[2],out[3]); - if (out[4]<0 || out[5]<0) - throw CImgIOException("CImg<%s>::load_inr(): Incomplete pixel type defined in header.", - pixel_type()); - if (out[6]<0) - throw CImgIOException("CImg<%s>::load_inr(): Incomplete PIXSIZE field defined in header.", - pixel_type()); - if (out[7]<0) - throw CImgIOException("CImg<%s>::load_inr(): Big/Little Endian coding type undefined in header.", - pixel_type()); - } - - CImg& _load_inr(std::FILE *const file, const char *const filename, float *const voxel_size) { -#define _cimg_load_inr_case(Tf,sign,pixsize,Ts) \ - if (!loaded && fopt[6]==pixsize && fopt[4]==Tf && fopt[5]==sign) { \ - Ts *xval, *const val = new Ts[(size_t)fopt[0]*fopt[3]]; \ - cimg_forYZ(*this,y,z) { \ - cimg::fread(val,fopt[0]*fopt[3],nfile); \ - if (fopt[7]!=endian) cimg::invert_endianness(val,fopt[0]*fopt[3]); \ - xval = val; cimg_forX(*this,x) cimg_forC(*this,c) (*this)(x,y,z,c) = (T)*(xval++); \ - } \ - delete[] val; \ - loaded = true; \ - } - - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_inr(): Specified filename is (null).", - cimg_instance); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - int fopt[8], endian = cimg::endianness()?1:0; - bool loaded = false; - if (voxel_size) voxel_size[0] = voxel_size[1] = voxel_size[2] = 1; - _load_inr_header(nfile,fopt,voxel_size); - assign(fopt[0],fopt[1],fopt[2],fopt[3]); - _cimg_load_inr_case(0,0,8,unsigned char); - _cimg_load_inr_case(0,1,8,char); - _cimg_load_inr_case(0,0,16,unsigned short); - _cimg_load_inr_case(0,1,16,short); - _cimg_load_inr_case(0,0,32,unsigned int); - _cimg_load_inr_case(0,1,32,int); - _cimg_load_inr_case(1,0,32,float); - _cimg_load_inr_case(1,1,32,float); - _cimg_load_inr_case(1,0,64,double); - _cimg_load_inr_case(1,1,64,double); - if (!loaded) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_inr(): Unknown pixel type defined in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Load image from a EXR file. - /** - \param filename Filename, as a C-string. - **/ - CImg& load_exr(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimg_instance - "load_exr(): Specified filename is (null).", - cimg_instance); -#if defined(cimg_use_openexr) - Imf::RgbaInputFile file(filename); - Imath::Box2i dw = file.dataWindow(); - const int - inwidth = dw.max.x - dw.min.x + 1, - inheight = dw.max.y - dw.min.y + 1; - Imf::Array2D pixels; - pixels.resizeErase(inheight,inwidth); - file.setFrameBuffer(&pixels[0][0] - dw.min.x - dw.min.y*inwidth, 1, inwidth); - file.readPixels(dw.min.y, dw.max.y); - assign(inwidth,inheight,1,4); - T *ptr_r = data(0,0,0,0), *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = data(0,0,0,3); - cimg_forXY(*this,x,y) { - *(ptr_r++) = (T)pixels[y][x].r; - *(ptr_g++) = (T)pixels[y][x].g; - *(ptr_b++) = (T)pixels[y][x].b; - *(ptr_a++) = (T)pixels[y][x].a; - } - return *this; -#elif defined(cimg_use_tinyexr) - float *res; - const char *err = 0; - int width = 0, height = 0; - const int ret = LoadEXR(&res,&width,&height,filename,&err); - if (ret) throw CImgIOException(_cimg_instance - "load_exr(): Unable to load EXR file '%s'.", - cimg_instance,filename); - CImg(res,4,width,height,1,true).get_permute_axes("yzcx").move_to(*this); - std::free(res); - return *this; -#else - return load_other(filename); -#endif - } - - //! Load image from a EXR file \newinstance. - static CImg get_load_exr(const char *const filename) { - return CImg().load_exr(filename); - } - - //! Load image from a PANDORE-5 file. - /** - \param filename Filename, as a C-string. - **/ - CImg& load_pandore(const char *const filename) { - return _load_pandore(0,filename); - } - - //! Load image from a PANDORE-5 file \newinstance. - static CImg get_load_pandore(const char *const filename) { - return CImg().load_pandore(filename); - } - - //! Load image from a PANDORE-5 file \overloading. - CImg& load_pandore(std::FILE *const file) { - return _load_pandore(file,0); - } - - //! Load image from a PANDORE-5 file \newinstance. - static CImg get_load_pandore(std::FILE *const file) { - return CImg().load_pandore(file); - } - - CImg& _load_pandore(std::FILE *const file, const char *const filename) { -#define __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,ndim,stype) \ - cimg::fread(dims,nbdim,nfile); \ - if (endian) cimg::invert_endianness(dims,nbdim); \ - if ((ulongT)nwidth*nheight*ndepth*ndim>fsiz) \ - throw CImgIOException(_cimg_instance \ - "load_pandore(): File size %lu for filename '%s' does not match "\ - "encoded image dimensions (%d,%d,%d,%d).",\ - cimg_instance,\ - (long)fsiz,filename?filename:"(FILE*)",\ - (int)nwidth,(int)nheight,(int)ndepth,(int)ndim); \ - assign(nwidth,nheight,ndepth,ndim); \ - const size_t siz = size(); \ - stype *buffer = new stype[siz]; \ - cimg::fread(buffer,siz,nfile); \ - if (endian) cimg::invert_endianness(buffer,siz); \ - T *ptrd = _data; \ - cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); \ - buffer-=siz; \ - delete[] buffer - -#define _cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1,stype2,stype3,ltype) { \ - if (sizeof(stype1)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype1); } \ - else if (sizeof(stype2)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype2); } \ - else if (sizeof(stype3)==ltype) { __cimg_load_pandore_case(nbdim,nwidth,nheight,ndepth,dim,stype3); } \ - else throw CImgIOException(_cimg_instance \ - "load_pandore(): Unknown pixel datatype in file '%s'.", \ - cimg_instance, \ - filename?filename:"(FILE*)"); } - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_pandore(): Specified filename is (null).", - cimg_instance); - - const ulongT fsiz = file?(ulongT)cimg_max_buf_size:(ulongT)cimg::fsize(filename); - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - CImg header(32); - cimg::fread(header._data,12,nfile); - if (cimg::strncasecmp("PANDORE",header,7)) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_pandore(): PANDORE header not found in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - } - unsigned int imageid, dims[8] = { 0 }; - int ptbuf[4] = { 0 }; - cimg::fread(&imageid,1,nfile); - const bool endian = imageid>255; - if (endian) cimg::invert_endianness(imageid); - cimg::fread(header._data,20,nfile); - - switch (imageid) { - case 2 : _cimg_load_pandore_case(2,dims[1],1,1,1,unsigned char,unsigned char,unsigned char,1); break; - case 3 : _cimg_load_pandore_case(2,dims[1],1,1,1,long,int,short,4); break; - case 4 : _cimg_load_pandore_case(2,dims[1],1,1,1,double,float,float,4); break; - case 5 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,unsigned char,unsigned char,unsigned char,1); break; - case 6 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,long,int,short,4); break; - case 7 : _cimg_load_pandore_case(3,dims[2],dims[1],1,1,double,float,float,4); break; - case 8 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,unsigned char,unsigned char,unsigned char,1); break; - case 9 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,long,int,short,4); break; - case 10 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],1,double,float,float,4); break; - case 11 : { // Region 1D - cimg::fread(dims,3,nfile); - if (endian) cimg::invert_endianness(dims,3); - assign(dims[1],1,1,1); - const unsigned siz = size(); - if (dims[2]<256) { - unsigned char *buffer = new unsigned char[siz]; - cimg::fread(buffer,siz,nfile); - T *ptrd = _data; - cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); - buffer-=siz; - delete[] buffer; - } else { - if (dims[2]<65536) { - unsigned short *buffer = new unsigned short[siz]; - cimg::fread(buffer,siz,nfile); - if (endian) cimg::invert_endianness(buffer,siz); - T *ptrd = _data; - cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); - buffer-=siz; - delete[] buffer; - } else { - unsigned int *buffer = new unsigned int[siz]; - cimg::fread(buffer,siz,nfile); - if (endian) cimg::invert_endianness(buffer,siz); - T *ptrd = _data; - cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); - buffer-=siz; - delete[] buffer; - } - } - } - break; - case 12 : { // Region 2D - cimg::fread(dims,4,nfile); - if (endian) cimg::invert_endianness(dims,4); - assign(dims[2],dims[1],1,1); - const size_t siz = size(); - if (dims[3]<256) { - unsigned char *buffer = new unsigned char[siz]; - cimg::fread(buffer,siz,nfile); - T *ptrd = _data; - cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); - buffer-=siz; - delete[] buffer; - } else { - if (dims[3]<65536) { - unsigned short *buffer = new unsigned short[siz]; - cimg::fread(buffer,siz,nfile); - if (endian) cimg::invert_endianness(buffer,siz); - T *ptrd = _data; - cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); - buffer-=siz; - delete[] buffer; - } else { - unsigned int *buffer = new unsigned int[siz]; - cimg::fread(buffer,siz,nfile); - if (endian) cimg::invert_endianness(buffer,siz); - T *ptrd = _data; - cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); - buffer-=siz; - delete[] buffer; - } - } - } - break; - case 13 : { // Region 3D - cimg::fread(dims,5,nfile); - if (endian) cimg::invert_endianness(dims,5); - assign(dims[3],dims[2],dims[1],1); - const size_t siz = size(); - if (dims[4]<256) { - unsigned char *buffer = new unsigned char[siz]; - cimg::fread(buffer,siz,nfile); - T *ptrd = _data; - cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); - buffer-=siz; - delete[] buffer; - } else { - if (dims[4]<65536) { - unsigned short *buffer = new unsigned short[siz]; - cimg::fread(buffer,siz,nfile); - if (endian) cimg::invert_endianness(buffer,siz); - T *ptrd = _data; - cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); - buffer-=siz; - delete[] buffer; - } else { - unsigned int *buffer = new unsigned int[siz]; - cimg::fread(buffer,siz,nfile); - if (endian) cimg::invert_endianness(buffer,siz); - T *ptrd = _data; - cimg_foroff(*this,off) *(ptrd++) = (T)*(buffer++); - buffer-=siz; - delete[] buffer; - } - } - } - break; - case 16 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,unsigned char,unsigned char,unsigned char,1); break; - case 17 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,long,int,short,4); break; - case 18 : _cimg_load_pandore_case(4,dims[2],dims[1],1,3,double,float,float,4); break; - case 19 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,unsigned char,unsigned char,unsigned char,1); break; - case 20 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,long,int,short,4); break; - case 21 : _cimg_load_pandore_case(5,dims[3],dims[2],dims[1],3,double,float,float,4); break; - case 22 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned char,unsigned char,unsigned char,1); break; - case 23 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],long,int,short,4); break; - case 24 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],unsigned long,unsigned int,unsigned short,4); break; - case 25 : _cimg_load_pandore_case(2,dims[1],1,1,dims[0],double,float,float,4); break; - case 26 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned char,unsigned char,unsigned char,1); break; - case 27 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],long,int,short,4); break; - case 28 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],unsigned long,unsigned int,unsigned short,4); break; - case 29 : _cimg_load_pandore_case(3,dims[2],dims[1],1,dims[0],double,float,float,4); break; - case 30 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned char,unsigned char,unsigned char,1); - break; - case 31 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],long,int,short,4); break; - case 32 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],unsigned long,unsigned int,unsigned short,4); - break; - case 33 : _cimg_load_pandore_case(4,dims[3],dims[2],dims[1],dims[0],double,float,float,4); break; - case 34 : { // Points 1D - cimg::fread(ptbuf,1,nfile); - if (endian) cimg::invert_endianness(ptbuf,1); - assign(1); (*this)(0) = (T)ptbuf[0]; - } break; - case 35 : { // Points 2D - cimg::fread(ptbuf,2,nfile); - if (endian) cimg::invert_endianness(ptbuf,2); - assign(2); (*this)(0) = (T)ptbuf[1]; (*this)(1) = (T)ptbuf[0]; - } break; - case 36 : { // Points 3D - cimg::fread(ptbuf,3,nfile); - if (endian) cimg::invert_endianness(ptbuf,3); - assign(3); (*this)(0) = (T)ptbuf[2]; (*this)(1) = (T)ptbuf[1]; (*this)(2) = (T)ptbuf[0]; - } break; - default : - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_pandore(): Unable to load data with ID_type %u in file '%s'.", - cimg_instance, - imageid,filename?filename:"(FILE*)"); - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Load image from a PAR-REC (Philips) file. - /** - \param filename Filename, as a C-string. - \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. - \param align Appending alignment. - **/ - CImg& load_parrec(const char *const filename, const char axis='c', const float align=0) { - CImgList list; - list.load_parrec(filename); - if (list._width==1) return list[0].move_to(*this); - return assign(list.get_append(axis,align)); - } - - //! Load image from a PAR-REC (Philips) file \newinstance. - static CImg get_load_parrec(const char *const filename, const char axis='c', const float align=0) { - return CImg().load_parrec(filename,axis,align); - } - - //! Load image from a raw binary file. - /** - \param filename Filename, as a C-string. - \param size_x Width of the image buffer. - \param size_y Height of the image buffer. - \param size_z Depth of the image buffer. - \param size_c Spectrum of the image buffer. - \param is_multiplexed Tells if the image values are multiplexed along the C-axis. - \param invert_endianness Tells if the endianness of the image buffer must be inverted. - \param offset Starting offset of the read in the specified file. - **/ - CImg& load_raw(const char *const filename, - const unsigned int size_x=0, const unsigned int size_y=1, - const unsigned int size_z=1, const unsigned int size_c=1, - const bool is_multiplexed=false, const bool invert_endianness=false, - const ulongT offset=0) { - return _load_raw(0,filename,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset); - } - - //! Load image from a raw binary file \newinstance. - static CImg get_load_raw(const char *const filename, - const unsigned int size_x=0, const unsigned int size_y=1, - const unsigned int size_z=1, const unsigned int size_c=1, - const bool is_multiplexed=false, const bool invert_endianness=false, - const ulongT offset=0) { - return CImg().load_raw(filename,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset); - } - - //! Load image from a raw binary file \overloading. - CImg& load_raw(std::FILE *const file, - const unsigned int size_x=0, const unsigned int size_y=1, - const unsigned int size_z=1, const unsigned int size_c=1, - const bool is_multiplexed=false, const bool invert_endianness=false, - const ulongT offset=0) { - return _load_raw(file,0,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset); - } - - //! Load image from a raw binary file \newinstance. - static CImg get_load_raw(std::FILE *const file, - const unsigned int size_x=0, const unsigned int size_y=1, - const unsigned int size_z=1, const unsigned int size_c=1, - const bool is_multiplexed=false, const bool invert_endianness=false, - const ulongT offset=0) { - return CImg().load_raw(file,size_x,size_y,size_z,size_c,is_multiplexed,invert_endianness,offset); - } - - CImg& _load_raw(std::FILE *const file, const char *const filename, - const unsigned int size_x, const unsigned int size_y, - const unsigned int size_z, const unsigned int size_c, - const bool is_multiplexed, const bool invert_endianness, - const ulongT offset) { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_raw(): Specified filename is (null).", - cimg_instance); - if (cimg::is_directory(filename)) - throw CImgArgumentException(_cimg_instance - "load_raw(): Specified filename '%s' is a directory.", - cimg_instance,filename); - const bool is_bool = pixel_type()==cimg::type::string(); - ulongT siz = (ulongT)size_x*size_y*size_z*size_c; - unsigned int - _size_x = size_x, - _size_y = size_y, - _size_z = size_z, - _size_c = size_c; - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - if (!siz) { // Retrieve file size - const longT fpos = cimg::ftell(nfile); - if (fpos<0) throw CImgArgumentException(_cimg_instance - "load_raw(): Cannot determine size of input file '%s'.", - cimg_instance,filename?filename:"(FILE*)"); - cimg::fseek(nfile,0,SEEK_END); - siz = (ulongT)cimg::ftell(nfile); - if (!is_bool) { siz/=sizeof(T); _size_y = (unsigned int)siz; } - else _size_y = (unsigned int)(siz*8); - _size_x = _size_z = _size_c = 1; - cimg::fseek(nfile,fpos,SEEK_SET); - } - cimg::fseek(nfile,(longT)offset,SEEK_SET); - assign(_size_x,_size_y,_size_z,_size_c,0); - - if (is_bool) { // Boolean data (bitwise) - unsigned char *const buf = new unsigned char[siz]; - cimg::fread(buf,siz,nfile); - _uchar2bool(buf,siz,is_multiplexed); - delete[] buf; - } else { // Non-boolean data - if (siz && (!is_multiplexed || size_c==1)) { // Non-multiplexed - cimg::fread(_data,siz,nfile); - if (invert_endianness) cimg::invert_endianness(_data,siz); - } else if (siz) { // Multiplexed - CImg buf(1,1,1,_size_c); - cimg_forXYZ(*this,x,y,z) { - cimg::fread(buf._data,_size_c,nfile); - if (invert_endianness) cimg::invert_endianness(buf._data,_size_c); - set_vector_at(buf,x,y,z); - } - } - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Load image sequence from a YUV file. - /** - \param filename Filename, as a C-string. - \param size_x Width of the frames. - \param size_y Height of the frames. - \param chroma_subsampling Type of chroma subsampling. Can be { 420 | 422 | 444 }. - \param first_frame Index of the first frame to read. - \param last_frame Index of the last frame to read. - \param step_frame Step value for frame reading. - \param yuv2rgb Tells if the YUV to RGB transform must be applied. - \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. - **/ - CImg& load_yuv(const char *const filename, - const unsigned int size_x, const unsigned int size_y=1, - const unsigned int chroma_subsampling=444, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') { - return get_load_yuv(filename,size_x,size_y,chroma_subsampling, - first_frame,last_frame,step_frame,yuv2rgb,axis).move_to(*this); - } - - //! Load image sequence from a YUV file \newinstance. - static CImg get_load_yuv(const char *const filename, - const unsigned int size_x, const unsigned int size_y=1, - const unsigned int chroma_subsampling=444, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') { - return CImgList().load_yuv(filename,size_x,size_y,chroma_subsampling, - first_frame,last_frame,step_frame,yuv2rgb).get_append(axis); - } - - //! Load image sequence from a YUV file \overloading. - CImg& load_yuv(std::FILE *const file, - const unsigned int size_x, const unsigned int size_y=1, - const unsigned int chroma_subsampling=444, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') { - return get_load_yuv(file,size_x,size_y,chroma_subsampling, - first_frame,last_frame,step_frame,yuv2rgb,axis).move_to(*this); - } - - //! Load image sequence from a YUV file \newinstance. - static CImg get_load_yuv(std::FILE *const file, - const unsigned int size_x, const unsigned int size_y=1, - const unsigned int chroma_subsampling=444, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool yuv2rgb=true, const char axis='z') { - return CImgList().load_yuv(file,size_x,size_y,chroma_subsampling, - first_frame,last_frame,step_frame,yuv2rgb).get_append(axis); - } - - //! Load 3D object from a .OFF file. - /** - \param[out] primitives Primitives data of the 3D object. - \param[out] colors Colors data of the 3D object. - \param filename Filename, as a C-string. - **/ - template - CImg& load_off(CImgList& primitives, CImgList& colors, const char *const filename) { - return _load_off(primitives,colors,0,filename); - } - - //! Load 3D object from a .OFF file \newinstance. - template - static CImg get_load_off(CImgList& primitives, CImgList& colors, const char *const filename) { - return CImg().load_off(primitives,colors,filename); - } - - //! Load 3D object from a .OFF file \overloading. - template - CImg& load_off(CImgList& primitives, CImgList& colors, std::FILE *const file) { - return _load_off(primitives,colors,file,0); - } - - //! Load 3D object from a .OFF file \newinstance. - template - static CImg get_load_off(CImgList& primitives, CImgList& colors, std::FILE *const file) { - return CImg().load_off(primitives,colors,file); - } - - template - CImg& _load_off(CImgList& primitives, CImgList& colors, - std::FILE *const file, const char *const filename) { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "load_off(): Specified filename is (null).", - cimg_instance); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"r"); - unsigned int nb_points = 0, nb_primitives = 0, nb_read = 0; - CImg line(256); *line = 0; - int err; - - // Skip comments, and read magic string OFF - do { err = std::fscanf(nfile,"%255[^\n] ",line._data); } while (!err || (err==1 && *line=='#')); - if (cimg::strncasecmp(line,"OFF",3) && cimg::strncasecmp(line,"COFF",4)) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_off(): OFF header not found in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - } - do { err = std::fscanf(nfile,"%255[^\n] ",line._data); } while (!err || (err==1 && *line=='#')); - if ((err = cimg_sscanf(line,"%u%u%*[^\n] ",&nb_points,&nb_primitives))!=2) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_off(): Invalid number of vertices or primitives specified in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - } - - // Read points data - assign(nb_points,3); - float X = 0, Y = 0, Z = 0; - cimg_forX(*this,l) { - do { err = std::fscanf(nfile,"%255[^\n] ",line._data); } while (!err || (err==1 && *line=='#')); - if ((err = cimg_sscanf(line,"%f%f%f%*[^\n] ",&X,&Y,&Z))!=3) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "load_off(): Failed to read vertex %u/%u in file '%s'.", - cimg_instance, - l + 1,nb_points,filename?filename:"(FILE*)"); - } - (*this)(l,0) = (T)X; (*this)(l,1) = (T)Y; (*this)(l,2) = (T)Z; - } - - // Read primitive data - primitives.assign(); - colors.assign(); - bool stop_flag = false; - while (!stop_flag) { - float c0 = 0.7f, c1 = 0.7f, c2 = 0.7f; - unsigned int prim = 0, i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0; - *line = 0; - if ((err = std::fscanf(nfile,"%u",&prim))!=1) stop_flag = true; - else { - ++nb_read; - switch (prim) { - case 1 : { - if ((err = std::fscanf(nfile,"%u%255[^\n] ",&i0,line._data))<2) { - cimg::warn(_cimg_instance - "load_off(): Failed to read primitive %u/%u from file '%s'.", - cimg_instance, - nb_read,nb_primitives,filename?filename:"(FILE*)"); - - err = std::fscanf(nfile,"%*[^\n] "); - } else { - err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); - CImg::vector(i0).move_to(primitives); - CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); - } - } break; - case 2 : { - if ((err = std::fscanf(nfile,"%u%u%255[^\n] ",&i0,&i1,line._data))<2) { - cimg::warn(_cimg_instance - "load_off(): Failed to read primitive %u/%u from file '%s'.", - cimg_instance, - nb_read,nb_primitives,filename?filename:"(FILE*)"); - - err = std::fscanf(nfile,"%*[^\n] "); - } else { - err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); - CImg::vector(i0,i1).move_to(primitives); - CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); - } - } break; - case 3 : { - if ((err = std::fscanf(nfile,"%u%u%u%255[^\n] ",&i0,&i1,&i2,line._data))<3) { - cimg::warn(_cimg_instance - "load_off(): Failed to read primitive %u/%u from file '%s'.", - cimg_instance, - nb_read,nb_primitives,filename?filename:"(FILE*)"); - - err = std::fscanf(nfile,"%*[^\n] "); - } else { - err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); - CImg::vector(i0,i2,i1).move_to(primitives); - CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); - } - } break; - case 4 : { - if ((err = std::fscanf(nfile,"%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,line._data))<4) { - cimg::warn(_cimg_instance - "load_off(): Failed to read primitive %u/%u from file '%s'.", - cimg_instance, - nb_read,nb_primitives,filename?filename:"(FILE*)"); - - err = std::fscanf(nfile,"%*[^\n] "); - } else { - err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); - CImg::vector(i0,i3,i2,i1).move_to(primitives); - CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255)).move_to(colors); - } - } break; - case 5 : { - if ((err = std::fscanf(nfile,"%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,line._data))<5) { - cimg::warn(_cimg_instance - "load_off(): Failed to read primitive %u/%u from file '%s'.", - cimg_instance, - nb_read,nb_primitives,filename?filename:"(FILE*)"); - - err = std::fscanf(nfile,"%*[^\n] "); - } else { - err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); - CImg::vector(i0,i3,i2,i1).move_to(primitives); - CImg::vector(i0,i4,i3).move_to(primitives); - colors.insert(2,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); - ++nb_primitives; - } - } break; - case 6 : { - if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,line._data))<6) { - cimg::warn(_cimg_instance - "load_off(): Failed to read primitive %u/%u from file '%s'.", - cimg_instance, - nb_read,nb_primitives,filename?filename:"(FILE*)"); - - err = std::fscanf(nfile,"%*[^\n] "); - } else { - err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); - CImg::vector(i0,i3,i2,i1).move_to(primitives); - CImg::vector(i0,i5,i4,i3).move_to(primitives); - colors.insert(2,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); - ++nb_primitives; - } - } break; - case 7 : { - if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,line._data))<7) { - cimg::warn(_cimg_instance - "load_off(): Failed to read primitive %u/%u from file '%s'.", - cimg_instance, - nb_read,nb_primitives,filename?filename:"(FILE*)"); - - err = std::fscanf(nfile,"%*[^\n] "); - } else { - err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); - CImg::vector(i0,i4,i3,i1).move_to(primitives); - CImg::vector(i0,i6,i5,i4).move_to(primitives); - CImg::vector(i3,i2,i1).move_to(primitives); - colors.insert(3,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); - ++(++nb_primitives); - } - } break; - case 8 : { - if ((err = std::fscanf(nfile,"%u%u%u%u%u%u%u%u%255[^\n] ",&i0,&i1,&i2,&i3,&i4,&i5,&i6,&i7,line._data))<7) { - cimg::warn(_cimg_instance - "load_off(): Failed to read primitive %u/%u from file '%s'.", - cimg_instance, - nb_read,nb_primitives,filename?filename:"(FILE*)"); - - err = std::fscanf(nfile,"%*[^\n] "); - } else { - err = cimg_sscanf(line,"%f%f%f",&c0,&c1,&c2); - CImg::vector(i0,i3,i2,i1).move_to(primitives); - CImg::vector(i0,i5,i4,i3).move_to(primitives); - CImg::vector(i0,i7,i6,i5).move_to(primitives); - colors.insert(3,CImg::vector((tc)(c0*255),(tc)(c1*255),(tc)(c2*255))); - ++(++nb_primitives); - } - } break; - default : - cimg::warn(_cimg_instance - "load_off(): Failed to read primitive %u/%u (%u vertices) from file '%s'.", - cimg_instance, - nb_read,nb_primitives,prim,filename?filename:"(FILE*)"); - - err = std::fscanf(nfile,"%*[^\n] "); - } - } - } - if (!file) cimg::fclose(nfile); - if (primitives._width!=nb_primitives) - cimg::warn(_cimg_instance - "load_off(): Only %u/%u primitives read from file '%s'.", - cimg_instance, - primitives._width,nb_primitives,filename?filename:"(FILE*)"); - return *this; - } - - //! Load image sequence from a video file, using OpenCV library. - /** - \param filename Filename, as a C-string. - \param first_frame Index of the first frame to read. - \param last_frame Index of the last frame to read. - \param step_frame Step value for frame reading. - \param axis Alignment axis. - \param align Appending alignment. - **/ - CImg& load_video(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, - const char axis='z', const float align=0) { - return get_load_video(filename,first_frame,last_frame,step_frame,axis,align).move_to(*this); - } - - //! Load image sequence from a video file, using OpenCV library \newinstance. - static CImg get_load_video(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, - const char axis='z', const float align=0) { - return CImgList().load_video(filename,first_frame,last_frame,step_frame).get_append(axis,align); - } - - //! Load image sequence using FFMPEG's external tool 'ffmpeg'. - /** - \param filename Filename, as a C-string. - \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. - \param align Appending alignment. - **/ - CImg& load_ffmpeg_external(const char *const filename, const char axis='z', const float align=0) { - return get_load_ffmpeg_external(filename,axis,align).move_to(*this); - } - - //! Load image sequence using FFMPEG's external tool 'ffmpeg' \newinstance. - static CImg get_load_ffmpeg_external(const char *const filename, const char axis='z', const float align=0) { - return CImgList().load_ffmpeg_external(filename).get_append(axis,align); - } - - //! Load gif file, using Imagemagick or GraphicsMagicks's external tools. - /** - \param filename Filename, as a C-string. - \param axis Appending axis, if file contains multiple images. Can be { 'x' | 'y' | 'z' | 'c' }. - \param align Appending alignment. - **/ - CImg& load_gif_external(const char *const filename, - const char axis='z', const float align=0) { - return get_load_gif_external(filename,axis,align).move_to(*this); - } - - //! Load gif file, using ImageMagick or GraphicsMagick's external tool 'convert' \newinstance. - static CImg get_load_gif_external(const char *const filename, - const char axis='z', const float align=0) { - return CImgList().load_gif_external(filename).get_append(axis,align); - } - - //! Load image from a HEIC file. - /** - \param filename Filename, as a C-string. - **/ - CImg& load_heif(const char *const filename) { - return _load_heif(filename); - } - - //! Load image from a HEIC file \newinstance. - static CImg get_load_heif(const char *const filename) { - return CImg().load_heif(filename); - } - - CImg& _load_heif(const char *const filename) { -#ifndef cimg_use_heif - return load_other(filename); -#else - try { - heif::Context ctx; - ctx.read_from_file(filename); - - heif::ImageHandle handle = ctx.get_primary_image_handle(); - const heif::Image image = - handle.decode_image(heif_colorspace_RGB,handle.has_alpha_channel()?heif_chroma_interleaved_RGBA: - heif_chroma_interleaved_RGB); - const int - W = image.get_width(heif_channel_interleaved), - H = image.get_height(heif_channel_interleaved), - S = handle.has_alpha_channel()?4:3; - assign(W,H,1,S); - - int stride; - const unsigned char *const buffer = image.get_plane(heif_channel_interleaved,&stride); - T *ptr_r = _data, *ptr_g = data(0,0,0,1), *ptr_b = data(0,0,0,2), *ptr_a = S>3?data(0,0,0,3):0; - cimg_forY(*this,y) { - const unsigned char *ptrs = buffer + y*stride; - if (ptr_a) cimg_forX(*this,x) { // RGBA - *(ptr_r++) = (T)*(ptrs++); - *(ptr_g++) = (T)*(ptrs++); - *(ptr_b++) = (T)*(ptrs++); - *(ptr_a++) = (T)*(ptrs++); - } - else cimg_forX(*this,x) { // RGB - *(ptr_r++) = (T)*(ptrs++); - *(ptr_g++) = (T)*(ptrs++); - *(ptr_b++) = (T)*(ptrs++); - } - } - } catch (const heif::Error& e) { - throw CImgInstanceException(_cimg_instance - "load_heif(): Unable to decode image: %s", - cimg_instance, - e.get_message().c_str()); - } catch (...) { - throw; - } - return *this; -#endif - } - - //! Load image using GraphicsMagick's external tool 'gm'. - /** - \param filename Filename, as a C-string. - **/ - CImg& load_graphicsmagick_external(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimg_instance - "load_graphicsmagick_external(): Specified filename is (null).", - cimg_instance); - cimg::fclose(cimg::fopen(filename,"rb")); // Check if file exists - CImg command(1024), filename_tmp(256); - std::FILE *file = 0; - const CImg s_filename = CImg::string(filename)._system_strescape(); -#if cimg_OS==1 - if (!cimg::system("which gm")) { - cimg_snprintf(command,command._width,"%s convert \"%s\" %s:-", - cimg::graphicsmagick_path(), - s_filename.data(), -#ifdef cimg_use_png - "png" -#else - "pnm" -#endif - ); - file = popen(command,"r"); - if (file) { - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - try { -#ifdef cimg_use_png - load_png(file); -#else - load_pnm(file); -#endif - } catch (...) { - pclose(file); - cimg::exception_mode(omode); - throw CImgIOException(_cimg_instance - "load_graphicsmagick_external(): Failed to load file '%s' " - "with external command 'gm'.", - cimg_instance, - filename); - } - pclose(file); - return *this; - } - } -#endif - do { - cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", - cimg::temporary_path(), - cimg_file_separator, - cimg::filenamerand(), -#ifdef cimg_use_png - "png" -#else - "pnm" -#endif - ); - if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); - } while (file); - cimg_snprintf(command,command._width,"\"%s\" convert \"%s\" \"%s\"", - cimg::graphicsmagick_path(), - s_filename.data(), - CImg::string(filename_tmp)._system_strescape().data()); - cimg::system(command,cimg::graphicsmagick_path()); - if (!(file=cimg::std_fopen(filename_tmp,"rb"))) { - cimg::fclose(cimg::fopen(filename,"r")); - throw CImgIOException(_cimg_instance - "load_graphicsmagick_external(): Failed to load file '%s' with external command 'gm'.", - cimg_instance, - filename); - - } else cimg::fclose(file); -#ifdef cimg_use_png - load_png(filename_tmp); -#else - load_pnm(filename_tmp); -#endif - std::remove(filename_tmp); - return *this; - } - - //! Load image using GraphicsMagick's external tool 'gm' \newinstance. - static CImg get_load_graphicsmagick_external(const char *const filename) { - return CImg().load_graphicsmagick_external(filename); - } - - //! Load gzipped image file, using external tool 'gunzip'. - /** - \param filename Filename, as a C-string. - **/ - CImg& load_gzip_external(const char *const filename) { - if (!filename) - throw CImgIOException(_cimg_instance - "load_gzip_external(): Specified filename is (null).", - cimg_instance); - cimg::fclose(cimg::fopen(filename,"rb")); // Check if file exists - CImg command(1024), filename_tmp(256), body(256); - const char - *const ext = cimg::split_filename(filename,body), - *const ext2 = cimg::split_filename(body,0); - - std::FILE *file = 0; - do { - if (!cimg::strcasecmp(ext,"gz")) { - if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2); - else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - } else { - if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); - else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - } - if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); - } while (file); - cimg_snprintf(command,command._width,"\"%s\" -c \"%s\" > \"%s\"", - cimg::gunzip_path(), - CImg::string(filename)._system_strescape().data(), - CImg::string(filename_tmp)._system_strescape().data()); - cimg::system(command); - if (!(file=cimg::std_fopen(filename_tmp,"rb"))) { - cimg::fclose(cimg::fopen(filename,"r")); - throw CImgIOException(_cimg_instance - "load_gzip_external(): Failed to load file '%s' with external command 'gunzip'.", - cimg_instance, - filename); - - } else cimg::fclose(file); - load(filename_tmp); - std::remove(filename_tmp); - return *this; - } - - //! Load gzipped image file, using external tool 'gunzip' \newinstance. - static CImg get_load_gzip_external(const char *const filename) { - return CImg().load_gzip_external(filename); - } - - //! Load image using ImageMagick's external tool 'convert'. - /** - \param filename Filename, as a C-string. - **/ - CImg& load_imagemagick_external(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimg_instance - "load_imagemagick_external(): Specified filename is (null).", - cimg_instance); - cimg::fclose(cimg::fopen(filename,"rb")); // Check if file exists - CImg command(1024), filename_tmp(256); - std::FILE *file = 0; - const CImg s_filename = CImg::string(filename)._system_strescape(); -#if cimg_OS==1 - if (!cimg::system("which convert")) { - cimg_snprintf(command,command._width,"%s%s \"%s\" %s:-", - cimg::imagemagick_path(), - !cimg::strcasecmp(cimg::split_filename(filename),"pdf")?" -density 400x400":"", - s_filename.data(), -#ifdef cimg_use_png - "png" -#else - "pnm" -#endif - ); - file = popen(command,"r"); - if (file) { - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - try { -#ifdef cimg_use_png - load_png(file); -#else - load_pnm(file); -#endif - } catch (...) { - pclose(file); - cimg::exception_mode(omode); - throw CImgIOException(_cimg_instance - "load_imagemagick_external(): Failed to load file '%s' with " - "external command 'magick/convert'.", - cimg_instance, - filename); - } - pclose(file); - return *this; - } - } -#endif - do { - cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", - cimg::temporary_path(), - cimg_file_separator, - cimg::filenamerand(), -#ifdef cimg_use_png - "png" -#else - "pnm" -#endif - ); - if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); - } while (file); - cimg_snprintf(command,command._width,"\"%s\"%s \"%s\" \"%s\"", - cimg::imagemagick_path(), - !cimg::strcasecmp(cimg::split_filename(filename),"pdf")?" -density 400x400":"", - s_filename.data(), - CImg::string(filename_tmp)._system_strescape().data()); - cimg::system(command,cimg::imagemagick_path()); - if (!(file=cimg::std_fopen(filename_tmp,"rb"))) { - cimg::fclose(cimg::fopen(filename,"r")); - throw CImgIOException(_cimg_instance - "load_imagemagick_external(): Failed to load file '%s' with " - "external command 'magick/convert'.", - cimg_instance, - filename); - - } else cimg::fclose(file); -#ifdef cimg_use_png - load_png(filename_tmp); -#else - load_pnm(filename_tmp); -#endif - std::remove(filename_tmp); - return *this; - } - - //! Load image using ImageMagick's external tool 'convert' \newinstance. - static CImg get_load_imagemagick_external(const char *const filename) { - return CImg().load_imagemagick_external(filename); - } - - //! Load image from a DICOM file, using Medcon's external tool 'medcon'. - /** - \param filename Filename, as a C-string. - **/ - CImg& load_medcon_external(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimg_instance - "load_medcon_external(): Specified filename is (null).", - cimg_instance); - cimg::fclose(cimg::fopen(filename,"rb")); // Check if file exists - CImg command(1024), filename_tmp(256), body(256); - cimg::fclose(cimg::fopen(filename,"r")); - std::FILE *file = 0; - do { - cimg_snprintf(filename_tmp,filename_tmp._width,"%s.hdr",cimg::filenamerand()); - if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); - } while (file); - cimg_snprintf(command,command._width,"\"%s\" -w -c anlz -o \"%s\" -f \"%s\"", - cimg::medcon_path(), - CImg::string(filename_tmp)._system_strescape().data(), - CImg::string(filename)._system_strescape().data()); - cimg::system(command, cimg::medcon_path()); - cimg::split_filename(filename_tmp,body); - - cimg_snprintf(command,command._width,"%s.hdr",body._data); - file = cimg::std_fopen(command,"rb"); - if (!file) { - cimg_snprintf(command,command._width,"m000-%s.hdr",body._data); - file = cimg::std_fopen(command,"rb"); - if (!file) { - throw CImgIOException(_cimg_instance - "load_medcon_external(): Failed to load file '%s' with external command 'medcon'.", - cimg_instance, - filename); - } - } - cimg::fclose(file); - load_analyze(command); - std::remove(command); - cimg::split_filename(command,body); - cimg_snprintf(command,command._width,"%s.img",body._data); - std::remove(command); - return *this; - } - - //! Load image from a DICOM file, using Medcon's external tool 'medcon' \newinstance. - static CImg get_load_medcon_external(const char *const filename) { - return CImg().load_medcon_external(filename); - } - - //! Load image from a .pdf file. - /** - \param filename Filename, as a C-string. - \param resolution Image resolution. - **/ - CImg& load_pdf_external(const char *const filename, const unsigned int resolution=400) { - if (!filename) - throw CImgArgumentException(_cimg_instance - "load_pdf_external(): Specified filename is (null).", - cimg_instance); - CImg command(1024), filename_tmp(256); - std::FILE *file = 0; - const CImg s_filename = CImg::string(filename)._system_strescape(); -#if cimg_OS==1 - cimg_snprintf(command,command._width,"gs -q -dNOPAUSE -sDEVICE=ppmraw -o - -r%u \"%s\"", - resolution,s_filename.data()); - file = popen(command,"r"); - if (file) { - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - try { load_pnm(file); } catch (...) { - pclose(file); - cimg::exception_mode(omode); - throw CImgIOException(_cimg_instance - "load_pdf_external(): Failed to load file '%s' with external command 'gs'.", - cimg_instance, - filename); - } - pclose(file); - return *this; - } -#endif - do { - cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.ppm", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); - } while (file); - cimg_snprintf(command,command._width,"gs -q -dNOPAUSE -sDEVICE=ppmraw -o \"%s\" -r%u \"%s\"", - CImg::string(filename_tmp)._system_strescape().data(),resolution,s_filename.data()); - cimg::system(command,"gs"); - if (!(file=cimg::std_fopen(filename_tmp,"rb"))) { - cimg::fclose(cimg::fopen(filename,"r")); - throw CImgIOException(_cimg_instance - "load_pdf_external(): Failed to load file '%s' with external command 'gs'.", - cimg_instance, - filename); - } else cimg::fclose(file); - load_pnm(filename_tmp); - std::remove(filename_tmp); - return *this; - } - - //! Load image from a .pdf file \newinstance. - static CImg get_load_pdf_external(const char *const filename, const unsigned int resolution=400) { - return CImg().load_pdf_external(filename,resolution); - } - - //! Load image from a RAW Color Camera file, using external tool 'dcraw'. - /** - \param filename Filename, as a C-string. - **/ - CImg& load_dcraw_external(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimg_instance - "load_dcraw_external(): Specified filename is (null).", - cimg_instance); - cimg::fclose(cimg::fopen(filename,"rb")); // Check if file exists - CImg command(1024), filename_tmp(256); - std::FILE *file = 0; - const CImg s_filename = CImg::string(filename)._system_strescape(); -#if cimg_OS==1 - cimg_snprintf(command,command._width,"%s -w -4 -c \"%s\"", - cimg::dcraw_path(),s_filename.data()); - file = popen(command,"r"); - if (file) { - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - try { load_pnm(file); } catch (...) { - pclose(file); - cimg::exception_mode(omode); - throw CImgIOException(_cimg_instance - "load_dcraw_external(): Failed to load file '%s' with external command 'dcraw'.", - cimg_instance, - filename); - } - pclose(file); - return *this; - } -#endif - do { - cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.ppm", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); - } while (file); - cimg_snprintf(command,command._width,"\"%s\" -w -4 -c \"%s\" > \"%s\"", - cimg::dcraw_path(),s_filename.data(),CImg::string(filename_tmp)._system_strescape().data()); - cimg::system(command,cimg::dcraw_path()); - if (!(file=cimg::std_fopen(filename_tmp,"rb"))) { - cimg::fclose(cimg::fopen(filename,"r")); - throw CImgIOException(_cimg_instance - "load_dcraw_external(): Failed to load file '%s' with external command 'dcraw'.", - cimg_instance, - filename); - - } else cimg::fclose(file); - load_pnm(filename_tmp); - std::remove(filename_tmp); - return *this; - } - - //! Load image from a RAW Color Camera file, using external tool 'dcraw' \newinstance. - static CImg get_load_dcraw_external(const char *const filename) { - return CImg().load_dcraw_external(filename); - } - -#ifdef cimg_use_opencv - - // Convert a continuous cv::Mat to a CImg. - static CImg _cvmat2cimg(const cv::Mat &src) { - if (src.channels()==1) return CImg(src.ptr(),src.cols,src.rows,1,1); - else if (src.channels()==3) { // BGR - CImg res(src.cols,src.rows,1,src.channels()); - const unsigned char *ptrs = src.ptr(); - unsigned char *pR = res.data(), *pG = res.data(0,0,0,1), *pB = res.data(0,0,0,2); - cimg_forXY(res,x,y) { *(pB++) = *(ptrs++); *(pG++) = *(ptrs++); *(pR++) = *(ptrs++); } - return res; - } - return CImg(src.ptr(),src.channels(),src.cols,src.rows,1,true).get_permute_axes("yzcx"); - } - - // Convert a CImg to a cv::Mat. - cv::Mat _cimg2cvmat() const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "_cimg2cvmat() : Instance image is empty.", - cimg_instance); - if (_spectrum==2) - throw CImgInstanceException(_cimg_instance - "_cimg2cvmat() : Invalid number of channels (should be '1' or '3+').", - cimg_instance); - if (_depth!=1) - throw CImgInstanceException(_cimg_instance - "_cimg2cvmat() : Invalid number of slices (should be '1').", - cimg_instance); - int mat_type = -1; - if (pixel_type()==cimg::type::string()) mat_type = CV_8UC1; - if (pixel_type()==cimg::type::string()) mat_type = CV_8SC1; - if (pixel_type()==cimg::type::string()) mat_type = CV_16UC1; - if (pixel_type()==cimg::type::string()) mat_type = CV_16SC1; - if (pixel_type()==cimg::type::string()) mat_type = CV_32SC1; - if (pixel_type()==cimg::type::string()) mat_type = CV_32FC1; - if (pixel_type()==cimg::type::string()) mat_type = CV_64FC1; - if (mat_type<0) - throw CImgInstanceException(_cimg_instance - "_cvmat2cimg() : pixel type '%s' is not supported.", - cimg_instance,pixel_type()); - cv::Mat res; - std::vector channels(_spectrum); - if (_spectrum>1) { - cimg_forC(*this,c) - channels[c] = cv::Mat(_height,_width,mat_type,_data + _width*_height*(_spectrum - 1 - c)); - cv::merge(channels,res); - } else res = cv::Mat(_height,_width,mat_type,_data).clone(); - return res; - } - -#endif - - //! Load image from a camera stream, using OpenCV. - /** - \param index Index of the camera to capture images from (from 0 to 63). - \param capture_width Width of the desired image ('0' stands for default value). - \param capture_height Height of the desired image ('0' stands for default value). - \param skip_frames Number of frames to skip before the capture. - \param release_camera Tells if the camera resource must be released at the end of the method. - **/ - CImg& load_camera(const unsigned int camera_index=0, - const unsigned int capture_width=0, const unsigned int capture_height=0, - const unsigned int skip_frames=0, const bool release_camera=true) { -#ifdef cimg_use_opencv - if (camera_index>=64) - throw CImgArgumentException(_cimg_instance - "load_camera(): Invalid request for camera #%u " - "(no more than 100 cameras can be managed simultaneously).", - cimg_instance, - camera_index); - static cv::VideoCapture *captures[64] = { 0 }; - static unsigned int captures_w[64], captures_h[64]; - if (release_camera) { - cimg::mutex(9); - if (captures[camera_index]) captures[camera_index]->release(); - delete captures[camera_index]; - captures[camera_index] = 0; - captures_w[camera_index] = captures_h[camera_index] = 0; - cimg::mutex(9,0); - return *this; - } - if (!captures[camera_index]) { - cimg::mutex(9); - captures[camera_index] = new cv::VideoCapture(camera_index); - captures_w[camera_index] = captures_h[camera_index] = 0; - if (!captures[camera_index]->isOpened()) { - delete captures[camera_index]; - captures[camera_index] = 0; - cimg::mutex(9,0); - throw CImgIOException(_cimg_instance - "load_camera(): Failed to initialize camera #%u.", - cimg_instance, - camera_index); - } - cimg::mutex(9,0); - } - cimg::mutex(9); - if (capture_width!=captures_w[camera_index]) { - captures[camera_index]->set(_cimg_cap_prop_frame_width,capture_width); - captures_w[camera_index] = capture_width; - } - if (capture_height!=captures_h[camera_index]) { - captures[camera_index]->set(_cimg_cap_prop_frame_height,capture_height); - captures_h[camera_index] = capture_height; - } - for (unsigned int i = 0; igrab(); - cv::Mat cvimg; - captures[camera_index]->read(cvimg); - if (cvimg.empty()) { - cimg::mutex(9,0); - load_camera(camera_index,0,0,0,true); // Release camera - throw CImgIOException(_cimg_instance - "load_camera(): Failed to retrieve a %ux%u frame from camera #%u.", - cimg_instance, - capture_width,capture_height,camera_index); - } else _cvmat2cimg(cvimg).move_to(*this); - cimg::mutex(9,0); - return *this; -#else - cimg::unused(camera_index,skip_frames,release_camera,capture_width,capture_height); - throw CImgIOException(_cimg_instance - "load_camera(): This function requires features from the OpenCV library " - "('-Dcimg_use_opencv' must be defined).", - cimg_instance); -#endif - } - - //! Load image from a camera stream, using OpenCV \newinstance. - static CImg get_load_camera(const unsigned int camera_index=0, - const unsigned int capture_width=0, const unsigned int capture_height=0, - const unsigned int skip_frames=0, const bool release_camera=true) { - return CImg().load_camera(camera_index,capture_width,capture_height,skip_frames,release_camera); - } - - //! Load image using various non-native ways. - /** - \param filename Filename, as a C-string. - **/ - CImg& load_other(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimg_instance - "load_other(): Specified filename is (null).", - cimg_instance); - - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - try { load_magick(filename); } - catch (CImgException&) { - try { load_imagemagick_external(filename); } - catch (CImgException&) { - try { load_graphicsmagick_external(filename); } - catch (CImgException&) { - try { load_cimg(filename); } - catch (CImgException&) { - try { - cimg::fclose(cimg::fopen(filename,"rb")); - } catch (CImgException&) { - cimg::exception_mode(omode); - throw CImgIOException(_cimg_instance - "load_other(): Failed to open file '%s'.", - cimg_instance, - filename); - } - cimg::exception_mode(omode); - throw CImgIOException(_cimg_instance - "load_other(): Failed to recognize format of file '%s'.", - cimg_instance, - filename); - } - } - } - } - cimg::exception_mode(omode); - return *this; - } - - //! Load image using various non-native ways \newinstance. - static CImg get_load_other(const char *const filename) { - return CImg().load_other(filename); - } - - //@} - //--------------------------- - // - //! \name Data Output - //@{ - //--------------------------- - - //! Display information about the image data. - /** - \param title Name for the considered image. - \param display_stats Tells to compute and display image statistics. - **/ - const CImg& print(const char *const title=0, const bool display_stats=true) const { - - int xm = 0, ym = 0, zm = 0, vm = 0, xM = 0, yM = 0, zM = 0, vM = 0; - CImg st; - if (!is_empty() && display_stats) { - st = get_stats(); - xm = (int)st[4]; ym = (int)st[5], zm = (int)st[6], vm = (int)st[7]; - xM = (int)st[8]; yM = (int)st[9], zM = (int)st[10], vM = (int)st[11]; - } - - const ulongT siz = size(), msiz = siz*sizeof(T), siz1 = siz - 1, - mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U, width1 = _width - 1; - - CImg _title(64); - if (!title) cimg_snprintf(_title,_title._width,"CImg<%s>",pixel_type()); - - std::fprintf(cimg::output(),"%s%s%s%s: %sthis%s = %p, %ssize%s = (%u,%u,%u,%u) [%lu %s], %sdata%s = (%s*)%p", - cimg::t_magenta,cimg::t_bold,title?title:_title._data,cimg::t_normal, - cimg::t_bold,cimg::t_normal,(void*)this, - cimg::t_bold,cimg::t_normal,_width,_height,_depth,_spectrum, - (unsigned long)(mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20))), - mdisp==0?"b":(mdisp==1?"Kio":"Mio"), - cimg::t_bold,cimg::t_normal,pixel_type(),(void*)begin()); - if (_data) - std::fprintf(cimg::output(),"..%p (%s) = [ ",(void*)((char*)end() - 1),_is_shared?"shared":"non-shared"); - else std::fprintf(cimg::output()," (%s) = [ ",_is_shared?"shared":"non-shared"); - - if (!is_empty()) cimg_foroff(*this,off) { - std::fprintf(cimg::output(),"%g",(double)_data[off]); - if (off!=siz1) std::fprintf(cimg::output(),"%s",off%_width==width1?" ; ":" "); - if (off==7 && siz>16) { off = siz1 - 8; std::fprintf(cimg::output(),"... "); } - } - if (!is_empty() && display_stats) - std::fprintf(cimg::output(), - " ], %smin%s = %g, %smax%s = %g, %smean%s = %g, %sstd%s = %g, %scoords_min%s = (%u,%u,%u,%u), " - "%scoords_max%s = (%u,%u,%u,%u).\n", - cimg::t_bold,cimg::t_normal,st[0], - cimg::t_bold,cimg::t_normal,st[1], - cimg::t_bold,cimg::t_normal,st[2], - cimg::t_bold,cimg::t_normal,std::sqrt(st[3]), - cimg::t_bold,cimg::t_normal,xm,ym,zm,vm, - cimg::t_bold,cimg::t_normal,xM,yM,zM,vM); - else std::fprintf(cimg::output(),"%s].\n",is_empty()?"":" "); - std::fflush(cimg::output()); - return *this; - } - - //! Display image into a CImgDisplay window. - /** - \param disp Display window. - **/ - const CImg& display(CImgDisplay& disp) const { - disp.display(*this); - return *this; - } - - //! Display image into a CImgDisplay window, in an interactive way. - /** - \param disp Display window. - \param display_info Tells if image information are displayed on the standard output. - \param[in,out] XYZ Contains the XYZ coordinates at start / exit of the function. - \param exit_on_anykey Exit function when any key is pressed. - **/ - const CImg& display(CImgDisplay &disp, const bool display_info, unsigned int *const XYZ=0, - const bool exit_on_anykey=false) const { - return _display(disp,0,display_info,XYZ,exit_on_anykey,false); - } - - //! Display image into an interactive window. - /** - \param title Window title - \param display_info Tells if image information are displayed on the standard output. - \param[in,out] XYZ Contains the XYZ coordinates at start / exit of the function. - \param exit_on_anykey Exit function when any key is pressed. - **/ - const CImg& display(const char *const title=0, const bool display_info=true, unsigned int *const XYZ=0, - const bool exit_on_anykey=false) const { - CImgDisplay disp; - return _display(disp,title,display_info,XYZ,exit_on_anykey,false); - } - - const CImg& _display(CImgDisplay &disp, const char *const title, const bool display_info, - unsigned int *const XYZ, const bool exit_on_anykey, - const bool exit_on_singleclick) const { - unsigned int oldw = 0, oldh = 0, _XYZ[3] = { 0 }, key = 0; - int x0 = 0, y0 = 0, z0 = 0, x1 = width() - 1, y1 = height() - 1, z1 = depth() - 1, - old_mouse_x = -1, old_mouse_y = -1; - - if (!disp) { - disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,1); - if (!title) disp.set_title("CImg<%s> (%ux%ux%ux%u)",pixel_type(),_width,_height,_depth,_spectrum); - else disp.set_title("%s",title); - } else if (title) disp.set_title("%s",title); - disp.show().flush(); - - const CImg dtitle = CImg::string(disp.title()); - if (display_info) print(dtitle); - - CImg zoom; - for (bool reset_view = true, resize_disp = false, is_first_select = true; !key && !disp.is_closed(); ) { - if (reset_view) { - if (XYZ) { _XYZ[0] = XYZ[0]; _XYZ[1] = XYZ[1]; _XYZ[2] = XYZ[2]; } - else { - _XYZ[0] = (unsigned int)(x0 + x1 + 1)/2; - _XYZ[1] = (unsigned int)(y0 + y1 + 1)/2; - _XYZ[2] = (unsigned int)(z0 + z1 + 1)/2; - } - x0 = 0; y0 = 0; z0 = 0; x1 = width() - 1; y1 = height() - 1; z1 = depth() - 1; - disp.resize(cimg_fitscreen(_width,_height,_depth),false); - oldw = disp._width; oldh = disp._height; - resize_disp = true; - reset_view = false; - } - if (!x0 && !y0 && !z0 && x1==width() - 1 && y1==height() - 1 && z1==depth() - 1) { - if (is_empty()) zoom.assign(1,1,1,1,(T)0); else zoom.assign(); - } else zoom = get_crop(x0,y0,z0,x1,y1,z1); - - const CImg& visu = zoom?zoom:*this; - const unsigned int - dx = 1U + x1 - x0, dy = 1U + y1 - y0, dz = 1U + z1 - z0, - tw = dx + (dz>1?dz:0U), th = dy + (dz>1?dz:0U); - if (!is_empty() && !disp.is_fullscreen() && resize_disp) { - const float - ttw = (float)tw*disp.width()/oldw, tth = (float)th*disp.height()/oldh, - dM = std::max(ttw,tth), diM = (float)std::max(disp.width(),disp.height()); - const unsigned int - imgw = (unsigned int)(ttw*diM/dM), imgh = (unsigned int)(tth*diM/dM); - disp.set_fullscreen(false).resize(cimg_fitscreen(imgw,imgh,1),false); - resize_disp = false; - } - oldw = tw; oldh = th; - - bool - go_up = false, go_down = false, go_left = false, go_right = false, - go_inc = false, go_dec = false, go_in = false, go_out = false, - go_in_center = false; - - disp.set_title("%s",dtitle._data); - if (_width>1 && visu._width==1) disp.set_title("%s | x=%u",disp._title,x0); - if (_height>1 && visu._height==1) disp.set_title("%s | y=%u",disp._title,y0); - if (_depth>1 && visu._depth==1) disp.set_title("%s | z=%u",disp._title,z0); - - disp._mouse_x = old_mouse_x; disp._mouse_y = old_mouse_y; - CImg selection = visu._select(disp,0,2,_XYZ,x0,y0,z0,true,is_first_select,_depth>1,true); - old_mouse_x = disp._mouse_x; old_mouse_y = disp._mouse_y; - is_first_select = false; - - if (disp.wheel()) { - if ((disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) && - (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT())) { - go_left = !(go_right = disp.wheel()>0); - } else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) { - go_down = !(go_up = disp.wheel()>0); - } else if (depth()==1 || disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - go_out = !(go_in = disp.wheel()>0); go_in_center = false; - } - disp.set_wheel(); - } - - const int - sx0 = selection(0), sy0 = selection(1), sz0 = selection(2), - sx1 = selection(3), sy1 = selection(4), sz1 = selection(5); - if (sx0>=0 && sy0>=0 && sz0>=0 && sx1>=0 && sy1>=0 && sz1>=0) { - x1 = x0 + sx1; y1 = y0 + sy1; z1 = z0 + sz1; - x0+=sx0; y0+=sy0; z0+=sz0; - if ((sx0==sx1 && sy0==sy1) || (_depth>1 && sx0==sx1 && sz0==sz1) || (_depth>1 && sy0==sy1 && sz0==sz1)) { - if (exit_on_singleclick && (!zoom || is_empty())) break; else reset_view = true; - } - resize_disp = true; - } else switch (key = disp.key()) { -#if cimg_OS!=2 - case cimg::keyCTRLRIGHT : case cimg::keySHIFTRIGHT : -#endif - case 0 : case cimg::keyCTRLLEFT : case cimg::keySHIFTLEFT : key = 0; break; - case cimg::keyP : if (visu._depth>1 && (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT())) { - // Special mode: play stack of frames - const unsigned int - w1 = visu._width*disp.width()/(visu._width + (visu._depth>1?visu._depth:0)), - h1 = visu._height*disp.height()/(visu._height + (visu._depth>1?visu._depth:0)); - float frame_timing = 5; - bool is_stopped = false; - disp.set_key(key,false).set_wheel().resize(cimg_fitscreen(w1,h1,1),false); key = 0; - for (unsigned int timer = 0; !key && !disp.is_closed() && !disp.button(); ) { - if (disp.is_resized()) disp.resize(false); - if (!timer) { - visu.get_slice((int)_XYZ[2]).display(disp.set_title("%s | z=%d",dtitle.data(),_XYZ[2])); - (++_XYZ[2])%=visu._depth; - } - if (!is_stopped) { if (++timer>(unsigned int)frame_timing) timer = 0; } else timer = ~0U; - if (disp.wheel()) { frame_timing-=disp.wheel()/3.f; disp.set_wheel(); } - switch (key = disp.key()) { -#if cimg_OS!=2 - case cimg::keyCTRLRIGHT : -#endif - case cimg::keyCTRLLEFT : key = 0; break; - case cimg::keyPAGEUP : frame_timing-=0.3f; key = 0; break; - case cimg::keyPAGEDOWN : frame_timing+=0.3f; key = 0; break; - case cimg::keySPACE : is_stopped = !is_stopped; disp.set_key(key,false); key = 0; break; - case cimg::keyARROWLEFT : case cimg::keyARROWUP : is_stopped = true; timer = 0; key = 0; break; - case cimg::keyARROWRIGHT : case cimg::keyARROWDOWN : is_stopped = true; - (_XYZ[2]+=visu._depth - 2)%=visu._depth; timer = 0; key = 0; break; - case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), - CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false); - disp.set_key(key,false); key = 0; - } break; - case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false).set_key(key,false); key = 0; - } break; - case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(cimg_fitscreen(_width,_height,_depth),false).set_key(key,false); key = 0; - } break; - case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.resize(disp.screen_width(),disp.screen_height(),false). - toggle_fullscreen().set_key(key,false); key = 0; - } break; - } - frame_timing = frame_timing<1?1:(frame_timing>39?39:frame_timing); - disp.wait(20); - } - const unsigned int - w2 = (visu._width + (visu._depth>1?visu._depth:0))*disp.width()/visu._width, - h2 = (visu._height + (visu._depth>1?visu._depth:0))*disp.height()/visu._height; - disp.resize(cimg_fitscreen(w2,h2,1),false).set_title(dtitle.data()).set_key().set_button().set_wheel(); - key = 0; - } break; - case cimg::keyHOME : reset_view = resize_disp = true; key = 0; break; - case cimg::keyPADADD : go_in = true; go_in_center = true; key = 0; break; - case cimg::keyPADSUB : go_out = true; key = 0; break; - case cimg::keyARROWLEFT : case cimg::keyPAD4: go_left = true; key = 0; break; - case cimg::keyARROWRIGHT : case cimg::keyPAD6: go_right = true; key = 0; break; - case cimg::keyARROWUP : case cimg::keyPAD8: go_up = true; key = 0; break; - case cimg::keyARROWDOWN : case cimg::keyPAD2: go_down = true; key = 0; break; - case cimg::keyPAD7 : go_up = go_left = true; key = 0; break; - case cimg::keyPAD9 : go_up = go_right = true; key = 0; break; - case cimg::keyPAD1 : go_down = go_left = true; key = 0; break; - case cimg::keyPAD3 : go_down = go_right = true; key = 0; break; - case cimg::keyPAGEUP : go_inc = true; key = 0; break; - case cimg::keyPAGEDOWN : go_dec = true; key = 0; break; - } - if (go_in) { - const int - mx = go_in_center?disp.width()/2:disp.mouse_x(), - my = go_in_center?disp.height()/2:disp.mouse_y(), - mX = mx*(width() + (depth()>1?depth():0))/disp.width(), - mY = my*(height() + (depth()>1?depth():0))/disp.height(); - int X = (int)_XYZ[0], Y = (int)_XYZ[1], Z = (int)_XYZ[2]; - if (mX=height()) { - X = x0 + mX*(1 + x1 - x0)/width(); Z = z0 + (mY - height())*(1 + z1 - z0)/depth(); - } - if (mX>=width() && mY4) { x0 = X - 3*(X - x0)/4; x1 = X + 3*(x1 - X)/4; } - if (y1 - y0>4) { y0 = Y - 3*(Y - y0)/4; y1 = Y + 3*(y1 - Y)/4; } - if (z1 - z0>4) { z0 = Z - 3*(Z - z0)/4; z1 = Z + 3*(z1 - Z)/4; } - } - if (go_out) { - const int - delta_x = (x1 - x0)/8, delta_y = (y1 - y0)/8, delta_z = (z1 - z0)/8, - ndelta_x = delta_x?delta_x:(_width>1), - ndelta_y = delta_y?delta_y:(_height>1), - ndelta_z = delta_z?delta_z:(_depth>1); - x0-=ndelta_x; y0-=ndelta_y; z0-=ndelta_z; - x1+=ndelta_x; y1+=ndelta_y; z1+=ndelta_z; - if (x0<0) { x1-=x0; x0 = 0; if (x1>=width()) x1 = width() - 1; } - if (y0<0) { y1-=y0; y0 = 0; if (y1>=height()) y1 = height() - 1; } - if (z0<0) { z1-=z0; z0 = 0; if (z1>=depth()) z1 = depth() - 1; } - if (x1>=width()) { x0-=(x1 - width() + 1); x1 = width() - 1; if (x0<0) x0 = 0; } - if (y1>=height()) { y0-=(y1 - height() + 1); y1 = height() - 1; if (y0<0) y0 = 0; } - if (z1>=depth()) { z0-=(z1 - depth() + 1); z1 = depth() - 1; if (z0<0) z0 = 0; } - const float - ratio = (float)(x1-x0)/(y1-y0), - ratiow = (float)disp._width/disp._height, - sub = std::min(cimg::abs(ratio - ratiow),cimg::abs(1/ratio-1/ratiow)); - if (sub>0.01) resize_disp = true; - } - if (go_left) { - const int delta = (x1 - x0)/4, ndelta = delta?delta:(_width>1); - if (x0 - ndelta>=0) { x0-=ndelta; x1-=ndelta; } - else { x1-=x0; x0 = 0; } - } - if (go_right) { - const int delta = (x1 - x0)/4, ndelta = delta?delta:(_width>1); - if (x1+ndelta1); - if (y0 - ndelta>=0) { y0-=ndelta; y1-=ndelta; } - else { y1-=y0; y0 = 0; } - } - if (go_down) { - const int delta = (y1 - y0)/4, ndelta = delta?delta:(_height>1); - if (y1+ndelta1); - if (z0 - ndelta>=0) { z0-=ndelta; z1-=ndelta; } - else { z1-=z0; z0 = 0; } - } - if (go_dec) { - const int delta = (z1 - z0)/4, ndelta = delta?delta:(_depth>1); - if (z1+ndelta - const CImg& display_object3d(CImgDisplay& disp, - const CImg& vertices, - const CImgList& primitives, - const CImgList& colors, - const to& opacities, - const bool centering=true, - const int render_static=4, const int render_motion=1, - const bool is_double_sided=true, const float focale=700, - const float light_x=0, const float light_y=0, const float light_z=-5e8f, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const bool display_axes=true, float *const pose_matrix=0, - const bool exit_on_anykey=false) const { - return _display_object3d(disp,0,vertices,primitives,colors,opacities,centering,render_static, - render_motion,is_double_sided,focale, - light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix,exit_on_anykey); - } - - //! Display object 3D in an interactive window \simplification. - template - const CImg& display_object3d(const char *const title, - const CImg& vertices, - const CImgList& primitives, - const CImgList& colors, - const to& opacities, - const bool centering=true, - const int render_static=4, const int render_motion=1, - const bool is_double_sided=true, const float focale=700, - const float light_x=0, const float light_y=0, const float light_z=-5e8f, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const bool display_axes=true, float *const pose_matrix=0, - const bool exit_on_anykey=false) const { - CImgDisplay disp; - return _display_object3d(disp,title,vertices,primitives,colors,opacities,centering,render_static, - render_motion,is_double_sided,focale, - light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix,exit_on_anykey); - } - - //! Display object 3D in an interactive window \simplification. - template - const CImg& display_object3d(CImgDisplay &disp, - const CImg& vertices, - const CImgList& primitives, - const CImgList& colors, - const bool centering=true, - const int render_static=4, const int render_motion=1, - const bool is_double_sided=true, const float focale=700, - const float light_x=0, const float light_y=0, const float light_z=-5e8f, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const bool display_axes=true, float *const pose_matrix=0, - const bool exit_on_anykey=false) const { - return display_object3d(disp,vertices,primitives,colors,CImgList(),centering, - render_static,render_motion,is_double_sided,focale, - light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix,exit_on_anykey); - } - - //! Display object 3D in an interactive window \simplification. - template - const CImg& display_object3d(const char *const title, - const CImg& vertices, - const CImgList& primitives, - const CImgList& colors, - const bool centering=true, - const int render_static=4, const int render_motion=1, - const bool is_double_sided=true, const float focale=700, - const float light_x=0, const float light_y=0, const float light_z=-5e8f, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const bool display_axes=true, float *const pose_matrix=0, - const bool exit_on_anykey=false) const { - return display_object3d(title,vertices,primitives,colors,CImgList(),centering, - render_static,render_motion,is_double_sided,focale, - light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix,exit_on_anykey); - } - - //! Display object 3D in an interactive window \simplification. - template - const CImg& display_object3d(CImgDisplay &disp, - const CImg& vertices, - const CImgList& primitives, - const bool centering=true, - const int render_static=4, const int render_motion=1, - const bool is_double_sided=true, const float focale=700, - const float light_x=0, const float light_y=0, const float light_z=-5e8f, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const bool display_axes=true, float *const pose_matrix=0, - const bool exit_on_anykey=false) const { - return display_object3d(disp,vertices,primitives,CImgList(),centering, - render_static,render_motion,is_double_sided,focale, - light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix,exit_on_anykey); - } - - - //! Display object 3D in an interactive window \simplification. - template - const CImg& display_object3d(const char *const title, - const CImg& vertices, - const CImgList& primitives, - const bool centering=true, - const int render_static=4, const int render_motion=1, - const bool is_double_sided=true, const float focale=700, - const float light_x=0, const float light_y=0, const float light_z=-5e8f, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const bool display_axes=true, float *const pose_matrix=0, - const bool exit_on_anykey=false) const { - return display_object3d(title,vertices,primitives,CImgList(),centering, - render_static,render_motion,is_double_sided,focale, - light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix,exit_on_anykey); - } - - //! Display object 3D in an interactive window \simplification. - template - const CImg& display_object3d(CImgDisplay &disp, - const CImg& vertices, - const bool centering=true, - const int render_static=4, const int render_motion=1, - const bool is_double_sided=true, const float focale=700, - const float light_x=0, const float light_y=0, const float light_z=-5e8f, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const bool display_axes=true, float *const pose_matrix=0, - const bool exit_on_anykey=false) const { - return display_object3d(disp,vertices,CImgList(),centering, - render_static,render_motion,is_double_sided,focale, - light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix,exit_on_anykey); - } - - //! Display object 3D in an interactive window \simplification. - template - const CImg& display_object3d(const char *const title, - const CImg& vertices, - const bool centering=true, - const int render_static=4, const int render_motion=1, - const bool is_double_sided=true, const float focale=700, - const float light_x=0, const float light_y=0, const float light_z=-5e8f, - const float specular_lightness=0.2f, const float specular_shininess=0.1f, - const bool display_axes=true, float *const pose_matrix=0, - const bool exit_on_anykey=false) const { - return display_object3d(title,vertices,CImgList(),centering, - render_static,render_motion,is_double_sided,focale, - light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix,exit_on_anykey); - } - - template - const CImg& _display_object3d(CImgDisplay& disp, const char *const title, - const CImg& vertices, - const CImgList& primitives, - const CImgList& colors, - const to& opacities, - const bool centering, - const int render_static, const int render_motion, - const bool is_double_sided, const float focale, - const float light_x, const float light_y, const float light_z, - const float specular_lightness, const float specular_shininess, - const bool display_axes, float *const pose_matrix, - const bool exit_on_anykey) const { - typedef typename cimg::superset::type tpfloat; - - // Check input arguments - if (is_empty()) { - CImg background; - if (colors && colors[0].size()==1) background.assign(1,2,1,1,64,128); - else background.assign(1,2,1,3,32,64,32,116,64,96); - if (disp) background.resize(disp.width(),disp.height(),1,-100,3); - else background.resize(cimg_fitscreen(CImgDisplay::screen_width()/2, - CImgDisplay::screen_height()/2,1),1,-100,3); - return background._display_object3d(disp,title,vertices,primitives,colors,opacities,centering, - render_static,render_motion,is_double_sided,focale, - light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix,exit_on_anykey); - } else { if (disp) disp.resize(*this,false); } - CImg error_message(1024); - if (!vertices.is_object3d(primitives,colors,opacities,true,error_message)) - throw CImgArgumentException(_cimg_instance - "display_object3d(): Invalid specified 3D object (%u,%u) (%s).", - cimg_instance,vertices._width,primitives._width,error_message.data()); - if (vertices._width && !primitives) { - CImgList nprimitives(vertices._width,1,1,1,1); - cimglist_for(nprimitives,l) nprimitives(l,0) = (tf)l; - return _display_object3d(disp,title,vertices,nprimitives,colors,opacities,centering, - render_static,render_motion,is_double_sided,focale, - light_x,light_y,light_z,specular_lightness,specular_shininess, - display_axes,pose_matrix,exit_on_anykey); - } - if (!disp) { - disp.assign(cimg_fitscreen(_width,_height,_depth),title?title:0,3); - if (!title) disp.set_title("CImg<%s> (%u vertices, %u primitives)", - pixel_type(),vertices._width,primitives._width); - } else if (title) disp.set_title("%s",title); - - // Init 3D objects and compute object statistics - CImg - pose, - rotated_vertices(vertices._width,3), - bbox_vertices, rotated_bbox_vertices, - axes_vertices, rotated_axes_vertices, - bbox_opacities, axes_opacities; - CImgList bbox_primitives, axes_primitives; - CImgList reverse_primitives; - CImgList bbox_colors, bbox_colors2, axes_colors; - unsigned int ns_width = 0, ns_height = 0; - int _is_double_sided = (int)is_double_sided; - bool ndisplay_axes = display_axes; - const CImg - background_color(1,1,1,_spectrum,0), - foreground_color(1,1,1,_spectrum,(T)std::min((int)cimg::type::max(),255)); - float - Xoff = 0, Yoff = 0, Zoff = 0, sprite_scale = 1, - xm = 0, xM = vertices?vertices.get_shared_row(0).max_min(xm):0, - ym = 0, yM = vertices?vertices.get_shared_row(1).max_min(ym):0, - zm = 0, zM = vertices?vertices.get_shared_row(2).max_min(zm):0; - const float delta = cimg::max(xM - xm,yM - ym,zM - zm); - - rotated_bbox_vertices = bbox_vertices.assign(8,3,1,1, - xm,xM,xM,xm,xm,xM,xM,xm, - ym,ym,yM,yM,ym,ym,yM,yM, - zm,zm,zm,zm,zM,zM,zM,zM); - bbox_primitives.assign(6,1,4,1,1, 0,3,2,1, 4,5,6,7, 1,2,6,5, 0,4,7,3, 0,1,5,4, 2,3,7,6); - bbox_colors.assign(6,_spectrum,1,1,1,background_color[0]); - bbox_colors2.assign(6,_spectrum,1,1,1,foreground_color[0]); - bbox_opacities.assign(bbox_colors._width,1,1,1,0.3f); - - rotated_axes_vertices = axes_vertices.assign(7,3,1,1, - 0,20,0,0,22,-6,-6, - 0,0,20,0,-6,22,-6, - 0,0,0,20,0,0,22); - axes_opacities.assign(3,1,1,1,1); - axes_colors.assign(3,_spectrum,1,1,1,foreground_color[0]); - axes_primitives.assign(3,1,2,1,1, 0,1, 0,2, 0,3); - - // Begin user interaction loop - CImg visu0(*this,false), visu; - CImg zbuffer(visu0.width(),visu0.height(),1,1,0); - bool init_pose = true, clicked = false, redraw = true; - unsigned int key = 0, font_size = 32; - int - x0 = 0, y0 = 0, x1 = 0, y1 = 0, - nrender_static = render_static, - nrender_motion = render_motion; - disp.show().flush(); - - while (!disp.is_closed() && !key) { - - // Init object pose - if (init_pose) { - const float - ratio = delta>0?(2.f*std::min(disp.width(),disp.height())/(3.f*delta)):1, - dx = (xM + xm)/2, dy = (yM + ym)/2, dz = (zM + zm)/2; - if (centering) - CImg(4,3,1,1, ratio,0.,0.,-ratio*dx, 0.,ratio,0.,-ratio*dy, 0.,0.,ratio,-ratio*dz).move_to(pose); - else CImg(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0).move_to(pose); - if (pose_matrix) { - CImg pose0(pose_matrix,4,3,1,1,false); - pose0.resize(4,4,1,1,0); pose.resize(4,4,1,1,0); - pose0(3,3) = pose(3,3) = 1; - (pose0*pose).get_crop(0,0,3,2).move_to(pose); - Xoff = pose_matrix[12]; Yoff = pose_matrix[13]; Zoff = pose_matrix[14]; sprite_scale = pose_matrix[15]; - } else { Xoff = Yoff = Zoff = 0; sprite_scale = 1; } - init_pose = false; - redraw = true; - } - - // Rotate and draw 3D object - if (redraw) { - const float - r00 = pose(0,0), r10 = pose(1,0), r20 = pose(2,0), r30 = pose(3,0), - r01 = pose(0,1), r11 = pose(1,1), r21 = pose(2,1), r31 = pose(3,1), - r02 = pose(0,2), r12 = pose(1,2), r22 = pose(2,2), r32 = pose(3,2); - if ((clicked && nrender_motion>=0) || (!clicked && nrender_static>=0)) { - const tp *const pv0 = vertices.data(), *const pv1 = vertices.data(0,1), *const pv2 = vertices.data(0,2); - float - *const prv0 = rotated_vertices.data(), - *const prv1 = rotated_vertices.data(0,1), - *const prv2 = rotated_vertices.data(0,2); - cimg_pragma_openmp(parallel for cimg_openmp_if(vertices.width()>(cimg_openmp_sizefactor)*1024)) - cimg_forX(vertices,l) { - const float x = (float)pv0[l], y = (float)pv1[l], z = (float)pv2[l]; - prv0[l] = r00*x + r10*y + r20*z + r30; - prv1[l] = r01*x + r11*y + r21*z + r31; - prv2[l] = r02*x + r12*y + r22*z + r32; - } - } - else cimg_forX(bbox_vertices,l) { - const float x = bbox_vertices(l,0), y = bbox_vertices(l,1), z = bbox_vertices(l,2); - rotated_bbox_vertices(l,0) = r00*x + r10*y + r20*z + r30; - rotated_bbox_vertices(l,1) = r01*x + r11*y + r21*z + r31; - rotated_bbox_vertices(l,2) = r02*x + r12*y + r22*z + r32; - } - - // Draw objects - const bool render_with_zbuffer = !clicked && nrender_static>0; - visu = visu0; - if ((clicked && nrender_motion<0) || (!clicked && nrender_static<0)) - visu.draw_object3d(Xoff + visu._width/2.f,Yoff + visu._height/2.f,Zoff, - rotated_bbox_vertices,bbox_primitives,bbox_colors,bbox_opacities,2,false,focale). - draw_object3d(Xoff + visu._width/2.f,Yoff + visu._height/2.f,Zoff, - rotated_bbox_vertices,bbox_primitives,bbox_colors2,1,false,focale); - else visu._draw_object3d((void*)0,render_with_zbuffer?zbuffer.fill(0):CImg::empty(), - Xoff + visu._width/2.f,Yoff + visu._height/2.f,Zoff, - rotated_vertices,reverse_primitives?reverse_primitives:primitives, - colors,opacities,clicked?nrender_motion:nrender_static,_is_double_sided==1,focale, - width()/2.f + light_x,height()/2.f + light_y,light_z + Zoff, - specular_lightness,specular_shininess,1,sprite_scale); - // Draw axes - if (ndisplay_axes) { - const float - n = 1e-8f + cimg::hypot(r00,r01,r02), - _r00 = r00/n, _r10 = r10/n, _r20 = r20/n, - _r01 = r01/n, _r11 = r11/n, _r21 = r21/n, - _r02 = r01/n, _r12 = r12/n, _r22 = r22/n, - Xaxes = 25, Yaxes = visu._height - 38.f; - cimg_forX(axes_vertices,l) { - const float - x = axes_vertices(l,0), - y = axes_vertices(l,1), - z = axes_vertices(l,2); - rotated_axes_vertices(l,0) = _r00*x + _r10*y + _r20*z; - rotated_axes_vertices(l,1) = _r01*x + _r11*y + _r21*z; - rotated_axes_vertices(l,2) = _r02*x + _r12*y + _r22*z; - } - axes_opacities(0,0) = (rotated_axes_vertices(1,2)>0)?0.5f:1.f; - axes_opacities(1,0) = (rotated_axes_vertices(2,2)>0)?0.5f:1.f; - axes_opacities(2,0) = (rotated_axes_vertices(3,2)>0)?0.5f:1.f; - visu.draw_object3d(Xaxes,Yaxes,0,rotated_axes_vertices,axes_primitives, - axes_colors,axes_opacities,1,false,focale). - draw_text((int)(Xaxes + rotated_axes_vertices(4,0)), - (int)(Yaxes + rotated_axes_vertices(4,1)), - "X",axes_colors[0]._data,0,axes_opacities(0,0),13). - draw_text((int)(Xaxes + rotated_axes_vertices(5,0)), - (int)(Yaxes + rotated_axes_vertices(5,1)), - "Y",axes_colors[1]._data,0,axes_opacities(1,0),13). - draw_text((int)(Xaxes + rotated_axes_vertices(6,0)), - (int)(Yaxes + rotated_axes_vertices(6,1)), - "Z",axes_colors[2]._data,0,axes_opacities(2,0),13); - } - visu.display(disp); - if (!clicked || nrender_motion==nrender_static) redraw = false; - } - - // Handle user interaction - if (!redraw) disp.wait(); - if ((disp.button() || disp.wheel()) && disp.mouse_x()>=0 && disp.mouse_y()>=0) { - redraw = true; - if (!clicked) { x0 = x1 = disp.mouse_x(); y0 = y1 = disp.mouse_y(); if (!disp.wheel()) clicked = true; } - else { x1 = disp.mouse_x(); y1 = disp.mouse_y(); } - const bool is_keyCTRL = disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT(); - if (disp.button()&1 && !is_keyCTRL) { - const float - R = 0.45f*std::min(disp.width(),disp.height()), - R2 = R*R, - u0 = (float)(x0 - disp.width()/2), - v0 = (float)(y0 - disp.height()/2), - u1 = (float)(x1 - disp.width()/2), - v1 = (float)(y1 - disp.height()/2), - n0 = cimg::hypot(u0,v0), - n1 = cimg::hypot(u1,v1), - nu0 = n0>R?(u0*R/n0):u0, - nv0 = n0>R?(v0*R/n0):v0, - nw0 = (float)std::sqrt(std::max(0.f,R2 - nu0*nu0 - nv0*nv0)), - nu1 = n1>R?(u1*R/n1):u1, - nv1 = n1>R?(v1*R/n1):v1, - nw1 = (float)std::sqrt(std::max(0.f,R2 - nu1*nu1 - nv1*nv1)), - u = nv0*nw1 - nw0*nv1, - v = nw0*nu1 - nu0*nw1, - w = nv0*nu1 - nu0*nv1, - n = cimg::hypot(u,v,w), - alpha = (float)std::asin(n/R2)*180/cimg::PI; - (CImg::rotation_matrix(u,v,w,-alpha)*pose).move_to(pose); - x0 = x1; y0 = y1; - } - if (disp.button()&2 && !is_keyCTRL) { - if (focale>0) Zoff-=(y0 - y1)*focale/400; - else { const float s = std::exp((y0 - y1)/400.f); pose*=s; sprite_scale*=s; } - x0 = x1; y0 = y1; - } - if (disp.wheel()) { - if (focale>0) Zoff-=disp.wheel()*focale/20; - else { const float s = std::exp(disp.wheel()/20.f); pose*=s; sprite_scale*=s; } - disp.set_wheel(); - } - if (disp.button()&4 || (disp.button()&1 && is_keyCTRL)) { - Xoff+=(x1 - x0); Yoff+=(y1 - y0); x0 = x1; y0 = y1; - } - if ((disp.button()&1) && (disp.button()&2) && !is_keyCTRL) { - init_pose = true; disp.set_button(); x0 = x1; y0 = y1; - pose = CImg(4,3,1,1, 1,0,0,0, 0,1,0,0, 0,0,1,0); - } - } else if (clicked) { x0 = x1; y0 = y1; clicked = false; redraw = true; } - - CImg filename(32); - switch (key = disp.key()) { -#if cimg_OS!=2 - case cimg::keyCTRLRIGHT : -#endif - case 0 : case cimg::keyCTRLLEFT : key = 0; break; - case cimg::keyD: if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), - CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false). - _is_resized = true; - disp.set_key(key,false); key = 0; - } break; - case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true; - disp.set_key(key,false); key = 0; - } break; - case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false).resize(cimg_fitscreen(_width,_height,_depth),false)._is_resized = true; - disp.set_key(key,false); key = 0; - } break; - case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - if (!ns_width || !ns_height || - ns_width>(unsigned int)disp.screen_width() || ns_height>(unsigned int)disp.screen_height()) { - ns_width = disp.screen_width()*3U/4; - ns_height = disp.screen_height()*3U/4; - } - if (disp.is_fullscreen()) disp.resize(ns_width,ns_height,false); - else { - ns_width = disp._width; ns_height = disp._height; - disp.resize(disp.screen_width(),disp.screen_height(),false); - } - disp.toggle_fullscreen()._is_resized = true; - disp.set_key(key,false); key = 0; - } break; - case cimg::keyT : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - // Switch single/double-sided primitives. - if (--_is_double_sided==-2) _is_double_sided = 1; - if (_is_double_sided>=0) reverse_primitives.assign(); - else primitives.get_reverse_object3d().move_to(reverse_primitives); - disp.set_key(key,false); key = 0; redraw = true; - } break; - case cimg::keyZ : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Enable/disable Z-buffer - if (zbuffer) zbuffer.assign(); - else zbuffer.assign(visu0.width(),visu0.height(),1,1,0); - disp.set_key(key,false); key = 0; redraw = true; - } break; - case cimg::keyX : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Show/hide 3D axes - ndisplay_axes = !ndisplay_axes; - disp.set_key(key,false); key = 0; redraw = true; - } break; - case cimg::keyF1 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to points - nrender_motion = (nrender_static==0 && nrender_motion!=0)?0:-1; nrender_static = 0; - disp.set_key(key,false); key = 0; redraw = true; - } break; - case cimg::keyF2 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to lines - nrender_motion = (nrender_static==1 && nrender_motion!=1)?1:-1; nrender_static = 1; - disp.set_key(key,false); key = 0; redraw = true; - } break; - case cimg::keyF3 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to flat - nrender_motion = (nrender_static==2 && nrender_motion!=2)?2:-1; nrender_static = 2; - disp.set_key(key,false); key = 0; redraw = true; - } break; - case cimg::keyF4 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to flat-shaded - nrender_motion = (nrender_static==3 && nrender_motion!=3)?3:-1; nrender_static = 3; - disp.set_key(key,false); key = 0; redraw = true; - } break; - case cimg::keyF5 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - // Set rendering mode to gouraud-shaded. - nrender_motion = (nrender_static==4 && nrender_motion!=4)?4:-1; nrender_static = 4; - disp.set_key(key,false); key = 0; redraw = true; - } break; - case cimg::keyF6 : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Set rendering mode to phong-shaded - nrender_motion = (nrender_static==5 && nrender_motion!=5)?5:-1; nrender_static = 5; - disp.set_key(key,false); key = 0; redraw = true; - } break; - case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save snapshot - static unsigned int snap_number = 0; - std::FILE *file; - do { - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++); - if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file); - } while (file); - (+visu).__draw_text(" Saving snapshot... ",font_size,0).display(disp); - visu.save(filename); - (+visu).__draw_text(" Snapshot '%s' saved. ",font_size,0,filename._data).display(disp); - disp.set_key(key,false); key = 0; - } break; - case cimg::keyG : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .off file - static unsigned int snap_number = 0; - std::FILE *file; - do { - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.off",snap_number++); - if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file); - } while (file); - (+visu).__draw_text(" Saving object... ",font_size,0).display(disp); - vertices.save_off(reverse_primitives?reverse_primitives:primitives,colors,filename); - (+visu).__draw_text(" Object '%s' saved. ",font_size,0,filename._data).display(disp); - disp.set_key(key,false); key = 0; - } break; - case cimg::keyO : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .cimg file - static unsigned int snap_number = 0; - std::FILE *file; - do { - -#ifdef cimg_use_zlib - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++); -#else - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++); -#endif - if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file); - } while (file); - (+visu).__draw_text(" Saving object... ",font_size,0).display(disp); - vertices.get_object3dtoCImg3d(reverse_primitives?reverse_primitives:primitives,colors,opacities). - save(filename); - (+visu).__draw_text(" Object '%s' saved. ",font_size,0,filename._data).display(disp); - disp.set_key(key,false); key = 0; - } break; - -#ifdef cimg_use_board - case cimg::keyP : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .EPS file - static unsigned int snap_number = 0; - std::FILE *file; - do { - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.eps",snap_number++); - if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file); - } while (file); - (+visu).__draw_text(" Saving EPS snapshot... ",font_size,0).display(disp); - LibBoard::Board board; - (+visu)._draw_object3d(&board,zbuffer.fill(0), - Xoff + visu._width/2.f,Yoff + visu._height/2.f,Zoff, - rotated_vertices,reverse_primitives?reverse_primitives:primitives, - colors,opacities,clicked?nrender_motion:nrender_static, - _is_double_sided==1,focale, - visu.width()/2.f + light_x,visu.height()/2.f + light_y,light_z + Zoff, - specular_lightness,specular_shininess,1, - sprite_scale); - board.saveEPS(filename); - (+visu).__draw_text(" Object '%s' saved. ",font_size,0,filename._data).display(disp); - disp.set_key(key,false); key = 0; - } break; - case cimg::keyV : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { // Save object as a .SVG file - static unsigned int snap_number = 0; - std::FILE *file; - do { - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.svg",snap_number++); - if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file); - } while (file); - (+visu).__draw_text(" Saving SVG snapshot... ",font_size,0).display(disp); - LibBoard::Board board; - (+visu)._draw_object3d(&board,zbuffer.fill(0), - Xoff + visu._width/2.f,Yoff + visu._height/2.f,Zoff, - rotated_vertices,reverse_primitives?reverse_primitives:primitives, - colors,opacities,clicked?nrender_motion:nrender_static, - _is_double_sided==1,focale, - visu.width()/2.f + light_x,visu.height()/2.f + light_y,light_z + Zoff, - specular_lightness,specular_shininess,1, - sprite_scale); - board.saveSVG(filename); - (+visu).__draw_text(" Object '%s' saved. ",font_size,0,filename._data).display(disp); - disp.set_key(key,false); key = 0; - } break; -#endif - } - if (disp.is_resized()) { - disp.resize(false); visu0 = get_resize(disp,1); - if (zbuffer) zbuffer.assign(disp.width(),disp.height()); - redraw = true; - } - if (!exit_on_anykey && key && key!=cimg::keyESC && - (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { - key = 0; - } - } - if (pose_matrix) { - std::memcpy(pose_matrix,pose._data,12*sizeof(float)); - pose_matrix[12] = Xoff; pose_matrix[13] = Yoff; pose_matrix[14] = Zoff; pose_matrix[15] = sprite_scale; - } - disp.set_button().set_key(key); - return *this; - } - - //! Display 1D graph in an interactive window. - /** - \param disp Display window. - \param plot_type Plot type. Can be { 0=points | 1=segments | 2=splines | 3=bars }. - \param vertex_type Vertex type. - \param labelx Title for the horizontal axis, as a C-string. - \param xmin Minimum value along the X-axis. - \param xmax Maximum value along the X-axis. - \param labely Title for the vertical axis, as a C-string. - \param ymin Minimum value along the X-axis. - \param ymax Maximum value along the X-axis. - \param exit_on_anykey Exit function when any key is pressed. - **/ - const CImg& display_graph(CImgDisplay &disp, - const unsigned int plot_type=1, const unsigned int vertex_type=1, - const char *const labelx=0, const double xmin=0, const double xmax=0, - const char *const labely=0, const double ymin=0, const double ymax=0, - const bool exit_on_anykey=false) const { - return _display_graph(disp,0,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey); - } - - //! Display 1D graph in an interactive window \overloading. - const CImg& display_graph(const char *const title=0, - const unsigned int plot_type=1, const unsigned int vertex_type=1, - const char *const labelx=0, const double xmin=0, const double xmax=0, - const char *const labely=0, const double ymin=0, const double ymax=0, - const bool exit_on_anykey=false) const { - CImgDisplay disp; - return _display_graph(disp,title,plot_type,vertex_type,labelx,xmin,xmax,labely,ymin,ymax,exit_on_anykey); - } - - const CImg& _display_graph(CImgDisplay &disp, const char *const title=0, - const unsigned int plot_type=1, const unsigned int vertex_type=1, - const char *const labelx=0, const double xmin=0, const double xmax=0, - const char *const labely=0, const double ymin=0, const double ymax=0, - const bool exit_on_anykey=false) const { - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "display_graph(): Empty instance.", - cimg_instance); - if (!disp) disp.assign(cimg_fitscreen(CImgDisplay::screen_width()/2,CImgDisplay::screen_height()/2,1),0,0). - set_title(title?"%s":"CImg<%s>",title?title:pixel_type()); - const ulongT siz = (ulongT)_width*_height*_depth, siz1 = std::max((ulongT)1,siz - 1); - const unsigned int old_normalization = disp.normalization(); - disp.show().flush()._normalization = 0; - - double y0 = ymin, y1 = ymax, nxmin = xmin, nxmax = xmax; - if (nxmin==nxmax) { nxmin = 0; nxmax = siz1; } - int x0 = 0, x1 = width()*height()*depth() - 1, key = 0; - - for (bool reset_view = true; !key && !disp.is_closed(); ) { - if (reset_view) { x0 = 0; x1 = width()*height()*depth() - 1; y0 = ymin; y1 = ymax; reset_view = false; } - CImg zoom(x1 - x0 + 1,1,1,spectrum()); - cimg_forC(*this,c) zoom.get_shared_channel(c) = CImg(data(x0,0,0,c),x1 - x0 + 1,1,1,1,true); - if (y0==y1) { y0 = zoom.min_max(y1); const double dy = y1 - y0; y0-=dy/20; y1+=dy/20; } - if (y0==y1) { --y0; ++y1; } - - const CImg selection = zoom.get_select_graph(disp,plot_type,vertex_type, - labelx, - nxmin + x0*(nxmax - nxmin)/siz1, - nxmin + x1*(nxmax - nxmin)/siz1, - labely,y0,y1,true); - const int mouse_x = disp.mouse_x(), mouse_y = disp.mouse_y(); - if (selection[0]>=0) { - if (selection[2]<0) reset_view = true; - else { - x1 = x0 + selection[2]; x0+=selection[0]; - if (selection[1]>=0 && selection[3]>=0) { - y0 = y1 - selection[3]*(y1 - y0)/(disp.height() - 32); - y1-=selection[1]*(y1 - y0)/(disp.height() - 32); - } - } - } else { - bool go_in = false, go_out = false, go_left = false, go_right = false, go_up = false, go_down = false; - switch (key = (int)disp.key()) { - case cimg::keyHOME : reset_view = true; key = 0; disp.set_key(); break; - case cimg::keyPADADD : go_in = true; go_out = false; key = 0; disp.set_key(); break; - case cimg::keyPADSUB : go_out = true; go_in = false; key = 0; disp.set_key(); break; - case cimg::keyARROWLEFT : case cimg::keyPAD4 : go_left = true; go_right = false; key = 0; disp.set_key(); - break; - case cimg::keyARROWRIGHT : case cimg::keyPAD6 : go_right = true; go_left = false; key = 0; disp.set_key(); - break; - case cimg::keyARROWUP : case cimg::keyPAD8 : go_up = true; go_down = false; key = 0; disp.set_key(); break; - case cimg::keyARROWDOWN : case cimg::keyPAD2 : go_down = true; go_up = false; key = 0; disp.set_key(); break; - case cimg::keyPAD7 : go_left = true; go_up = true; key = 0; disp.set_key(); break; - case cimg::keyPAD9 : go_right = true; go_up = true; key = 0; disp.set_key(); break; - case cimg::keyPAD1 : go_left = true; go_down = true; key = 0; disp.set_key(); break; - case cimg::keyPAD3 : go_right = true; go_down = true; key = 0; disp.set_key(); break; - } - if (disp.wheel()) { - if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) go_up = !(go_down = disp.wheel()<0); - else if (disp.is_keySHIFTLEFT() || disp.is_keySHIFTRIGHT()) go_left = !(go_right = disp.wheel()>0); - else go_out = !(go_in = disp.wheel()>0); - key = 0; - } - - if (go_in) { - const int - xsiz = x1 - x0, - mx = (mouse_x - 16)*xsiz/(disp.width() - 32), - cx = x0 + cimg::cut(mx,0,xsiz); - if (x1 - x0>4) { - x0 = cx - 7*(cx - x0)/8; x1 = cx + 7*(x1 - cx)/8; - if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - const double - ysiz = y1 - y0, - my = (mouse_y - 16)*ysiz/(disp.height() - 32), - cy = y1 - cimg::cut(my,0.,ysiz); - y0 = cy - 7*(cy - y0)/8; y1 = cy + 7*(y1 - cy)/8; - } else y0 = y1 = 0; - } - } - if (go_out) { - if (x0>0 || x1<(int)siz1) { - const int delta_x = (x1 - x0)/8, ndelta_x = delta_x?delta_x:(siz>1); - const double ndelta_y = (y1 - y0)/8; - x0-=ndelta_x; x1+=ndelta_x; - y0-=ndelta_y; y1+=ndelta_y; - if (x0<0) { x1-=x0; x0 = 0; if (x1>=(int)siz) x1 = (int)siz1; } - if (x1>=(int)siz) { x0-=(x1 - siz1); x1 = (int)siz1; if (x0<0) x0 = 0; } - } - } - if (go_left) { - const int delta = (x1 - x0)/5, ndelta = delta?delta:1; - if (x0 - ndelta>=0) { x0-=ndelta; x1-=ndelta; } - else { x1-=x0; x0 = 0; } - go_left = false; - } - if (go_right) { - const int delta = (x1 - x0)/5, ndelta = delta?delta:1; - if (x1 + ndelta<(int)siz) { x0+=ndelta; x1+=ndelta; } - else { x0+=(siz1 - x1); x1 = (int)siz1; } - go_right = false; - } - if (go_up) { - const double delta = (y1 - y0)/10, ndelta = delta?delta:1; - y0+=ndelta; y1+=ndelta; - go_up = false; - } - if (go_down) { - const double delta = (y1 - y0)/10, ndelta = delta?delta:1; - y0-=ndelta; y1-=ndelta; - go_down = false; - } - } - if (!exit_on_anykey && key && key!=(int)cimg::keyESC && - (key!=(int)cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { - disp.set_key(key,false); - key = 0; - } - } - disp._normalization = old_normalization; - return *this; - } - - //! Save image as a file. - /** - \param filename Filename, as a C-string. - \param number When positive, represents an index added to the filename. Otherwise, no number is added. - \param digits Number of digits used for adding the number to the filename. - \note - - The used file format is defined by the file extension in the filename \p filename. - - Parameter \p number can be used to add a 6-digit number to the filename before saving. - - **/ - const CImg& save(const char *const filename, const int number=-1, const unsigned int digits=6) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save(): Specified filename is (null).", - cimg_instance); - // Do not test for empty instances, since .cimg format is able to manage empty instances. - const bool is_stdout = *filename=='-' && (!filename[1] || filename[1]=='.'); - const char *const ext = cimg::split_filename(filename); - CImg nfilename(1024); - const char *const fn = is_stdout?filename:(number>=0)?cimg::number_filename(filename,number,digits,nfilename): - filename; - -#ifdef cimg_save_plugin - cimg_save_plugin(fn); -#endif -#ifdef cimg_save_plugin1 - cimg_save_plugin1(fn); -#endif -#ifdef cimg_save_plugin2 - cimg_save_plugin2(fn); -#endif -#ifdef cimg_save_plugin3 - cimg_save_plugin3(fn); -#endif -#ifdef cimg_save_plugin4 - cimg_save_plugin4(fn); -#endif -#ifdef cimg_save_plugin5 - cimg_save_plugin5(fn); -#endif -#ifdef cimg_save_plugin6 - cimg_save_plugin6(fn); -#endif -#ifdef cimg_save_plugin7 - cimg_save_plugin7(fn); -#endif -#ifdef cimg_save_plugin8 - cimg_save_plugin8(fn); -#endif - // Text formats - if (!cimg::strcasecmp(ext,"asc")) return save_ascii(fn); - else if (!cimg::strcasecmp(ext,"csv") || - !cimg::strcasecmp(ext,"dlm") || - !cimg::strcasecmp(ext,"txt")) return save_dlm(fn); - else if (!cimg::strcasecmp(ext,"cpp") || - !cimg::strcasecmp(ext,"hpp") || - !cimg::strcasecmp(ext,"h") || - !cimg::strcasecmp(ext,"c")) return save_cpp(fn); - - // 2D binary formats - else if (!cimg::strcasecmp(ext,"bmp")) return save_bmp(fn); - else if (!cimg::strcasecmp(ext,"jpg") || - !cimg::strcasecmp(ext,"jpeg") || - !cimg::strcasecmp(ext,"jpe") || - !cimg::strcasecmp(ext,"jfif") || - !cimg::strcasecmp(ext,"jif")) return save_jpeg(fn); - else if (!cimg::strcasecmp(ext,"rgb")) return save_rgb(fn); - else if (!cimg::strcasecmp(ext,"rgba")) return save_rgba(fn); - else if (!cimg::strcasecmp(ext,"png")) return save_png(fn); - else if (!cimg::strcasecmp(ext,"pgm") || - !cimg::strcasecmp(ext,"ppm") || - !cimg::strcasecmp(ext,"pnm")) return save_pnm(fn); - else if (!cimg::strcasecmp(ext,"pnk")) return save_pnk(fn); - else if (!cimg::strcasecmp(ext,"pfm")) return save_pfm(fn); - else if (!cimg::strcasecmp(ext,"exr")) return save_exr(fn); - else if (!cimg::strcasecmp(ext,"tif") || - !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn); - - // 3D binary formats - else if (!*ext) { -#ifdef cimg_use_zlib - return save_cimg(fn,true); -#else - return save_cimg(fn,false); -#endif - } else if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true); - else if (!cimg::strcasecmp(ext,"cimg")) return save_cimg(fn,false); - else if (!cimg::strcasecmp(ext,"dcm")) return save_medcon_external(fn); - else if (!cimg::strcasecmp(ext,"hdr") || - !cimg::strcasecmp(ext,"nii")) return save_analyze(fn); - else if (!cimg::strcasecmp(ext,"inr")) return save_inr(fn); - else if (!cimg::strcasecmp(ext,"mnc")) return save_minc2(fn); - else if (!cimg::strcasecmp(ext,"pan")) return save_pandore(fn); - else if (!cimg::strcasecmp(ext,"raw")) return save_raw(fn); - - // Archive files - else if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn); - - // Image sequences - else if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,444,true); - else if (!cimg::strcasecmp(ext,"avi") || - !cimg::strcasecmp(ext,"mov") || - !cimg::strcasecmp(ext,"asf") || - !cimg::strcasecmp(ext,"divx") || - !cimg::strcasecmp(ext,"flv") || - !cimg::strcasecmp(ext,"mpg") || - !cimg::strcasecmp(ext,"m1v") || - !cimg::strcasecmp(ext,"m2v") || - !cimg::strcasecmp(ext,"m4v") || - !cimg::strcasecmp(ext,"mjp") || - !cimg::strcasecmp(ext,"mp4") || - !cimg::strcasecmp(ext,"mkv") || - !cimg::strcasecmp(ext,"mpe") || - !cimg::strcasecmp(ext,"movie") || - !cimg::strcasecmp(ext,"ogm") || - !cimg::strcasecmp(ext,"ogg") || - !cimg::strcasecmp(ext,"ogv") || - !cimg::strcasecmp(ext,"qt") || - !cimg::strcasecmp(ext,"rm") || - !cimg::strcasecmp(ext,"vob") || - !cimg::strcasecmp(ext,"webm") || - !cimg::strcasecmp(ext,"wmv") || - !cimg::strcasecmp(ext,"xvid") || - !cimg::strcasecmp(ext,"mpeg")) return save_video(fn); - return save_other(fn); - } - - //! Save image as an ascii file. - /** - \param filename Filename, as a C-string. - **/ - const CImg& save_ascii(const char *const filename) const { - return _save_ascii(0,filename); - } - - //! Save image as an Ascii file \overloading. - const CImg& save_ascii(std::FILE *const file) const { - return _save_ascii(file,0); - } - - const CImg& _save_ascii(std::FILE *const file, const char *const filename) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_ascii(): Specified filename is (null).", - cimg_instance); - std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); - std::fprintf(nfile,"%u %u %u %u\n",_width,_height,_depth,_spectrum); - const T* ptrs = _data; - cimg_forYZC(*this,y,z,c) { - cimg_forX(*this,x) std::fprintf(nfile,"%.17g ",(double)*(ptrs++)); - std::fputc('\n',nfile); - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Save image as a .cpp source file. - /** - \param filename Filename, as a C-string. - **/ - const CImg& save_cpp(const char *const filename) const { - return _save_cpp(0,filename); - } - - //! Save image as a .cpp source file \overloading. - const CImg& save_cpp(std::FILE *const file) const { - return _save_cpp(file,0); - } - - const CImg& _save_cpp(std::FILE *const file, const char *const filename) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_cpp(): Specified filename is (null).", - cimg_instance); - std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); - CImg varname(1024); *varname = 0; - if (filename) cimg_sscanf(cimg::basename(filename),"%1023[a-zA-Z0-9_]",varname._data); - if (!*varname) cimg_snprintf(varname,varname._width,"unnamed"); - std::fprintf(nfile, - "/* Define image '%s' of size %ux%ux%ux%u and type '%s' */\n" - "%s data_%s[] = { %s\n ", - varname._data,_width,_height,_depth,_spectrum,pixel_type(),pixel_type(),varname._data, - is_empty()?"};":""); - if (!is_empty()) for (ulongT off = 0, siz = size() - 1; off<=siz; ++off) { - std::fprintf(nfile,cimg::type::format(),cimg::type::format((*this)[off])); - if (off==siz) std::fprintf(nfile," };\n"); - else if (!((off + 1)%16)) std::fprintf(nfile,",\n "); - else std::fprintf(nfile,", "); - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Save image as a DLM file. - /** - \param filename Filename, as a C-string. - **/ - const CImg& save_dlm(const char *const filename) const { - return _save_dlm(0,filename); - } - - //! Save image as a DLM file \overloading. - const CImg& save_dlm(std::FILE *const file) const { - return _save_dlm(file,0); - } - - const CImg& _save_dlm(std::FILE *const file, const char *const filename) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_dlm(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - if (_depth>1) - cimg::warn(_cimg_instance - "save_dlm(): Instance is volumetric, values along Z will be unrolled in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - if (_spectrum>1) - cimg::warn(_cimg_instance - "save_dlm(): Instance is multispectral, values along C will be unrolled in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); - const T* ptrs = _data; - cimg_forYZC(*this,y,z,c) { - cimg_forX(*this,x) std::fprintf(nfile,"%.17g%s",(double)*(ptrs++),(x==width() - 1)?"":","); - std::fputc('\n',nfile); - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Save image as a BMP file. - /** - \param filename Filename, as a C-string. - **/ - const CImg& save_bmp(const char *const filename) const { - return _save_bmp(0,filename); - } - - //! Save image as a BMP file \overloading. - const CImg& save_bmp(std::FILE *const file) const { - return _save_bmp(file,0); - } - - const CImg& _save_bmp(std::FILE *const file, const char *const filename) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_bmp(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - if (_depth>1) - cimg::warn(_cimg_instance - "save_bmp(): Instance is volumetric, only the first slice will be saved in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - if (_spectrum>3) - cimg::warn(_cimg_instance - "save_bmp(): Instance is multispectral, only the three first channels will be saved in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - CImg header(54,1,1,1,0); - unsigned char align_buf[4] = { 0 }; - const unsigned int - align = (4 - (3*_width)%4)%4, - buf_size = (3*_width + align)*height(), - file_size = 54 + buf_size; - header[0] = 'B'; header[1] = 'M'; - header[0x02] = file_size&0xFF; - header[0x03] = (file_size>>8)&0xFF; - header[0x04] = (file_size>>16)&0xFF; - header[0x05] = (file_size>>24)&0xFF; - header[0x0A] = 0x36; - header[0x0E] = 0x28; - header[0x12] = _width&0xFF; - header[0x13] = (_width>>8)&0xFF; - header[0x14] = (_width>>16)&0xFF; - header[0x15] = (_width>>24)&0xFF; - header[0x16] = _height&0xFF; - header[0x17] = (_height>>8)&0xFF; - header[0x18] = (_height>>16)&0xFF; - header[0x19] = (_height>>24)&0xFF; - header[0x1A] = 1; - header[0x1B] = 0; - header[0x1C] = 24; - header[0x1D] = 0; - header[0x22] = buf_size&0xFF; - header[0x23] = (buf_size>>8)&0xFF; - header[0x24] = (buf_size>>16)&0xFF; - header[0x25] = (buf_size>>24)&0xFF; - header[0x27] = 0x1; - header[0x2B] = 0x1; - cimg::fwrite(header._data,54,nfile); - - const T - *ptr_r = data(0,_height - 1,0,0), - *ptr_g = (_spectrum>=2)?data(0,_height - 1,0,1):0, - *ptr_b = (_spectrum>=3)?data(0,_height - 1,0,2):0; - - switch (_spectrum) { - case 1 : { - cimg_forY(*this,y) { - cimg_forX(*this,x) { - const unsigned char val = (unsigned char)*(ptr_r++); - std::fputc(val,nfile); std::fputc(val,nfile); std::fputc(val,nfile); - } - cimg::fwrite(align_buf,align,nfile); - ptr_r-=2*_width; - } - } break; - case 2 : { - cimg_forY(*this,y) { - cimg_forX(*this,x) { - std::fputc(0,nfile); - std::fputc((unsigned char)(*(ptr_g++)),nfile); - std::fputc((unsigned char)(*(ptr_r++)),nfile); - } - cimg::fwrite(align_buf,align,nfile); - ptr_r-=2*_width; ptr_g-=2*_width; - } - } break; - default : { - cimg_forY(*this,y) { - cimg_forX(*this,x) { - std::fputc((unsigned char)(*(ptr_b++)),nfile); - std::fputc((unsigned char)(*(ptr_g++)),nfile); - std::fputc((unsigned char)(*(ptr_r++)),nfile); - } - cimg::fwrite(align_buf,align,nfile); - ptr_r-=2*_width; ptr_g-=2*_width; ptr_b-=2*_width; - } - } - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Save image as a JPEG file. - /** - \param filename Filename, as a C-string. - \param quality Image quality (in %) - **/ - const CImg& save_jpeg(const char *const filename, const unsigned int quality=100) const { - return _save_jpeg(0,filename,quality); - } - - //! Save image as a JPEG file \overloading. - const CImg& save_jpeg(std::FILE *const file, const unsigned int quality=100) const { - return _save_jpeg(file,0,quality); - } - - const CImg& _save_jpeg(std::FILE *const file, const char *const filename, const unsigned int quality) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_jpeg(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - if (_depth>1) - cimg::warn(_cimg_instance - "save_jpeg(): Instance is volumetric, only the first slice will be saved in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - -#ifndef cimg_use_jpeg - if (!file) return save_other(filename,quality); - else throw CImgIOException(_cimg_instance - "save_jpeg(): Unable to save data in '(*FILE)' unless libjpeg is enabled.", - cimg_instance); -#else - unsigned int dimbuf = 0; - J_COLOR_SPACE colortype = JCS_RGB; - - switch (_spectrum) { - case 1 : dimbuf = 1; colortype = JCS_GRAYSCALE; break; - case 2 : dimbuf = 3; colortype = JCS_RGB; break; - case 3 : dimbuf = 3; colortype = JCS_RGB; break; - default : dimbuf = 4; colortype = JCS_CMYK; break; - } - - // Call libjpeg functions - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - cinfo.err = jpeg_std_error(&jerr); - jpeg_create_compress(&cinfo); - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - jpeg_stdio_dest(&cinfo,nfile); - cinfo.image_width = _width; - cinfo.image_height = _height; - cinfo.input_components = dimbuf; - cinfo.in_color_space = colortype; - jpeg_set_defaults(&cinfo); - jpeg_set_quality(&cinfo,quality<100?quality:100,TRUE); - jpeg_start_compress(&cinfo,TRUE); - - JSAMPROW row_pointer[1]; - CImg buffer(_width*dimbuf); - - while (cinfo.next_scanline& save_magick(const char *const filename, const unsigned int bytes_per_pixel=0) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save_magick(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - -#ifdef cimg_use_magick - double stmin, stmax = (double)max_min(stmin); - if (_depth>1) - cimg::warn(_cimg_instance - "save_magick(): Instance is volumetric, only the first slice will be saved in file '%s'.", - cimg_instance, - filename); - - if (_spectrum>3) - cimg::warn(_cimg_instance - "save_magick(): Instance is multispectral, only the three first channels will be " - "saved in file '%s'.", - cimg_instance, - filename); - - if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536) - cimg::warn(_cimg_instance - "save_magick(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.", - cimg_instance, - stmin,stmax,filename); - - Magick::Image image(Magick::Geometry(_width,_height),"black"); - image.type(Magick::TrueColorType); - image.depth(bytes_per_pixel?(8*bytes_per_pixel):(stmax>=256?16:8)); - const T - *ptr_r = data(0,0,0,0), - *ptr_g = _spectrum>1?data(0,0,0,1):0, - *ptr_b = _spectrum>2?data(0,0,0,2):0; - Magick::PixelPacket *pixels = image.getPixels(0,0,_width,_height); - switch (_spectrum) { - case 1 : // Scalar images - for (ulongT off = (ulongT)_width*_height; off; --off) { - pixels->red = pixels->green = pixels->blue = (Magick::Quantum)*(ptr_r++); - ++pixels; - } - break; - case 2 : // RG images - for (ulongT off = (ulongT)_width*_height; off; --off) { - pixels->red = (Magick::Quantum)*(ptr_r++); - pixels->green = (Magick::Quantum)*(ptr_g++); - pixels->blue = 0; ++pixels; - } - break; - default : // RGB images - for (ulongT off = (ulongT)_width*_height; off; --off) { - pixels->red = (Magick::Quantum)*(ptr_r++); - pixels->green = (Magick::Quantum)*(ptr_g++); - pixels->blue = (Magick::Quantum)*(ptr_b++); - ++pixels; - } - } - image.syncPixels(); - image.write(filename); - return *this; -#else - cimg::unused(bytes_per_pixel); - throw CImgIOException(_cimg_instance - "save_magick(): Unable to save file '%s' unless libMagick++ is enabled.", - cimg_instance, - filename); -#endif - } - - //! Save image as a PNG file. - /** - \param filename Filename, as a C-string. - \param bytes_per_pixel Force the number of bytes per pixels for the saving, when possible. - **/ - const CImg& save_png(const char *const filename, const unsigned int bytes_per_pixel=0) const { - return _save_png(0,filename,bytes_per_pixel); - } - - //! Save image as a PNG file \overloading. - const CImg& save_png(std::FILE *const file, const unsigned int bytes_per_pixel=0) const { - return _save_png(file,0,bytes_per_pixel); - } - - const CImg& _save_png(std::FILE *const file, const char *const filename, - const unsigned int bytes_per_pixel=0) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_png(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - -#ifndef cimg_use_png - cimg::unused(bytes_per_pixel); - if (!file) return save_other(filename); - else throw CImgIOException(_cimg_instance - "save_png(): Unable to save data in '(*FILE)' unless libpng is enabled.", - cimg_instance); -#else - -#if defined __GNUC__ - const char *volatile nfilename = filename; // Use 'volatile' to avoid (wrong) g++ warning - std::FILE *volatile nfile = file?file:cimg::fopen(nfilename,"wb"); - volatile double stmin, stmax = (double)max_min(stmin); -#else - const char *nfilename = filename; - std::FILE *nfile = file?file:cimg::fopen(nfilename,"wb"); - double stmin, stmax = (double)max_min(stmin); -#endif - - if (_depth>1) - cimg::warn(_cimg_instance - "save_png(): Instance is volumetric, only the first slice will be saved in file '%s'.", - cimg_instance, - filename); - - if (_spectrum>4) - cimg::warn(_cimg_instance - "save_png(): Instance is multispectral, only the three first channels will be saved in file '%s'.", - cimg_instance, - filename); - - if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536) - cimg::warn(_cimg_instance - "save_png(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.", - cimg_instance, - stmin,stmax,filename); - - // Setup PNG structures for write - png_voidp user_error_ptr = 0; - png_error_ptr user_error_fn = 0, user_warning_fn = 0; - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,user_error_ptr, user_error_fn, - user_warning_fn); - if (!png_ptr){ - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "save_png(): Failed to initialize 'png_ptr' structure when saving file '%s'.", - cimg_instance, - nfilename?nfilename:"(FILE*)"); - } - png_infop info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct(&png_ptr,(png_infopp)0); - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "save_png(): Failed to initialize 'info_ptr' structure when saving file '%s'.", - cimg_instance, - nfilename?nfilename:"(FILE*)"); - } - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_write_struct(&png_ptr, &info_ptr); - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "save_png(): Encountered unknown fatal error in libpng when saving file '%s'.", - cimg_instance, - nfilename?nfilename:"(FILE*)"); - } - png_init_io(png_ptr, nfile); - - const int bit_depth = bytes_per_pixel?(bytes_per_pixel*8):(stmax>=256?16:8); - - int color_type; - switch (spectrum()) { - case 1 : color_type = PNG_COLOR_TYPE_GRAY; break; - case 2 : color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; - case 3 : color_type = PNG_COLOR_TYPE_RGB; break; - default : color_type = PNG_COLOR_TYPE_RGB_ALPHA; - } - const int interlace_type = PNG_INTERLACE_NONE; - const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT; - const int filter_method = PNG_FILTER_TYPE_DEFAULT; - png_set_IHDR(png_ptr,info_ptr,_width,_height,bit_depth,color_type,interlace_type,compression_type,filter_method); - png_write_info(png_ptr,info_ptr); - const int byte_depth = bit_depth>>3; - const int numChan = spectrum()>4?4:spectrum(); - const int pixel_bit_depth_flag = numChan * (bit_depth - 1); - - // Allocate Memory for Image Save and Fill pixel data - png_bytep *const imgData = new png_byte*[_height]; - for (unsigned int row = 0; row<_height; ++row) imgData[row] = new png_byte[byte_depth*numChan*_width]; - const T *pC0 = data(0,0,0,0); - switch (pixel_bit_depth_flag) { - case 7 : { // Gray 8-bit - cimg_forY(*this,y) { - unsigned char *ptrd = imgData[y]; - cimg_forX(*this,x) *(ptrd++) = (unsigned char)*(pC0++); - } - } break; - case 14 : { // Gray w/ Alpha 8-bit - const T *pC1 = data(0,0,0,1); - cimg_forY(*this,y) { - unsigned char *ptrd = imgData[y]; - cimg_forX(*this,x) { - *(ptrd++) = (unsigned char)*(pC0++); - *(ptrd++) = (unsigned char)*(pC1++); - } - } - } break; - case 21 : { // RGB 8-bit - const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2); - cimg_forY(*this,y) { - unsigned char *ptrd = imgData[y]; - cimg_forX(*this,x) { - *(ptrd++) = (unsigned char)*(pC0++); - *(ptrd++) = (unsigned char)*(pC1++); - *(ptrd++) = (unsigned char)*(pC2++); - } - } - } break; - case 28 : { // RGB x/ Alpha 8-bit - const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2), *pC3 = data(0,0,0,3); - cimg_forY(*this,y){ - unsigned char *ptrd = imgData[y]; - cimg_forX(*this,x){ - *(ptrd++) = (unsigned char)*(pC0++); - *(ptrd++) = (unsigned char)*(pC1++); - *(ptrd++) = (unsigned char)*(pC2++); - *(ptrd++) = (unsigned char)*(pC3++); - } - } - } break; - case 15 : { // Gray 16-bit - cimg_forY(*this,y){ - unsigned short *ptrd = (unsigned short*)(imgData[y]); - cimg_forX(*this,x) *(ptrd++) = (unsigned short)*(pC0++); - if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],_width); - } - } break; - case 30 : { // Gray w/ Alpha 16-bit - const T *pC1 = data(0,0,0,1); - cimg_forY(*this,y){ - unsigned short *ptrd = (unsigned short*)(imgData[y]); - cimg_forX(*this,x) { - *(ptrd++) = (unsigned short)*(pC0++); - *(ptrd++) = (unsigned short)*(pC1++); - } - if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],2*_width); - } - } break; - case 45 : { // RGB 16-bit - const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2); - cimg_forY(*this,y) { - unsigned short *ptrd = (unsigned short*)(imgData[y]); - cimg_forX(*this,x) { - *(ptrd++) = (unsigned short)*(pC0++); - *(ptrd++) = (unsigned short)*(pC1++); - *(ptrd++) = (unsigned short)*(pC2++); - } - if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],3*_width); - } - } break; - case 60 : { // RGB w/ Alpha 16-bit - const T *pC1 = data(0,0,0,1), *pC2 = data(0,0,0,2), *pC3 = data(0,0,0,3); - cimg_forY(*this,y) { - unsigned short *ptrd = (unsigned short*)(imgData[y]); - cimg_forX(*this,x) { - *(ptrd++) = (unsigned short)*(pC0++); - *(ptrd++) = (unsigned short)*(pC1++); - *(ptrd++) = (unsigned short)*(pC2++); - *(ptrd++) = (unsigned short)*(pC3++); - } - if (!cimg::endianness()) cimg::invert_endianness((unsigned short*)imgData[y],4*_width); - } - } break; - default : - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimg_instance - "save_png(): Encountered unknown fatal error in libpng when saving file '%s'.", - cimg_instance, - nfilename?nfilename:"(FILE*)"); - } - png_write_image(png_ptr,imgData); - png_write_end(png_ptr,info_ptr); - png_destroy_write_struct(&png_ptr, &info_ptr); - - // Deallocate Image Write Memory - cimg_forY(*this,n) delete[] imgData[n]; - delete[] imgData; - - if (!file) cimg::fclose(nfile); - return *this; -#endif - } - - //! Save image as a PNM file. - /** - \param filename Filename, as a C-string. - \param bytes_per_pixel Force the number of bytes per pixels for the saving. - **/ - const CImg& save_pnm(const char *const filename, const unsigned int bytes_per_pixel=0) const { - return _save_pnm(0,filename,bytes_per_pixel); - } - - //! Save image as a PNM file \overloading. - const CImg& save_pnm(std::FILE *const file, const unsigned int bytes_per_pixel=0) const { - return _save_pnm(file,0,bytes_per_pixel); - } - - const CImg& _save_pnm(std::FILE *const file, const char *const filename, - const unsigned int bytes_per_pixel=0) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_pnm(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - - double stmin, stmax = (double)max_min(stmin); - if (_depth>1) - cimg::warn(_cimg_instance - "save_pnm(): Instance is volumetric, only the first slice will be saved in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - if (_spectrum>3) - cimg::warn(_cimg_instance - "save_pnm(): Instance is multispectral, only the three first channels will be saved in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - if (stmin<0 || (bytes_per_pixel==1 && stmax>=256) || stmax>=65536) - cimg::warn(_cimg_instance - "save_pnm(): Instance has pixel values in [%g,%g], probable type overflow in file '%s'.", - cimg_instance, - stmin,stmax,filename?filename:"(FILE*)"); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - const T - *ptr_r = data(0,0,0,0), - *ptr_g = (_spectrum>=2)?data(0,0,0,1):0, - *ptr_b = (_spectrum>=3)?data(0,0,0,2):0; - const ulongT buf_size = std::min((ulongT)(1024*1024),(ulongT)(_width*_height*(_spectrum==1?1UL:3UL))); - - std::fprintf(nfile,"P%c\n%u %u\n%u\n", - (_spectrum==1?'5':'6'),_width,_height,stmax<256?255:(stmax<4096?4095:65535)); - - switch (_spectrum) { - case 1 : { // Scalar image - if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PGM 8 bits - CImg buf((unsigned int)buf_size); - for (longT to_write = (longT)width()*height(); to_write>0; ) { - const ulongT N = std::min((ulongT)to_write,buf_size); - unsigned char *ptrd = buf._data; - for (ulongT i = N; i>0; --i) *(ptrd++) = (unsigned char)*(ptr_r++); - cimg::fwrite(buf._data,N,nfile); - to_write-=N; - } - } else { // Binary PGM 16 bits - CImg buf((unsigned int)buf_size); - for (longT to_write = (longT)width()*height(); to_write>0; ) { - const ulongT N = std::min((ulongT)to_write,buf_size); - unsigned short *ptrd = buf._data; - for (ulongT i = N; i>0; --i) *(ptrd++) = (unsigned short)*(ptr_r++); - if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); - cimg::fwrite(buf._data,N,nfile); - to_write-=N; - } - } - } break; - case 2 : { // RG image - if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits - CImg buf((unsigned int)buf_size); - for (longT to_write = (longT)width()*height(); to_write>0; ) { - const ulongT N = std::min((ulongT)to_write,buf_size/3); - unsigned char *ptrd = buf._data; - for (ulongT i = N; i>0; --i) { - *(ptrd++) = (unsigned char)*(ptr_r++); - *(ptrd++) = (unsigned char)*(ptr_g++); - *(ptrd++) = 0; - } - cimg::fwrite(buf._data,3*N,nfile); - to_write-=N; - } - } else { // Binary PPM 16 bits - CImg buf((unsigned int)buf_size); - for (longT to_write = (longT)width()*height(); to_write>0; ) { - const ulongT N = std::min((ulongT)to_write,buf_size/3); - unsigned short *ptrd = buf._data; - for (ulongT i = N; i>0; --i) { - *(ptrd++) = (unsigned short)*(ptr_r++); - *(ptrd++) = (unsigned short)*(ptr_g++); - *(ptrd++) = 0; - } - if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); - cimg::fwrite(buf._data,3*N,nfile); - to_write-=N; - } - } - } break; - default : { // RGB image - if (bytes_per_pixel==1 || (!bytes_per_pixel && stmax<256)) { // Binary PPM 8 bits - CImg buf((unsigned int)buf_size); - for (longT to_write = (longT)width()*height(); to_write>0; ) { - const ulongT N = std::min((ulongT)to_write,buf_size/3); - unsigned char *ptrd = buf._data; - for (ulongT i = N; i>0; --i) { - *(ptrd++) = (unsigned char)*(ptr_r++); - *(ptrd++) = (unsigned char)*(ptr_g++); - *(ptrd++) = (unsigned char)*(ptr_b++); - } - cimg::fwrite(buf._data,3*N,nfile); - to_write-=N; - } - } else { // Binary PPM 16 bits - CImg buf((unsigned int)buf_size); - for (longT to_write = (longT)width()*height(); to_write>0; ) { - const ulongT N = std::min((ulongT)to_write,buf_size/3); - unsigned short *ptrd = buf._data; - for (ulongT i = N; i>0; --i) { - *(ptrd++) = (unsigned short)*(ptr_r++); - *(ptrd++) = (unsigned short)*(ptr_g++); - *(ptrd++) = (unsigned short)*(ptr_b++); - } - if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); - cimg::fwrite(buf._data,3*N,nfile); - to_write-=N; - } - } - } - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Save image as a PNK file. - /** - \param filename Filename, as a C-string. - **/ - const CImg& save_pnk(const char *const filename) const { - return _save_pnk(0,filename); - } - - //! Save image as a PNK file \overloading. - const CImg& save_pnk(std::FILE *const file) const { - return _save_pnk(file,0); - } - - const CImg& _save_pnk(std::FILE *const file, const char *const filename) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_pnk(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - if (_spectrum>1) - cimg::warn(_cimg_instance - "save_pnk(): Instance is multispectral, only the first channel will be saved in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - - const ulongT buf_size = std::min((ulongT)1024*1024,(ulongT)_width*_height*_depth); - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - const T *ptr = data(0,0,0,0); - - if (!cimg::type::is_float() && sizeof(T)==1 && _depth<2) // Can be saved as regular PNM file - _save_pnm(file,filename,0); - else if (!cimg::type::is_float() && sizeof(T)==1) { // Save as extended P5 file: Binary byte-valued 3D - std::fprintf(nfile,"P5\n%u %u %u\n255\n",_width,_height,_depth); - CImg buf((unsigned int)buf_size); - for (longT to_write = (longT)width()*height()*depth(); to_write>0; ) { - const ulongT N = std::min((ulongT)to_write,buf_size); - unsigned char *ptrd = buf._data; - for (ulongT i = N; i>0; --i) *(ptrd++) = (unsigned char)*(ptr++); - cimg::fwrite(buf._data,N,nfile); - to_write-=N; - } - } else if (!cimg::type::is_float()) { // Save as P8: Binary int32-valued 3D - if (_depth>1) std::fprintf(nfile,"P8\n%u %u %u\n%d\n",_width,_height,_depth,(int)max()); - else std::fprintf(nfile,"P8\n%u %u\n%d\n",_width,_height,(int)max()); - CImg buf((unsigned int)buf_size); - for (longT to_write = (longT)width()*height()*depth(); to_write>0; ) { - const ulongT N = std::min((ulongT)to_write,buf_size); - int *ptrd = buf._data; - for (ulongT i = N; i>0; --i) *(ptrd++) = (int)*(ptr++); - cimg::fwrite(buf._data,N,nfile); - to_write-=N; - } - } else { // Save as P9: Binary float-valued 3D - if (_depth>1) std::fprintf(nfile,"P9\n%u %u %u\n%g\n",_width,_height,_depth,(double)max()); - else std::fprintf(nfile,"P9\n%u %u\n%g\n",_width,_height,(double)max()); - CImg buf((unsigned int)buf_size); - for (longT to_write = (longT)width()*height()*depth(); to_write>0; ) { - const ulongT N = std::min((ulongT)to_write,buf_size); - float *ptrd = buf._data; - for (ulongT i = N; i>0; --i) *(ptrd++) = (float)*(ptr++); - cimg::fwrite(buf._data,N,nfile); - to_write-=N; - } - } - - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Save image as a PFM file. - /** - \param filename Filename, as a C-string. - **/ - const CImg& save_pfm(const char *const filename) const { - get_mirror('y')._save_pfm(0,filename); - return *this; - } - - //! Save image as a PFM file \overloading. - const CImg& save_pfm(std::FILE *const file) const { - get_mirror('y')._save_pfm(file,0); - return *this; - } - - const CImg& _save_pfm(std::FILE *const file, const char *const filename) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_pfm(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - if (_depth>1) - cimg::warn(_cimg_instance - "save_pfm(): Instance is volumetric, only the first slice will be saved in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - if (_spectrum>3) - cimg::warn(_cimg_instance - "save_pfm(): image instance is multispectral, only the three first channels will be saved " - "in file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - const T - *ptr_r = data(0,0,0,0), - *ptr_g = (_spectrum>=2)?data(0,0,0,1):0, - *ptr_b = (_spectrum>=3)?data(0,0,0,2):0; - const unsigned int buf_size = std::min(1024*1024U,_width*_height*(_spectrum==1?1:3)); - - std::fprintf(nfile,"P%c\n%u %u\n1.0\n", - (_spectrum==1?'f':'F'),_width,_height); - - switch (_spectrum) { - case 1 : { // Scalar image - CImg buf(buf_size); - for (longT to_write = (longT)width()*height(); to_write>0; ) { - const ulongT N = std::min((ulongT)to_write,(ulongT)buf_size); - float *ptrd = buf._data; - for (ulongT i = N; i>0; --i) *(ptrd++) = (float)*(ptr_r++); - if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); - cimg::fwrite(buf._data,N,nfile); - to_write-=N; - } - } break; - case 2 : { // RG image - CImg buf(buf_size); - for (longT to_write = (longT)width()*height(); to_write>0; ) { - const unsigned int N = std::min((unsigned int)to_write,buf_size/3); - float *ptrd = buf._data; - for (ulongT i = N; i>0; --i) { - *(ptrd++) = (float)*(ptr_r++); - *(ptrd++) = (float)*(ptr_g++); - *(ptrd++) = 0; - } - if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); - cimg::fwrite(buf._data,3*N,nfile); - to_write-=N; - } - } break; - default : { // RGB image - CImg buf(buf_size); - for (longT to_write = (longT)width()*height(); to_write>0; ) { - const unsigned int N = std::min((unsigned int)to_write,buf_size/3); - float *ptrd = buf._data; - for (ulongT i = N; i>0; --i) { - *(ptrd++) = (float)*(ptr_r++); - *(ptrd++) = (float)*(ptr_g++); - *(ptrd++) = (float)*(ptr_b++); - } - if (!cimg::endianness()) cimg::invert_endianness(buf._data,buf_size); - cimg::fwrite(buf._data,3*N,nfile); - to_write-=N; - } - } - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Save image as a RGB file. - /** - \param filename Filename, as a C-string. - **/ - const CImg& save_rgb(const char *const filename) const { - return _save_rgb(0,filename); - } - - //! Save image as a RGB file \overloading. - const CImg& save_rgb(std::FILE *const file) const { - return _save_rgb(file,0); - } - - const CImg& _save_rgb(std::FILE *const file, const char *const filename) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_rgb(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - if (_spectrum!=3) - cimg::warn(_cimg_instance - "save_rgb(): image instance has not exactly 3 channels, for file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - const ulongT wh = (ulongT)_width*_height; - unsigned char *const buffer = new unsigned char[3*wh], *nbuffer = buffer; - const T - *ptr1 = data(0,0,0,0), - *ptr2 = _spectrum>1?data(0,0,0,1):0, - *ptr3 = _spectrum>2?data(0,0,0,2):0; - switch (_spectrum) { - case 1 : { // Scalar image - for (ulongT k = 0; k& save_rgba(const char *const filename) const { - return _save_rgba(0,filename); - } - - //! Save image as a RGBA file \overloading. - const CImg& save_rgba(std::FILE *const file) const { - return _save_rgba(file,0); - } - - const CImg& _save_rgba(std::FILE *const file, const char *const filename) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_rgba(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - if (_spectrum!=4) - cimg::warn(_cimg_instance - "save_rgba(): image instance has not exactly 4 channels, for file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - const ulongT wh = (ulongT)_width*_height; - unsigned char *const buffer = new unsigned char[4*wh], *nbuffer = buffer; - const T - *ptr1 = data(0,0,0,0), - *ptr2 = _spectrum>1?data(0,0,0,1):0, - *ptr3 = _spectrum>2?data(0,0,0,2):0, - *ptr4 = _spectrum>3?data(0,0,0,3):0; - switch (_spectrum) { - case 1 : { // Scalar images - for (ulongT k = 0; k{ 0=None | 1=LZW | 2=JPEG }. - \param[out] voxel_size Voxel size, to be stored in the filename. - \param[out] description Description, to be stored in the filename. - \param use_bigtiff Allow to save big tiff files (>4Gb). - \note - - libtiff support is enabled by defining the precompilation - directive \c cimg_use_tif. - - When libtiff is enabled, 2D and 3D (multipage) several - channel per pixel are supported for - char,uchar,short,ushort,float and \c double pixel types. - - If \c cimg_use_tiff is not defined at compile time the - function uses CImg&save_other(const char*). - **/ - const CImg& save_tiff(const char *const filename, const unsigned int compression_type=0, - - const float *const voxel_size=0, const char *const description=0, - const bool use_bigtiff=true) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save_tiff(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - -#ifdef cimg_use_tiff - const bool - _use_bigtiff = use_bigtiff && sizeof(ulongT)>=8 && size()*sizeof(T)>=1UL<<31; // No bigtiff for small images - TIFF *tif = TIFFOpen(filename,_use_bigtiff?"w8":"w4"); - if (tif) { - cimg_forZ(*this,z) _save_tiff(tif,z,z,compression_type,voxel_size,description); - TIFFClose(tif); - } else throw CImgIOException(_cimg_instance - "save_tiff(): Failed to open file '%s' for writing.", - cimg_instance, - filename); - return *this; -#else - cimg::unused(compression_type,voxel_size,description,use_bigtiff); - return save_other(filename); -#endif - } - -#ifdef cimg_use_tiff - -#define _cimg_save_tiff(types,typed) if (!std::strcmp(types,pixel_type())) { \ - const typed foo = (typed)0; return _save_tiff(tif,directory,z,foo,compression_type,voxel_size,description); } - - // [internal] Save a plane into a tiff file - template - const CImg& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int z, const t& pixel_t, - const unsigned int compression_type, const float *const voxel_size, - const char *const description) const { - if (is_empty() || !tif || pixel_t) return *this; - const char *const filename = TIFFFileName(tif); - cimg_uint32 rowsperstrip = (cimg_uint32)-1; - cimg_uint16 spp = _spectrum, bpp = sizeof(t)*8, photometric; - if (spp==3 || spp==4) photometric = PHOTOMETRIC_RGB; - else photometric = PHOTOMETRIC_MINISBLACK; - TIFFSetDirectory(tif,directory); - TIFFSetField(tif,TIFFTAG_IMAGEWIDTH,_width); - TIFFSetField(tif,TIFFTAG_IMAGELENGTH,_height); - if (voxel_size) { - const float vx = voxel_size[0], vy = voxel_size[1], vz = voxel_size[2]; - TIFFSetField(tif,TIFFTAG_RESOLUTIONUNIT,RESUNIT_NONE); - TIFFSetField(tif,TIFFTAG_XRESOLUTION,1.f/vx); - TIFFSetField(tif,TIFFTAG_YRESOLUTION,1.f/vy); - CImg s_description(256); - cimg_snprintf(s_description,s_description._width,"VX=%g VY=%g VZ=%g spacing=%g",vx,vy,vz,vz); - TIFFSetField(tif,TIFFTAG_IMAGEDESCRIPTION,s_description.data()); - } - if (description) TIFFSetField(tif,TIFFTAG_IMAGEDESCRIPTION,description); - TIFFSetField(tif,TIFFTAG_ORIENTATION,ORIENTATION_TOPLEFT); - TIFFSetField(tif,TIFFTAG_SAMPLESPERPIXEL,spp); - if (cimg::type::is_float()) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,3); - else if (cimg::type::min()==0) TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,1); - else TIFFSetField(tif,TIFFTAG_SAMPLEFORMAT,2); - double valm, valM = max_min(valm); - TIFFSetField(tif,TIFFTAG_SMINSAMPLEVALUE,valm); - TIFFSetField(tif,TIFFTAG_SMAXSAMPLEVALUE,valM); - TIFFSetField(tif,TIFFTAG_BITSPERSAMPLE,bpp); - TIFFSetField(tif,TIFFTAG_PLANARCONFIG,PLANARCONFIG_CONTIG); - TIFFSetField(tif,TIFFTAG_PHOTOMETRIC,photometric); - TIFFSetField(tif,TIFFTAG_COMPRESSION,compression_type==2?COMPRESSION_JPEG: - compression_type==1?COMPRESSION_LZW:COMPRESSION_NONE); - rowsperstrip = TIFFDefaultStripSize(tif,rowsperstrip); - TIFFSetField(tif,TIFFTAG_ROWSPERSTRIP,rowsperstrip); - TIFFSetField(tif,TIFFTAG_FILLORDER,FILLORDER_MSB2LSB); - TIFFSetField(tif,TIFFTAG_SOFTWARE,cimg_appname); - - t *const buf = (t*)_TIFFmalloc(TIFFStripSize(tif)); - if (buf) { - for (unsigned int row = 0; row<_height; row+=rowsperstrip) { - cimg_uint32 nrow = (row + rowsperstrip>_height?_height - row:rowsperstrip); - tstrip_t strip = TIFFComputeStrip(tif,row,0); - tsize_t i = 0; - for (unsigned int rr = 0; rr& _save_tiff(TIFF *tif, const unsigned int directory, const unsigned int z, - const unsigned int compression_type, const float *const voxel_size, - const char *const description) const { - _cimg_save_tiff("uint8",cimg_uint8); - _cimg_save_tiff("int8",cimg_int8); - _cimg_save_tiff("uint16",cimg_uint16); - _cimg_save_tiff("int16",cimg_int16); - _cimg_save_tiff("uint32",cimg_uint32); - _cimg_save_tiff("int32",cimg_int32); - _cimg_save_tiff("uint64",cimg_uint32); // 'int64' as 'int32' - _cimg_save_tiff("int64",cimg_int32); - _cimg_save_tiff("float32",cimg_float32); - _cimg_save_tiff("float64",cimg_float32); // 'float64' as 'float32' - const char *const filename = TIFFFileName(tif); - throw CImgInstanceException(_cimg_instance - "save_tiff(): Unsupported pixel type '%s' for file '%s'.", - cimg_instance, - pixel_type(),filename?filename:"(FILE*)"); - return *this; - } -#endif - - //! Save image as a MINC2 file. - /** - \param filename Filename, as a C-string. - \param imitate_file If non-zero, reference filename, as a C-string, to borrow header from. - **/ - const CImg& save_minc2(const char *const filename, - const char *const imitate_file=0) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save_minc2(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - -#ifndef cimg_use_minc2 - cimg::unused(imitate_file); - return save_other(filename); -#else - minc::minc_1_writer wtr; - if (imitate_file) - wtr.open(filename, imitate_file); - else { - minc::minc_info di; - if (width()) di.push_back(minc::dim_info(width(),width()*0.5,-1,minc::dim_info::DIM_X)); - if (height()) di.push_back(minc::dim_info(height(),height()*0.5,-1,minc::dim_info::DIM_Y)); - if (depth()) di.push_back(minc::dim_info(depth(),depth()*0.5,-1,minc::dim_info::DIM_Z)); - if (spectrum()) di.push_back(minc::dim_info(spectrum(),spectrum()*0.5,-1,minc::dim_info::DIM_TIME)); - wtr.open(filename,di,1,NC_FLOAT,0); - } - if (pixel_type()==cimg::type::string()) - wtr.setup_write_byte(); - else if (pixel_type()==cimg::type::string()) - wtr.setup_write_int(); - else if (pixel_type()==cimg::type::string()) - wtr.setup_write_double(); - else - wtr.setup_write_float(); - minc::save_standard_volume(wtr, this->_data); - return *this; -#endif - } - - //! Save image as an ANALYZE7.5 or NIFTI file. - /** - \param filename Filename, as a C-string. - \param voxel_size Pointer to 3 consecutive values that tell about the voxel sizes along the X,Y and Z dimensions. - **/ - const CImg& save_analyze(const char *const filename, const float *const voxel_size=0) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save_analyze(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - - std::FILE *file; - CImg hname(1024), iname(1024); - const char *const ext = cimg::split_filename(filename); - short datatype = -1; - if (!*ext) { - cimg_snprintf(hname,hname._width,"%s.hdr",filename); - cimg_snprintf(iname,iname._width,"%s.img",filename); - } - if (!cimg::strncasecmp(ext,"hdr",3)) { - std::strcpy(hname,filename); - std::strncpy(iname,filename,iname._width - 1); - cimg_sprintf(iname._data + std::strlen(iname) - 3,"img"); - } - if (!cimg::strncasecmp(ext,"img",3)) { - std::strcpy(hname,filename); - std::strncpy(iname,filename,iname._width - 1); - cimg_sprintf(hname._data + std::strlen(iname) - 3,"hdr"); - } - if (!cimg::strncasecmp(ext,"nii",3)) { - std::strncpy(hname,filename,hname._width - 1); *iname = 0; - } - - CImg header(*iname?348:352,1,1,1,0); - int *const iheader = (int*)header._data; - *iheader = 348; - std::strcpy(header._data + 4,"CImg"); - std::strcpy(header._data + 14," "); - ((short*)&(header[36]))[0] = 4096; - ((char*)&(header[38]))[0] = 114; - ((short*)&(header[40]))[0] = 4; - ((short*)&(header[40]))[1] = (short)_width; - ((short*)&(header[40]))[2] = (short)_height; - ((short*)&(header[40]))[3] = (short)_depth; - ((short*)&(header[40]))[4] = (short)_spectrum; - if (!cimg::strcasecmp(pixel_type(),"bool") || - !cimg::strcasecmp(pixel_type(),"uint8") || - !cimg::strcasecmp(pixel_type(),"int8")) datatype = 2; - if (!cimg::strcasecmp(pixel_type(),"uint16") || - !cimg::strcasecmp(pixel_type(),"int16")) datatype = 4; - if (!cimg::strcasecmp(pixel_type(),"uint32") || - !cimg::strcasecmp(pixel_type(),"int32")) datatype = 8; - if (!cimg::strcasecmp(pixel_type(),"uint64") || - !cimg::strcasecmp(pixel_type(),"int64")) datatype = 8; - if (!cimg::strcasecmp(pixel_type(),"float32")) datatype = 16; - if (!cimg::strcasecmp(pixel_type(),"float64")) datatype = 64; - if (datatype<0) - throw CImgIOException(_cimg_instance - "save_analyze(): Unsupported pixel type '%s' for file '%s'.", - cimg_instance, - pixel_type(),filename); - - ((short*)&(header[70]))[0] = datatype; - ((short*)&(header[72]))[0] = sizeof(T); - ((float*)&(header[108]))[0] = (float)(*iname?0:header.width()); - ((float*)&(header[112]))[0] = 1; - ((float*)&(header[76]))[0] = 0; - if (voxel_size) { - ((float*)&(header[76]))[1] = voxel_size[0]; - ((float*)&(header[76]))[2] = voxel_size[1]; - ((float*)&(header[76]))[3] = voxel_size[2]; - } else ((float*)&(header[76]))[1] = ((float*)&(header[76]))[2] = ((float*)&(header[76]))[3] = 1; - file = cimg::fopen(hname,"wb"); - cimg::fwrite(header._data,header.width(),file); - if (*iname) { cimg::fclose(file); file = cimg::fopen(iname,"wb"); } - cimg::fwrite(_data,size(),file); - cimg::fclose(file); - return *this; - } - - //! Save image as a .cimg file. - /** - \param filename Filename, as a C-string. - \param is_compressed Tells if the file contains compressed image data. - **/ - const CImg& save_cimg(const char *const filename, const bool is_compressed=false) const { - CImgList(*this,true).save_cimg(filename,is_compressed); - return *this; - } - - //! Save image as a .cimg file \overloading. - const CImg& save_cimg(std::FILE *const file, const bool is_compressed=false) const { - CImgList(*this,true).save_cimg(file,is_compressed); - return *this; - } - - //! Save image as a sub-image into an existing .cimg file. - /** - \param filename Filename, as a C-string. - \param n0 Index of the image inside the file. - \param x0 X-coordinate of the sub-image location. - \param y0 Y-coordinate of the sub-image location. - \param z0 Z-coordinate of the sub-image location. - \param c0 C-coordinate of the sub-image location. - **/ - const CImg& save_cimg(const char *const filename, - const unsigned int n0, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0) const { - CImgList(*this,true).save_cimg(filename,n0,x0,y0,z0,c0); - return *this; - } - - //! Save image as a sub-image into an existing .cimg file \overloading. - const CImg& save_cimg(std::FILE *const file, - const unsigned int n0, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0) const { - CImgList(*this,true).save_cimg(file,n0,x0,y0,z0,c0); - return *this; - } - - //! Save blank image as a .cimg file. - /** - \param filename Filename, as a C-string. - \param dx Width of the image. - \param dy Height of the image. - \param dz Depth of the image. - \param dc Number of channels of the image. - \note - - All pixel values of the saved image are set to \c 0. - - Use this method to save large images without having to instantiate and allocate them. - **/ - static void save_empty_cimg(const char *const filename, - const unsigned int dx, const unsigned int dy=1, - const unsigned int dz=1, const unsigned int dc=1) { - return CImgList::save_empty_cimg(filename,1,dx,dy,dz,dc); - } - - //! Save blank image as a .cimg file \overloading. - /** - Same as save_empty_cimg(const char *,unsigned int,unsigned int,unsigned int,unsigned int) - with a file stream argument instead of a filename string. - **/ - static void save_empty_cimg(std::FILE *const file, - const unsigned int dx, const unsigned int dy=1, - const unsigned int dz=1, const unsigned int dc=1) { - return CImgList::save_empty_cimg(file,1,dx,dy,dz,dc); - } - - //! Save image as an INRIMAGE-4 file. - /** - \param filename Filename, as a C-string. - \param voxel_size Pointer to 3 values specifying the voxel sizes along the X,Y and Z dimensions. - **/ - const CImg& save_inr(const char *const filename, const float *const voxel_size=0) const { - return _save_inr(0,filename,voxel_size); - } - - //! Save image as an INRIMAGE-4 file \overloading. - const CImg& save_inr(std::FILE *const file, const float *const voxel_size=0) const { - return _save_inr(file,0,voxel_size); - } - - const CImg& _save_inr(std::FILE *const file, const char *const filename, const float *const voxel_size) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_inr(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - - int inrpixsize = -1; - const char *inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; - if (!cimg::strcasecmp(pixel_type(),"uint8")) { - inrtype = "unsigned fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; - } - if (!cimg::strcasecmp(pixel_type(),"int8")) { - inrtype = "fixed\nPIXSIZE=8 bits\nSCALE=2**0"; inrpixsize = 1; - } - if (!cimg::strcasecmp(pixel_type(),"uint16")) { - inrtype = "unsigned fixed\nPIXSIZE=16 bits\nSCALE=2**0";inrpixsize = 2; - } - if (!cimg::strcasecmp(pixel_type(),"int16")) { - inrtype = "fixed\nPIXSIZE=16 bits\nSCALE=2**0"; inrpixsize = 2; - } - if (!cimg::strcasecmp(pixel_type(),"uint32")) { - inrtype = "unsigned fixed\nPIXSIZE=32 bits\nSCALE=2**0";inrpixsize = 4; - } - if (!cimg::strcasecmp(pixel_type(),"int32")) { - inrtype = "fixed\nPIXSIZE=32 bits\nSCALE=2**0"; inrpixsize = 4; - } - if (!cimg::strcasecmp(pixel_type(),"float32")) { - inrtype = "float\nPIXSIZE=32 bits"; inrpixsize = 4; - } - if (!cimg::strcasecmp(pixel_type(),"float64")) { - inrtype = "float\nPIXSIZE=64 bits"; inrpixsize = 8; - } - if (inrpixsize<=0) - throw CImgIOException(_cimg_instance - "save_inr(): Unsupported pixel type '%s' for file '%s'", - cimg_instance, - pixel_type(),filename?filename:"(FILE*)"); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - CImg header(257); - int err = cimg_snprintf(header,header._width,"#INRIMAGE-4#{\nXDIM=%u\nYDIM=%u\nZDIM=%u\nVDIM=%u\n", - _width,_height,_depth,_spectrum); - if (voxel_size) err+=cimg_sprintf(header._data + err,"VX=%g\nVY=%g\nVZ=%g\n", - voxel_size[0],voxel_size[1],voxel_size[2]); - err+=cimg_sprintf(header._data + err,"TYPE=%s\nCPU=%s\n",inrtype,cimg::endianness()?"sun":"decm"); - std::memset(header._data + err,'\n',252 - err); - std::memcpy(header._data + 252,"##}\n",4); - cimg::fwrite(header._data,256,nfile); - cimg_forXYZ(*this,x,y,z) cimg_forC(*this,c) cimg::fwrite(&((*this)(x,y,z,c)),1,nfile); - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Save image as an OpenEXR file. - /** - \param filename Filename, as a C-string. - \note The OpenEXR file format is described here. - **/ - const CImg& save_exr(const char *const filename) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save_exr(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - if (_depth>1) - cimg::warn(_cimg_instance - "save_exr(): Instance is volumetric, only the first slice will be saved in file '%s'.", - cimg_instance, - filename); - -#ifndef cimg_use_openexr - return save_other(filename); -#else - Imf::Rgba *const ptrd0 = new Imf::Rgba[(size_t)_width*_height], *ptrd = ptrd0, rgba; - switch (_spectrum) { - case 1 : { // Grayscale image - for (const T *ptr_r = data(), *const ptr_e = ptr_r + (ulongT)_width*_height; ptr_rPandore file specifications - for more information). - **/ - const CImg& save_pandore(const char *const filename, const unsigned int colorspace=0) const { - return _save_pandore(0,filename,colorspace); - } - - //! Save image as a Pandore-5 file \overloading. - /** - Same as save_pandore(const char *,unsigned int) const - with a file stream argument instead of a filename string. - **/ - const CImg& save_pandore(std::FILE *const file, const unsigned int colorspace=0) const { - return _save_pandore(file,0,colorspace); - } - - unsigned int _save_pandore_header_length(unsigned int id, unsigned int *dims, const unsigned int colorspace) const { - unsigned int nbdims = 0; - if (id==2 || id==3 || id==4) { - dims[0] = 1; dims[1] = _width; nbdims = 2; - } - if (id==5 || id==6 || id==7) { - dims[0] = 1; dims[1] = _height; dims[2] = _width; nbdims=3; - } - if (id==8 || id==9 || id==10) { - dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4; - } - if (id==16 || id==17 || id==18) { - dims[0] = 3; dims[1] = _height; dims[2] = _width; dims[3] = colorspace; nbdims = 4; - } - if (id==19 || id==20 || id==21) { - dims[0] = 3; dims[1] = _depth; dims[2] = _height; dims[3] = _width; dims[4] = colorspace; nbdims = 5; - } - if (id==22 || id==23 || id==25) { - dims[0] = _spectrum; dims[1] = _width; nbdims = 2; - } - if (id==26 || id==27 || id==29) { - dims[0] = _spectrum; dims[1] = _height; dims[2] = _width; nbdims=3; - } - if (id==30 || id==31 || id==33) { - dims[0] = _spectrum; dims[1] = _depth; dims[2] = _height; dims[3] = _width; nbdims = 4; - } - return nbdims; - } - - const CImg& _save_pandore(std::FILE *const file, const char *const filename, - const unsigned int colorspace) const { - -#define __cimg_save_pandore_case(dtype) \ - dtype *buffer = new dtype[size()]; \ - const T *ptrs = _data; \ - cimg_foroff(*this,off) *(buffer++) = (dtype)(*(ptrs++)); \ - buffer-=size(); \ - cimg::fwrite(buffer,size(),nfile); \ - delete[] buffer - -#define _cimg_save_pandore_case(sy,sz,sv,stype,id) \ - if (!saved && (sy?(sy==_height):true) && (sz?(sz==_depth):true) && \ - (sv?(sv==_spectrum):true) && !std::strcmp(stype,pixel_type())) { \ - unsigned int *iheader = (unsigned int*)(header + 12); \ - nbdims = _save_pandore_header_length((*iheader=id),dims,colorspace); \ - cimg::fwrite(header,36,nfile); \ - if (sizeof(unsigned long)==4) { CImg ndims(5); \ - for (int d = 0; d<5; ++d) ndims[d] = (unsigned long)dims[d]; \ - cimg::fwrite(ndims._data,nbdims,nfile); } \ - else if (sizeof(unsigned int)==4) { CImg ndims(5); \ - for (int d = 0; d<5; ++d) ndims[d] = (unsigned int)dims[d]; \ - cimg::fwrite(ndims._data,nbdims,nfile); } \ - else if (sizeof(unsigned short)==4) { CImg ndims(5); \ - for (int d = 0; d<5; ++d) ndims[d] = (unsigned short)dims[d]; \ - cimg::fwrite(ndims._data,nbdims,nfile); } \ - else throw CImgIOException(_cimg_instance \ - "save_pandore(): Unsupported datatype for file '%s'.",\ - cimg_instance, \ - filename?filename:"(FILE*)"); \ - if (id==2 || id==5 || id==8 || id==16 || id==19 || id==22 || id==26 || id==30) { \ - __cimg_save_pandore_case(unsigned char); \ - } else if (id==3 || id==6 || id==9 || id==17 || id==20 || id==23 || id==27 || id==31) { \ - if (sizeof(unsigned long)==4) { __cimg_save_pandore_case(unsigned long); } \ - else if (sizeof(unsigned int)==4) { __cimg_save_pandore_case(unsigned int); } \ - else if (sizeof(unsigned short)==4) { __cimg_save_pandore_case(unsigned short); } \ - else throw CImgIOException(_cimg_instance \ - "save_pandore(): Unsupported datatype for file '%s'.",\ - cimg_instance, \ - filename?filename:"(FILE*)"); \ - } else if (id==4 || id==7 || id==10 || id==18 || id==21 || id==25 || id==29 || id==33) { \ - if (sizeof(double)==4) { __cimg_save_pandore_case(double); } \ - else if (sizeof(float)==4) { __cimg_save_pandore_case(float); } \ - else throw CImgIOException(_cimg_instance \ - "save_pandore(): Unsupported datatype for file '%s'.",\ - cimg_instance, \ - filename?filename:"(FILE*)"); \ - } \ - saved = true; \ - } - - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_pandore(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - unsigned char header[36] = { 'P','A','N','D','O','R','E','0','4',0,0,0, - 0,0,0,0,'C','I','m','g',0,0,0,0,0, - 'N','o',' ','d','a','t','e',0,0,0,0 }; - unsigned int nbdims, dims[5] = { 0 }; - bool saved = false; - _cimg_save_pandore_case(1,1,1,"uint8",2); - _cimg_save_pandore_case(1,1,1,"int8",3); - _cimg_save_pandore_case(1,1,1,"uint16",3); - _cimg_save_pandore_case(1,1,1,"int16",3); - _cimg_save_pandore_case(1,1,1,"uint32",3); - _cimg_save_pandore_case(1,1,1,"int32",3); - _cimg_save_pandore_case(1,1,1,"uint64",3); - _cimg_save_pandore_case(1,1,1,"int64",3); - _cimg_save_pandore_case(1,1,1,"float32",4); - _cimg_save_pandore_case(1,1,1,"float64",4); - - _cimg_save_pandore_case(0,1,1,"uint8",5); - _cimg_save_pandore_case(0,1,1,"int8",6); - _cimg_save_pandore_case(0,1,1,"uint16",6); - _cimg_save_pandore_case(0,1,1,"int16",6); - _cimg_save_pandore_case(0,1,1,"uint32",6); - _cimg_save_pandore_case(0,1,1,"int32",6); - _cimg_save_pandore_case(0,1,1,"uint64",6); - _cimg_save_pandore_case(0,1,1,"int64",6); - _cimg_save_pandore_case(0,1,1,"float32",7); - _cimg_save_pandore_case(0,1,1,"float64",7); - - _cimg_save_pandore_case(0,0,1,"uint8",8); - _cimg_save_pandore_case(0,0,1,"int8",9); - _cimg_save_pandore_case(0,0,1,"uint16",9); - _cimg_save_pandore_case(0,0,1,"int16",9); - _cimg_save_pandore_case(0,0,1,"uint32",9); - _cimg_save_pandore_case(0,0,1,"int32",9); - _cimg_save_pandore_case(0,0,1,"uint64",9); - _cimg_save_pandore_case(0,0,1,"int64",9); - _cimg_save_pandore_case(0,0,1,"float32",10); - _cimg_save_pandore_case(0,0,1,"float64",10); - - _cimg_save_pandore_case(0,1,3,"uint8",16); - _cimg_save_pandore_case(0,1,3,"int8",17); - _cimg_save_pandore_case(0,1,3,"uint16",17); - _cimg_save_pandore_case(0,1,3,"int16",17); - _cimg_save_pandore_case(0,1,3,"uint32",17); - _cimg_save_pandore_case(0,1,3,"int32",17); - _cimg_save_pandore_case(0,1,3,"uint64",17); - _cimg_save_pandore_case(0,1,3,"int64",17); - _cimg_save_pandore_case(0,1,3,"float32",18); - _cimg_save_pandore_case(0,1,3,"float64",18); - - _cimg_save_pandore_case(0,0,3,"uint8",19); - _cimg_save_pandore_case(0,0,3,"int8",20); - _cimg_save_pandore_case(0,0,3,"uint16",20); - _cimg_save_pandore_case(0,0,3,"int16",20); - _cimg_save_pandore_case(0,0,3,"uint32",20); - _cimg_save_pandore_case(0,0,3,"int32",20); - _cimg_save_pandore_case(0,0,3,"uint64",20); - _cimg_save_pandore_case(0,0,3,"int64",20); - _cimg_save_pandore_case(0,0,3,"float32",21); - _cimg_save_pandore_case(0,0,3,"float64",21); - - _cimg_save_pandore_case(1,1,0,"uint8",22); - _cimg_save_pandore_case(1,1,0,"int8",23); - _cimg_save_pandore_case(1,1,0,"uint16",23); - _cimg_save_pandore_case(1,1,0,"int16",23); - _cimg_save_pandore_case(1,1,0,"uint32",23); - _cimg_save_pandore_case(1,1,0,"int32",23); - _cimg_save_pandore_case(1,1,0,"uint64",23); - _cimg_save_pandore_case(1,1,0,"int64",23); - _cimg_save_pandore_case(1,1,0,"float32",25); - _cimg_save_pandore_case(1,1,0,"float64",25); - - _cimg_save_pandore_case(0,1,0,"uint8",26); - _cimg_save_pandore_case(0,1,0,"int8",27); - _cimg_save_pandore_case(0,1,0,"uint16",27); - _cimg_save_pandore_case(0,1,0,"int16",27); - _cimg_save_pandore_case(0,1,0,"uint32",27); - _cimg_save_pandore_case(0,1,0,"int32",27); - _cimg_save_pandore_case(0,1,0,"uint64",27); - _cimg_save_pandore_case(0,1,0,"int64",27); - _cimg_save_pandore_case(0,1,0,"float32",29); - _cimg_save_pandore_case(0,1,0,"float64",29); - - _cimg_save_pandore_case(0,0,0,"uint8",30); - _cimg_save_pandore_case(0,0,0,"int8",31); - _cimg_save_pandore_case(0,0,0,"uint16",31); - _cimg_save_pandore_case(0,0,0,"int16",31); - _cimg_save_pandore_case(0,0,0,"uint32",31); - _cimg_save_pandore_case(0,0,0,"int32",31); - _cimg_save_pandore_case(0,0,0,"uint64",31); - _cimg_save_pandore_case(0,0,0,"int64",31); - _cimg_save_pandore_case(0,0,0,"float32",33); - _cimg_save_pandore_case(0,0,0,"float64",33); - - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Save image as a raw data file. - /** - \param filename Filename, as a C-string. - \param is_multiplexed Tells if the image channels are stored in a multiplexed way (\c true) or not (\c false). - \note The .raw format does not store the image dimensions in the output file, - so you have to keep track of them somewhere to be able to read the file correctly afterwards. - **/ - const CImg& save_raw(const char *const filename, const bool is_multiplexed=false) const { - return _save_raw(0,filename,is_multiplexed); - } - - //! Save image as a raw data file \overloading. - /** - Same as save_raw(const char *,bool) const - with a file stream argument instead of a filename string. - **/ - const CImg& save_raw(std::FILE *const file, const bool is_multiplexed=false) const { - return _save_raw(file,0,is_multiplexed); - } - - const CImg& _save_raw(std::FILE *const file, const char *const filename, const bool is_multiplexed) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_raw(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - if (pixel_type()==cimg::type::string()) { // Boolean data (bitwise) - ulongT siz; - const unsigned char *const buf = _bool2uchar(siz,is_multiplexed); - cimg::fwrite(buf,siz,nfile); - delete[] buf; - } else { // Non boolean data - if (!is_multiplexed || _spectrum==1) cimg::fwrite(_data,size(),nfile); // Non-multiplexed - else { // Multiplexed - CImg buf(_spectrum); - cimg_forXYZ(*this,x,y,z) { - cimg_forC(*this,c) buf[c] = (*this)(x,y,z,c); - cimg::fwrite(buf._data,_spectrum,nfile); - } - } - } - if (!file) cimg::fclose(nfile); - return *this; - } - - // Return unsigned char buffer that encodes data of a CImg instance bitwise. - // (buffer needs to be deallocated afterwards, with delete[]). - const unsigned char *_bool2uchar(ulongT &siz, const bool is_multiplexed) const { - const ulongT _siz = size(); - siz = _siz/8 + (_siz%8?1:0); - unsigned char *const buf = new unsigned char[siz], *ptrd = buf, val = 0, bit = 0; - - if (!is_multiplexed || _spectrum==1) // Non-multiplexed - cimg_for(*this,ptrs,T) { (val<<=1)|=(*ptrs?1:0); if (++bit==8) { *(ptrd++) = val; val = bit = 0; }} - else // Multiplexed - cimg_forXYZ(*this,x,y,z) cimg_forC(*this,c) { - (val<<=1)|=((*this)(x,y,z,c)?1:0); if (++bit==8) { *(ptrd++) = val; val = bit = 0; } - } - if (bit) *ptrd = val; - return buf; - } - - // Fill CImg instance from bitwise data encoded in an unsigned char buffer. - void _uchar2bool(const unsigned char *buf, const ulongT siz, const bool is_multiplexed) { - const ulongT S = std::min(siz*8,size()); - const unsigned char *ptrs = buf; - unsigned char val = 0, mask = 0; - T *ptrd = _data; - if (S && (!is_multiplexed || _spectrum==1)) // Non-multiplexed - for (ulongT off = 0; off>=1)) { val = *(ptrs++); mask = 128; } - *(ptrd++) = (T)((val&mask)?1:0); - } - else if (S) { // Multiplexed - ulongT off = 0; - for (int z = 0; z>=1)) { val = *(ptrs++); ++off; mask = 128; } - (*this)(x,y,z,c) = (T)((val&mask)?1:0); - } - } - } - - //! Save image as a .yuv video file. - /** - \param filename Filename, as a C-string. - \param chroma_subsampling Type of chroma subsampling. Can be { 420 | 422 | 444 }. - \param is_rgb Tells if pixel values of the instance image are RGB-coded (\c true) or YUV-coded (\c false). - \note Each slice of the instance image is considered to be a single frame of the output video file. - **/ - const CImg& save_yuv(const char *const filename, - const unsigned int chroma_subsampling=444, - const bool is_rgb=true) const { - CImgList(*this,true).save_yuv(filename,chroma_subsampling,is_rgb); - return *this; - } - - //! Save image as a .yuv video file \overloading. - /** - Same as save_yuv(const char*,const unsigned int,const bool) const - with a file stream argument instead of a filename string. - **/ - const CImg& save_yuv(std::FILE *const file, - const unsigned int chroma_subsampling=444, - const bool is_rgb=true) const { - CImgList(*this,true).save_yuv(file,chroma_subsampling,is_rgb); - return *this; - } - - //! Save 3D object as an Object File Format (.off) file. - /** - \param filename Filename, as a C-string. - \param primitives List of 3D object primitives. - \param colors List of 3D object colors. - \note - - Instance image contains the vertices data of the 3D object. - - Textured, transparent or sphere-shaped primitives cannot be managed by the .off file format. - Such primitives will be lost or simplified during file saving. - - The .off file format is described here. - **/ - template - const CImg& save_off(const CImgList& primitives, const CImgList& colors, - const char *const filename) const { - return _save_off(primitives,colors,0,filename); - } - - //! Save 3D object as an Object File Format (.off) file \overloading. - /** - Same as save_off(const CImgList&,const CImgList&,const char*) const - with a file stream argument instead of a filename string. - **/ - template - const CImg& save_off(const CImgList& primitives, const CImgList& colors, - std::FILE *const file) const { - return _save_off(primitives,colors,file,0); - } - - template - const CImg& _save_off(const CImgList& primitives, const CImgList& colors, - std::FILE *const file, const char *const filename) const { - if (!file && !filename) - throw CImgArgumentException(_cimg_instance - "save_off(): Specified filename is (null).", - cimg_instance); - if (is_empty()) - throw CImgInstanceException(_cimg_instance - "save_off(): Empty instance, for file '%s'.", - cimg_instance, - filename?filename:"(FILE*)"); - - CImgList opacities; - CImg error_message(1024); - if (!is_object3d(primitives,colors,opacities,true,error_message)) - throw CImgInstanceException(_cimg_instance - "save_off(): Invalid specified 3D object, for file '%s' (%s).", - cimg_instance, - filename?filename:"(FILE*)",error_message.data()); - - const CImg default_color(1,3,1,1,(tc)std::min((int)cimg::type::max(),200)); - std::FILE *const nfile = file?file:cimg::fopen(filename,"w"); - unsigned int supported_primitives = 0; - cimglist_for(primitives,l) if (primitives[l].size()!=5) ++supported_primitives; - std::fprintf(nfile,"OFF\n%u %u %u\n",_width,supported_primitives,3*primitives._width); - cimg_forX(*this,i) std::fprintf(nfile,"%f %f %f\n", - (float)((*this)(i,0)),(float)((*this)(i,1)),(float)((*this)(i,2))); - cimglist_for(primitives,l) { - const CImg& color = l1?color[1]:r)/255.f, b = (csiz>2?color[2]:g)/255.f; - switch (psiz) { - case 1 : std::fprintf(nfile,"1 %u %f %f %f\n", - (unsigned int)primitives(l,0),r,g,b); break; - case 2 : std::fprintf(nfile,"2 %u %u %f %f %f\n", - (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b); break; - case 3 : std::fprintf(nfile,"3 %u %u %u %f %f %f\n", - (unsigned int)primitives(l,0),(unsigned int)primitives(l,2), - (unsigned int)primitives(l,1),r,g,b); break; - case 4 : std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n", - (unsigned int)primitives(l,0),(unsigned int)primitives(l,3), - (unsigned int)primitives(l,2),(unsigned int)primitives(l,1),r,g,b); break; - case 5 : std::fprintf(nfile,"2 %u %u %f %f %f\n", - (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),r,g,b); break; - case 6 : { - const unsigned int xt = (unsigned int)primitives(l,2), yt = (unsigned int)primitives(l,3); - const float - rt = color.atXY(xt,yt,0)/255.f, - gt = (csiz>1?color.atXY(xt,yt,1):r)/255.f, - bt = (csiz>2?color.atXY(xt,yt,2):g)/255.f; - std::fprintf(nfile,"2 %u %u %f %f %f\n", - (unsigned int)primitives(l,0),(unsigned int)primitives(l,1),rt,gt,bt); - } break; - case 9 : { - const unsigned int xt = (unsigned int)primitives(l,3), yt = (unsigned int)primitives(l,4); - const float - rt = color.atXY(xt,yt,0)/255.f, - gt = (csiz>1?color.atXY(xt,yt,1):r)/255.f, - bt = (csiz>2?color.atXY(xt,yt,2):g)/255.f; - std::fprintf(nfile,"3 %u %u %u %f %f %f\n", - (unsigned int)primitives(l,0),(unsigned int)primitives(l,2), - (unsigned int)primitives(l,1),rt,gt,bt); - } break; - case 12 : { - const unsigned int xt = (unsigned int)primitives(l,4), yt = (unsigned int)primitives(l,5); - const float - rt = color.atXY(xt,yt,0)/255.f, - gt = (csiz>1?color.atXY(xt,yt,1):r)/255.f, - bt = (csiz>2?color.atXY(xt,yt,2):g)/255.f; - std::fprintf(nfile,"4 %u %u %u %u %f %f %f\n", - (unsigned int)primitives(l,0),(unsigned int)primitives(l,3), - (unsigned int)primitives(l,2),(unsigned int)primitives(l,1),rt,gt,bt); - } break; - } - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Save volumetric image as a video (using the OpenCV library when available). - /** - \param filename Filename to write data to. - \param fps Number of frames per second. - \param codec Type of compression (See http://www.fourcc.org/codecs.php to see available codecs). - \param keep_open Tells if the video writer associated to the specified filename - must be kept open or not (to allow frames to be added in the same file afterwards). - **/ - const CImg& save_video(const char *const filename, const unsigned int fps=25, - const char *codec=0, const bool keep_open=false) const { - if (is_empty()) { CImgList().save_video(filename,fps,codec,keep_open); return *this; } - CImgList list; - get_split('z').move_to(list); - list.save_video(filename,fps,codec,keep_open); - return *this; - } - - //! Save volumetric image as a video, using ffmpeg external binary. - /** - \param filename Filename, as a C-string. - \param fps Video framerate. - \param codec Video codec, as a C-string. - \param bitrate Video bitrate. - \note - - Each slice of the instance image is considered to be a single frame of the output video file. - - This method uses \c ffmpeg, an external executable binary provided by - FFmpeg. - It must be installed for the method to succeed. - **/ - const CImg& save_ffmpeg_external(const char *const filename, const unsigned int fps=25, - const char *const codec=0, const unsigned int bitrate=2048) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save_ffmpeg_external(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - - CImgList list; - get_split('z').move_to(list); - list.save_ffmpeg_external(filename,fps,codec,bitrate); - return *this; - } - - //! Save image using gzip external binary. - /** - \param filename Filename, as a C-string. - \note This method uses \c gzip, an external executable binary provided by - gzip. - It must be installed for the method to succeed. - **/ - const CImg& save_gzip_external(const char *const filename) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save_gzip_external(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - - CImg command(1024), filename_tmp(256), body(256); - const char - *ext = cimg::split_filename(filename,body), - *ext2 = cimg::split_filename(body,0); - std::FILE *file; - do { - if (!cimg::strcasecmp(ext,"gz")) { - if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2); - else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - } else { - if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); - else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - } - if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); - } while (file); - save(filename_tmp); - cimg_snprintf(command,command._width,"\"%s\" -c \"%s\" > \"%s\"", - cimg::gzip_path(), - CImg::string(filename_tmp)._system_strescape().data(), - CImg::string(filename)._system_strescape().data()); - cimg::system(command, cimg::gzip_path()); - file = cimg::std_fopen(filename,"rb"); - if (!file) - throw CImgIOException(_cimg_instance - "save_gzip_external(): Failed to save file '%s' with external command 'gzip'.", - cimg_instance, - filename); - - else cimg::fclose(file); - std::remove(filename_tmp); - return *this; - } - - //! Save image using GraphicsMagick's external binary. - /** - \param filename Filename, as a C-string. - \param quality Image quality (expressed in percent), when the file format supports it. - \note This method uses \c gm, an external executable binary provided by - GraphicsMagick. - It must be installed for the method to succeed. - **/ - const CImg& save_graphicsmagick_external(const char *const filename, const unsigned int quality=100) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save_graphicsmagick_external(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - if (_depth>1) - cimg::warn(_cimg_instance - "save_other(): File '%s', saving a volumetric image with an external call to " - "GraphicsMagick only writes the first image slice.", - cimg_instance,filename); - -#ifdef cimg_use_png -#define _cimg_sge_extension1 "png" -#define _cimg_sge_extension2 "png" -#else -#define _cimg_sge_extension1 "pgm" -#define _cimg_sge_extension2 "ppm" -#endif - CImg command(1024), filename_tmp(256); - std::FILE *file; - do { - cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(), - _spectrum==1?_cimg_sge_extension1:_cimg_sge_extension2); - if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); - } while (file); - -#ifdef cimg_use_png - save_png(filename_tmp); -#else - save_pnm(filename_tmp); -#endif - cimg_snprintf(command,command._width,"\"%s\" convert -quality %u \"%s\" \"%s\"", - cimg::graphicsmagick_path(),quality, - CImg::string(filename_tmp)._system_strescape().data(), - CImg::string(filename)._system_strescape().data()); - cimg::system(command, cimg::graphicsmagick_path()); - file = cimg::std_fopen(filename,"rb"); - if (!file) - throw CImgIOException(_cimg_instance - "save_graphicsmagick_external(): Failed to save file '%s' with external command 'gm'.", - cimg_instance, - filename); - - if (file) cimg::fclose(file); - std::remove(filename_tmp); - return *this; - } - - //! Save image using ImageMagick's external binary. - /** - \param filename Filename, as a C-string. - \param quality Image quality (expressed in percent), when the file format supports it. - \note This method uses \c convert, an external executable binary provided by - ImageMagick. - It must be installed for the method to succeed. - **/ - const CImg& save_imagemagick_external(const char *const filename, const unsigned int quality=100) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save_imagemagick_external(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - if (_depth>1) - cimg::warn(_cimg_instance - "save_other(): File '%s', saving a volumetric image with an external call to " - "ImageMagick only writes the first image slice.", - cimg_instance,filename); -#ifdef cimg_use_png -#define _cimg_sie_extension1 "png" -#define _cimg_sie_extension2 "png" -#else -#define _cimg_sie_extension1 "pgm" -#define _cimg_sie_extension2 "ppm" -#endif - CImg command(1024), filename_tmp(256); - std::FILE *file; - do { - cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s",cimg::temporary_path(), - cimg_file_separator,cimg::filenamerand(),_spectrum==1?_cimg_sie_extension1:_cimg_sie_extension2); - if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); - } while (file); -#ifdef cimg_use_png - save_png(filename_tmp); -#else - save_pnm(filename_tmp); -#endif - cimg_snprintf(command,command._width,"\"%s\" -quality %u \"%s\" \"%s\"", - cimg::imagemagick_path(),quality, - CImg::string(filename_tmp)._system_strescape().data(), - CImg::string(filename)._system_strescape().data()); - cimg::system(command, cimg::imagemagick_path()); - file = cimg::std_fopen(filename,"rb"); - if (!file) - throw CImgIOException(_cimg_instance - "save_imagemagick_external(): Failed to save file '%s' with " - "external command 'magick/convert'.", - cimg_instance, - filename); - - if (file) cimg::fclose(file); - std::remove(filename_tmp); - return *this; - } - - //! Save image as a Dicom file. - /** - \param filename Filename, as a C-string. - \note This method uses \c medcon, an external executable binary provided by - (X)Medcon. - It must be installed for the method to succeed. - **/ - const CImg& save_medcon_external(const char *const filename) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save_medcon_external(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - - CImg command(1024), filename_tmp(256), body(256); - std::FILE *file; - do { - cimg_snprintf(filename_tmp,filename_tmp._width,"%s.hdr",cimg::filenamerand()); - if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); - } while (file); - save_analyze(filename_tmp); - cimg_snprintf(command,command._width,"\"%s\" -w -c dicom -o \"%s\" -f \"%s\"", - cimg::medcon_path(), - CImg::string(filename)._system_strescape().data(), - CImg::string(filename_tmp)._system_strescape().data()); - cimg::system(command, cimg::medcon_path()); - std::remove(filename_tmp); - cimg::split_filename(filename_tmp,body); - cimg_snprintf(filename_tmp,filename_tmp._width,"%s.img",body._data); - std::remove(filename_tmp); - - file = cimg::std_fopen(filename,"rb"); - if (!file) { - cimg_snprintf(command,command._width,"m000-%s",filename); - file = cimg::std_fopen(command,"rb"); - if (!file) { - cimg::fclose(cimg::fopen(filename,"r")); - throw CImgIOException(_cimg_instance - "save_medcon_external(): Failed to save file '%s' with external command 'medcon'.", - cimg_instance, - filename); - } - } - cimg::fclose(file); - std::rename(command,filename); - return *this; - } - - // Save image for non natively supported formats. - /** - \param filename Filename, as a C-string. - \param quality Image quality (expressed in percent), when the file format supports it. - \note - - The filename extension tells about the desired file format. - - This method tries to save the instance image as a file, using external tools from - ImageMagick or - GraphicsMagick. - At least one of these tool must be installed for the method to succeed. - - It is recommended to use the generic method save(const char*, int) const instead, - as it can handle some file formats natively. - **/ - const CImg& save_other(const char *const filename, const unsigned int quality=100) const { - if (!filename) - throw CImgArgumentException(_cimg_instance - "save_other(): Specified filename is (null).", - cimg_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - if (_depth>1) - cimg::warn(_cimg_instance - "save_other(): File '%s', saving a volumetric image with an external call to " - "ImageMagick or GraphicsMagick only writes the first image slice.", - cimg_instance,filename); - - const unsigned int omode = cimg::exception_mode(); - bool is_saved = true; - cimg::exception_mode(0); - try { save_magick(filename); } - catch (CImgException&) { - try { save_imagemagick_external(filename,quality); } - catch (CImgException&) { - try { save_graphicsmagick_external(filename,quality); } - catch (CImgException&) { - is_saved = false; - } - } - } - cimg::exception_mode(omode); - if (!is_saved) - throw CImgIOException(_cimg_instance - "save_other(): Failed to save file '%s'. Format is not natively supported, " - "and no external commands succeeded.", - cimg_instance, - filename); - return *this; - } - - //! Serialize a CImg instance into a raw CImg buffer. - /** - \param is_compressed tells if zlib compression must be used for serialization - (this requires 'cimg_use_zlib' been enabled). - \param header_size Reserve empty bytes as a starting header. - **/ - CImg get_serialize(const bool is_compressed=false, const unsigned int header_size=0) const { - return CImgList(*this,true).get_serialize(is_compressed,header_size); - } - - // [internal] Return a 40x38 color logo of a 'danger' item. - static CImg _logo40x38() { - CImg res(40,38,1,3); - const unsigned char *ptrs = cimg::logo40x38; - T *ptr1 = res.data(0,0,0,0), *ptr2 = res.data(0,0,0,1), *ptr3 = res.data(0,0,0,2); - for (ulongT off = 0; off<(ulongT)res._width*res._height;) { - const unsigned char n = *(ptrs++), r = *(ptrs++), g = *(ptrs++), b = *(ptrs++); - for (unsigned int l = 0; l structure - # - # - # - #------------------------------------------ - */ - //! Represent a list of images CImg. - template - struct CImgList { - unsigned int _width, _allocated_width; - CImg *_data; - - //! Simple iterator type, to loop through each image of a list. - /** - \note - - The \c CImgList::iterator type is defined as a CImg*. - - You may use it like this: - \code - CImgList<> list; // Assuming this image list is not empty - for (CImgList<>::iterator it = list.begin(); it* iterator; - - //! Simple const iterator type, to loop through each image of a \c const list instance. - /** - \note - - The \c CImgList::const_iterator type is defined to be a const CImg*. - - Similar to CImgList::iterator, but for constant list instances. - **/ - typedef const CImg* const_iterator; - - //! Pixel value type. - /** - Refer to the pixels value type of the images in the list. - \note - - The \c CImgList::value_type type of a \c CImgList is defined to be a \c T. - It is then similar to CImg::value_type. - - \c CImgList::value_type is actually not used in %CImg methods. It has been mainly defined for - compatibility with STL naming conventions. - **/ - typedef T value_type; - - // Define common types related to template type T. - typedef typename cimg::superset::type Tbool; - typedef typename cimg::superset::type Tuchar; - typedef typename cimg::superset::type Tchar; - typedef typename cimg::superset::type Tushort; - typedef typename cimg::superset::type Tshort; - typedef typename cimg::superset::type Tuint; - typedef typename cimg::superset::type Tint; - typedef typename cimg::superset::type Tulong; - typedef typename cimg::superset::type Tlong; - typedef typename cimg::superset::type Tfloat; - typedef typename cimg::superset::type Tdouble; - typedef typename cimg::last::type boolT; - typedef typename cimg::last::type ucharT; - typedef typename cimg::last::type charT; - typedef typename cimg::last::type ushortT; - typedef typename cimg::last::type shortT; - typedef typename cimg::last::type uintT; - typedef typename cimg::last::type intT; - typedef typename cimg::last::type ulongT; - typedef typename cimg::last::type longT; - typedef typename cimg::last::type uint64T; - typedef typename cimg::last::type int64T; - typedef typename cimg::last::type floatT; - typedef typename cimg::last::type doubleT; - - //@} - //--------------------------- - // - //! \name Plugins - //@{ - //--------------------------- -#ifdef cimglist_plugin -#include cimglist_plugin -#endif -#ifdef cimglist_plugin1 -#include cimglist_plugin1 -#endif -#ifdef cimglist_plugin2 -#include cimglist_plugin2 -#endif -#ifdef cimglist_plugin3 -#include cimglist_plugin3 -#endif -#ifdef cimglist_plugin4 -#include cimglist_plugin4 -#endif -#ifdef cimglist_plugin5 -#include cimglist_plugin5 -#endif -#ifdef cimglist_plugin6 -#include cimglist_plugin6 -#endif -#ifdef cimglist_plugin7 -#include cimglist_plugin7 -#endif -#ifdef cimglist_plugin8 -#include cimglist_plugin8 -#endif - - //@} - //-------------------------------------------------------- - // - //! \name Constructors / Destructor / Instance Management - //@{ - //-------------------------------------------------------- - - //! Destructor. - /** - Destroy current list instance. - \note - - Any allocated buffer is deallocated. - - Destroying an empty list does nothing actually. - **/ - ~CImgList() { - delete[] _data; - } - - //! Default constructor. - /** - Construct a new empty list instance. - \note - - An empty list has no pixel data and its dimension width() is set to \c 0, as well as its - image buffer pointer data(). - - An empty list may be reassigned afterwards, with the family of the assign() methods. - In all cases, the type of pixels stays \c T. - **/ - CImgList(): - _width(0),_allocated_width(0),_data(0) {} - - //! Construct list containing empty images. - /** - \param n Number of empty images. - \note Useful when you know by advance the number of images you want to manage, as - it will allocate the right amount of memory for the list, without needs for reallocation - (that may occur when starting from an empty list and inserting several images in it). - **/ - explicit CImgList(const unsigned int n):_width(n) { - if (n) _data = new CImg[_allocated_width = std::max(16U,(unsigned int)cimg::nearest_pow2(n))]; - else { _allocated_width = 0; _data = 0; } - } - - //! Construct list containing images of specified size. - /** - \param n Number of images. - \param width Width of images. - \param height Height of images. - \param depth Depth of images. - \param spectrum Number of channels of images. - \note Pixel values are not initialized and may probably contain garbage. - **/ - CImgList(const unsigned int n, const unsigned int width, const unsigned int height=1, - const unsigned int depth=1, const unsigned int spectrum=1): - _width(0),_allocated_width(0),_data(0) { - assign(n); - cimglist_apply(*this,assign)(width,height,depth,spectrum); - } - - //! Construct list containing images of specified size, and initialize pixel values. - /** - \param n Number of images. - \param width Width of images. - \param height Height of images. - \param depth Depth of images. - \param spectrum Number of channels of images. - \param val Initialization value for images pixels. - **/ - CImgList(const unsigned int n, const unsigned int width, const unsigned int height, - const unsigned int depth, const unsigned int spectrum, const T& val): - _width(0),_allocated_width(0),_data(0) { - assign(n); - cimglist_apply(*this,assign)(width,height,depth,spectrum,val); - } - - //! Construct list containing images of specified size, and initialize pixel values from a sequence of integers. - /** - \param n Number of images. - \param width Width of images. - \param height Height of images. - \param depth Depth of images. - \param spectrum Number of channels of images. - \param val0 First value of the initializing integers sequence. - \param val1 Second value of the initializing integers sequence. - \warning You must specify at least width*height*depth*spectrum values in your argument list, - or you will probably segfault. - **/ - CImgList(const unsigned int n, const unsigned int width, const unsigned int height, - const unsigned int depth, const unsigned int spectrum, const int val0, const int val1, ...): - _width(0),_allocated_width(0),_data(0) { -#define _CImgList_stdarg(t) { \ - assign(n,width,height,depth,spectrum); \ - const ulongT siz = (ulongT)width*height*depth*spectrum, nsiz = siz*n; \ - T *ptrd = _data->_data; \ - va_list ap; \ - va_start(ap,val1); \ - for (ulongT l = 0, s = 0, i = 0; iwidth*height*depth*spectrum values in your argument list, - or you will probably segfault. - **/ - CImgList(const unsigned int n, const unsigned int width, const unsigned int height, - const unsigned int depth, const unsigned int spectrum, const double val0, const double val1, ...): - _width(0),_allocated_width(0),_data(0) { - _CImgList_stdarg(double); - } - - //! Construct list containing copies of an input image. - /** - \param n Number of images. - \param img Input image to copy in the constructed list. - \param is_shared Tells if the elements of the list are shared or non-shared copies of \c img. - **/ - template - CImgList(const unsigned int n, const CImg& img, const bool is_shared=false): - _width(0),_allocated_width(0),_data(0) { - assign(n); - cimglist_apply(*this,assign)(img,is_shared); - } - - //! Construct list from one image. - /** - \param img Input image to copy in the constructed list. - \param is_shared Tells if the element of the list is a shared or non-shared copy of \c img. - **/ - template - explicit CImgList(const CImg& img, const bool is_shared=false): - _width(0),_allocated_width(0),_data(0) { - assign(1); - _data[0].assign(img,is_shared); - } - - //! Construct list from two images. - /** - \param img1 First input image to copy in the constructed list. - \param img2 Second input image to copy in the constructed list. - \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. - **/ - template - CImgList(const CImg& img1, const CImg& img2, const bool is_shared=false): - _width(0),_allocated_width(0),_data(0) { - assign(2); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); - } - - //! Construct list from three images. - /** - \param img1 First input image to copy in the constructed list. - \param img2 Second input image to copy in the constructed list. - \param img3 Third input image to copy in the constructed list. - \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. - **/ - template - CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const bool is_shared=false): - _width(0),_allocated_width(0),_data(0) { - assign(3); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); - } - - //! Construct list from four images. - /** - \param img1 First input image to copy in the constructed list. - \param img2 Second input image to copy in the constructed list. - \param img3 Third input image to copy in the constructed list. - \param img4 Fourth input image to copy in the constructed list. - \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. - **/ - template - CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, - const bool is_shared=false): - _width(0),_allocated_width(0),_data(0) { - assign(4); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); - _data[3].assign(img4,is_shared); - } - - //! Construct list from five images. - /** - \param img1 First input image to copy in the constructed list. - \param img2 Second input image to copy in the constructed list. - \param img3 Third input image to copy in the constructed list. - \param img4 Fourth input image to copy in the constructed list. - \param img5 Fifth input image to copy in the constructed list. - \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. - **/ - template - CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, - const CImg& img5, const bool is_shared=false): - _width(0),_allocated_width(0),_data(0) { - assign(5); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); - _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); - } - - //! Construct list from six images. - /** - \param img1 First input image to copy in the constructed list. - \param img2 Second input image to copy in the constructed list. - \param img3 Third input image to copy in the constructed list. - \param img4 Fourth input image to copy in the constructed list. - \param img5 Fifth input image to copy in the constructed list. - \param img6 Sixth input image to copy in the constructed list. - \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. - **/ - template - CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, - const CImg& img5, const CImg& img6, const bool is_shared=false): - _width(0),_allocated_width(0),_data(0) { - assign(6); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); - _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared); - } - - //! Construct list from seven images. - /** - \param img1 First input image to copy in the constructed list. - \param img2 Second input image to copy in the constructed list. - \param img3 Third input image to copy in the constructed list. - \param img4 Fourth input image to copy in the constructed list. - \param img5 Fifth input image to copy in the constructed list. - \param img6 Sixth input image to copy in the constructed list. - \param img7 Seventh input image to copy in the constructed list. - \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. - **/ - template - CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, - const CImg& img5, const CImg& img6, const CImg& img7, const bool is_shared=false): - _width(0),_allocated_width(0),_data(0) { - assign(7); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); - _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared); - _data[6].assign(img7,is_shared); - } - - //! Construct list from eight images. - /** - \param img1 First input image to copy in the constructed list. - \param img2 Second input image to copy in the constructed list. - \param img3 Third input image to copy in the constructed list. - \param img4 Fourth input image to copy in the constructed list. - \param img5 Fifth input image to copy in the constructed list. - \param img6 Sixth input image to copy in the constructed list. - \param img7 Seventh input image to copy in the constructed list. - \param img8 Eighth input image to copy in the constructed list. - \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. - **/ - template - CImgList(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, - const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, - const bool is_shared=false): - _width(0),_allocated_width(0),_data(0) { - assign(8); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); - _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared); - _data[6].assign(img7,is_shared); _data[7].assign(img8,is_shared); - } - - //! Construct list copy. - /** - \param list Input list to copy. - \note The shared state of each element of the constructed list is kept the same as in \c list. - **/ - template - CImgList(const CImgList& list):_width(0),_allocated_width(0),_data(0) { - assign(list._width); - cimglist_for(*this,l) _data[l].assign(list[l],false); - } - - //! Construct list copy \specialization. - CImgList(const CImgList& list):_width(0),_allocated_width(0),_data(0) { - assign(list._width); - cimglist_for(*this,l) _data[l].assign(list[l],list[l]._is_shared); - } - - //! Construct list copy, and force the shared state of the list elements. - /** - \param list Input list to copy. - \param is_shared Tells if the elements of the list are shared or non-shared copies of input images. - **/ - template - CImgList(const CImgList& list, const bool is_shared):_width(0),_allocated_width(0),_data(0) { - assign(list._width); - cimglist_for(*this,l) _data[l].assign(list[l],is_shared); - } - - //! Construct list by reading the content of a file. - /** - \param filename Filename, as a C-string. - **/ - explicit CImgList(const char *const filename):_width(0),_allocated_width(0),_data(0) { - assign(filename); - } - - //! Construct list from the content of a display window. - /** - \param disp Display window to get content from. - \note Constructed list contains a single image only. - **/ - explicit CImgList(const CImgDisplay& disp):_width(0),_allocated_width(0),_data(0) { - assign(disp); - } - - //! Return a list with elements being shared copies of images in the list instance. - /** - \note list2 = list1.get_shared() is equivalent to list2.assign(list1,true). - **/ - CImgList get_shared() { - CImgList res(_width); - cimglist_for(*this,l) res[l].assign(_data[l],true); - return res; - } - - //! Return a list with elements being shared copies of images in the list instance \const. - const CImgList get_shared() const { - CImgList res(_width); - cimglist_for(*this,l) res[l].assign(_data[l],true); - return res; - } - - //! Destructor \inplace. - /** - \see CImgList(). - **/ - CImgList& assign() { - delete[] _data; - _width = _allocated_width = 0; - _data = 0; - return *this; - } - - //! Destructor \inplace. - /** - Equivalent to assign(). - \note Only here for compatibility with STL naming conventions. - **/ - CImgList& clear() { - return assign(); - } - - //! Construct list containing empty images \inplace. - /** - \see CImgList(unsigned int). - **/ - CImgList& assign(const unsigned int n) { - if (!n) return assign(); - if (_allocated_width(n<<2)) { - delete[] _data; - _data = new CImg[_allocated_width = std::max(16U,(unsigned int)cimg::nearest_pow2(n))]; - } - _width = n; - return *this; - } - - //! Construct list containing images of specified size \inplace. - /** - \see CImgList(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int). - **/ - CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height=1, - const unsigned int depth=1, const unsigned int spectrum=1) { - assign(n); - cimglist_apply(*this,assign)(width,height,depth,spectrum); - return *this; - } - - //! Construct list containing images of specified size, and initialize pixel values \inplace. - /** - \see CImgList(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, const T). - **/ - CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height, - const unsigned int depth, const unsigned int spectrum, const T& val) { - assign(n); - cimglist_apply(*this,assign)(width,height,depth,spectrum,val); - return *this; - } - - //! Construct list with images of specified size, and initialize pixel values from a sequence of integers \inplace. - /** - \see CImgList(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, const int, const int, ...). - **/ - CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height, - const unsigned int depth, const unsigned int spectrum, const int val0, const int val1, ...) { - _CImgList_stdarg(int); - return *this; - } - - //! Construct list with images of specified size, and initialize pixel values from a sequence of doubles \inplace. - /** - \see CImgList(unsigned int,unsigned int,unsigned int,unsigned int,unsigned int,const double,const double,...). - **/ - CImgList& assign(const unsigned int n, const unsigned int width, const unsigned int height, - const unsigned int depth, const unsigned int spectrum, - const double val0, const double val1, ...) { - _CImgList_stdarg(double); - return *this; - } - - //! Construct list containing copies of an input image \inplace. - /** - \see CImgList(unsigned int, const CImg&, bool). - **/ - template - CImgList& assign(const unsigned int n, const CImg& img, const bool is_shared=false) { - assign(n); - cimglist_apply(*this,assign)(img,is_shared); - return *this; - } - - //! Construct list from one image \inplace. - /** - \see CImgList(const CImg&, bool). - **/ - template - CImgList& assign(const CImg& img, const bool is_shared=false) { - assign(1); - _data[0].assign(img,is_shared); - return *this; - } - - //! Construct list from two images \inplace. - /** - \see CImgList(const CImg&, const CImg&, bool). - **/ - template - CImgList& assign(const CImg& img1, const CImg& img2, const bool is_shared=false) { - assign(2); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); - return *this; - } - - //! Construct list from three images \inplace. - /** - \see CImgList(const CImg&, const CImg&, const CImg&, bool). - **/ - template - CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const bool is_shared=false) { - assign(3); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); - return *this; - } - - //! Construct list from four images \inplace. - /** - \see CImgList(const CImg&, const CImg&, const CImg&, const CImg&, bool). - **/ - template - CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, - const bool is_shared=false) { - assign(4); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); - _data[3].assign(img4,is_shared); - return *this; - } - - //! Construct list from five images \inplace. - /** - \see CImgList(const CImg&, const CImg&, const CImg&, const CImg&, const CImg&, bool). - **/ - template - CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, - const CImg& img5, const bool is_shared=false) { - assign(5); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); - _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); - return *this; - } - - //! Construct list from six images \inplace. - /** - \see CImgList(const CImg&,const CImg&,const CImg&,const CImg&,const CImg&,const CImg&, bool). - **/ - template - CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, - const CImg& img5, const CImg& img6, const bool is_shared=false) { - assign(6); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); - _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared); - return *this; - } - - //! Construct list from seven images \inplace. - /** - \see CImgList(const CImg&,const CImg&,const CImg&,const CImg&,const CImg&,const CImg&, - const CImg&, bool). - **/ - template - CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, - const CImg& img5, const CImg& img6, const CImg& img7, const bool is_shared=false) { - assign(7); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); - _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared); - _data[6].assign(img7,is_shared); - return *this; - } - - //! Construct list from eight images \inplace. - /** - \see CImgList(const CImg&,const CImg&,const CImg&,const CImg&,const CImg&,const CImg&, - const CImg&, const CImg&, bool). - **/ - template - CImgList& assign(const CImg& img1, const CImg& img2, const CImg& img3, const CImg& img4, - const CImg& img5, const CImg& img6, const CImg& img7, const CImg& img8, - const bool is_shared=false) { - assign(8); - _data[0].assign(img1,is_shared); _data[1].assign(img2,is_shared); _data[2].assign(img3,is_shared); - _data[3].assign(img4,is_shared); _data[4].assign(img5,is_shared); _data[5].assign(img6,is_shared); - _data[6].assign(img7,is_shared); _data[7].assign(img8,is_shared); - return *this; - } - - //! Construct list as a copy of an existing list and force the shared state of the list elements \inplace. - /** - \see CImgList(const CImgList&, bool is_shared). - **/ - template - CImgList& assign(const CImgList& list, const bool is_shared=false) { - cimg::unused(is_shared); - assign(list._width); - cimglist_for(*this,l) _data[l].assign(list[l],false); - return *this; - } - - //! Construct list as a copy of an existing list and force shared state of elements \inplace \specialization. - CImgList& assign(const CImgList& list, const bool is_shared=false) { - if (this==&list) return *this; - CImgList res(list._width); - cimglist_for(res,l) res[l].assign(list[l],is_shared); - return res.move_to(*this); - } - - //! Construct list by reading the content of a file \inplace. - /** - \see CImgList(const char *const). - **/ - CImgList& assign(const char *const filename) { - return load(filename); - } - - //! Construct list from the content of a display window \inplace. - /** - \see CImgList(const CImgDisplay&). - **/ - CImgList& assign(const CImgDisplay &disp) { - return assign(CImg(disp)); - } - - //! Transfer the content of the list instance to another list. - /** - \param list Destination list. - \note When returning, the current list instance is empty and the initial content of \c list is destroyed. - **/ - template - CImgList& move_to(CImgList& list) { - list.assign(_width); - bool is_one_shared_element = false; - cimglist_for(*this,l) is_one_shared_element|=_data[l]._is_shared; - if (is_one_shared_element) cimglist_for(*this,l) list[l].assign(_data[l]); - else cimglist_for(*this,l) _data[l].move_to(list[l]); - assign(); - return list; - } - - //! Transfer the content of the list instance at a specified position in another list. - /** - \param list Destination list. - \param pos Index of the insertion in the list. - \note When returning, the list instance is empty and the initial content of \c list is preserved - (only images indexes may be modified). - **/ - template - CImgList& move_to(CImgList& list, const unsigned int pos) { - if (is_empty()) return list; - const unsigned int npos = pos>list._width?list._width:pos; - list.insert(_width,npos); - bool is_one_shared_element = false; - cimglist_for(*this,l) is_one_shared_element|=_data[l]._is_shared; - if (is_one_shared_element) cimglist_for(*this,l) list[npos + l].assign(_data[l]); - else cimglist_for(*this,l) _data[l].move_to(list[npos + l]); - assign(); - return list; - } - - //! Swap all fields between two list instances. - /** - \param list List to swap fields with. - \note Can be used to exchange the content of two lists in a fast way. - **/ - CImgList& swap(CImgList& list) { - cimg::swap(_width,list._width,_allocated_width,list._allocated_width); - cimg::swap(_data,list._data); - return list; - } - - //! Return a reference to an empty list. - /** - \note Can be used to define default values in a function taking a CImgList as an argument. - \code - void f(const CImgList& list=CImgList::empty()); - \endcode - **/ - static CImgList& empty() { - static CImgList _empty; - return _empty.assign(); - } - - //! Return a reference to an empty list \const. - static const CImgList& const_empty() { - static const CImgList _empty; - return _empty; - } - - //@} - //------------------------------------------ - // - //! \name Overloaded Operators - //@{ - //------------------------------------------ - - //! Return a reference to one image element of the list. - /** - \param pos Index of the image element. - **/ - CImg& operator()(const unsigned int pos) { -#if cimg_verbosity>=3 - if (pos>=_width) { - cimg::warn(_cimglist_instance - "operator(): Invalid image request, at position [%u].", - cimglist_instance, - pos); - return *_data; - } -#endif - return _data[pos]; - } - - //! Return a reference to one image of the list. - /** - \param pos Index of the image element. - **/ - const CImg& operator()(const unsigned int pos) const { - return const_cast*>(this)->operator()(pos); - } - - //! Return a reference to one pixel value of one image of the list. - /** - \param pos Index of the image element. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note list(n,x,y,z,c) is equivalent to list[n](x,y,z,c). - **/ - T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0, - const unsigned int z=0, const unsigned int c=0) { - return (*this)[pos](x,y,z,c); - } - - //! Return a reference to one pixel value of one image of the list \const. - const T& operator()(const unsigned int pos, const unsigned int x, const unsigned int y=0, - const unsigned int z=0, const unsigned int c=0) const { - return (*this)[pos](x,y,z,c); - } - - //! Return pointer to the first image of the list. - /** - \note Images in a list are stored as a buffer of \c CImg. - **/ - operator CImg*() { - return _data; - } - - //! Return pointer to the first image of the list \const. - operator const CImg*() const { - return _data; - } - - //! Construct list from one image \inplace. - /** - \param img Input image to copy in the constructed list. - \note list = img; is equivalent to list.assign(img);. - **/ - template - CImgList& operator=(const CImg& img) { - return assign(img); - } - - //! Construct list from another list. - /** - \param list Input list to copy. - \note list1 = list2 is equivalent to list1.assign(list2);. - **/ - template - CImgList& operator=(const CImgList& list) { - return assign(list); - } - - //! Construct list from another list \specialization. - CImgList& operator=(const CImgList& list) { - return assign(list); - } - - //! Construct list by reading the content of a file \inplace. - /** - \see CImgList(const char *const). - **/ - CImgList& operator=(const char *const filename) { - return assign(filename); - } - - //! Construct list from the content of a display window \inplace. - /** - \see CImgList(const CImgDisplay&). - **/ - CImgList& operator=(const CImgDisplay& disp) { - return assign(disp); - } - - //! Return a non-shared copy of a list. - /** - \note +list is equivalent to CImgList(list,false). - It forces the copy to have non-shared elements. - **/ - CImgList operator+() const { - return CImgList(*this,false); - } - - //! Return a copy of the list instance, where image \c img has been inserted at the end. - /** - \param img Image inserted at the end of the instance copy. - \note Define a convenient way to create temporary lists of images, as in the following code: - \code - (img1,img2,img3,img4).display("My four images"); - \endcode - **/ - template - CImgList& operator,(const CImg& img) { - return insert(img); - } - - //! Return a copy of the list instance, where image \c img has been inserted at the end \const. - template - CImgList operator,(const CImg& img) const { - return (+*this).insert(img); - } - - //! Return a copy of the list instance, where all elements of input list \c list have been inserted at the end. - /** - \param list List inserted at the end of the instance copy. - **/ - template - CImgList& operator,(const CImgList& list) { - return insert(list); - } - - //! Return a copy of the list instance, where all elements of input \c list have been inserted at the end \const. - template - CImgList& operator,(const CImgList& list) const { - return (+*this).insert(list); - } - - //! Return image corresponding to the appending of all images of the instance list along specified axis. - /** - \param axis Appending axis. Can be { 'x' | 'y' | 'z' | 'c' }. - \note list>'x' is equivalent to list.get_append('x'). - **/ - CImg operator>(const char axis) const { - return get_append(axis,0); - } - - //! Return list corresponding to the splitting of all images of the instance list along specified axis. - /** - \param axis Axis used for image splitting. - \note list<'x' is equivalent to list.get_split('x'). - **/ - CImgList operator<(const char axis) const { - return get_split(axis); - } - - //@} - //------------------------------------- - // - //! \name Instance Characteristics - //@{ - //------------------------------------- - - //! Return the type of image pixel values as a C string. - /** - Return a \c char* string containing the usual type name of the image pixel values - (i.e. a stringified version of the template parameter \c T). - \note - - The returned string does not contain any spaces. - - If the pixel type \c T does not correspond to a registered type, the string "unknown" is returned. - **/ - static const char* pixel_type() { - return cimg::type::string(); - } - - //! Return the size of the list, i.e. the number of images contained in it. - /** - \note Similar to size() but returns result as a (signed) integer. - **/ - int width() const { - return (int)_width; - } - - //! Return the size of the list, i.e. the number of images contained in it. - /** - \note Similar to width() but returns result as an unsigned integer. - **/ - unsigned int size() const { - return _width; - } - - //! Return pointer to the first image of the list. - /** - \note Images in a list are stored as a buffer of \c CImg. - **/ - CImg *data() { - return _data; - } - - //! Return pointer to the first image of the list \const. - const CImg *data() const { - return _data; - } - - //! Return pointer to the pos-th image of the list. - /** - \param pos Index of the image element to access. - \note list.data(n); is equivalent to list.data + n;. - **/ -#if cimg_verbosity>=3 - CImg *data(const unsigned int pos) { - if (pos>=size()) - cimg::warn(_cimglist_instance - "data(): Invalid pointer request, at position [%u].", - cimglist_instance, - pos); - return _data + pos; - } - - const CImg *data(const unsigned int l) const { - return const_cast*>(this)->data(l); - } -#else - CImg *data(const unsigned int l) { - return _data + l; - } - - //! Return pointer to the pos-th image of the list \const. - const CImg *data(const unsigned int l) const { - return _data + l; - } -#endif - - //! Return iterator to the first image of the list. - /** - **/ - iterator begin() { - return _data; - } - - //! Return iterator to the first image of the list \const. - const_iterator begin() const { - return _data; - } - - //! Return iterator to one position after the last image of the list. - /** - **/ - iterator end() { - return _data + _width; - } - - //! Return iterator to one position after the last image of the list \const. - const_iterator end() const { - return _data + _width; - } - - //! Return reference to the first image of the list. - /** - **/ - CImg& front() { - return *_data; - } - - //! Return reference to the first image of the list \const. - const CImg& front() const { - return *_data; - } - - //! Return a reference to the last image of the list. - /** - **/ - const CImg& back() const { - return *(_data + _width - 1); - } - - //! Return a reference to the last image of the list \const. - CImg& back() { - return *(_data + _width - 1); - } - - //! Return pos-th image of the list. - /** - \param pos Index of the image element to access. - **/ - CImg& at(const int pos) { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "at(): Empty instance.", - cimglist_instance); - - return _data[cimg::cut(pos,0,width() - 1)]; - } - - //! Access to pixel value with Dirichlet boundary conditions. - /** - \param pos Index of the image element to access. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \param out_value Default value returned if \c offset is outside image bounds. - \note list.atNXYZC(p,x,y,z,c); is equivalent to list[p].atXYZC(x,y,z,c);. - **/ - T& atNXYZC(const int pos, const int x, const int y, const int z, const int c, const T& out_value) { - return (pos<0 || pos>=width())?(cimg::temporary(out_value)=out_value):_data[pos].atXYZC(x,y,z,c,out_value); - } - - //! Access to pixel value with Dirichlet boundary conditions \const. - T atNXYZC(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const { - return (pos<0 || pos>=width())?out_value:_data[pos].atXYZC(x,y,z,c,out_value); - } - - //! Access to pixel value with Neumann boundary conditions. - /** - \param pos Index of the image element to access. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note list.atNXYZC(p,x,y,z,c); is equivalent to list[p].atXYZC(x,y,z,c);. - **/ - T& atNXYZC(const int pos, const int x, const int y, const int z, const int c) { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "atNXYZC(): Empty instance.", - cimglist_instance); - - return _atNXYZC(pos,x,y,z,c); - } - - //! Access to pixel value with Neumann boundary conditions \const. - T atNXYZC(const int pos, const int x, const int y, const int z, const int c) const { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "atNXYZC(): Empty instance.", - cimglist_instance); - - return _atNXYZC(pos,x,y,z,c); - } - - T& _atNXYZC(const int pos, const int x, const int y, const int z, const int c) { - return _data[cimg::cut(pos,0,width() - 1)].atXYZC(x,y,z,c); - } - - T _atNXYZC(const int pos, const int x, const int y, const int z, const int c) const { - return _data[cimg::cut(pos,0,width() - 1)].atXYZC(x,y,z,c); - } - - //! Access pixel value with Dirichlet boundary conditions for the 3 coordinates (\c pos, \c x,\c y,\c z). - /** - \param pos Index of the image element to access. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \param out_value Default value returned if \c offset is outside image bounds. - \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. - **/ - T& atNXYZ(const int pos, const int x, const int y, const int z, const int c, const T& out_value) { - return (pos<0 || pos>=width())?(cimg::temporary(out_value)=out_value):_data[pos].atXYZ(x,y,z,c,out_value); - } - - //! Access pixel value with Dirichlet boundary conditions for the 3 coordinates (\c pos, \c x,\c y,\c z) \const. - T atNXYZ(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const { - return (pos<0 || pos>=width())?out_value:_data[pos].atXYZ(x,y,z,c,out_value); - } - - //! Access to pixel value with Neumann boundary conditions for the 4 coordinates (\c pos, \c x,\c y,\c z). - /** - \param pos Index of the image element to access. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. - **/ - T& atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "atNXYZ(): Empty instance.", - cimglist_instance); - - return _atNXYZ(pos,x,y,z,c); - } - - //! Access to pixel value with Neumann boundary conditions for the 4 coordinates (\c pos, \c x,\c y,\c z) \const. - T atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "atNXYZ(): Empty instance.", - cimglist_instance); - - return _atNXYZ(pos,x,y,z,c); - } - - T& _atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) { - return _data[cimg::cut(pos,0,width() - 1)].atXYZ(x,y,z,c); - } - - T _atNXYZ(const int pos, const int x, const int y, const int z, const int c=0) const { - return _data[cimg::cut(pos,0,width() - 1)].atXYZ(x,y,z,c); - } - - //! Access to pixel value with Dirichlet boundary conditions for the 3 coordinates (\c pos, \c x,\c y). - /** - \param pos Index of the image element to access. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \param out_value Default value returned if \c offset is outside image bounds. - \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. - **/ - T& atNXY(const int pos, const int x, const int y, const int z, const int c, const T& out_value) { - return (pos<0 || pos>=width())?(cimg::temporary(out_value)=out_value):_data[pos].atXY(x,y,z,c,out_value); - } - - //! Access to pixel value with Dirichlet boundary conditions for the 3 coordinates (\c pos, \c x,\c y) \const. - T atNXY(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const { - return (pos<0 || pos>=width())?out_value:_data[pos].atXY(x,y,z,c,out_value); - } - - //! Access to pixel value with Neumann boundary conditions for the 3 coordinates (\c pos, \c x,\c y). - /** - \param pos Index of the image element to access. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. - **/ - T& atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "atNXY(): Empty instance.", - cimglist_instance); - - return _atNXY(pos,x,y,z,c); - } - - //! Access to pixel value with Neumann boundary conditions for the 3 coordinates (\c pos, \c x,\c y) \const. - T atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "atNXY(): Empty instance.", - cimglist_instance); - - return _atNXY(pos,x,y,z,c); - } - - T& _atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) { - return _data[cimg::cut(pos,0,width() - 1)].atXY(x,y,z,c); - } - - T _atNXY(const int pos, const int x, const int y, const int z=0, const int c=0) const { - return _data[cimg::cut(pos,0,width() - 1)].atXY(x,y,z,c); - } - - //! Access to pixel value with Dirichlet boundary conditions for the 2 coordinates (\c pos,\c x). - /** - \param pos Index of the image element to access. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \param out_value Default value returned if \c offset is outside image bounds. - \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. - **/ - T& atNX(const int pos, const int x, const int y, const int z, const int c, const T& out_value) { - return (pos<0 || pos>=width())?(cimg::temporary(out_value)=out_value):_data[pos].atX(x,y,z,c,out_value); - } - - //! Access to pixel value with Dirichlet boundary conditions for the 2 coordinates (\c pos,\c x) \const. - T atNX(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const { - return (pos<0 || pos>=width())?out_value:_data[pos].atX(x,y,z,c,out_value); - } - - //! Access to pixel value with Neumann boundary conditions for the 2 coordinates (\c pos, \c x). - /** - \param pos Index of the image element to access. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. - **/ - T& atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "atNX(): Empty instance.", - cimglist_instance); - - return _atNX(pos,x,y,z,c); - } - - //! Access to pixel value with Neumann boundary conditions for the 2 coordinates (\c pos, \c x) \const. - T atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "atNX(): Empty instance.", - cimglist_instance); - - return _atNX(pos,x,y,z,c); - } - - T& _atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) { - return _data[cimg::cut(pos,0,width() - 1)].atX(x,y,z,c); - } - - T _atNX(const int pos, const int x, const int y=0, const int z=0, const int c=0) const { - return _data[cimg::cut(pos,0,width() - 1)].atX(x,y,z,c); - } - - //! Access to pixel value with Dirichlet boundary conditions for the coordinate (\c pos). - /** - \param pos Index of the image element to access. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \param out_value Default value returned if \c offset is outside image bounds. - \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. - **/ - T& atN(const int pos, const int x, const int y, const int z, const int c, const T& out_value) { - return (pos<0 || pos>=width())?(cimg::temporary(out_value)=out_value):(*this)(pos,x,y,z,c); - } - - //! Access to pixel value with Dirichlet boundary conditions for the coordinate (\c pos) \const. - T atN(const int pos, const int x, const int y, const int z, const int c, const T& out_value) const { - return (pos<0 || pos>=width())?out_value:(*this)(pos,x,y,z,c); - } - - //! Return pixel value with Neumann boundary conditions for the coordinate (\c pos). - /** - \param pos Index of the image element to access. - \param x X-coordinate of the pixel value. - \param y Y-coordinate of the pixel value. - \param z Z-coordinate of the pixel value. - \param c C-coordinate of the pixel value. - \note list.atNXYZ(p,x,y,z,c); is equivalent to list[p].atXYZ(x,y,z,c);. - **/ - T& atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "atN(): Empty instance.", - cimglist_instance); - return _atN(pos,x,y,z,c); - } - - //! Return pixel value with Neumann boundary conditions for the coordinate (\c pos) \const. - T atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) const { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "atN(): Empty instance.", - cimglist_instance); - return _atN(pos,x,y,z,c); - } - - T& _atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) { - return _data[cimg::cut(pos,0,width() - 1)](x,y,z,c); - } - - T _atN(const int pos, const int x=0, const int y=0, const int z=0, const int c=0) const { - return _data[cimg::cut(pos,0,width() - 1)](x,y,z,c); - } - - //@} - //------------------------------------- - // - //! \name Instance Checking - //@{ - //------------------------------------- - - //! Return \c true if list is empty. - /** - **/ - bool is_empty() const { - return (!_data || !_width); - } - - //! Test if number of image elements is equal to specified value. - /** - \param size_n Number of image elements to test. - **/ - bool is_sameN(const unsigned int size_n) const { - return _width==size_n; - } - - //! Test if number of image elements is equal between two images lists. - /** - \param list Input list to compare with. - **/ - template - bool is_sameN(const CImgList& list) const { - return is_sameN(list._width); - } - - // Define useful functions to check list dimensions. - // (cannot be documented because macro-generated). -#define _cimglist_def_is_same1(axis) \ - bool is_same##axis(const unsigned int val) const { \ - bool res = true; \ - for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis(val); \ - return res; \ - } \ - bool is_sameN##axis(const unsigned int n, const unsigned int val) const { \ - return is_sameN(n) && is_same##axis(val); \ - } \ - -#define _cimglist_def_is_same2(axis1,axis2) \ - bool is_same##axis1##axis2(const unsigned int val1, const unsigned int val2) const { \ - bool res = true; \ - for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis1##axis2(val1,val2); \ - return res; \ - } \ - bool is_sameN##axis1##axis2(const unsigned int n, const unsigned int val1, const unsigned int val2) const { \ - return is_sameN(n) && is_same##axis1##axis2(val1,val2); \ - } \ - -#define _cimglist_def_is_same3(axis1,axis2,axis3) \ - bool is_same##axis1##axis2##axis3(const unsigned int val1, const unsigned int val2, \ - const unsigned int val3) const { \ - bool res = true; \ - for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis1##axis2##axis3(val1,val2,val3); \ - return res; \ - } \ - bool is_sameN##axis1##axis2##axis3(const unsigned int n, const unsigned int val1, \ - const unsigned int val2, const unsigned int val3) const { \ - return is_sameN(n) && is_same##axis1##axis2##axis3(val1,val2,val3); \ - } \ - -#define _cimglist_def_is_same(axis) \ - template bool is_same##axis(const CImg& img) const { \ - bool res = true; \ - for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_same##axis(img); \ - return res; \ - } \ - template bool is_same##axis(const CImgList& list) const { \ - const unsigned int lmin = std::min(_width,list._width); \ - bool res = true; \ - for (unsigned int l = 0; l bool is_sameN##axis(const unsigned int n, const CImg& img) const { \ - return (is_sameN(n) && is_same##axis(img)); \ - } \ - template bool is_sameN##axis(const CImgList& list) const { \ - return (is_sameN(list) && is_same##axis(list)); \ - } - - _cimglist_def_is_same(XY) - _cimglist_def_is_same(XZ) - _cimglist_def_is_same(XC) - _cimglist_def_is_same(YZ) - _cimglist_def_is_same(YC) - _cimglist_def_is_same(XYZ) - _cimglist_def_is_same(XYC) - _cimglist_def_is_same(YZC) - _cimglist_def_is_same(XYZC) - _cimglist_def_is_same1(X) - _cimglist_def_is_same1(Y) - _cimglist_def_is_same1(Z) - _cimglist_def_is_same1(C) - _cimglist_def_is_same2(X,Y) - _cimglist_def_is_same2(X,Z) - _cimglist_def_is_same2(X,C) - _cimglist_def_is_same2(Y,Z) - _cimglist_def_is_same2(Y,C) - _cimglist_def_is_same2(Z,C) - _cimglist_def_is_same3(X,Y,Z) - _cimglist_def_is_same3(X,Y,C) - _cimglist_def_is_same3(X,Z,C) - _cimglist_def_is_same3(Y,Z,C) - - //! Test if dimensions of each image of the list match specified arguments. - /** - \param dx Checked image width. - \param dy Checked image height. - \param dz Checked image depth. - \param dc Checked image spectrum. - **/ - bool is_sameXYZC(const unsigned int dx, const unsigned int dy, - const unsigned int dz, const unsigned int dc) const { - bool res = true; - for (unsigned int l = 0; l<_width && res; ++l) res = _data[l].is_sameXYZC(dx,dy,dz,dc); - return res; - } - - //! Test if list dimensions match specified arguments. - /** - \param n Number of images in the list. - \param dx Checked image width. - \param dy Checked image height. - \param dz Checked image depth. - \param dc Checked image spectrum. - **/ - bool is_sameNXYZC(const unsigned int n, - const unsigned int dx, const unsigned int dy, - const unsigned int dz, const unsigned int dc) const { - return is_sameN(n) && is_sameXYZC(dx,dy,dz,dc); - } - - //! Test if list contains one particular pixel location. - /** - \param n Index of the image whom checked pixel value belong to. - \param x X-coordinate of the checked pixel value. - \param y Y-coordinate of the checked pixel value. - \param z Z-coordinate of the checked pixel value. - \param c C-coordinate of the checked pixel value. - **/ - bool containsNXYZC(const int n, const int x=0, const int y=0, const int z=0, const int c=0) const { - if (is_empty()) return false; - return n>=0 && n=0 && x<_data[n].width() && y>=0 && y<_data[n].height() && - z>=0 && z<_data[n].depth() && c>=0 && c<_data[n].spectrum(); - } - - //! Test if list contains image with specified index. - /** - \param n Index of the checked image. - **/ - bool containsN(const int n) const { - if (is_empty()) return false; - return n>=0 && n - bool contains(const T& pixel, t& n, t& x, t&y, t& z, t& c) const { - if (is_empty()) return false; - cimglist_for(*this,l) if (_data[l].contains(pixel,x,y,z,c)) { n = (t)l; return true; } - return false; - } - - //! Test if one of the image list contains the specified referenced value. - /** - \param pixel Reference to pixel value to test. - \param[out] n Index of image containing the pixel value, if test succeeds. - \param[out] x X-coordinate of the pixel value, if test succeeds. - \param[out] y Y-coordinate of the pixel value, if test succeeds. - \param[out] z Z-coordinate of the pixel value, if test succeeds. - \note If true, set coordinates (n,x,y,z). - **/ - template - bool contains(const T& pixel, t& n, t& x, t&y, t& z) const { - t c; - return contains(pixel,n,x,y,z,c); - } - - //! Test if one of the image list contains the specified referenced value. - /** - \param pixel Reference to pixel value to test. - \param[out] n Index of image containing the pixel value, if test succeeds. - \param[out] x X-coordinate of the pixel value, if test succeeds. - \param[out] y Y-coordinate of the pixel value, if test succeeds. - \note If true, set coordinates (n,x,y). - **/ - template - bool contains(const T& pixel, t& n, t& x, t&y) const { - t z, c; - return contains(pixel,n,x,y,z,c); - } - - //! Test if one of the image list contains the specified referenced value. - /** - \param pixel Reference to pixel value to test. - \param[out] n Index of image containing the pixel value, if test succeeds. - \param[out] x X-coordinate of the pixel value, if test succeeds. - \note If true, set coordinates (n,x). - **/ - template - bool contains(const T& pixel, t& n, t& x) const { - t y, z, c; - return contains(pixel,n,x,y,z,c); - } - - //! Test if one of the image list contains the specified referenced value. - /** - \param pixel Reference to pixel value to test. - \param[out] n Index of image containing the pixel value, if test succeeds. - \note If true, set coordinates (n). - **/ - template - bool contains(const T& pixel, t& n) const { - t x, y, z, c; - return contains(pixel,n,x,y,z,c); - } - - //! Test if one of the image list contains the specified referenced value. - /** - \param pixel Reference to pixel value to test. - **/ - bool contains(const T& pixel) const { - unsigned int n, x, y, z, c; - return contains(pixel,n,x,y,z,c); - } - - //! Test if the list contains the image 'img'. - /** - \param img Reference to image to test. - \param[out] n Index of image in the list, if test succeeds. - \note If true, returns the position (n) of the image in the list. - **/ - template - bool contains(const CImg& img, t& n) const { - if (is_empty()) return false; - const CImg *const ptr = &img; - cimglist_for(*this,i) if (_data + i==ptr) { n = (t)i; return true; } - return false; - } - - //! Test if the list contains the image img. - /** - \param img Reference to image to test. - **/ - bool contains(const CImg& img) const { - unsigned int n; - return contains(img,n); - } - - //@} - //------------------------------------- - // - //! \name Mathematical Functions - //@{ - //------------------------------------- - - //! Return a reference to the minimum pixel value of the instance list. - /** - **/ - T& min() { - bool is_all_empty = true; - T *ptr_min = 0; - cimglist_for(*this,l) if (!_data[l].is_empty()) { - ptr_min = _data[l]._data; - is_all_empty = false; - break; - } - if (is_all_empty) - throw CImgInstanceException(_cimglist_instance - "min(): %s.", - _data?"List of empty images":"Empty instance", - cimglist_instance); - T min_value = *ptr_min; - cimglist_for(*this,l) { - const CImg& img = _data[l]; - cimg_for(img,ptrs,T) if (*ptrs& img = _data[l]; - cimg_for(img,ptrs,T) if (*ptrs& img = _data[l]; - cimg_for(img,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs); - } - return *ptr_max; - } - - //! Return a reference to the maximum pixel value of the instance list \const. - const T& max() const { - bool is_all_empty = true; - T *ptr_max = 0; - cimglist_for(*this,l) if (!_data[l].is_empty()) { - ptr_max = _data[l]._data; - is_all_empty = false; - break; - } - if (is_all_empty) - throw CImgInstanceException(_cimglist_instance - "max(): %s.", - _data?"List of empty images":"Empty instance", - cimglist_instance); - T max_value = *ptr_max; - cimglist_for(*this,l) { - const CImg& img = _data[l]; - cimg_for(img,ptrs,T) if (*ptrs>max_value) max_value = *(ptr_max=ptrs); - } - return *ptr_max; - } - - //! Return a reference to the minimum pixel value of the instance list and return the maximum vvalue as well. - /** - \param[out] max_val Value of the maximum value found. - **/ - template - T& min_max(t& max_val) { - bool is_all_empty = true; - T *ptr_min = 0; - cimglist_for(*this,l) if (!_data[l].is_empty()) { - ptr_min = _data[l]._data; - is_all_empty = false; - break; - } - if (is_all_empty) - throw CImgInstanceException(_cimglist_instance - "min_max(): %s.", - _data?"List of empty images":"Empty instance", - cimglist_instance); - T min_value = *ptr_min, max_value = min_value; - cimglist_for(*this,l) { - const CImg& img = _data[l]; - cimg_for(img,ptrs,T) { - const T val = *ptrs; - if (valmax_value) max_value = val; - } - } - max_val = (t)max_value; - return *ptr_min; - } - - //! Return a reference to the minimum pixel value of the instance list and return the maximum vvalue as well \const. - /** - \param[out] max_val Value of the maximum value found. - **/ - template - const T& min_max(t& max_val) const { - bool is_all_empty = true; - T *ptr_min = 0; - cimglist_for(*this,l) if (!_data[l].is_empty()) { - ptr_min = _data[l]._data; - is_all_empty = false; - break; - } - if (is_all_empty) - throw CImgInstanceException(_cimglist_instance - "min_max(): %s.", - _data?"List of empty images":"Empty instance", - cimglist_instance); - T min_value = *ptr_min, max_value = min_value; - cimglist_for(*this,l) { - const CImg& img = _data[l]; - cimg_for(img,ptrs,T) { - const T val = *ptrs; - if (valmax_value) max_value = val; - } - } - max_val = (t)max_value; - return *ptr_min; - } - - //! Return a reference to the minimum pixel value of the instance list and return the minimum value as well. - /** - \param[out] min_val Value of the minimum value found. - **/ - template - T& max_min(t& min_val) { - bool is_all_empty = true; - T *ptr_max = 0; - cimglist_for(*this,l) if (!_data[l].is_empty()) { - ptr_max = _data[l]._data; - is_all_empty = false; - break; - } - if (is_all_empty) - throw CImgInstanceException(_cimglist_instance - "max_min(): %s.", - _data?"List of empty images":"Empty instance", - cimglist_instance); - T min_value = *ptr_max, max_value = min_value; - cimglist_for(*this,l) { - const CImg& img = _data[l]; - cimg_for(img,ptrs,T) { - const T val = *ptrs; - if (val>max_value) { max_value = val; ptr_max = ptrs; } - if (val - const T& max_min(t& min_val) const { - bool is_all_empty = true; - T *ptr_max = 0; - cimglist_for(*this,l) if (!_data[l].is_empty()) { - ptr_max = _data[l]._data; - is_all_empty = false; - break; - } - if (is_all_empty) - throw CImgInstanceException(_cimglist_instance - "max_min(): %s.", - _data?"List of empty images":"Empty instance", - cimglist_instance); - T min_value = *ptr_max, max_value = min_value; - cimglist_for(*this,l) { - const CImg& img = _data[l]; - cimg_for(img,ptrs,T) { - const T val = *ptrs; - if (val>max_value) { max_value = val; ptr_max = ptrs; } - if (val - CImgList& insert(const CImg& img, const unsigned int pos=~0U, const bool is_shared=false) { - const unsigned int npos = pos==~0U?_width:pos; - if (npos>_width) - throw CImgArgumentException(_cimglist_instance - "insert(): Invalid insertion request of specified image (%u,%u,%u,%u,%p) " - "at position %u.", - cimglist_instance, - img._width,img._height,img._depth,img._spectrum,img._data,npos); - if (is_shared) - throw CImgArgumentException(_cimglist_instance - "insert(): Invalid insertion request of specified shared image " - "CImg<%s>(%u,%u,%u,%u,%p) at position %u (pixel types are different).", - cimglist_instance, - img.pixel_type(),img._width,img._height,img._depth,img._spectrum,img._data,npos); - - CImg *const new_data = (++_width>_allocated_width)?new CImg[_allocated_width?(_allocated_width<<=1): - (_allocated_width=16)]:0; - if (!_data) { // Insert new element into empty list - _data = new_data; - *_data = img; - } else { - if (new_data) { // Insert with re-allocation - if (npos) std::memcpy((void*)new_data,(void*)_data,sizeof(CImg)*npos); - if (npos!=_width - 1) - std::memcpy((void*)(new_data + npos + 1),(void*)(_data + npos),sizeof(CImg)*(_width - 1 - npos)); - std::memset((void*)_data,0,sizeof(CImg)*(_width - 1)); - delete[] _data; - _data = new_data; - } else if (npos!=_width - 1) // Insert without re-allocation - std::memmove((void*)(_data + npos + 1),(void*)(_data + npos),sizeof(CImg)*(_width - 1 - npos)); - _data[npos]._width = _data[npos]._height = _data[npos]._depth = _data[npos]._spectrum = 0; - _data[npos]._data = 0; - _data[npos] = img; - } - return *this; - } - - //! Insert a copy of the image \c img into the current image list, at position \c pos \specialization. - CImgList& insert(const CImg& img, const unsigned int pos=~0U, const bool is_shared=false) { - const unsigned int npos = pos==~0U?_width:pos; - if (npos>_width) - throw CImgArgumentException(_cimglist_instance - "insert(): Invalid insertion request of specified image (%u,%u,%u,%u,%p) " - "at position %u.", - cimglist_instance, - img._width,img._height,img._depth,img._spectrum,img._data,npos); - CImg *const new_data = (++_width>_allocated_width)?new CImg[_allocated_width?(_allocated_width<<=1): - (_allocated_width=16)]:0; - if (!_data) { // Insert new element into empty list - _data = new_data; - if (is_shared && img) { - _data->_width = img._width; - _data->_height = img._height; - _data->_depth = img._depth; - _data->_spectrum = img._spectrum; - _data->_is_shared = true; - _data->_data = img._data; - } else *_data = img; - } - else { - if (new_data) { // Insert with re-allocation - if (npos) std::memcpy((void*)new_data,(void*)_data,sizeof(CImg)*npos); - if (npos!=_width - 1) - std::memcpy((void*)(new_data + npos + 1),(void*)(_data + npos),sizeof(CImg)*(_width - 1 - npos)); - if (is_shared && img) { - new_data[npos]._width = img._width; - new_data[npos]._height = img._height; - new_data[npos]._depth = img._depth; - new_data[npos]._spectrum = img._spectrum; - new_data[npos]._is_shared = true; - new_data[npos]._data = img._data; - } else { - new_data[npos]._width = new_data[npos]._height = new_data[npos]._depth = new_data[npos]._spectrum = 0; - new_data[npos]._data = 0; - new_data[npos] = img; - } - std::memset((void*)_data,0,sizeof(CImg)*(_width - 1)); - delete[] _data; - _data = new_data; - } else { // Insert without re-allocation - if (npos!=_width - 1) - std::memmove((void*)(_data + npos + 1),(void*)(_data + npos),sizeof(CImg)*(_width - 1 - npos)); - if (is_shared && img) { - _data[npos]._width = img._width; - _data[npos]._height = img._height; - _data[npos]._depth = img._depth; - _data[npos]._spectrum = img._spectrum; - _data[npos]._is_shared = true; - _data[npos]._data = img._data; - } else { - _data[npos]._width = _data[npos]._height = _data[npos]._depth = _data[npos]._spectrum = 0; - _data[npos]._data = 0; - _data[npos] = img; - } - } - } - return *this; - } - - //! Insert a copy of the image \c img into the current image list, at position \c pos \newinstance. - template - CImgList get_insert(const CImg& img, const unsigned int pos=~0U, const bool is_shared=false) const { - return (+*this).insert(img,pos,is_shared); - } - - //! Insert n empty images img into the current image list, at position \p pos. - /** - \param n Number of empty images to insert. - \param pos Index of the insertion. - **/ - CImgList& insert(const unsigned int n, const unsigned int pos=~0U) { - CImg empty; - if (!n) return *this; - const unsigned int npos = pos==~0U?_width:pos; - for (unsigned int i = 0; i get_insert(const unsigned int n, const unsigned int pos=~0U) const { - return (+*this).insert(n,pos); - } - - //! Insert \c n copies of the image \c img into the current image list, at position \c pos. - /** - \param n Number of image copies to insert. - \param img Image to insert by copy. - \param pos Index of the insertion. - \param is_shared Tells if inserted images are shared copies of \c img or not. - **/ - template - CImgList& insert(const unsigned int n, const CImg& img, const unsigned int pos=~0U, - const bool is_shared=false) { - if (!n) return *this; - const unsigned int npos = pos==~0U?_width:pos; - insert(img,npos,is_shared); - for (unsigned int i = 1; i - CImgList get_insert(const unsigned int n, const CImg& img, const unsigned int pos=~0U, - const bool is_shared=false) const { - return (+*this).insert(n,img,pos,is_shared); - } - - //! Insert a copy of the image list \c list into the current image list, starting from position \c pos. - /** - \param list Image list to insert. - \param pos Index of the insertion. - \param is_shared Tells if inserted images are shared copies of images of \c list or not. - **/ - template - CImgList& insert(const CImgList& list, const unsigned int pos=~0U, const bool is_shared=false) { - const unsigned int npos = pos==~0U?_width:pos; - if ((void*)this!=(void*)&list) cimglist_for(list,l) insert(list[l],npos + l,is_shared); - else insert(CImgList(list),npos,is_shared); - return *this; - } - - //! Insert a copy of the image list \c list into the current image list, starting from position \c pos \newinstance. - template - CImgList get_insert(const CImgList& list, const unsigned int pos=~0U, const bool is_shared=false) const { - return (+*this).insert(list,pos,is_shared); - } - - //! Insert n copies of the list \c list at position \c pos of the current list. - /** - \param n Number of list copies to insert. - \param list Image list to insert. - \param pos Index of the insertion. - \param is_shared Tells if inserted images are shared copies of images of \c list or not. - **/ - template - CImgList& insert(const unsigned int n, const CImgList& list, const unsigned int pos=~0U, - const bool is_shared=false) { - if (!n) return *this; - const unsigned int npos = pos==~0U?_width:pos; - for (unsigned int i = 0; i - CImgList get_insert(const unsigned int n, const CImgList& list, const unsigned int pos=~0U, - const bool is_shared=false) const { - return (+*this).insert(n,list,pos,is_shared); - } - - //! Remove all images between from indexes. - /** - \param pos1 Starting index of the removal. - \param pos2 Ending index of the removal. - **/ - CImgList& remove(const unsigned int pos1, const unsigned int pos2) { - const unsigned int - npos1 = pos1=_width) - throw CImgArgumentException(_cimglist_instance - "remove(): Invalid remove request at positions %u->%u.", - cimglist_instance, - npos1,tpos2); - else { - if (tpos2>=_width) - throw CImgArgumentException(_cimglist_instance - "remove(): Invalid remove request at positions %u->%u.", - cimglist_instance, - npos1,tpos2); - - for (unsigned int k = npos1; k<=npos2; ++k) _data[k].assign(); - const unsigned int nb = 1 + npos2 - npos1; - if (!(_width-=nb)) return assign(); - if (_width>(_allocated_width>>4) || _allocated_width<=16) { // Removing items without reallocation - if (npos1!=_width) - std::memmove((void*)(_data + npos1),(void*)(_data + npos2 + 1),sizeof(CImg)*(_width - npos1)); - std::memset((void*)(_data + _width),0,sizeof(CImg)*nb); - } else { // Removing items with reallocation - _allocated_width>>=4; - while (_allocated_width>16 && _width<(_allocated_width>>1)) _allocated_width>>=1; - CImg *const new_data = new CImg[_allocated_width]; - if (npos1) std::memcpy((void*)new_data,(void*)_data,sizeof(CImg)*npos1); - if (npos1!=_width) - std::memcpy((void*)(new_data + npos1),(void*)(_data + npos2 + 1),sizeof(CImg)*(_width - npos1)); - if (_width!=_allocated_width) - std::memset((void*)(new_data + _width),0,sizeof(CImg)*(_allocated_width - _width)); - std::memset((void*)_data,0,sizeof(CImg)*(_width + nb)); - delete[] _data; - _data = new_data; - } - } - return *this; - } - - //! Remove all images between from indexes \newinstance. - CImgList get_remove(const unsigned int pos1, const unsigned int pos2) const { - return (+*this).remove(pos1,pos2); - } - - //! Remove image at index \c pos from the image list. - /** - \param pos Index of the image to remove. - **/ - CImgList& remove(const unsigned int pos) { - return remove(pos,pos); - } - - //! Remove image at index \c pos from the image list \newinstance. - CImgList get_remove(const unsigned int pos) const { - return (+*this).remove(pos); - } - - //! Remove last image. - /** - **/ - CImgList& remove() { - return remove(_width - 1); - } - - //! Remove last image \newinstance. - CImgList get_remove() const { - return (+*this).remove(); - } - - //! Reverse list order. - CImgList& reverse() { - for (unsigned int l = 0; l<_width/2; ++l) (*this)[l].swap((*this)[_width - 1 - l]); - return *this; - } - - //! Reverse list order \newinstance. - CImgList get_reverse() const { - return (+*this).reverse(); - } - - //! Return a sublist. - /** - \param pos0 Starting index of the sublist. - \param pos1 Ending index of the sublist. - **/ - CImgList& images(const unsigned int pos0, const unsigned int pos1) { - return get_images(pos0,pos1).move_to(*this); - } - - //! Return a sublist \newinstance. - CImgList get_images(const unsigned int pos0, const unsigned int pos1) const { - if (pos0>pos1 || pos1>=_width) - throw CImgArgumentException(_cimglist_instance - "images(): Specified sub-list indices (%u->%u) are out of bounds.", - cimglist_instance, - pos0,pos1); - CImgList res(pos1 - pos0 + 1); - cimglist_for(res,l) res[l].assign(_data[pos0 + l]); - return res; - } - - //! Return a shared sublist. - /** - \param pos0 Starting index of the sublist. - \param pos1 Ending index of the sublist. - **/ - CImgList get_shared_images(const unsigned int pos0, const unsigned int pos1) { - if (pos0>pos1 || pos1>=_width) - throw CImgArgumentException(_cimglist_instance - "get_shared_images(): Specified sub-list indices (%u->%u) are out of bounds.", - cimglist_instance, - pos0,pos1); - CImgList res(pos1 - pos0 + 1); - cimglist_for(res,l) res[l].assign(_data[pos0 + l],_data[pos0 + l]?true:false); - return res; - } - - //! Return a shared sublist \newinstance. - const CImgList get_shared_images(const unsigned int pos0, const unsigned int pos1) const { - if (pos0>pos1 || pos1>=_width) - throw CImgArgumentException(_cimglist_instance - "get_shared_images(): Specified sub-list indices (%u->%u) are out of bounds.", - cimglist_instance, - pos0,pos1); - CImgList res(pos1 - pos0 + 1); - cimglist_for(res,l) res[l].assign(_data[pos0 + l],_data[pos0 + l]?true:false); - return res; - } - - //! Return a single image which is the appending of all images of the current CImgList instance. - /** - \param axis Appending axis. Can be { 'x' | 'y' | 'z' | 'c' }. - \param align Appending alignment. - **/ - CImg get_append(const char axis, const float align=0) const { - if (is_empty()) return CImg(); - if (_width==1) return +((*this)[0]); - unsigned int dx = 0, dy = 0, dz = 0, dc = 0, pos = 0; - CImg res; - switch (cimg::lowercase(axis)) { - case 'x' : { // Along the X-axis - cimglist_for(*this,l) { - const CImg& img = (*this)[l]; - if (img) { - dx+=img._width; - dy = std::max(dy,img._height); - dz = std::max(dz,img._depth); - dc = std::max(dc,img._spectrum); - } - } - res.assign(dx,dy,dz,dc,(T)0); - if (res) cimglist_for(*this,l) { - const CImg& img = (*this)[l]; - if (img) { - if (img._height==1 && img._depth==1 && img._spectrum==1 && - res._height==1 && res._depth==1 && res._spectrum==1) - std::memcpy(&res[pos],img._data,sizeof(T)*img._width); - else - res.draw_image(pos, - (int)(align*(dy - img._height)), - (int)(align*(dz - img._depth)), - (int)(align*(dc - img._spectrum)), - img); - } - pos+=img._width; - } - } break; - case 'y' : { // Along the Y-axis - cimglist_for(*this,l) { - const CImg& img = (*this)[l]; - if (img) { - dx = std::max(dx,img._width); - dy+=img._height; - dz = std::max(dz,img._depth); - dc = std::max(dc,img._spectrum); - } - } - res.assign(dx,dy,dz,dc,(T)0); - if (res) cimglist_for(*this,l) { - const CImg& img = (*this)[l]; - if (img) { - if (img._width==1 && img._depth==1 && img._spectrum==1 && - res._width==1 && res._depth==1 && res._spectrum==1) - std::memcpy(&res[pos],img._data,sizeof(T)*img._height); - else - res.draw_image((int)(align*(dx - img._width)), - pos, - (int)(align*(dz - img._depth)), - (int)(align*(dc - img._spectrum)), - img); - } - pos+=img._height; - } - } break; - case 'z' : { // Along the Z-axis - cimglist_for(*this,l) { - const CImg& img = (*this)[l]; - if (img) { - dx = std::max(dx,img._width); - dy = std::max(dy,img._height); - dz+=img._depth; - dc = std::max(dc,img._spectrum); - } - } - res.assign(dx,dy,dz,dc,(T)0); - if (res) cimglist_for(*this,l) { - const CImg& img = (*this)[l]; - if (img) { - if (img._width==1 && img._height==1 && img._spectrum==1 && - res._width==1 && res._height==1 && res._spectrum==1) - std::memcpy(&res[pos],img._data,sizeof(T)*img._depth); - else - res.draw_image((int)(align*(dx - img._width)), - (int)(align*(dy - img._height)), - pos, - (int)(align*(dc - img._spectrum)), - img); - } - pos+=img._depth; - } - } break; - default : { // Along the C-axis - cimglist_for(*this,l) { - const CImg& img = (*this)[l]; - if (img) { - dx = std::max(dx,img._width); - dy = std::max(dy,img._height); - dz = std::max(dz,img._depth); - dc+=img._spectrum; - } - } - res.assign(dx,dy,dz,dc,(T)0); - if (res) cimglist_for(*this,l) { - const CImg& img = (*this)[l]; - if (img) { - if (img._width==1 && img._height==1 && img._depth==1 && - res._width==1 && res._height==1 && res._depth==1) - std::memcpy(&res[pos],img._data,sizeof(T)*img._spectrum); - else - res.draw_image((int)(align*(dx - img._width)), - (int)(align*(dy - img._height)), - (int)(align*(dz - img._depth)), - pos, - img); - } - pos+=img._spectrum; - } - } - } - return res; - } - - //! Return a list where each image has been split along the specified axis. - /** - \param axis Axis to split images along. - \param nb Number of split parts for each image. - **/ - CImgList& split(const char axis, const int nb=-1) { - return get_split(axis,nb).move_to(*this); - } - - //! Return a list where each image has been split along the specified axis \newinstance. - CImgList get_split(const char axis, const int nb=-1) const { - CImgList res; - cimglist_for(*this,l) _data[l].get_split(axis,nb).move_to(res,~0U); - return res; - } - - //! Insert image at the end of the list. - /** - \param img Image to insert. - **/ - template - CImgList& push_back(const CImg& img) { - return insert(img); - } - - //! Insert image at the front of the list. - /** - \param img Image to insert. - **/ - template - CImgList& push_front(const CImg& img) { - return insert(img,0); - } - - //! Insert list at the end of the current list. - /** - \param list List to insert. - **/ - template - CImgList& push_back(const CImgList& list) { - return insert(list); - } - - //! Insert list at the front of the current list. - /** - \param list List to insert. - **/ - template - CImgList& push_front(const CImgList& list) { - return insert(list,0); - } - - //! Remove last image. - /** - **/ - CImgList& pop_back() { - return remove(_width - 1); - } - - //! Remove first image. - /** - **/ - CImgList& pop_front() { - return remove(0); - } - - //! Remove image pointed by iterator. - /** - \param iter Iterator pointing to the image to remove. - **/ - CImgList& erase(const iterator iter) { - return remove(iter - _data); - } - - //@} - //---------------------------------- - // - //! \name Data Input - //@{ - //---------------------------------- - - //! Display a simple interactive interface to select images or sublists. - /** - \param disp Window instance to display selection and user interface. - \param feature_type Can be \c false to select a single image, or \c true to select a sublist. - \param axis Axis along whom images are appended for visualization. - \param align Alignment setting when images have not all the same size. - \param exit_on_anykey Exit function when any key is pressed. - \return A one-column vector containing the selected image indexes. - **/ - CImg get_select(CImgDisplay &disp, const bool feature_type=true, - const char axis='x', const float align=0, - const bool exit_on_anykey=false) const { - return _select(disp,0,feature_type,axis,align,exit_on_anykey,0,false,false,false); - } - - //! Display a simple interactive interface to select images or sublists. - /** - \param title Title of a new window used to display selection and user interface. - \param feature_type Can be \c false to select a single image, or \c true to select a sublist. - \param axis Axis along whom images are appended for visualization. - \param align Alignment setting when images have not all the same size. - \param exit_on_anykey Exit function when any key is pressed. - \return A one-column vector containing the selected image indexes. - **/ - CImg get_select(const char *const title, const bool feature_type=true, - const char axis='x', const float align=0, - const bool exit_on_anykey=false) const { - CImgDisplay disp; - return _select(disp,title,feature_type,axis,align,exit_on_anykey,0,false,false,false); - } - - CImg _select(CImgDisplay &disp, const char *const title, const bool feature_type, - const char axis, const float align, const bool exit_on_anykey, - const unsigned int orig, const bool resize_disp, - const bool exit_on_rightbutton, const bool exit_on_wheel) const { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "select(): Empty instance.", - cimglist_instance); - - // Create image correspondence table and get list dimensions for visualization. - CImgList _indices; - unsigned int max_width = 0, max_height = 0, sum_width = 0, sum_height = 0; - cimglist_for(*this,l) { - const CImg& img = _data[l]; - const unsigned int - w = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,false), - h = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,true); - if (w>max_width) max_width = w; - if (h>max_height) max_height = h; - sum_width+=w; sum_height+=h; - if (axis=='x') CImg(w,1,1,1,(unsigned int)l).move_to(_indices); - else CImg(h,1,1,1,(unsigned int)l).move_to(_indices); - } - const CImg indices0 = _indices>'x'; - - // Create display window. - if (!disp) { - if (axis=='x') disp.assign(cimg_fitscreen(sum_width,max_height,1),title?title:0,1); - else disp.assign(cimg_fitscreen(max_width,sum_height,1),title?title:0,1); - if (!title) disp.set_title("CImgList<%s> (%u)",pixel_type(),_width); - } else { - if (title) disp.set_title("%s",title); - disp.move_inside_screen(); - } - if (resize_disp) { - if (axis=='x') disp.resize(cimg_fitscreen(sum_width,max_height,1),false); - else disp.resize(cimg_fitscreen(max_width,sum_height,1),false); - } - - const unsigned int old_normalization = disp.normalization(); - bool old_is_resized = disp.is_resized(); - disp._normalization = 0; - disp.show().set_key(0).show_mouse(); - static const unsigned char foreground_color[] = { 255,255,255 }, background_color[] = { 0,0,0 }; - - // Enter event loop. - CImg visu0, visu; - CImg indices; - CImg positions(_width,4,1,1,-1); - int oindex0 = -1, oindex1 = -1, index0 = -1, index1 = -1; - bool is_clicked = false, is_selected = false, text_down = false, update_display = true; - unsigned int key = 0, font_size = 32; - - while (!is_selected && !disp.is_closed() && !key) { - - // Create background image. - if (!visu0) { - visu0.assign(disp._width,disp._height,1,3,0); visu.assign(); - (indices0.get_resize(axis=='x'?visu0._width:visu0._height,1)).move_to(indices); - unsigned int _ind = 0; - const CImg onexone(1,1,1,1,(T)0); - if (axis=='x') - cimg_pragma_openmp(parallel for cimg_openmp_if_size(_width,4)) - cimglist_for(*this,ind) { - unsigned int x0 = 0; - while (x0 &src = _data[ind]?_data[ind]:onexone; - CImg res; - src._get_select(disp,old_normalization,src._width/2,src._height/2,src._depth/2). - move_to(res); - const unsigned int h = CImgDisplay::_fitscreen(res._width,res._height,1,128,-85,true); - res.resize(x1 - x0,std::max(32U,h*disp._height/max_height),1,res._spectrum==1?3:-100); - positions(ind,0) = positions(ind,2) = (int)x0; - positions(ind,1) = positions(ind,3) = (int)(align*(visu0.height() - res.height())); - positions(ind,2)+=res._width; - positions(ind,3)+=res._height - 1; - visu0.draw_image(positions(ind,0),positions(ind,1),res); - } - else - cimg_pragma_openmp(parallel for cimg_openmp_if_size(_width,4)) - cimglist_for(*this,ind) { - unsigned int y0 = 0; - while (y0 &src = _data[ind]?_data[ind]:onexone; - CImg res; - src._get_select(disp,old_normalization,(src._width - 1)/2,(src._height - 1)/2,(src._depth - 1)/2). - move_to(res); - const unsigned int w = CImgDisplay::_fitscreen(res._width,res._height,1,128,-85,false); - res.resize(std::max(32U,w*disp._width/max_width),y1 - y0,1,res._spectrum==1?3:-100); - positions(ind,0) = positions(ind,2) = (int)(align*(visu0.width() - res.width())); - positions(ind,1) = positions(ind,3) = (int)y0; - positions(ind,2)+=res._width - 1; - positions(ind,3)+=res._height; - visu0.draw_image(positions(ind,0),positions(ind,1),res); - } - if (axis=='x') --positions(_ind,2); else --positions(_ind,3); - update_display = true; - } - - if (!visu || oindex0!=index0 || oindex1!=index1) { - if (index0>=0 && index1>=0) { - visu.assign(visu0,false); - const int indm = std::min(index0,index1), indM = std::max(index0,index1); - for (int ind = indm; ind<=indM; ++ind) if (positions(ind,0)>=0) { - visu.draw_rectangle(positions(ind,0),positions(ind,1),positions(ind,2),positions(ind,3), - background_color,0.2f); - if ((axis=='x' && positions(ind,2) - positions(ind,0)>=8) || - (axis!='x' && positions(ind,3) - positions(ind,1)>=8)) - visu.draw_rectangle(positions(ind,0),positions(ind,1),positions(ind,2),positions(ind,3), - foreground_color,0.9f,0xAAAAAAAA); - } - if (is_clicked) visu.__draw_text(" Images #%u - #%u, Size = %u ",font_size,(int)text_down, - orig + indm,orig + indM,indM - indm + 1); - else visu.__draw_text(" Image #%u (%u,%u,%u,%u) ",font_size,(int)text_down, - orig + index0, - _data[index0]._width, - _data[index0]._height, - _data[index0]._depth, - _data[index0]._spectrum); - update_display = true; - } else visu.assign(); - } - if (!visu) { visu.assign(visu0,true); update_display = true; } - if (update_display) { visu.display(disp); update_display = false; } - disp.wait(); - - // Manage user events. - const int xm = disp.mouse_x(), ym = disp.mouse_y(); - int index = -1; - - if (xm>=0) { - index = (int)indices(axis=='x'?xm:ym); - if (disp.button()&1) { - if (!is_clicked) { is_clicked = true; oindex0 = index0; index0 = index; } - oindex1 = index1; index1 = index; - if (!feature_type) is_selected = true; - } else { - if (!is_clicked) { oindex0 = oindex1 = index0; index0 = index1 = index; } - else is_selected = true; - } - } else { - if (is_clicked) { - if (!(disp.button()&1)) { is_clicked = is_selected = false; index0 = index1 = -1; } - else index1 = -1; - } else index0 = index1 = -1; - } - - if (disp.button()&4) { is_clicked = is_selected = false; index0 = index1 = -1; } - if (disp.button()&2 && exit_on_rightbutton) { is_selected = true; index1 = index0 = -1; } - if (disp.wheel() && exit_on_wheel) is_selected = true; - - CImg filename(32); - switch (key = disp.key()) { -#if cimg_OS!=2 - case cimg::keyCTRLRIGHT : -#endif - case 0 : case cimg::keyCTRLLEFT : key = 0; break; - case cimg::keyD : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,false), - CImgDisplay::_fitscreen(3*disp.width()/2,3*disp.height()/2,1,128,-100,true),false). - _is_resized = true; - disp.set_key(key,false); key = 0; visu0.assign(); - } break; - case cimg::keyC : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(cimg_fitscreen(2*disp.width()/3,2*disp.height()/3,1),false)._is_resized = true; - disp.set_key(key,false); key = 0; visu0.assign(); - } break; - case cimg::keyR : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.set_fullscreen(false). - resize(cimg_fitscreen(axis=='x'?sum_width:max_width,axis=='x'?max_height:sum_height,1),false). - _is_resized = true; - disp.set_key(key,false); key = 0; visu0.assign(); - } break; - case cimg::keyF : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - disp.resize(disp.screen_width(),disp.screen_height(),false).toggle_fullscreen()._is_resized = true; - disp.set_key(key,false); key = 0; visu0.assign(); - } break; - case cimg::keyS : if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - static unsigned int snap_number = 0; - std::FILE *file; - do { - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.bmp",snap_number++); - if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file); - } while (file); - if (visu0) { - (+visu0).__draw_text(" Saving snapshot... ",font_size,(int)text_down).display(disp); - visu0.save(filename); - (+visu0).__draw_text(" Snapshot '%s' saved. ",font_size,(int)text_down,filename._data).display(disp); - } - disp.set_key(key,false).wait(); key = 0; - } break; - case cimg::keyO : - if (disp.is_keyCTRLLEFT() || disp.is_keyCTRLRIGHT()) { - static unsigned int snap_number = 0; - std::FILE *file; - do { -#ifdef cimg_use_zlib - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimgz",snap_number++); -#else - cimg_snprintf(filename,filename._width,cimg_appname "_%.4u.cimg",snap_number++); -#endif - if ((file=cimg::std_fopen(filename,"r"))!=0) cimg::fclose(file); - } while (file); - (+visu0).__draw_text(" Saving instance... ",font_size,(int)text_down).display(disp); - save(filename); - (+visu0).__draw_text(" Instance '%s' saved. ",font_size,(int)text_down,filename._data).display(disp); - disp.set_key(key,false).wait(); key = 0; - } break; - } - if (disp.is_resized()) { disp.resize(false); visu0.assign(); } - if (ym>=0 && ym<13) { if (!text_down) { visu.assign(); text_down = true; }} - else if (ym>=visu.height() - 13) { if (text_down) { visu.assign(); text_down = false; }} - if (!exit_on_anykey && key && key!=cimg::keyESC && - (key!=cimg::keyW || (!disp.is_keyCTRLLEFT() && !disp.is_keyCTRLRIGHT()))) { - key = 0; - } - } - CImg res(1,2,1,1,-1); - if (is_selected) { - if (feature_type) res.fill(std::min(index0,index1),std::max(index0,index1)); - else res.fill(index0); - } - if (!(disp.button()&2)) disp.set_button(); - disp._normalization = old_normalization; - disp._is_resized = old_is_resized; - disp.set_key(key); - return res; - } - - //! Load a list from a file. - /** - \param filename Filename to read data from. - **/ - CImgList& load(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimglist_instance - "load(): Specified filename is (null).", - cimglist_instance); - - if (!cimg::strncasecmp(filename,"http://",7) || !cimg::strncasecmp(filename,"https://",8)) { - CImg filename_local(256); - load(cimg::load_network(filename,filename_local)); - std::remove(filename_local); - return *this; - } - - const bool is_stdin = *filename=='-' && (!filename[1] || filename[1]=='.'); - const char *const ext = cimg::split_filename(filename); - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - bool is_loaded = true; - try { -#ifdef cimglist_load_plugin - cimglist_load_plugin(filename); -#endif -#ifdef cimglist_load_plugin1 - cimglist_load_plugin1(filename); -#endif -#ifdef cimglist_load_plugin2 - cimglist_load_plugin2(filename); -#endif -#ifdef cimglist_load_plugin3 - cimglist_load_plugin3(filename); -#endif -#ifdef cimglist_load_plugin4 - cimglist_load_plugin4(filename); -#endif -#ifdef cimglist_load_plugin5 - cimglist_load_plugin5(filename); -#endif -#ifdef cimglist_load_plugin6 - cimglist_load_plugin6(filename); -#endif -#ifdef cimglist_load_plugin7 - cimglist_load_plugin7(filename); -#endif -#ifdef cimglist_load_plugin8 - cimglist_load_plugin8(filename); -#endif - if (!cimg::strcasecmp(ext,"tif") || - !cimg::strcasecmp(ext,"tiff")) load_tiff(filename); - else if (!cimg::strcasecmp(ext,"gif")) load_gif_external(filename); - else if (!cimg::strcasecmp(ext,"cimg") || - !cimg::strcasecmp(ext,"cimgz") || - !*ext) load_cimg(filename); - else if (!cimg::strcasecmp(ext,"rec") || - !cimg::strcasecmp(ext,"par")) load_parrec(filename); - else if (!cimg::strcasecmp(ext,"avi") || - !cimg::strcasecmp(ext,"mov") || - !cimg::strcasecmp(ext,"asf") || - !cimg::strcasecmp(ext,"divx") || - !cimg::strcasecmp(ext,"flv") || - !cimg::strcasecmp(ext,"mpg") || - !cimg::strcasecmp(ext,"m1v") || - !cimg::strcasecmp(ext,"m2v") || - !cimg::strcasecmp(ext,"m4v") || - !cimg::strcasecmp(ext,"mjp") || - !cimg::strcasecmp(ext,"mp4") || - !cimg::strcasecmp(ext,"mkv") || - !cimg::strcasecmp(ext,"mpe") || - !cimg::strcasecmp(ext,"movie") || - !cimg::strcasecmp(ext,"ogm") || - !cimg::strcasecmp(ext,"ogg") || - !cimg::strcasecmp(ext,"ogv") || - !cimg::strcasecmp(ext,"qt") || - !cimg::strcasecmp(ext,"rm") || - !cimg::strcasecmp(ext,"vob") || - !cimg::strcasecmp(ext,"webm") || - !cimg::strcasecmp(ext,"wmv") || - !cimg::strcasecmp(ext,"xvid") || - !cimg::strcasecmp(ext,"mpeg")) load_video(filename); - else if (!cimg::strcasecmp(ext,"gz")) load_gzip_external(filename); - else is_loaded = false; - } catch (CImgIOException&) { is_loaded = false; } - - // If nothing loaded, try to guess file format from magic number in file. - if (!is_loaded && !is_stdin) { - std::FILE *const file = cimg::std_fopen(filename,"rb"); - if (!file) { - cimg::exception_mode(omode); - throw CImgIOException(_cimglist_instance - "load(): Failed to open file '%s'.", - cimglist_instance, - filename); - } - - const char *const f_type = cimg::ftype(file,filename); - cimg::fclose(file); - is_loaded = true; - try { - if (!cimg::strcasecmp(f_type,"gif")) load_gif_external(filename); - else if (!cimg::strcasecmp(f_type,"tif") && - cimg::strcasecmp(ext,"nef") && - cimg::strcasecmp(ext,"dng")) load_tiff(filename); - else is_loaded = false; - } catch (CImgIOException&) { is_loaded = false; } - } - - // If nothing loaded, try to load file as a single image. - if (!is_loaded) { - assign(1); - try { - _data->load(filename); - } catch (CImgIOException&) { - cimg::exception_mode(omode); - throw CImgIOException(_cimglist_instance - "load(): Failed to recognize format of file '%s'.", - cimglist_instance, - filename); - } - } - cimg::exception_mode(omode); - return *this; - } - - //! Load a list from a file \newinstance. - static CImgList get_load(const char *const filename) { - return CImgList().load(filename); - } - - //! Load a list from a .cimg file. - /** - \param filename Filename to read data from. - **/ - CImgList& load_cimg(const char *const filename) { - return _load_cimg(0,filename); - } - - //! Load a list from a .cimg file \newinstance. - static CImgList get_load_cimg(const char *const filename) { - return CImgList().load_cimg(filename); - } - - //! Load a list from a .cimg file. - /** - \param file File to read data from. - **/ - CImgList& load_cimg(std::FILE *const file) { - return _load_cimg(file,0); - } - - //! Load a list from a .cimg file \newinstance. - static CImgList get_load_cimg(std::FILE *const file) { - return CImgList().load_cimg(file); - } - - CImgList& _load_cimg(std::FILE *const file, const char *const filename) { -#ifdef cimg_use_zlib -#define _cimgz_load_cimg_case(Tss) { \ - Bytef *const cbuf = new Bytef[csiz]; \ - cimg::fread(cbuf,(size_t)csiz,nfile); \ - if (is_bool) { \ - CImg raw(W*H*D*C/8); \ - uLongf destlen = (uLongf)raw.size(); \ - uncompress((Bytef*)raw._data,&destlen,cbuf,(uLong)csiz); \ - img.assign(W,H,D,C); \ - img._uchar2bool(raw,raw.size(),false); \ - } else { \ - CImg raw(W,H,D,C); \ - uLongf destlen = (uLongf)(raw.size()*sizeof(Tss)); \ - uncompress((Bytef*)raw._data,&destlen,cbuf,(uLong)csiz); \ - if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \ - raw.move_to(img); \ - } \ - delete[] cbuf; \ -} -#else -#define _cimgz_load_cimg_case(Tss) \ - throw CImgIOException(_cimglist_instance \ - "load_cimg(): Unable to load compressed data from file '%s' unless zlib is enabled.", \ - cimglist_instance, \ - filename?filename:"(FILE*)"); -#endif - -#define _cimg_load_cimg_case(Ts1,Ts2,Ts3,Tss) \ - if (!loaded && ((Ts1 && !cimg::strcasecmp(Ts1,str_pixeltype)) || \ - (Ts2 && !cimg::strcasecmp(Ts2,str_pixeltype)) || \ - (Ts3 && !cimg::strcasecmp(Ts3,str_pixeltype)))) { \ - const bool is_bool = cimg::type::string()==cimg::type::string(); \ - for (unsigned int l = 0; l=0 && j<255) tmp[j++] = (char)i; tmp[j] = 0; \ - W = H = D = C = 0; csiz = 0; \ - if ((err = cimg_sscanf(tmp,"%u %u %u %u #" cimg_fuint64,&W,&H,&D,&C,&csiz))<4) \ - throw CImgIOException(_cimglist_instance \ - "load_cimg(): Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'.", \ - cimglist_instance, \ - W,H,D,C,l,filename?filename:("(FILE*)")); \ - if (W*H*D*C>0) { \ - CImg &img = _data[l]; \ - if (err==5) _cimgz_load_cimg_case(Tss) \ - else { \ - img.assign(W,H,D,C); \ - T *ptrd = img._data; \ - if (is_bool) { \ - CImg raw; \ - for (ulongT to_read = img.size(); to_read; ) { \ - raw.assign((unsigned int)std::min(to_read,cimg_iobuffer)); \ - cimg::fread(raw._data,raw._width,nfile); \ - CImg(ptrd,std::min(8*raw._width,(unsigned int)(img.end() - ptrd)),1,1,1,true).\ - _uchar2bool(raw,raw._width,false); \ - to_read-=raw._width; \ - } \ - } else { \ - CImg raw; \ - for (ulongT to_read = img.size(); to_read; ) { \ - raw.assign((unsigned int)std::min(to_read,cimg_iobuffer)); \ - cimg::fread(raw._data,raw._width,nfile); \ - if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \ - const Tss *ptrs = raw._data; \ - for (ulongT off = (ulongT)raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \ - to_read-=raw._width; \ - } \ - } \ - } \ - } \ - } \ - loaded = true; \ - } - - if (!filename && !file) - throw CImgArgumentException(_cimglist_instance - "load_cimg(): Specified filename is (null).", - cimglist_instance); - - const ulongT cimg_iobuffer = (ulongT)24*1024*1024; - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - bool loaded = false, endian = cimg::endianness(); - CImg tmp(256), str_pixeltype(256), str_endian(256); - *tmp = *str_pixeltype = *str_endian = 0; - unsigned int j, N = 0, W, H, D, C; - cimg_uint64 csiz; - int i, err; - do { - j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0 && j<255) tmp[j++] = (char)i; tmp[j] = 0; - } while (*tmp=='#' && i>=0); - err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z123468_]%*c%255[sA-Za-z_ ]", - &N,str_pixeltype._data,str_endian._data); - if (err<2) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimglist_instance - "load_cimg(): File or CImg header not found in file '%s'.", - cimglist_instance, - filename?filename:"(FILE*)"); - } - if (!cimg::strncasecmp("little",str_endian,6)) endian = false; - else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; - assign(N); - _cimg_load_cimg_case("bool",0,0,cimg_uint8); - _cimg_load_cimg_case("uint8","unsigned_char","uchar",cimg_uint8); - _cimg_load_cimg_case("int8",0,0,cimg_int8); - _cimg_load_cimg_case("char",0,0,char); - _cimg_load_cimg_case("uint16","unsigned_short","ushort",cimg_uint16); - _cimg_load_cimg_case("int16","short",0,cimg_int16); - _cimg_load_cimg_case("uint32","unsigned_int","uint",cimg_uint32); - _cimg_load_cimg_case("int32","int",0,cimg_int32); - _cimg_load_cimg_case("unsigned_long","ulong",0,cimg_ulong); - _cimg_load_cimg_case("long",0,0,cimg_long); - _cimg_load_cimg_case("uint64","unsigned_int64",0,cimg_uint64); - _cimg_load_cimg_case("int64",0,0,cimg_int64); - _cimg_load_cimg_case("float32","float",0,cimg_float32); - _cimg_load_cimg_case("float64","double",0,cimg_float64); - - if (!loaded) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimglist_instance - "load_cimg(): Unsupported pixel type '%s' for file '%s'.", - cimglist_instance, - str_pixeltype._data,filename?filename:"(FILE*)"); - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Load a sublist list from a (non compressed) .cimg file. - /** - \param filename Filename to read data from. - \param n0 Starting index of images to read (~0U for max). - \param n1 Ending index of images to read (~0U for max). - \param x0 Starting X-coordinates of image regions to read. - \param y0 Starting Y-coordinates of image regions to read. - \param z0 Starting Z-coordinates of image regions to read. - \param c0 Starting C-coordinates of image regions to read. - \param x1 Ending X-coordinates of image regions to read (~0U for max). - \param y1 Ending Y-coordinates of image regions to read (~0U for max). - \param z1 Ending Z-coordinates of image regions to read (~0U for max). - \param c1 Ending C-coordinates of image regions to read (~0U for max). - **/ - CImgList& load_cimg(const char *const filename, - const unsigned int n0, const unsigned int n1, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0, - const unsigned int x1, const unsigned int y1, - const unsigned int z1, const unsigned int c1) { - return _load_cimg(0,filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); - } - - //! Load a sublist list from a (non compressed) .cimg file \newinstance. - static CImgList get_load_cimg(const char *const filename, - const unsigned int n0, const unsigned int n1, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0, - const unsigned int x1, const unsigned int y1, - const unsigned int z1, const unsigned int c1) { - return CImgList().load_cimg(filename,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); - } - - //! Load a sub-image list from a (non compressed) .cimg file \overloading. - CImgList& load_cimg(std::FILE *const file, - const unsigned int n0, const unsigned int n1, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0, - const unsigned int x1, const unsigned int y1, - const unsigned int z1, const unsigned int c1) { - return _load_cimg(file,0,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); - } - - //! Load a sub-image list from a (non compressed) .cimg file \newinstance. - static CImgList get_load_cimg(std::FILE *const file, - const unsigned int n0, const unsigned int n1, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0, - const unsigned int x1, const unsigned int y1, - const unsigned int z1, const unsigned int c1) { - return CImgList().load_cimg(file,n0,n1,x0,y0,z0,c0,x1,y1,z1,c1); - } - - CImgList& _load_cimg(std::FILE *const file, const char *const filename, - const unsigned int n0, const unsigned int n1, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0, - const unsigned int x1, const unsigned int y1, - const unsigned int z1, const unsigned int c1) { -#define _cimg_load_cimg_case2(Ts1,Ts2,Ts3,Tss) \ - if (!loaded && ((Ts1 && !cimg::strcasecmp(Ts1,str_pixeltype)) || \ - (Ts2 && !cimg::strcasecmp(Ts2,str_pixeltype)) || \ - (Ts3 && !cimg::strcasecmp(Ts3,str_pixeltype)))) { \ - for (unsigned int l = 0; l<=nn1; ++l) { \ - j = 0; while ((i=std::fgetc(nfile))!='\n' && i>=0) tmp[j++] = (char)i; tmp[j] = 0; \ - W = H = D = C = 0; \ - if (cimg_sscanf(tmp,"%u %u %u %u",&W,&H,&D,&C)!=4) \ - throw CImgIOException(_cimglist_instance \ - "load_cimg(): Invalid specified size (%u,%u,%u,%u) of image %u in file '%s'", \ - cimglist_instance, \ - W,H,D,C,l,filename?filename:"(FILE*)"); \ - if (W*H*D*C>0) { \ - if (l=W || ny0>=H || nz0>=D || nc0>=C) cimg::fseek(nfile,W*H*D*C*sizeof(Tss),SEEK_CUR); \ - else { \ - const unsigned int \ - _nx1 = nx1==~0U?W - 1:nx1, \ - _ny1 = ny1==~0U?H - 1:ny1, \ - _nz1 = nz1==~0U?D - 1:nz1, \ - _nc1 = nc1==~0U?C - 1:nc1; \ - if (_nx1>=W || _ny1>=H || _nz1>=D || _nc1>=C) \ - throw CImgArgumentException(_cimglist_instance \ - "load_cimg(): Invalid specified coordinates " \ - "[%u](%u,%u,%u,%u) -> [%u](%u,%u,%u,%u) " \ - "because image [%u] in file '%s' has size (%u,%u,%u,%u).", \ - cimglist_instance, \ - n0,x0,y0,z0,c0,n1,x1,y1,z1,c1,l,filename?filename:"(FILE*)",W,H,D,C); \ - CImg raw(1 + _nx1 - nx0); \ - CImg &img = _data[l - nn0]; \ - img.assign(1 + _nx1 - nx0,1 + _ny1 - ny0,1 + _nz1 - nz0,1 + _nc1 - nc0); \ - T *ptrd = img._data; \ - ulongT skipvb = nc0*W*H*D*sizeof(Tss); \ - if (skipvb) cimg::fseek(nfile,skipvb,SEEK_CUR); \ - for (unsigned int c = 1 + _nc1 - nc0; c; --c) { \ - const ulongT skipzb = nz0*W*H*sizeof(Tss); \ - if (skipzb) cimg::fseek(nfile,skipzb,SEEK_CUR); \ - for (unsigned int z = 1 + _nz1 - nz0; z; --z) { \ - const ulongT skipyb = ny0*W*sizeof(Tss); \ - if (skipyb) cimg::fseek(nfile,skipyb,SEEK_CUR); \ - for (unsigned int y = 1 + _ny1 - ny0; y; --y) { \ - const ulongT skipxb = nx0*sizeof(Tss); \ - if (skipxb) cimg::fseek(nfile,skipxb,SEEK_CUR); \ - cimg::fread(raw._data,raw._width,nfile); \ - if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw._width); \ - const Tss *ptrs = raw._data; \ - for (unsigned int off = raw._width; off; --off) *(ptrd++) = (T)*(ptrs++); \ - const ulongT skipxe = (W - 1 - _nx1)*sizeof(Tss); \ - if (skipxe) cimg::fseek(nfile,skipxe,SEEK_CUR); \ - } \ - const ulongT skipye = (H - 1 - _ny1)*W*sizeof(Tss); \ - if (skipye) cimg::fseek(nfile,skipye,SEEK_CUR); \ - } \ - const ulongT skipze = (D - 1 - _nz1)*W*H*sizeof(Tss); \ - if (skipze) cimg::fseek(nfile,skipze,SEEK_CUR); \ - } \ - const ulongT skipve = (C - 1 - _nc1)*W*H*D*sizeof(Tss); \ - if (skipve) cimg::fseek(nfile,skipve,SEEK_CUR); \ - } \ - } \ - } \ - loaded = true; \ - } - - if (!filename && !file) - throw CImgArgumentException(_cimglist_instance - "load_cimg(): Specified filename is (null).", - cimglist_instance); - unsigned int - nn0 = std::min(n0,n1), nn1 = std::max(n0,n1), - nx0 = std::min(x0,x1), nx1 = std::max(x0,x1), - ny0 = std::min(y0,y1), ny1 = std::max(y0,y1), - nz0 = std::min(z0,z1), nz1 = std::max(z0,z1), - nc0 = std::min(c0,c1), nc1 = std::max(c0,c1); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - bool loaded = false, endian = cimg::endianness(); - CImg tmp(256), str_pixeltype(256), str_endian(256); - *tmp = *str_pixeltype = *str_endian = 0; - unsigned int j, N, W, H, D, C; - int i, err; - j = 0; while ((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0; - err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z123468_]%*c%255[sA-Za-z_ ]", - &N,str_pixeltype._data,str_endian._data); - if (err<2) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimglist_instance - "load_cimg(): CImg header not found in file '%s'.", - cimglist_instance, - filename?filename:"(FILE*)"); - } - if (!cimg::strncasecmp("little",str_endian,6)) endian = false; - else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; - nn1 = n1==~0U?N - 1:n1; - if (nn1>=N) - throw CImgArgumentException(_cimglist_instance - "load_cimg(): Invalid specified coordinates [%u](%u,%u,%u,%u) -> [%u](%u,%u,%u,%u) " - "because file '%s' contains only %u images.", - cimglist_instance, - n0,x0,y0,z0,c0,n1,x1,y1,z1,c1,filename?filename:"(FILE*)",N); - assign(1 + nn1 - n0); - _cimg_load_cimg_case2("bool",0,0,cimg_uint8); - _cimg_load_cimg_case2("uint8","unsigned char","uchar",cimg_uint8); - _cimg_load_cimg_case2("int8",0,0,cimg_int8); - _cimg_load_cimg_case2("char",0,0,char); - _cimg_load_cimg_case2("uint16","unsigned_short","ushort",cimg_uint16); - _cimg_load_cimg_case2("int16","short",0,cimg_int16); - _cimg_load_cimg_case2("uint32","unsigned_int","uint",cimg_uint32); - _cimg_load_cimg_case2("int32","int",0,cimg_int32); - _cimg_load_cimg_case2("unsigned_long","ulong",0,cimg_ulong); - _cimg_load_cimg_case2("long",0,0,cimg_long); - _cimg_load_cimg_case2("uint64","unsigned_int64",0,cimg_uint64); - _cimg_load_cimg_case2("int64",0,0,cimg_int64); - _cimg_load_cimg_case2("float32","float",0,cimg_float32); - _cimg_load_cimg_case2("float64","double",0,cimg_float64); - if (!loaded) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimglist_instance - "load_cimg(): Unsupported pixel type '%s' for file '%s'.", - cimglist_instance, - str_pixeltype._data,filename?filename:"(FILE*)"); - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Load a list from a PAR/REC (Philips) file. - /** - \param filename Filename to read data from. - **/ - CImgList& load_parrec(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimglist_instance - "load_parrec(): Specified filename is (null).", - cimglist_instance); - - CImg body(1024), filenamepar(1024), filenamerec(1024); - *body = *filenamepar = *filenamerec = 0; - const char *const ext = cimg::split_filename(filename,body); - if (!std::strcmp(ext,"par")) { - std::strncpy(filenamepar,filename,filenamepar._width - 1); - cimg_snprintf(filenamerec,filenamerec._width,"%s.rec",body._data); - } - if (!std::strcmp(ext,"PAR")) { - std::strncpy(filenamepar,filename,filenamepar._width - 1); - cimg_snprintf(filenamerec,filenamerec._width,"%s.REC",body._data); - } - if (!std::strcmp(ext,"rec")) { - std::strncpy(filenamerec,filename,filenamerec._width - 1); - cimg_snprintf(filenamepar,filenamepar._width,"%s.par",body._data); - } - if (!std::strcmp(ext,"REC")) { - std::strncpy(filenamerec,filename,filenamerec._width - 1); - cimg_snprintf(filenamepar,filenamepar._width,"%s.PAR",body._data); - } - std::FILE *file = cimg::fopen(filenamepar,"r"); - - // Parse header file - CImgList st_slices; - CImgList st_global; - CImg line(256); *line = 0; - int err; - do { err = std::fscanf(file,"%255[^\n]%*c",line._data); } while (err!=EOF && (*line=='#' || *line=='.')); - do { - unsigned int sn,size_x,size_y,pixsize; - float rs,ri,ss; - err = std::fscanf(file,"%u%*u%*u%*u%*u%*u%*u%u%*u%u%u%g%g%g%*[^\n]",&sn,&pixsize,&size_x,&size_y,&ri,&rs,&ss); - if (err==7) { - CImg::vector((float)sn,(float)pixsize,(float)size_x,(float)size_y,ri,rs,ss,0).move_to(st_slices); - unsigned int i; for (i = 0; i::vector(size_x,size_y,sn).move_to(st_global); - else { - CImg &vec = st_global[i]; - if (size_x>vec[0]) vec[0] = size_x; - if (size_y>vec[1]) vec[1] = size_y; - vec[2] = sn; - } - st_slices[st_slices._width - 1][7] = (float)i; - } - } while (err==7); - - // Read data - std::FILE *file2 = cimg::fopen(filenamerec,"rb"); - cimglist_for(st_global,l) { - const CImg& vec = st_global[l]; - CImg(vec[0],vec[1],vec[2]).move_to(*this); - } - - cimglist_for(st_slices,l) { - const CImg& vec = st_slices[l]; - const unsigned int - sn = (unsigned int)vec[0] - 1, - pixsize = (unsigned int)vec[1], - size_x = (unsigned int)vec[2], - size_y = (unsigned int)vec[3], - imn = (unsigned int)vec[7]; - const float ri = vec[4], rs = vec[5], ss = vec[6]; - switch (pixsize) { - case 8 : { - CImg buf(size_x,size_y); - cimg::fread(buf._data,size_x*size_y,file2); - if (cimg::endianness()) cimg::invert_endianness(buf._data,size_x*size_y); - CImg& img = (*this)[imn]; - cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); - } break; - case 16 : { - CImg buf(size_x,size_y); - cimg::fread(buf._data,size_x*size_y,file2); - if (cimg::endianness()) cimg::invert_endianness(buf._data,size_x*size_y); - CImg& img = (*this)[imn]; - cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); - } break; - case 32 : { - CImg buf(size_x,size_y); - cimg::fread(buf._data,size_x*size_y,file2); - if (cimg::endianness()) cimg::invert_endianness(buf._data,size_x*size_y); - CImg& img = (*this)[imn]; - cimg_forXY(img,x,y) img(x,y,sn) = (T)(( buf(x,y)*rs + ri )/(rs*ss)); - } break; - default : - cimg::fclose(file); - cimg::fclose(file2); - throw CImgIOException(_cimglist_instance - "load_parrec(): Unsupported %d-bits pixel type for file '%s'.", - cimglist_instance, - pixsize,filename); - } - } - cimg::fclose(file); - cimg::fclose(file2); - if (!_width) - throw CImgIOException(_cimglist_instance - "load_parrec(): Failed to recognize valid PAR-REC data in file '%s'.", - cimglist_instance, - filename); - return *this; - } - - //! Load a list from a PAR/REC (Philips) file \newinstance. - static CImgList get_load_parrec(const char *const filename) { - return CImgList().load_parrec(filename); - } - - //! Load a list from a YUV image sequence file. - /** - \param filename Filename to read data from. - \param size_x Width of the images. - \param size_y Height of the images. - \param chroma_subsampling Type of chroma subsampling. Can be { 420 | 422 | 444 }. - \param first_frame Index of first image frame to read. - \param last_frame Index of last image frame to read. - \param step_frame Step applied between each frame. - \param yuv2rgb Apply YUV to RGB transformation during reading. - **/ - CImgList& load_yuv(const char *const filename, - const unsigned int size_x, const unsigned int size_y, - const unsigned int chroma_subsampling=444, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool yuv2rgb=true) { - return _load_yuv(0,filename,size_x,size_y,chroma_subsampling, - first_frame,last_frame,step_frame,yuv2rgb); - } - - //! Load a list from a YUV image sequence file \newinstance. - static CImgList get_load_yuv(const char *const filename, - const unsigned int size_x, const unsigned int size_y=1, - const unsigned int chroma_subsampling=444, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool yuv2rgb=true) { - return CImgList().load_yuv(filename,size_x,size_y,chroma_subsampling, - first_frame,last_frame,step_frame,yuv2rgb); - } - - //! Load a list from an image sequence YUV file \overloading. - CImgList& load_yuv(std::FILE *const file, - const unsigned int size_x, const unsigned int size_y, - const unsigned int chroma_subsampling=444, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool yuv2rgb=true) { - return _load_yuv(file,0,size_x,size_y,chroma_subsampling, - first_frame,last_frame,step_frame,yuv2rgb); - } - - //! Load a list from an image sequence YUV file \newinstance. - static CImgList get_load_yuv(std::FILE *const file, - const unsigned int size_x, const unsigned int size_y=1, - const unsigned int chroma_subsampling=444, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, const bool yuv2rgb=true) { - return CImgList().load_yuv(file,size_x,size_y,chroma_subsampling, - first_frame,last_frame,step_frame,yuv2rgb); - } - - CImgList& _load_yuv(std::FILE *const file, const char *const filename, - const unsigned int size_x, const unsigned int size_y, - const unsigned int chroma_subsampling, - const unsigned int first_frame, const unsigned int last_frame, - const unsigned int step_frame, const bool yuv2rgb) { - if (!filename && !file) - throw CImgArgumentException(_cimglist_instance - "load_yuv(): Specified filename is (null).", - cimglist_instance); - if (chroma_subsampling!=420 && chroma_subsampling!=422 && chroma_subsampling!=444) - throw CImgArgumentException(_cimglist_instance - "load_yuv(): Specified chroma subsampling %u is invalid, for file '%s'.", - cimglist_instance, - chroma_subsampling,filename?filename:"(FILE*)"); - const unsigned int - cfx = chroma_subsampling==420 || chroma_subsampling==422?2:1, - cfy = chroma_subsampling==420?2:1, - nfirst_frame = first_frame YUV(size_x,size_y,1,3), UV(size_x/cfx,size_y/cfy,1,2); - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb"); - bool stop_flag = false; - int err; - if (nfirst_frame) { - err = cimg::fseek(nfile,(uint64T)nfirst_frame*(YUV._width*YUV._height + 2*UV._width*UV._height),SEEK_CUR); - if (err) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimglist_instance - "load_yuv(): File '%s' doesn't contain frame number %u.", - cimglist_instance, - filename?filename:"(FILE*)",nfirst_frame); - } - } - unsigned int frame; - for (frame = nfirst_frame; !stop_flag && frame<=nlast_frame; frame+=nstep_frame) { - YUV.get_shared_channel(0).fill(0); - // *TRY* to read the luminance part, do not replace by cimg::fread! - err = (int)std::fread((void*)(YUV._data),1,(size_t)YUV._width*YUV._height,nfile); - if (err!=(int)(YUV._width*YUV._height)) { - stop_flag = true; - if (err>0) - cimg::warn(_cimglist_instance - "load_yuv(): File '%s' contains incomplete data or given image dimensions " - "(%u,%u) are incorrect.", - cimglist_instance, - filename?filename:"(FILE*)",size_x,size_y); - } else { - UV.fill(0); - // *TRY* to read the luminance part, do not replace by cimg::fread! - err = (int)std::fread((void*)(UV._data),1,(size_t)UV.size(),nfile); - if (err!=(int)(UV.size())) { - stop_flag = true; - if (err>0) - cimg::warn(_cimglist_instance - "load_yuv(): File '%s' contains incomplete data or given image dimensions " - "(%u,%u) are incorrect.", - cimglist_instance, - filename?filename:"(FILE*)",size_x,size_y); - } else { - const ucharT *ptrs1 = UV._data, *ptrs2 = UV.data(0,0,0,1); - ucharT *ptrd1 = YUV.data(0,0,0,1), *ptrd2 = YUV.data(0,0,0,2); - const unsigned int wd = YUV._width; - switch (chroma_subsampling) { - case 420 : - cimg_forY(UV,y) { - cimg_forX(UV,x) { - const ucharT U = *(ptrs1++), V = *(ptrs2++); - ptrd1[wd] = U; *(ptrd1)++ = U; - ptrd1[wd] = U; *(ptrd1)++ = U; - ptrd2[wd] = V; *(ptrd2)++ = V; - ptrd2[wd] = V; *(ptrd2)++ = V; - } - ptrd1+=wd; ptrd2+=wd; - } - break; - case 422 : - cimg_forXY(UV,x,y) { - const ucharT U = *(ptrs1++), V = *(ptrs2++); - *(ptrd1++) = U; *(ptrd1++) = U; - *(ptrd2++) = V; *(ptrd2++) = V; - } - break; - default : - YUV.draw_image(0,0,0,1,UV); - } - if (yuv2rgb) YUV.YCbCrtoRGB(); - insert(YUV); - if (nstep_frame>1) cimg::fseek(nfile,(uint64T)(nstep_frame - 1)*(size_x*size_y + size_x*size_y/2),SEEK_CUR); - } - } - } - if (is_empty()) - throw CImgIOException(_cimglist_instance - "load_yuv() : Missing data in file '%s'.", - cimglist_instance, - filename?filename:"(FILE*)"); - if (stop_flag && nlast_frame!=~0U && frame!=nlast_frame) - cimg::warn(_cimglist_instance - "load_yuv(): Frame %d not reached since only %u frames were found in file '%s'.", - cimglist_instance, - nlast_frame,frame - 1,filename?filename:"(FILE*)"); - - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Load an image from a video file, using OpenCV library. - /** - \param filename Filename, as a C-string. - \param first_frame Index of the first frame to read. - \param last_frame Index of the last frame to read (can be higher than the actual number of frames, e.g. '~0U'). - \param step_frame Step value for frame reading. - \note If step_frame==0, the current video stream is forced to be released (without any frames read). - **/ - CImgList& load_video(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1) { -#ifndef cimg_use_opencv - if (first_frame || last_frame!=~0U || step_frame>1) - throw CImgArgumentException(_cimglist_instance - "load_video() : File '%s', arguments 'first_frame', 'last_frame' " - "and 'step_frame' requires features from the OpenCV library " - "('-Dcimg_use_opencv' must be defined).", - cimglist_instance,filename); - return load_ffmpeg_external(filename); -#else - static cv::VideoCapture *captures[32] = { 0 }; - static CImgList filenames(32); - static CImg positions(32,1,1,1,0); - static int last_used_index = -1; - - // Detect if a video capture already exists for the specified filename. - cimg::mutex(9); - int index = -1; - if (filename) { - if (last_used_index>=0 && !std::strcmp(filename,filenames[last_used_index])) { - index = last_used_index; - } else cimglist_for(filenames,l) if (filenames[l] && !std::strcmp(filename,filenames[l])) { - index = l; break; - } - } else index = last_used_index; - cimg::mutex(9,0); - - // Release stream if needed. - if (!step_frame || (index>=0 && positions[index]>first_frame)) { - if (index>=0) { - cimg::mutex(9); - captures[index]->release(); - delete captures[index]; - captures[index] = 0; - positions[index] = 0; - filenames[index].assign(); - if (last_used_index==index) last_used_index = -1; - index = -1; - cimg::mutex(9,0); - } else - if (filename) - cimg::warn(_cimglist_instance - "load_video() : File '%s', no opened video stream associated with filename found.", - cimglist_instance,filename); - else - cimg::warn(_cimglist_instance - "load_video() : No opened video stream found.", - cimglist_instance,filename); - if (!step_frame) return *this; - } - - // Find empty slot for capturing video stream. - if (index<0) { - if (!filename) - throw CImgArgumentException(_cimglist_instance - "load_video(): No already open video reader found. You must specify a " - "non-(null) filename argument for the first call.", - cimglist_instance); - else { cimg::mutex(9); cimglist_for(filenames,l) if (!filenames[l]) { index = l; break; } cimg::mutex(9,0); } - if (index<0) - throw CImgIOException(_cimglist_instance - "load_video(): File '%s', no video reader slots available. " - "You have to release some of your previously opened videos.", - cimglist_instance,filename); - cimg::mutex(9); - captures[index] = new cv::VideoCapture(filename); - positions[index] = 0; - if (!captures[index]->isOpened()) { - delete captures[index]; - captures[index] = 0; - cimg::mutex(9,0); - cimg::fclose(cimg::fopen(filename,"rb")); // Check file availability - throw CImgIOException(_cimglist_instance - "load_video(): File '%s', unable to detect format of video file.", - cimglist_instance,filename); - } - CImg::string(filename).move_to(filenames[index]); - cimg::mutex(9,0); - } - - cimg::mutex(9); - const unsigned int nb_frames = (unsigned int)std::max(0.,captures[index]->get(_cimg_cap_prop_frame_count)); - cimg::mutex(9,0); - assign(); - - // Skip frames if requested. - bool go_on = true; - unsigned int &pos = positions[index]; - while (posgrab()) { cimg::mutex(9,0); go_on = false; break; } - cimg::mutex(9,0); - ++pos; - } - - // Read and convert frames. - const unsigned int _last_frame = std::min(nb_frames?nb_frames - 1:~0U,last_frame); - while (go_on && pos<=_last_frame) { - cv::Mat cvimg; - cimg::mutex(9); - if (captures[index]->read(cvimg)) { CImg::_cvmat2cimg(cvimg).move_to(*this); ++pos; } - else go_on = false; - cimg::mutex(9,0); - if (go_on) - for (unsigned int i = 1; go_on && igrab()) go_on = false; - cimg::mutex(9,0); - } - } - - if (!go_on || (nb_frames && pos>=nb_frames)) { // Close video stream when necessary - cimg::mutex(9); - captures[index]->release(); - delete captures[index]; - captures[index] = 0; - filenames[index].assign(); - positions[index] = 0; - index = -1; - cimg::mutex(9,0); - } - - cimg::mutex(9); - last_used_index = index; - cimg::mutex(9,0); - - if (is_empty()) - throw CImgIOException(_cimglist_instance - "load_video(): File '%s', unable to locate frame %u.", - cimglist_instance,filename,first_frame); - return *this; -#endif - } - - //! Load an image from a video file, using OpenCV library \newinstance. - static CImgList get_load_video(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1) { - return CImgList().load_video(filename,first_frame,last_frame,step_frame); - } - - //! Load an image from a video file using the external tool 'ffmpeg'. - /** - \param filename Filename to read data from. - **/ - CImgList& load_ffmpeg_external(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimglist_instance - "load_ffmpeg_external(): Specified filename is (null).", - cimglist_instance); - cimg::fclose(cimg::fopen(filename,"rb")); // Check if file exists - CImg command(1024), filename_tmp(256), filename_tmp2(256); - std::FILE *file = 0; - do { - cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_000001.ppm",filename_tmp._data); - if ((file=cimg::std_fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file); - } while (file); - cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%%6d.ppm",filename_tmp._data); - cimg_snprintf(command,command._width,"\"%s\" -v -8 -i \"%s\" \"%s\"", - cimg::ffmpeg_path(), - CImg::string(filename)._system_strescape().data(), - CImg::string(filename_tmp2)._system_strescape().data()); - cimg::system(command, cimg::ffmpeg_path()); - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - assign(); - unsigned int i = 1; - for (bool stop_flag = false; !stop_flag; ++i) { - cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%.6u.ppm",filename_tmp._data,i); - CImg img; - try { img.load_pnm(filename_tmp2); } - catch (CImgException&) { stop_flag = true; } - if (img) { img.move_to(*this); std::remove(filename_tmp2); } - } - cimg::exception_mode(omode); - if (is_empty()) - throw CImgIOException(_cimglist_instance - "load_ffmpeg_external(): Failed to open file '%s' with external command 'ffmpeg'.", - cimglist_instance, - filename); - return *this; - } - - //! Load an image from a video file using the external tool 'ffmpeg' \newinstance. - static CImgList get_load_ffmpeg_external(const char *const filename) { - return CImgList().load_ffmpeg_external(filename); - } - - //! Load gif file, using ImageMagick or GraphicsMagick's external tools. - /** - \param filename Filename to read data from. - **/ - CImgList& load_gif_external(const char *const filename) { - if (!filename) - throw CImgArgumentException(_cimglist_instance - "load_gif_external(): Specified filename is (null).", - cimglist_instance); - cimg::fclose(cimg::fopen(filename,"rb")); // Check if file exists - if (!_load_gif_external(filename,false)) - if (!_load_gif_external(filename,true)) - try { assign(CImg().load_other(filename)); } catch (CImgException&) { assign(); } - if (is_empty()) - throw CImgIOException(_cimglist_instance - "load_gif_external(): Failed to open file '%s'.", - cimglist_instance,filename); - return *this; - } - - CImgList& _load_gif_external(const char *const filename, const bool use_graphicsmagick=false) { - CImg command(1024), filename_tmp(256), filename_tmp2(256); - std::FILE *file = 0; - do { - cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - if (use_graphicsmagick) cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s.png.0",filename_tmp._data); - else cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s-0.png",filename_tmp._data); - if ((file=cimg::std_fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file); - } while (file); - if (use_graphicsmagick) cimg_snprintf(command,command._width,"%s convert \"%s\" \"%s.png\"", - cimg::graphicsmagick_path(), - CImg::string(filename)._system_strescape().data(), - CImg::string(filename_tmp)._system_strescape().data()); - else cimg_snprintf(command,command._width,"\"%s\" -coalesce \"%s\" \"%s.png\"", - cimg::imagemagick_path(), - CImg::string(filename)._system_strescape().data(), - CImg::string(filename_tmp)._system_strescape().data()); - cimg::system(command, cimg::imagemagick_path()); - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - assign(); - - // Try to read a single frame gif. - cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s.png",filename_tmp._data); - CImg img; - try { img.load_png(filename_tmp2); } - catch (CImgException&) { } - if (img) { img.move_to(*this); std::remove(filename_tmp2); } - else { // Try to read animated gif - unsigned int i = 0; - for (bool stop_flag = false; !stop_flag; ++i) { - if (use_graphicsmagick) cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s.png.%u",filename_tmp._data,i); - else cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s-%u.png",filename_tmp._data,i); - try { img.load_png(filename_tmp2); } - catch (CImgException&) { stop_flag = true; } - if (img) { img.move_to(*this); std::remove(filename_tmp2); } - } - } - cimg::exception_mode(omode); - return *this; - } - - //! Load gif file, using ImageMagick or GraphicsMagick's external tools \newinstance. - static CImgList get_load_gif_external(const char *const filename) { - return CImgList().load_gif_external(filename); - } - - //! Load a gzipped list, using external tool 'gunzip'. - /** - \param filename Filename to read data from. - **/ - CImgList& load_gzip_external(const char *const filename) { - if (!filename) - throw CImgIOException(_cimglist_instance - "load_gzip_external(): Specified filename is (null).", - cimglist_instance); - cimg::fclose(cimg::fopen(filename,"rb")); // Check if file exists - CImg command(1024), filename_tmp(256), body(256); - const char - *ext = cimg::split_filename(filename,body), - *ext2 = cimg::split_filename(body,0); - std::FILE *file = 0; - do { - if (!cimg::strcasecmp(ext,"gz")) { - if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2); - else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - } else { - if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); - else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - } - if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); - } while (file); - cimg_snprintf(command,command._width,"\"%s\" -c \"%s\" > \"%s\"", - cimg::gunzip_path(), - CImg::string(filename)._system_strescape().data(), - CImg::string(filename_tmp)._system_strescape().data()); - cimg::system(command, cimg::gunzip_path()); - if (!(file=cimg::std_fopen(filename_tmp,"rb"))) { - cimg::fclose(cimg::fopen(filename,"r")); - throw CImgIOException(_cimglist_instance - "load_gzip_external(): Failed to open file '%s'.", - cimglist_instance, - filename); - - } else cimg::fclose(file); - load(filename_tmp); - std::remove(filename_tmp); - return *this; - } - - //! Load a gzipped list, using external tool 'gunzip' \newinstance. - static CImgList get_load_gzip_external(const char *const filename) { - return CImgList().load_gzip_external(filename); - } - - //! Load images from a TIFF file. - /** - \param filename Filename to read data from. - \param first_frame Index of first image frame to read. - \param last_frame Index of last image frame to read. - \param step_frame Step applied between each frame. - \param[out] bits_per_value Number of bits used to store a scalar value in the image file. - \param[out] voxel_size Voxel size, as stored in the filename. - \param[out] description Description, as stored in the filename. - **/ - CImgList& load_tiff(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, unsigned int *const bits_per_value=0, - float *const voxel_size=0, CImg *const description=0) { - const unsigned int - nfirst_frame = first_frame::get_load_tiff(filename)); -#else -#if cimg_verbosity<3 - TIFFSetWarningHandler(0); - TIFFSetErrorHandler(0); -#endif - TIFF *tif = TIFFOpen(filename,"r"); - if (tif) { - unsigned int nb_images = 0; - do ++nb_images; while (TIFFReadDirectory(tif)); - if (nfirst_frame>=nb_images || (nlast_frame!=~0U && nlast_frame>=nb_images)) - cimg::warn(_cimglist_instance - "load_tiff(): Invalid specified frame range is [%u,%u] (step %u) since " - "file '%s' contains %u image(s).", - cimglist_instance, - nfirst_frame,nlast_frame,nstep_frame,filename,nb_images); - - if (nfirst_frame>=nb_images) return assign(); - if (nlast_frame>=nb_images) nlast_frame = nb_images - 1; - assign(1 + (nlast_frame - nfirst_frame)/nstep_frame); - TIFFSetDirectory(tif,0); - cimglist_for(*this,l) - _data[l]._load_tiff(tif,nfirst_frame + l*nstep_frame,bits_per_value,voxel_size,description); - TIFFClose(tif); - } else throw CImgIOException(_cimglist_instance - "load_tiff(): Failed to open file '%s'.", - cimglist_instance, - filename); - return *this; -#endif - } - - //! Load a multi-page TIFF file \newinstance. - static CImgList get_load_tiff(const char *const filename, - const unsigned int first_frame=0, const unsigned int last_frame=~0U, - const unsigned int step_frame=1, unsigned int *const bits_per_value=0, - float *const voxel_size=0, CImg *const description=0) { - return CImgList().load_tiff(filename,first_frame,last_frame,step_frame,bits_per_value,voxel_size,description); - } - - //@} - //---------------------------------- - // - //! \name Data Output - //@{ - //---------------------------------- - - //! Print information about the list on the standard output. - /** - \param title Label set to the information displayed. - \param display_stats Tells if image statistics must be computed and displayed. - **/ - const CImgList& print(const char *const title=0, const bool display_stats=true) const { - unsigned int msiz = 0; - cimglist_for(*this,l) msiz+=_data[l].size(); - msiz*=sizeof(T); - const unsigned int mdisp = msiz<8*1024?0U:msiz<8*1024*1024?1U:2U; - CImg _title(64); - if (!title) cimg_snprintf(_title,_title._width,"CImgList<%s>",pixel_type()); - std::fprintf(cimg::output(),"%s%s%s%s: %sthis%s = %p, %ssize%s = %u/%u [%u %s], %sdata%s = (CImg<%s>*)%p", - cimg::t_magenta,cimg::t_bold,title?title:_title._data,cimg::t_normal, - cimg::t_bold,cimg::t_normal,(void*)this, - cimg::t_bold,cimg::t_normal,_width,_allocated_width, - mdisp==0?msiz:(mdisp==1?(msiz>>10):(msiz>>20)), - mdisp==0?"b":(mdisp==1?"Kio":"Mio"), - cimg::t_bold,cimg::t_normal,pixel_type(),(void*)begin()); - if (_data) std::fprintf(cimg::output(),"..%p.\n",(void*)((char*)end() - 1)); - else std::fprintf(cimg::output(),".\n"); - - char tmp[16] = { 0 }; - cimglist_for(*this,ll) { - cimg_snprintf(tmp,sizeof(tmp),"[%d]",ll); - std::fprintf(cimg::output()," "); - _data[ll].print(tmp,display_stats); - if (ll==3 && width()>8) { ll = width() - 5; std::fprintf(cimg::output()," ...\n"); } - } - std::fflush(cimg::output()); - return *this; - } - - //! Display the current CImgList instance in an existing CImgDisplay window (by reference). - /** - \param disp Reference to an existing CImgDisplay instance, where the current image list will be displayed. - \param axis Appending axis. Can be { 'x' | 'y' | 'z' | 'c' }. - \param align Appending alignment. - \note This function displays the list images of the current CImgList instance into an existing - CImgDisplay window. - Images of the list are appended in a single temporary image for visualization purposes. - The function returns immediately. - **/ - const CImgList& display(CImgDisplay &disp, const char axis='x', const float align=0) const { - disp.display(*this,axis,align); - return *this; - } - - //! Display the current CImgList instance in a new display window. - /** - \param disp Display window. - \param display_info Tells if image information are displayed on the standard output. - \param axis Alignment axis for images viewing. - \param align Appending alignment. - \param[in,out] XYZ Contains the XYZ coordinates at start / exit of the function. - \param exit_on_anykey Exit function when any key is pressed. - \note This function opens a new window with a specific title and displays the list images of the - current CImgList instance into it. - Images of the list are appended in a single temporary image for visualization purposes. - The function returns when a key is pressed or the display window is closed by the user. - **/ - const CImgList& display(CImgDisplay &disp, const bool display_info, - const char axis='x', const float align=0, - unsigned int *const XYZ=0, const bool exit_on_anykey=false) const { - bool is_exit = false; - return _display(disp,0,0,display_info,axis,align,XYZ,exit_on_anykey,0,true,is_exit); - } - - //! Display the current CImgList instance in a new display window. - /** - \param title Title of the opening display window. - \param display_info Tells if list information must be written on standard output. - \param axis Appending axis. Can be { 'x' | 'y' | 'z' | 'c' }. - \param align Appending alignment. - \param[in,out] XYZ Contains the XYZ coordinates at start / exit of the function. - \param exit_on_anykey Exit function when any key is pressed. - **/ - const CImgList& display(const char *const title=0, const bool display_info=true, - const char axis='x', const float align=0, - unsigned int *const XYZ=0, const bool exit_on_anykey=false) const { - CImgDisplay disp; - bool is_exit = false; - return _display(disp,title,0,display_info,axis,align,XYZ,exit_on_anykey,0,true,is_exit); - } - - const CImgList& _display(CImgDisplay &disp, const char *const title, const CImgList *const titles, - const bool display_info, const char axis, const float align, unsigned int *const XYZ, - const bool exit_on_anykey, const unsigned int orig, const bool is_first_call, - bool &is_exit) const { - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "display(): Empty instance.", - cimglist_instance); - if (!disp) { - if (axis=='x') { - unsigned int sum_width = 0, max_height = 0; - cimglist_for(*this,l) { - const CImg &img = _data[l]; - const unsigned int - w = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,false), - h = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,true); - sum_width+=w; - if (h>max_height) max_height = h; - } - disp.assign(cimg_fitscreen(sum_width,max_height,1),title?title:titles?titles->__display()._data:0,1); - } else { - unsigned int max_width = 0, sum_height = 0; - cimglist_for(*this,l) { - const CImg &img = _data[l]; - const unsigned int - w = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,false), - h = CImgDisplay::_fitscreen(img._width,img._height,img._depth,128,-85,true); - if (w>max_width) max_width = w; - sum_height+=h; - } - disp.assign(cimg_fitscreen(max_width,sum_height,1),title?title:titles?titles->__display()._data:0,1); - } - if (!title && !titles) disp.set_title("CImgList<%s> (%u)",pixel_type(),_width); - } else if (title) disp.set_title("%s",title); - else if (titles) disp.set_title("%s",titles->__display()._data); - const CImg dtitle = CImg::string(disp.title()); - if (display_info) print(disp.title()); - disp.show().flush(); - - if (_width==1) { - const unsigned int dw = disp._width, dh = disp._height; - if (!is_first_call) - disp.resize(cimg_fitscreen(_data[0]._width,_data[0]._height,_data[0]._depth),false); - disp.set_title("%s (%ux%ux%ux%u)", - dtitle.data(),_data[0]._width,_data[0]._height,_data[0]._depth,_data[0]._spectrum); - _data[0]._display(disp,0,false,XYZ,exit_on_anykey,!is_first_call); - if (disp.key()) is_exit = true; - disp.resize(cimg_fitscreen(dw,dh,1),false).set_title("%s",dtitle.data()); - } else { - bool disp_resize = !is_first_call; - while (!disp.is_closed() && !is_exit) { - const CImg s = _select(disp,0,true,axis,align,exit_on_anykey,orig,disp_resize,!is_first_call,true); - disp_resize = true; - if (s[0]<0 && !disp.wheel()) { // No selections done - if (disp.button()&2) { disp.flush(); break; } - is_exit = true; - } else if (disp.wheel()) { // Zoom in/out - const int wheel = disp.wheel(); - disp.set_wheel(); - if (!is_first_call && wheel<0) break; - if (wheel>0 && _width>=4) { - const unsigned int - delta = std::max(1U,(unsigned int)cimg::round(0.3*_width)), - ind0 = (unsigned int)std::max(0,s[0] - (int)delta), - ind1 = (unsigned int)std::min(width() - 1,s[0] + (int)delta); - if ((ind0!=0 || ind1!=_width - 1) && ind1 - ind0>=3) { - const CImgList sublist = get_shared_images(ind0,ind1); - CImgList t_sublist; - if (titles) t_sublist = titles->get_shared_images(ind0,ind1); - sublist._display(disp,0,titles?&t_sublist:0,false,axis,align,XYZ,exit_on_anykey, - orig + ind0,false,is_exit); - } - } - } else if (s[0]!=0 || s[1]!=width() - 1) { - const CImgList sublist = get_shared_images(s[0],s[1]); - CImgList t_sublist; - if (titles) t_sublist = titles->get_shared_images(s[0],s[1]); - sublist._display(disp,0,titles?&t_sublist:0,false,axis,align,XYZ,exit_on_anykey, - orig + s[0],false,is_exit); - } - disp.set_title("%s",dtitle.data()); - } - } - return *this; - } - - // [internal] Return string to describe display title. - CImg __display() const { - CImg res, str; - cimglist_for(*this,l) { - CImg::string((char*)_data[l]).move_to(str); - if (l!=width() - 1) { - str.resize(str._width + 1,1,1,1,0); - str[str._width - 2] = ','; - str[str._width - 1] = ' '; - } - res.append(str,'x'); - } - if (!res) return CImg(1,1,1,1,0).move_to(res); - cimg::strellipsize(res,128,false); - if (_width>1) { - const unsigned int l = (unsigned int)std::strlen(res); - if (res._width<=l + 16) res.resize(l + 16,1,1,1,0); - cimg_snprintf(res._data + l,16," (#%u)",_width); - } - return res; - } - - //! Save list into a file. - /** - \param filename Filename to write data to. - \param number When positive, represents an index added to the filename. Otherwise, no number is added. - \param digits Number of digits used for adding the number to the filename. - **/ - const CImgList& save(const char *const filename, const int number=-1, const unsigned int digits=6) const { - if (!filename) - throw CImgArgumentException(_cimglist_instance - "save(): Specified filename is (null).", - cimglist_instance); - // Do not test for empty instances, since .cimg format is able to manage empty instances. - const bool is_stdout = *filename=='-' && (!filename[1] || filename[1]=='.'); - const char *const ext = cimg::split_filename(filename); - CImg nfilename(1024); - const char *const fn = is_stdout?filename:number>=0?cimg::number_filename(filename,number,digits,nfilename): - filename; - -#ifdef cimglist_save_plugin - cimglist_save_plugin(fn); -#endif -#ifdef cimglist_save_plugin1 - cimglist_save_plugin1(fn); -#endif -#ifdef cimglist_save_plugin2 - cimglist_save_plugin2(fn); -#endif -#ifdef cimglist_save_plugin3 - cimglist_save_plugin3(fn); -#endif -#ifdef cimglist_save_plugin4 - cimglist_save_plugin4(fn); -#endif -#ifdef cimglist_save_plugin5 - cimglist_save_plugin5(fn); -#endif -#ifdef cimglist_save_plugin6 - cimglist_save_plugin6(fn); -#endif -#ifdef cimglist_save_plugin7 - cimglist_save_plugin7(fn); -#endif -#ifdef cimglist_save_plugin8 - cimglist_save_plugin8(fn); -#endif - if (!cimg::strcasecmp(ext,"cimgz")) return save_cimg(fn,true); - else if (!cimg::strcasecmp(ext,"cimg") || !*ext) return save_cimg(fn,false); - else if (!cimg::strcasecmp(ext,"yuv")) return save_yuv(fn,444,true); - else if (!cimg::strcasecmp(ext,"avi") || - !cimg::strcasecmp(ext,"mov") || - !cimg::strcasecmp(ext,"asf") || - !cimg::strcasecmp(ext,"divx") || - !cimg::strcasecmp(ext,"flv") || - !cimg::strcasecmp(ext,"mpg") || - !cimg::strcasecmp(ext,"m1v") || - !cimg::strcasecmp(ext,"m2v") || - !cimg::strcasecmp(ext,"m4v") || - !cimg::strcasecmp(ext,"mjp") || - !cimg::strcasecmp(ext,"mp4") || - !cimg::strcasecmp(ext,"mkv") || - !cimg::strcasecmp(ext,"mpe") || - !cimg::strcasecmp(ext,"movie") || - !cimg::strcasecmp(ext,"ogm") || - !cimg::strcasecmp(ext,"ogg") || - !cimg::strcasecmp(ext,"ogv") || - !cimg::strcasecmp(ext,"qt") || - !cimg::strcasecmp(ext,"rm") || - !cimg::strcasecmp(ext,"vob") || - !cimg::strcasecmp(ext,"webm") || - !cimg::strcasecmp(ext,"wmv") || - !cimg::strcasecmp(ext,"xvid") || - !cimg::strcasecmp(ext,"mpeg")) return save_video(fn); -#ifdef cimg_use_tiff - else if (!cimg::strcasecmp(ext,"tif") || - !cimg::strcasecmp(ext,"tiff")) return save_tiff(fn); -#endif - else if (!cimg::strcasecmp(ext,"gz")) return save_gzip_external(fn); - else { - if (_width==1) _data[0].save(fn,-1); - else cimglist_for(*this,l) { _data[l].save(fn,is_stdout?-1:l); if (is_stdout) std::fputc(EOF,cimg::_stdout()); } - } - return *this; - } - - //! Tell if an image list can be saved as one single file. - /** - \param filename Filename, as a C-string. - \return \c true if the file format supports multiple images, \c false otherwise. - **/ - static bool is_saveable(const char *const filename) { - const char *const ext = cimg::split_filename(filename); - if (!cimg::strcasecmp(ext,"cimgz") || -#ifdef cimg_use_tiff - !cimg::strcasecmp(ext,"tif") || - !cimg::strcasecmp(ext,"tiff") || -#endif - !cimg::strcasecmp(ext,"yuv") || - !cimg::strcasecmp(ext,"avi") || - !cimg::strcasecmp(ext,"mov") || - !cimg::strcasecmp(ext,"asf") || - !cimg::strcasecmp(ext,"divx") || - !cimg::strcasecmp(ext,"flv") || - !cimg::strcasecmp(ext,"mpg") || - !cimg::strcasecmp(ext,"m1v") || - !cimg::strcasecmp(ext,"m2v") || - !cimg::strcasecmp(ext,"m4v") || - !cimg::strcasecmp(ext,"mjp") || - !cimg::strcasecmp(ext,"mp4") || - !cimg::strcasecmp(ext,"mkv") || - !cimg::strcasecmp(ext,"mpe") || - !cimg::strcasecmp(ext,"movie") || - !cimg::strcasecmp(ext,"ogm") || - !cimg::strcasecmp(ext,"ogg") || - !cimg::strcasecmp(ext,"ogv") || - !cimg::strcasecmp(ext,"qt") || - !cimg::strcasecmp(ext,"rm") || - !cimg::strcasecmp(ext,"vob") || - !cimg::strcasecmp(ext,"webm") || - !cimg::strcasecmp(ext,"wmv") || - !cimg::strcasecmp(ext,"xvid") || - !cimg::strcasecmp(ext,"mpeg")) return true; - return false; - } - - //! Save image sequence as a GIF animated file. - /** - \param filename Filename to write data to. - \param fps Number of desired frames per second. - \param nb_loops Number of loops (\c 0 for infinite looping). - **/ - const CImgList& save_gif_external(const char *const filename, const float fps=25, - const unsigned int nb_loops=0) { - CImg command(1024), filename_tmp(256), filename_tmp2(256); - CImgList filenames; - std::FILE *file = 0; - -#ifdef cimg_use_png -#define _cimg_save_gif_extension "png" -#else -#define _cimg_save_gif_extension "ppm" -#endif - - do { - cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_000001." _cimg_save_gif_extension,filename_tmp._data); - if ((file=cimg::std_fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file); - } while (file); - cimglist_for(*this,l) { - cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%.6u." _cimg_save_gif_extension,filename_tmp._data,l + 1); - CImg::string(filename_tmp2).move_to(filenames); - if (_data[l]._depth>1 || _data[l]._spectrum!=3) _data[l].get_resize(-100,-100,1,3).save(filename_tmp2); - else _data[l].save(filename_tmp2); - } - cimg_snprintf(command,command._width,"\"%s\" -delay %u -loop %u", - cimg::imagemagick_path(),(unsigned int)std::max(0.f,cimg::round(100/fps)),nb_loops); - CImg::string(command).move_to(filenames,0); - cimg_snprintf(command,command._width,"\"%s\"", - CImg::string(filename)._system_strescape().data()); - CImg::string(command).move_to(filenames); - CImg _command = filenames>'x'; - cimg_for(_command,p,char) if (!*p) *p = ' '; - _command.back() = 0; - - cimg::system(_command, cimg::imagemagick_path()); - file = cimg::std_fopen(filename,"rb"); - if (!file) - throw CImgIOException(_cimglist_instance - "save_gif_external(): Failed to save file '%s' with external command 'magick/convert'.", - cimglist_instance, - filename); - else cimg::fclose(file); - cimglist_for_in(*this,1,filenames._width - 1,l) std::remove(filenames[l]); - return *this; - } - - //! Save list as a YUV image sequence file. - /** - \param filename Filename to write data to. - \param chroma_subsampling Type of chroma subsampling. Can be { 420 | 422 | 444 }. - \param is_rgb Tells if the RGB to YUV conversion must be done for saving. - **/ - const CImgList& save_yuv(const char *const filename=0, - const unsigned int chroma_subsampling=444, - const bool is_rgb=true) const { - return _save_yuv(0,filename,chroma_subsampling,is_rgb); - } - - //! Save image sequence into a YUV file. - /** - \param file File to write data to. - \param chroma_subsampling Type of chroma subsampling. Can be { 420 | 422 | 444 }. - \param is_rgb Tells if the RGB to YUV conversion must be done for saving. - **/ - const CImgList& save_yuv(std::FILE *const file, - const unsigned int chroma_subsampling=444, - const bool is_rgb=true) const { - return _save_yuv(file,0,chroma_subsampling,is_rgb); - } - - const CImgList& _save_yuv(std::FILE *const file, const char *const filename, - const unsigned int chroma_subsampling, - const bool is_rgb) const { - if (!file && !filename) - throw CImgArgumentException(_cimglist_instance - "save_yuv(): Specified filename is (null).", - cimglist_instance); - if (chroma_subsampling!=420 && chroma_subsampling!=422 && chroma_subsampling!=444) - throw CImgArgumentException(_cimglist_instance - "save_yuv(): Specified chroma subsampling %u is invalid, for file '%s'.", - cimglist_instance, - chroma_subsampling,filename?filename:"(FILE*)"); - if (is_empty()) { cimg::fempty(file,filename); return *this; } - const unsigned int - cfx = chroma_subsampling==420 || chroma_subsampling==422?2:1, - cfy = chroma_subsampling==420?2:1, - w0 = (*this)[0]._width, h0 = (*this)[0]._height, - width0 = w0 + (w0%cfx), height0 = h0 + (h0%cfy); - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - cimglist_for(*this,l) { - const CImg &frame = (*this)[l]; - cimg_forZ(frame,z) { - CImg YUV; - if (sizeof(T)==1 && !is_rgb && - frame._width==width0 && frame._height==height0 && frame._depth==1 && frame._spectrum==3) - YUV.assign((unsigned char*)frame._data,width0,height0,1,3,true); - else { - YUV = frame.get_slice(z); - if (YUV._width!=width0 || YUV._height!=height0) YUV.resize(width0,height0,1,-100,0); - if (YUV._spectrum!=3) YUV.resize(-100,-100,1,3,YUV._spectrum==1?1:0); - if (is_rgb) YUV.RGBtoYCbCr(); - } - if (chroma_subsampling==444) - cimg::fwrite(YUV._data,(size_t)YUV._width*YUV._height*3,nfile); - else { - cimg::fwrite(YUV._data,(size_t)YUV._width*YUV._height,nfile); - CImg UV = YUV.get_channels(1,2); - UV.resize(UV._width/cfx,UV._height/cfy,1,2,2); - cimg::fwrite(UV._data,(size_t)UV._width*UV._height*2,nfile); - } - } - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Save list into a .cimg file. - /** - \param filename Filename to write data to. - \param is_compressed Tells if data compression must be enabled. - **/ - const CImgList& save_cimg(const char *const filename, const bool is_compressed=false) const { - return _save_cimg(0,filename,is_compressed); - } - - const CImgList& _save_cimg(std::FILE *const file, const char *const filename, const bool is_compressed) const { - if (!file && !filename) - throw CImgArgumentException(_cimglist_instance - "save_cimg(): Specified filename is (null).", - cimglist_instance); -#ifndef cimg_use_zlib - if (is_compressed) - cimg::warn(_cimglist_instance - "save_cimg(): Unable to save compressed data in file '%s' unless zlib is enabled, " - "saving them uncompressed.", - cimglist_instance, - filename?filename:"(FILE*)"); -#endif - const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little"; - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - const bool is_bool = ptype==cimg::type::string(); - std::fprintf(nfile,"%u %s %s_endian\n",_width,ptype,etype); - - cimglist_for(*this,l) { - const CImg& img = _data[l]; - std::fprintf(nfile,"%u %u %u %u",img._width,img._height,img._depth,img._spectrum); - if (img._data) { - CImg tmp; - if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp._data,tmp.size()); } - const CImg& ref = cimg::endianness()?tmp:img; - bool failed_to_compress = true; - if (is_compressed) { -#ifdef cimg_use_zlib - Bytef *cbuf = 0; - uLongf csiz = 0; - - if (is_bool) { // Boolean data (bitwise) - ulongT siz; - const unsigned char *const buf = ref._bool2uchar(siz,false); - csiz = siz + siz/100 + 16; - cbuf = new Bytef[csiz]; - failed_to_compress = (bool)compress(cbuf,&csiz,(Bytef*)buf,siz); - if (!failed_to_compress) { - std::fprintf(nfile," #%lu\n",csiz); - cimg::fwrite(cbuf,csiz,nfile); - } - delete[] buf; - } else { // Non-boolean data - const ulongT siz = sizeof(T)*ref.size(); - csiz = siz + siz/100 + 16; - cbuf = new Bytef[csiz]; - failed_to_compress = (bool)compress(cbuf,&csiz,(Bytef*)ref._data,siz); - if (!failed_to_compress) { - std::fprintf(nfile," #%lu\n",csiz); - cimg::fwrite(cbuf,csiz,nfile); - } - } - if (failed_to_compress) - cimg::warn(_cimglist_instance - "save_cimg(): Failed to save compressed data for file '%s', saving them uncompressed.", - cimglist_instance, - filename?filename:"(FILE*)"); - delete[] cbuf; -#endif - } - if (failed_to_compress) { // Write non-compressed - std::fputc('\n',nfile); - if (is_bool) { // Boolean data (bitwise) - ulongT siz; - const unsigned char *const buf = ref._bool2uchar(siz,false); - cimg::fwrite(buf,siz,nfile); - delete[] buf; - } else cimg::fwrite(ref._data,ref.size(),nfile); // Non-boolean data - } - } else std::fputc('\n',nfile); - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Save list into a .cimg file. - /** - \param file File to write data to. - \param is_compressed Tells if data compression must be enabled. - **/ - const CImgList& save_cimg(std::FILE *file, const bool is_compressed=false) const { - return _save_cimg(file,0,is_compressed); - } - - const CImgList& _save_cimg(std::FILE *const file, const char *const filename, - const unsigned int n0, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0) const { -#define _cimg_save_cimg_case(Ts1,Ts2,Ts3,Tss) \ - if (!saved && ((Ts1 && !cimg::strcasecmp(Ts1,str_pixeltype)) || \ - (Ts2 && !cimg::strcasecmp(Ts2,str_pixeltype)) || \ - (Ts3 && !cimg::strcasecmp(Ts3,str_pixeltype)))) { \ - for (unsigned int l = 0; l0) { \ - if (l=W || y0>=H || z0>=D || c0>=D) cimg::fseek(nfile,W*H*D*C*sizeof(Tss),SEEK_CUR); \ - else { \ - const CImg& img = (*this)[l - n0]; \ - const T *ptrs = img._data; \ - const unsigned int \ - x1 = x0 + img._width - 1, \ - y1 = y0 + img._height - 1, \ - z1 = z0 + img._depth - 1, \ - c1 = c0 + img._spectrum - 1, \ - nx1 = x1>=W?W - 1:x1, \ - ny1 = y1>=H?H - 1:y1, \ - nz1 = z1>=D?D - 1:z1, \ - nc1 = c1>=C?C - 1:c1; \ - CImg raw(1 + nx1 - x0); \ - const unsigned int skipvb = c0*W*H*D*sizeof(Tss); \ - if (skipvb) cimg::fseek(nfile,skipvb,SEEK_CUR); \ - for (unsigned int v = 1 + nc1 - c0; v; --v) { \ - const unsigned int skipzb = z0*W*H*sizeof(Tss); \ - if (skipzb) cimg::fseek(nfile,skipzb,SEEK_CUR); \ - for (unsigned int z = 1 + nz1 - z0; z; --z) { \ - const unsigned int skipyb = y0*W*sizeof(Tss); \ - if (skipyb) cimg::fseek(nfile,skipyb,SEEK_CUR); \ - for (unsigned int y = 1 + ny1 - y0; y; --y) { \ - const unsigned int skipxb = x0*sizeof(Tss); \ - if (skipxb) cimg::fseek(nfile,skipxb,SEEK_CUR); \ - raw.assign(ptrs, raw._width); \ - ptrs+=img._width; \ - if (endian) cimg::invert_endianness(raw._data,raw._width); \ - cimg::fwrite(raw._data,raw._width,nfile); \ - const unsigned int skipxe = (W - 1 - nx1)*sizeof(Tss); \ - if (skipxe) cimg::fseek(nfile,skipxe,SEEK_CUR); \ - } \ - const unsigned int skipye = (H - 1 - ny1)*W*sizeof(Tss); \ - if (skipye) cimg::fseek(nfile,skipye,SEEK_CUR); \ - } \ - const unsigned int skipze = (D - 1 - nz1)*W*H*sizeof(Tss); \ - if (skipze) cimg::fseek(nfile,skipze,SEEK_CUR); \ - } \ - const unsigned int skipve = (C - 1 - nc1)*W*H*D*sizeof(Tss); \ - if (skipve) cimg::fseek(nfile,skipve,SEEK_CUR); \ - } \ - } \ - } \ - saved = true; \ - } - - if (!file && !filename) - throw CImgArgumentException(_cimglist_instance - "save_cimg(): Specified filename is (null).", - cimglist_instance); - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "save_cimg(): Empty instance, for file '%s'.", - cimglist_instance, - filename?filename:"(FILE*)"); - - std::FILE *const nfile = file?file:cimg::fopen(filename,"rb+"); - bool saved = false, endian = cimg::endianness(); - CImg tmp(256), str_pixeltype(256), str_endian(256); - *tmp = *str_pixeltype = *str_endian = 0; - unsigned int j, N, W, H, D, C; - int i, err; - j = 0; while ((i=std::fgetc(nfile))!='\n' && i!=EOF && j<256) tmp[j++] = (char)i; tmp[j] = 0; - err = cimg_sscanf(tmp,"%u%*c%255[A-Za-z123468_]%*c%255[sA-Za-z_ ]",&N,str_pixeltype._data,str_endian._data); - if (err<2) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimglist_instance - "save_cimg(): CImg header not found in file '%s'.", - cimglist_instance, - filename?filename:"(FILE*)"); - } - if (!cimg::strncasecmp("little",str_endian,6)) endian = false; - else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; - const unsigned int lmax = std::min(N,n0 + _width); - _cimg_save_cimg_case("bool",0,0,cimg_uint8); - _cimg_save_cimg_case("uint8","unsigned_char","uchar",cimg_uint8); - _cimg_save_cimg_case("int8",0,0,cimg_int8); - _cimg_save_cimg_case("char",0,0,char); - _cimg_save_cimg_case("uint16","unsigned_short","ushort",cimg_uint16); - _cimg_save_cimg_case("int16","short",0,cimg_int16); - _cimg_save_cimg_case("uint32","unsigned_int","uint",cimg_uint32); - _cimg_save_cimg_case("int32","int",0,cimg_int32); - _cimg_save_cimg_case("uint64","unsigned_int64",0,cimg_uint64); - _cimg_save_cimg_case("int64",0,0,cimg_int64); - _cimg_save_cimg_case("float","float32",0,cimg_float32); - _cimg_save_cimg_case("float64","double",0,cimg_float64); - - if (!saved) { - if (!file) cimg::fclose(nfile); - throw CImgIOException(_cimglist_instance - "save_cimg(): Unsupported data type '%s' for file '%s'.", - cimglist_instance, - filename?filename:"(FILE*)",str_pixeltype._data); - } - if (!file) cimg::fclose(nfile); - return *this; - } - - //! Insert the image instance into into an existing .cimg file, at specified coordinates. - /** - \param filename Filename to write data to. - \param n0 Starting index of images to write. - \param x0 Starting X-coordinates of image regions to write. - \param y0 Starting Y-coordinates of image regions to write. - \param z0 Starting Z-coordinates of image regions to write. - \param c0 Starting C-coordinates of image regions to write. - **/ - const CImgList& save_cimg(const char *const filename, - const unsigned int n0, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0) const { - return _save_cimg(0,filename,n0,x0,y0,z0,c0); - } - - //! Insert the image instance into into an existing .cimg file, at specified coordinates. - /** - \param file File to write data to. - \param n0 Starting index of images to write. - \param x0 Starting X-coordinates of image regions to write. - \param y0 Starting Y-coordinates of image regions to write. - \param z0 Starting Z-coordinates of image regions to write. - \param c0 Starting C-coordinates of image regions to write. - **/ - const CImgList& save_cimg(std::FILE *const file, - const unsigned int n0, - const unsigned int x0, const unsigned int y0, - const unsigned int z0, const unsigned int c0) const { - return _save_cimg(file,0,n0,x0,y0,z0,c0); - } - - static void _save_empty_cimg(std::FILE *const file, const char *const filename, - const unsigned int nb, - const unsigned int dx, const unsigned int dy, - const unsigned int dz, const unsigned int dc) { - std::FILE *const nfile = file?file:cimg::fopen(filename,"wb"); - const ulongT siz = (ulongT)dx*dy*dz*dc*sizeof(T); - std::fprintf(nfile,"%u %s\n",nb,pixel_type()); - for (unsigned int i=nb; i; --i) { - std::fprintf(nfile,"%u %u %u %u\n",dx,dy,dz,dc); - for (ulongT off = siz; off; --off) std::fputc(0,nfile); - } - if (!file) cimg::fclose(nfile); - } - - //! Save empty (non-compressed) .cimg file with specified dimensions. - /** - \param filename Filename to write data to. - \param nb Number of images to write. - \param dx Width of images in the written file. - \param dy Height of images in the written file. - \param dz Depth of images in the written file. - \param dc Spectrum of images in the written file. - **/ - static void save_empty_cimg(const char *const filename, - const unsigned int nb, - const unsigned int dx, const unsigned int dy=1, - const unsigned int dz=1, const unsigned int dc=1) { - return _save_empty_cimg(0,filename,nb,dx,dy,dz,dc); - } - - //! Save empty .cimg file with specified dimensions. - /** - \param file File to write data to. - \param nb Number of images to write. - \param dx Width of images in the written file. - \param dy Height of images in the written file. - \param dz Depth of images in the written file. - \param dc Spectrum of images in the written file. - **/ - static void save_empty_cimg(std::FILE *const file, - const unsigned int nb, - const unsigned int dx, const unsigned int dy=1, - const unsigned int dz=1, const unsigned int dc=1) { - return _save_empty_cimg(file,0,nb,dx,dy,dz,dc); - } - - //! Save list as a TIFF file. - /** - \param filename Filename to write data to. - \param compression_type Compression mode used to write data. - \param voxel_size Voxel size, to be stored in the filename. - \param description Description, to be stored in the filename. - \param use_bigtiff Allow to save big tiff files (>4Gb). - **/ - const CImgList& save_tiff(const char *const filename, const unsigned int compression_type=0, - const float *const voxel_size=0, const char *const description=0, - const bool use_bigtiff=true) const { - if (!filename) - throw CImgArgumentException(_cimglist_instance - "save_tiff(): Specified filename is (null).", - cimglist_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - -#ifndef cimg_use_tiff - if (_width==1) _data[0].save_tiff(filename,compression_type,voxel_size,description,use_bigtiff); - else cimglist_for(*this,l) { - CImg nfilename(1024); - cimg::number_filename(filename,l,6,nfilename); - _data[l].save_tiff(nfilename,compression_type,voxel_size,description,use_bigtiff); - } -#else - ulongT siz = 0; - cimglist_for(*this,l) siz+=_data[l].size(); - const bool _use_bigtiff = use_bigtiff && sizeof(siz)>=8 && siz*sizeof(T)>=1UL<<31; // No bigtiff for small images - TIFF *tif = TIFFOpen(filename,_use_bigtiff?"w8":"w4"); - if (tif) { - for (unsigned int dir = 0, l = 0; l<_width; ++l) { - const CImg& img = (*this)[l]; - cimg_forZ(img,z) img._save_tiff(tif,dir++,z,compression_type,voxel_size,description); - } - TIFFClose(tif); - } else - throw CImgIOException(_cimglist_instance - "save_tiff(): Failed to open stream for file '%s'.", - cimglist_instance, - filename); -#endif - return *this; - } - - //! Save list as a gzipped file, using external tool 'gzip'. - /** - \param filename Filename to write data to. - **/ - const CImgList& save_gzip_external(const char *const filename) const { - if (!filename) - throw CImgIOException(_cimglist_instance - "save_gzip_external(): Specified filename is (null).", - cimglist_instance); - CImg command(1024), filename_tmp(256), body(256); - const char - *ext = cimg::split_filename(filename,body), - *ext2 = cimg::split_filename(body,0); - std::FILE *file; - do { - if (!cimg::strcasecmp(ext,"gz")) { - if (*ext2) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext2); - else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - } else { - if (*ext) cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext); - else cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s.cimg", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - } - if ((file=cimg::std_fopen(filename_tmp,"rb"))!=0) cimg::fclose(file); - } while (file); - - if (is_saveable(body)) { - save(filename_tmp); - cimg_snprintf(command,command._width,"\"%s\" -c \"%s\" > \"%s\"", - cimg::gzip_path(), - CImg::string(filename_tmp)._system_strescape().data(), - CImg::string(filename)._system_strescape().data()); - cimg::system(command, cimg::gzip_path()); - file = cimg::std_fopen(filename,"rb"); - if (!file) - throw CImgIOException(_cimglist_instance - "save_gzip_external(): Failed to save file '%s' with external command 'gzip'.", - cimglist_instance, - filename); - else cimg::fclose(file); - std::remove(filename_tmp); - } else { - CImg nfilename(1024); - cimglist_for(*this,l) { - cimg::number_filename(body,l,6,nfilename); - if (*ext) cimg_sprintf(nfilename._data + std::strlen(nfilename),".%s",ext); - _data[l].save_gzip_external(nfilename); - } - } - return *this; - } - - //! Save image sequence (using the OpenCV library when available). - /** - \param filename Filename to write data to. - \param fps Number of frames per second. - \param codec Type of compression (See http://www.fourcc.org/codecs.php to see available codecs). - \param keep_open Tells if the video writer associated to the specified filename - must be kept open or not (to allow frames to be added in the same file afterwards). - **/ - const CImgList& save_video(const char *const filename, const unsigned int fps=25, - const char *codec=0, const bool keep_open=false) const { -#ifndef cimg_use_opencv - cimg::unused(codec,keep_open); - return save_ffmpeg_external(filename,fps); -#else - try { - static cv::VideoWriter *writers[32] = { 0 }; - static CImgList filenames(32); - static CImg sizes(32,2,1,1,0); - static int last_used_index = -1; - - // Detect if a video writer already exists for the specified filename. - cimg::mutex(9); - int index = -1; - if (filename) { - if (last_used_index>=0 && !std::strcmp(filename,filenames[last_used_index])) { - index = last_used_index; - } else cimglist_for(filenames,l) if (filenames[l] && !std::strcmp(filename,filenames[l])) { - index = l; break; - } - } else index = last_used_index; - cimg::mutex(9,0); - - // Find empty slot for capturing video stream. - if (index<0) { - if (!filename) - throw CImgArgumentException(_cimglist_instance - "save_video(): No already open video writer found. You must specify a " - "non-(null) filename argument for the first call.", - cimglist_instance); - else { cimg::mutex(9); cimglist_for(filenames,l) if (!filenames[l]) { index = l; break; } cimg::mutex(9,0); } - if (index<0) - throw CImgIOException(_cimglist_instance - "save_video(): File '%s', no video writer slots available. " - "You have to release some of your previously opened videos.", - cimglist_instance,filename); - if (is_empty()) - throw CImgInstanceException(_cimglist_instance - "save_video(): Instance list is empty.", - cimglist_instance); - const unsigned int W = _data?_data[0]._width:0, H = _data?_data[0]._height:0; - if (!W || !H) - throw CImgInstanceException(_cimglist_instance - "save_video(): Frame [0] is an empty image.", - cimglist_instance); - const char - *const _codec = codec && *codec?codec:"h264", - codec0 = cimg::uppercase(_codec[0]), - codec1 = _codec[0]?cimg::uppercase(_codec[1]):0, - codec2 = _codec[1]?cimg::uppercase(_codec[2]):0, - codec3 = _codec[2]?cimg::uppercase(_codec[3]):0; - cimg::mutex(9); - writers[index] = new cv::VideoWriter(filename,_cimg_fourcc(codec0,codec1,codec2,codec3),fps,cv::Size(W,H)); - if (!writers[index]->isOpened()) { - delete writers[index]; - writers[index] = 0; - cimg::mutex(9,0); - throw CImgIOException(_cimglist_instance - "save_video(): File '%s', unable to initialize video writer with codec '%c%c%c%c'.", - cimglist_instance,filename, - codec0,codec1,codec2,codec3); - } - CImg::string(filename).move_to(filenames[index]); - sizes(index,0) = W; - sizes(index,1) = H; - cimg::mutex(9,0); - } - - if (!is_empty()) { - const unsigned int W = sizes(index,0), H = sizes(index,1); - cimg::mutex(9); - cimglist_for(*this,l) { - CImg &src = _data[l]; - if (src.is_empty()) - cimg::warn(_cimglist_instance - "save_video(): Skip empty frame %d for file '%s'.", - cimglist_instance,l,filename); - if (src._spectrum>3) - cimg::warn(_cimglist_instance - "save_video(): Frame %u has incompatible dimension (%u,%u,%u,%u). " - "Some image data may be ignored when writing frame into video file '%s'.", - cimglist_instance,l,src._width,src._height,src._depth,src._spectrum,filename); - cimg_forZ(src,z) { - CImg _src = src._depth>1?src.get_slice(z):src.get_shared(); - if (_src._width==W && _src._height==H && _src._spectrum==3) - writers[index]->write(CImg(_src)._cimg2cvmat()); - else { - CImg __src(_src,false); - __src.channels(0,std::min(__src._spectrum - 1,2U)).resize(W,H); - __src.resize(W,H,1,3,__src._spectrum==1); - writers[index]->write(__src._cimg2cvmat()); - } - } - } - cimg::mutex(9,0); - } - - cimg::mutex(9); - if (!keep_open) { - delete writers[index]; - writers[index] = 0; - filenames[index].assign(); - sizes(index,0) = sizes(index,1) = 0; - last_used_index = -1; - } else last_used_index = index; - cimg::mutex(9,0); - } catch (CImgIOException &e) { - if (!keep_open) return save_ffmpeg_external(filename,fps); - throw e; - } - return *this; -#endif - } - - //! Save image sequence, using the external tool 'ffmpeg'. - /** - \param filename Filename to write data to. - \param fps Number of frames per second. - \param codec Type of compression. - \param bitrate Output bitrate - **/ - const CImgList& save_ffmpeg_external(const char *const filename, const unsigned int fps=25, - const char *const codec=0, const unsigned int bitrate=2048) const { - if (!filename) - throw CImgArgumentException(_cimglist_instance - "save_ffmpeg_external(): Specified filename is (null).", - cimglist_instance); - if (is_empty()) { cimg::fempty(0,filename); return *this; } - - const char - *const ext = cimg::split_filename(filename), - *const _codec = codec?codec: - !cimg::strcasecmp(ext,"flv")?"flv": - !cimg::strcasecmp(ext,"mp4")?"h264":"mpeg2video"; - - CImg command(1024), filename_tmp(256), filename_tmp2(256); - CImgList filenames; - std::FILE *file = 0; - cimglist_for(*this,l) if (!_data[l].is_sameXYZ(_data[0])) - throw CImgInstanceException(_cimglist_instance - "save_ffmpeg_external(): Invalid instance dimensions for file '%s'.", - cimglist_instance, - filename); - do { - cimg_snprintf(filename_tmp,filename_tmp._width,"%s%c%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand()); - cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_000001.ppm",filename_tmp._data); - if ((file=cimg::std_fopen(filename_tmp2,"rb"))!=0) cimg::fclose(file); - } while (file); - unsigned int frame = 1; - cimglist_for(*this,l) { - CImg& src = _data[l]; - cimg_forZ(src,z) { - cimg_snprintf(filename_tmp2,filename_tmp2._width,"%s_%.6u.ppm",filename_tmp._data,frame); - CImg::string(filename_tmp2).move_to(filenames); - CImg _src = src._depth>1?src.get_slice(z):src.get_shared(); - if (_src._width%2 || _src._height%2) // Force output to have an even number of columns and rows - _src.assign(_src.get_resize(_src._width + (_src._width%2),_src._height + (_src._height%2),1,-100,0),false); - if (_src._spectrum!=3) // Force output to be one slice, in color - _src.assign(_src.get_resize(-100,-100,1,3),false); - _src.save_pnm(filename_tmp2); - ++frame; - } - } - cimg_snprintf(command,command._width, - "\"%s\" -v -8 -y -i \"%s_%%6d.ppm\" -pix_fmt yuv420p -vcodec %s -b %uk -r %u \"%s\"", - cimg::ffmpeg_path(), - CImg::string(filename_tmp)._system_strescape().data(), - _codec,bitrate,fps, - CImg::string(filename)._system_strescape().data()); - cimg::system(command, cimg::ffmpeg_path()); - file = cimg::std_fopen(filename,"rb"); - if (!file) - throw CImgIOException(_cimglist_instance - "save_ffmpeg_external(): Failed to save file '%s' with external command 'ffmpeg'.", - cimglist_instance, - filename); - else cimg::fclose(file); - cimglist_for(*this,l) std::remove(filenames[l]); - return *this; - } - - //! Serialize a CImgList instance into a raw CImg buffer. - /** - \param is_compressed tells if zlib compression must be used for serialization - (this requires 'cimg_use_zlib' been enabled). - \param header_size Reserve empty bytes as a starting header. - **/ - CImg get_serialize(const bool is_compressed=false, const unsigned int header_size=0) const { -#ifndef cimg_use_zlib - if (is_compressed) - cimg::warn(_cimglist_instance - "get_serialize(): Unable to compress data unless zlib is enabled, " - "storing them uncompressed.", - cimglist_instance); -#endif - CImgList stream; - if (header_size) CImg(1,header_size,1,1,0).move_to(stream); - CImg tmpstr(128); - const char *const ptype = pixel_type(), *const etype = cimg::endianness()?"big":"little"; - cimg_snprintf(tmpstr,tmpstr._width,"%u %s %s_endian\n",_width,ptype,etype); - CImg::string(tmpstr,false).move_to(stream); - cimglist_for(*this,l) { - const CImg& img = _data[l]; - cimg_snprintf(tmpstr,tmpstr._width,"%u %u %u %u",img._width,img._height,img._depth,img._spectrum); - CImg::string(tmpstr,false).move_to(stream); - if (img._data) { - CImg tmp; - if (cimg::endianness()) { tmp = img; cimg::invert_endianness(tmp._data,tmp.size()); } - const CImg& ref = cimg::endianness()?tmp:img; - bool failed_to_compress = true; - if (is_compressed) { -#ifdef cimg_use_zlib - const ulongT siz = sizeof(T)*ref.size(); - uLongf csiz = (ulongT)compressBound(siz); - Bytef *const cbuf = new Bytef[csiz]; - if (compress(cbuf,&csiz,(Bytef*)ref._data,siz)) - cimg::warn(_cimglist_instance - "get_serialize(): Failed to save compressed data, saving them uncompressed.", - cimglist_instance); - else { - cimg_snprintf(tmpstr,tmpstr._width," #%lu\n",csiz); - CImg::string(tmpstr,false).move_to(stream); - CImg(cbuf,csiz).move_to(stream); - delete[] cbuf; - failed_to_compress = false; - } -#endif - } - if (failed_to_compress) { // Write in a non-compressed way - CImg::string("\n",false).move_to(stream); - stream.insert(1); - stream.back(). - assign((unsigned char*)ref._data,ref._width,ref._height,ref._depth,ref._spectrum*sizeof(T),true); - } - } else CImg::string("\n",false).move_to(stream); - } - - // Determine best serialized image dimensions to store the whole buffer. - ulongT siz = 0; - cimglist_for(stream,l) siz+=stream[l].size(); - const ulongT max_siz = (ulongT)cimg::type::max(); - const unsigned int - nw = (unsigned int)(siz/max_siz + ((siz%max_siz)?1:0)), - nh = (unsigned int)(siz/nw + (siz%nw?1:0)); - CImg res(nw,nh,1,1,0); - unsigned char *ptr = res.data(); - cimglist_for(stream,l) { siz = stream[l].size(); std::memcpy(ptr,stream[l]._data,siz); ptr+=siz; } - return res; - } - - //! Unserialize a CImg serialized buffer into a CImgList list. - template - static CImgList get_unserialize(const CImg& buffer, const unsigned int header_size=0) { -#ifdef cimg_use_zlib -#define _cimgz_unserialize_case(Tss) { \ - Bytef *cbuf = 0; \ - if (sizeof(t)!=1 || buffer.pixel_type()==cimg::type::string()) { \ - cbuf = new Bytef[csiz]; Bytef *_cbuf = cbuf; \ - for (ulongT k = 0; k::get_unserialize(): Unable to unserialize compressed data " \ - "unless zlib is enabled.", \ - pixel_type()); -#endif - -#define _cimg_unserialize_case(Ts1,Ts2,Ts3,Tss) \ - if (!loaded && ((Ts1 && !cimg::strcasecmp(Ts1,str_pixeltype)) || \ - (Ts2 && !cimg::strcasecmp(Ts2,str_pixeltype)) || \ - (Ts3 && !cimg::strcasecmp(Ts3,str_pixeltype)))) { \ - for (unsigned int l = 0; l::unserialize(): Invalid specified size (%u,%u,%u,%u) for " \ - "image #%u in serialized buffer.", \ - pixel_type(),W,H,D,C,l); \ - if (W*H*D*C>0) { \ - CImg raw; \ - CImg &img = res._data[l]; \ - if (err==5) _cimgz_unserialize_case(Tss) \ - else { \ - raw.assign(W,H,D,C); \ - CImg _raw((unsigned char*)raw._data,W*sizeof(Tss),H,D,C,true); \ - if (sizeof(t)==1) { std::memcpy(_raw,stream,_raw.size()); stream+=_raw.size(); } \ - else cimg_for(_raw,p,unsigned char) *p = (unsigned char)*(stream++); \ - } \ - if (endian!=cimg::endianness()) cimg::invert_endianness(raw._data,raw.size()); \ - raw.move_to(img); \ - } \ - } \ - loaded = true; \ - } - - if (buffer.is_empty()) - throw CImgArgumentException("CImgList<%s>::get_unserialize(): Specified serialized buffer is (null).", - pixel_type()); - CImgList res; - const t *stream = buffer._data + header_size, *const estream = buffer._data + buffer.size(); - bool loaded = false, endian = cimg::endianness(), is_bytef = false; - CImg tmp(256), str_pixeltype(256), str_endian(256); - *tmp = *str_pixeltype = *str_endian = 0; - unsigned int j, N = 0, W, H, D, C; - uint64T csiz; - int i, err; - cimg::unused(is_bytef); - do { - j = 0; while ((i=(int)*stream)!='\n' && stream::get_unserialize(): CImg header not found in serialized buffer.", - pixel_type()); - if (!cimg::strncasecmp("little",str_endian,6)) endian = false; - else if (!cimg::strncasecmp("big",str_endian,3)) endian = true; - res.assign(N); - _cimg_unserialize_case("bool",0,0,cimg_uint8); - _cimg_unserialize_case("uint8","unsigned_char","uchar",cimg_uint8); - _cimg_unserialize_case("int8",0,0,cimg_int8); - _cimg_unserialize_case("char",0,0,char); - _cimg_unserialize_case("uint16","unsigned_short","ushort",cimg_uint16); - _cimg_unserialize_case("int16","short",0,cimg_int16); - _cimg_unserialize_case("uint32","unsigned_int","uint",cimg_uint32); - _cimg_unserialize_case("int32","int",0,cimg_int32); - _cimg_unserialize_case("uint64","unsigned_int64",0,cimg_uint64); - _cimg_unserialize_case("int64",0,0,cimg_int64); - _cimg_unserialize_case("float32","float",0,cimg_float32); - _cimg_unserialize_case("float64","double",0,cimg_float64); - if (!loaded) - throw CImgArgumentException("CImgList<%s>::get_unserialize(): Unsupported pixel type '%s' defined " - "in serialized buffer.", - pixel_type(),str_pixeltype._data); - return res; - } - - //@} - //---------------------------------- - // - //! \name Others - //@{ - //---------------------------------- - - //! Return a CImg pre-defined font with requested height. - /** - \param font_height Height of the desired font (exact match for 13,23,53,103). - \param is_variable_width Decide if the font has a variable (\c true) or fixed (\c false) width. - **/ - static const CImgList& font(const unsigned int requested_height, const bool is_variable_width=true) { - if (!requested_height) return CImgList::const_empty(); - cimg::mutex(11); - static const unsigned char font_resizemap[] = { - 0, 4, 7, 9, 11, 13, 15, 17, 19, 21, 22, 24, 26, 27, 29, 30, - 32, 33, 35, 36, 38, 39, 41, 42, 43, 45, 46, 47, 49, 50, 51, 52, - 54, 55, 56, 58, 59, 60, 61, 62, 64, 65, 66, 67, 68, 69, 71, 72, - 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 123, 124, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 157, 158, 159, 160, 161, 162, 163, 164, 164, 165, - 166, 167, 168, 169, 170, 170, 171, 172, 173, 174, 175, 176, 176, 177, 178, 179, - 180, 181, 181, 182, 183, 184, 185, 186, 186, 187, 188, 189, 190, 191, 191, 192, - 193, 194, 195, 196, 196, 197, 198, 199, 200, 200, 201, 202, 203, 204, 205, 205, - 206, 207, 208, 209, 209, 210, 211, 212, 213, 213, 214, 215, 216, 216, 217, 218, - 219, 220, 220, 221, 222, 223, 224, 224, 225, 226, 227, 227, 228, 229, 230, 231, - 231, 232, 233, 234, 234, 235, 236, 237, 238, 238, 239, 240, 241, 241, 242, 243, - 244, 244, 245, 246, 247, 247, 248, 249, 250, 250, 251, 252, 253, 253, 254, 255 }; - static const char *const *font_data[] = { - cimg::data_font_small, - cimg::data_font_normal, - cimg::data_font_large, - cimg::data_font_huge }; - static const unsigned int - font_width[] = { 10,26,52,104 }, - font_height[] = { 13,32,64,128 }, - font_M[] = { 86,91,91,47 }, - font_chunk[] = { sizeof(cimg::data_font_small)/sizeof(char*), - sizeof(cimg::data_font_normal)/sizeof(char*), - sizeof(cimg::data_font_large)/sizeof(char*), - sizeof(cimg::data_font_huge)/sizeof(char*) }; - static const unsigned char font_is_binary[] = { 1,0,0,1 }; - static CImg font_base[4]; - - unsigned int ind = - requested_height<=font_height[0]?0U: - requested_height<=font_height[1]?1U: - requested_height<=font_height[2]?2U:3U; - - // Decompress nearest base font data if needed. - CImg &basef = font_base[ind]; - if (!basef) { - basef.assign(256*font_width[ind],font_height[ind]); - - unsigned char *ptrd = basef; - const unsigned char *const ptrde = basef.end(); - - // Recompose font data from several chunks, to deal with MS compiler limit with big strings (64 Kb). - CImg dataf; - for (unsigned int k = 0; k::string(font_data[ind][k],k==font_chunk[ind] - 1,true),'x'); - - // Uncompress font data (decode RLE). - const unsigned int M = font_M[ind]; - if (font_is_binary[ind]) - for (const char *ptrs = dataf; *ptrs; ++ptrs) { - const int _n = (int)(*ptrs - M - 32), v = _n>=0?255:0, n = _n>=0?_n:-_n; - if (ptrd + n<=ptrde) { std::memset(ptrd,v,n); ptrd+=n; } - else { std::memset(ptrd,v,ptrde - ptrd); break; } - } - else - for (const char *ptrs = dataf; *ptrs; ++ptrs) { - int n = (int)*ptrs - M - 32, v = 0; - if (n>=0) { v = 85*n; n = 1; } - else { - n = -n; - v = (int)*(++ptrs) - M - 32; - if (v<0) { v = 0; --ptrs; } else v*=85; - } - if (ptrd + n<=ptrde) { std::memset(ptrd,v,n); ptrd+=n; } - else { std::memset(ptrd,v,ptrde - ptrd); break; } - } - } - - // Find optimal font cache location to return. - static CImgList fonts[16]; - static bool is_variable_widths[16] = { 0 }; - ind = ~0U; - for (int i = 0; i<16; ++i) - if (!fonts[i] || (is_variable_widths[i]==is_variable_width && requested_height==fonts[i][0]._height)) { - ind = (unsigned int)i; break; // Found empty slot or cached font - } - if (ind==~0U) { // No empty slots nor existing font in cache - fonts->assign(); - std::memmove((void*)fonts,(void*)(fonts + 1),15*sizeof(CImgList)); - std::memmove(is_variable_widths,is_variable_widths + 1,15*sizeof(bool)); - std::memset((void*)(fonts + (ind=15)),0,sizeof(CImgList)); // Free a slot in cache for new font - } - CImgList &font = fonts[ind]; - - // Render requested font. - if (!font) { - is_variable_widths[ind] = is_variable_width; - basef.get_split('x',256).move_to(font); - -// cimg::tic(); - - if (requested_height!=font[0]._height) - cimglist_for(font,l) { - font[l].resize(std::max(1U,font[l]._width*requested_height/font[l]._height),requested_height,-100,-100,5); - cimg_for(font[l],ptr,ucharT) *ptr = font_resizemap[*ptr]; - } - -// cimg::toc(); -// std::exit(0); - - if (is_variable_width) { // Crop font - cimglist_for(font,l) { - CImg& letter = font[l]; - int xmin = letter.width(), xmax = 0; - cimg_forX(letter,x) { // Find xmin - cimg_forY(letter,y) if (letter(x,y)) { xmin = x; break; } - if (xmin!=letter.width()) break; - } - cimg_rofX(letter,x) { // Find xmax - cimg_forY(letter,y) if (letter(x,y)) { xmax = x; break; } - if (xmax) break; - } - if (xmin<=xmax) letter.crop(xmin,0,xmax,letter._height - 1); - } - font[(int)' '].resize(font[(int)'f']._width,-100,-100,-100,0); - if (' ' + 256& FFT(const char axis, const bool invert=false) { - if (is_empty()) return *this; - if (_width==1) insert(1); - if (_width>2) - cimg::warn(_cimglist_instance - "FFT(): Instance has more than 2 images", - cimglist_instance); - CImg::FFT(_data[0],_data[1],axis,invert); - return *this; - } - - //! Compute a 1-D Fast Fourier Transform, along specified axis \newinstance. - CImgList get_FFT(const char axis, const bool invert=false) const { - return CImgList(*this,false).FFT(axis,invert); - } - - //! Compute n-D Fast Fourier Transform. - /** - \param invert Tells if the direct (\c false) or inverse transform (\c true) is computed. - **/ - CImgList& FFT(const bool invert=false) { - if (is_empty()) return *this; - if (_width==1) insert(1); - if (_width>2) - cimg::warn(_cimglist_instance - "FFT(): Instance has more than 2 images", - cimglist_instance); - - CImg::FFT(_data[0],_data[1],invert); - return *this; - } - - //! Compute n-D Fast Fourier Transform \newinstance. - CImgList get_FFT(const bool invert=false) const { - return CImgList(*this,false).FFT(invert); - } - - //! Reverse primitives orientations of a 3D object. - /** - **/ - CImgList& reverse_object3d() { - cimglist_for(*this,l) { - CImg& p = _data[l]; - switch (p.size()) { - case 2 : case 3: cimg::swap(p[0],p[1]); break; - case 6 : cimg::swap(p[0],p[1],p[2],p[4],p[3],p[5]); break; - case 9 : cimg::swap(p[0],p[1],p[3],p[5],p[4],p[6]); break; - case 4 : cimg::swap(p[0],p[1],p[2],p[3]); break; - case 12 : cimg::swap(p[0],p[1],p[2],p[3],p[4],p[6],p[5],p[7],p[8],p[10],p[9],p[11]); break; - } - } - return *this; - } - - //! Reverse primitives orientations of a 3D object \newinstance. - CImgList get_reverse_object3d() const { - return (+*this).reverse_object3d(); - } - - //@} - }; // struct CImgList { ... - - // Completion of previously declared functions - //-------------------------------------------- - namespace cimg { - - // Functions to return standard streams 'stdin', 'stdout' and 'stderr'. - // (throw a CImgIOException when macro 'cimg_use_r' is defined). - inline FILE* _stdin(const bool throw_exception) { -#ifndef cimg_use_r - cimg::unused(throw_exception); - return stdin; -#else - if (throw_exception) { - cimg::exception_mode(0); - throw CImgIOException("cimg::stdin(): Reference to 'stdin' stream not allowed in R mode " - "('cimg_use_r' is defined)."); - } - return 0; -#endif - } - - inline FILE* _stdout(const bool throw_exception) { -#ifndef cimg_use_r - cimg::unused(throw_exception); - return stdout; -#else - if (throw_exception) { - cimg::exception_mode(0); - throw CImgIOException("cimg::stdout(): Reference to 'stdout' stream not allowed in R mode " - "('cimg_use_r' is defined)."); - } - return 0; -#endif - } - - inline FILE* _stderr(const bool throw_exception) { -#ifndef cimg_use_r - cimg::unused(throw_exception); - return stderr; -#else - if (throw_exception) { - cimg::exception_mode(0); - throw CImgIOException("cimg::stderr(): Reference to 'stderr' stream not allowed in R mode " - "('cimg_use_r' is defined)."); - } - return 0; -#endif - } - - // Open a file (similar to std:: fopen(), but with wide character support on Windows). - inline std::FILE *std_fopen(const char *const path, const char *const mode) { - std::FILE *const res = std::fopen(path,mode); - if (res) return res; -#if cimg_OS==2 - // Try alternative method, with wide-character string. - int err = MultiByteToWideChar(CP_UTF8,0,path,-1,0,0); - if (err) { - CImg wpath((unsigned int)err); - err = MultiByteToWideChar(CP_UTF8,0,path,-1,wpath,err); - if (err) { // Convert 'mode' to a wide-character string - err = MultiByteToWideChar(CP_UTF8,0,mode,-1,0,0); - if (err) { - CImg wmode((unsigned int)err); - if (MultiByteToWideChar(CP_UTF8,0,mode,-1,wmode,err)) - return _wfopen(wpath,wmode); - } - } - } -#endif - return 0; - } - - //! Search path of an executable (Windows only). -#if cimg_OS==2 - inline bool win_searchpath(const char *const exec_name, char *const res, const unsigned int size_res) { - char *ptr = 0; - DWORD err = SearchPathA(0,exec_name,0,size_res,res,&ptr); - return err!=0; - } -#endif - - //! Get the file or directory attributes with support for UTF-8 paths (Windows only). -#if cimg_OS==2 - inline DWORD win_getfileattributes(const char *const path) { - DWORD res = GetFileAttributesA(path); - if (res==INVALID_FILE_ATTRIBUTES) { - // Try alternative method, with wide-character string. - int err = MultiByteToWideChar(CP_UTF8,0,path,-1,0,0); - if (err) { - CImg wpath((unsigned int)err); - if (MultiByteToWideChar(CP_UTF8,0,path,-1,wpath,err)) res = GetFileAttributesW(wpath); - } - } - return res; - } -#endif - - //! Get/set path to the Program Files/ directory (Windows only). - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the program files. - **/ -#if cimg_OS==2 - inline const char* win_programfiles_path(const char *const user_path=0, const bool reinit_path=false) { - static CImg s_path; - cimg::mutex(7); - if (reinit_path) s_path.assign(); - if (user_path) { - if (!s_path) s_path.assign(1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path.assign(MAX_PATH); - *s_path = 0; - // Note: in the following line, 0x26 = CSIDL_PROGRAM_FILES (not defined on every compiler). -#if !defined(__INTEL_COMPILER) - if (!SHGetSpecialFolderPathA(0,s_path,0x0026,false)) { - const char *const pfPath = std::getenv("PROGRAMFILES"); - if (pfPath) std::strncpy(s_path,pfPath,MAX_PATH - 1); - else std::strcpy(s_path,"C:\\PROGRA~1"); - } -#else - std::strcpy(s_path,"C:\\PROGRA~1"); -#endif - } - cimg::mutex(7,0); - return s_path; - } -#endif - - //! Get/set path to the \c curl binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c curl binary. - **/ - inline const char *curl_path(const char *const user_path, const bool reinit_path) { - static CImg s_path; - cimg::mutex(7); - if (reinit_path) s_path.assign(); - if (user_path) { - if (!s_path) s_path.assign(1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path.assign(1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (win_searchpath("curl.exe",s_path,s_path._width)) path_found = true; - if (!path_found) { - std::strcpy(s_path,".\\curl.exe"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"curl.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./curl"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"curl"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } - - //! Get/set path to the \c dcraw binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c dcraw binary. - **/ - inline const char *dcraw_path(const char *const user_path, const bool reinit_path) { - static CImg s_path; - cimg::mutex(7); - if (reinit_path) s_path.assign(); - if (user_path) { - if (!s_path) s_path.assign(1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path.assign(1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (win_searchpath("dcraw.exe",s_path,s_path._width)) path_found = true; - if (!path_found) { - std::strcpy(s_path,".\\dcraw.exe"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"dcraw.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./dcraw"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"dcraw"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } - - //! Get/set path to the FFMPEG's \c ffmpeg binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c ffmpeg binary. - **/ - inline const char *ffmpeg_path(const char *const user_path, const bool reinit_path) { - static CImg s_path; - cimg::mutex(7); - if (reinit_path) s_path.assign(); - if (user_path) { - if (!s_path) s_path.assign(1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path.assign(1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (win_searchpath("ffmpeg.exe",s_path,s_path._width)) path_found = true; - if (!path_found) { - std::strcpy(s_path,".\\ffmpeg.exe"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"ffmpeg.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./ffmpeg"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"ffmpeg"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } - - //! Get/set path to the GraphicsMagick's \c gm binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c gm binary. - **/ - inline const char* graphicsmagick_path(const char *const user_path, const bool reinit_path) { - static CImg s_path; - cimg::mutex(7); - if (reinit_path) s_path.assign(); - if (user_path) { - if (!s_path) s_path.assign(1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path.assign(1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (win_searchpath("gm.exe",s_path,s_path._width)) path_found = true; - const char *const pf_path = win_programfiles_path(); - if (!path_found) { - std::strcpy(s_path,".\\gm.exe"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%.2d-\\gm.exe",pf_path,k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%d-Q\\gm.exe",pf_path,k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%d\\gm.exe",pf_path,k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",pf_path,k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",pf_path,k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"%s\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",pf_path,k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%.2d-\\gm.exe",k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%d-Q\\gm.exe",k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%d\\gm.exe",k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"C:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%.2d-\\gm.exe",k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%d-Q\\gm.exe",k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%d\\gm.exe",k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%.2d-\\VISUA~1\\BIN\\gm.exe",k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%d-Q\\VISUA~1\\BIN\\gm.exe",k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"D:\\GRAPHI~1.%d\\VISUA~1\\BIN\\gm.exe",k); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"gm.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./gm"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"gm"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } - - //! Get/set path to the \c gunzip binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c gunzip binary. - **/ - inline const char *gunzip_path(const char *const user_path, const bool reinit_path) { - static CImg s_path; - cimg::mutex(7); - if (reinit_path) s_path.assign(); - if (user_path) { - if (!s_path) s_path.assign(1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path.assign(1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (win_searchpath("gunzip.exe",s_path,s_path._width)) path_found = true; - if (!path_found) { - std::strcpy(s_path,".\\gunzip.exe"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"gunzip.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./gunzip"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"gunzip"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } - - //! Get/set path to the \c gzip binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c gzip binary. - **/ - inline const char *gzip_path(const char *const user_path, const bool reinit_path) { - static CImg s_path; - cimg::mutex(7); - if (reinit_path) s_path.assign(); - if (user_path) { - if (!s_path) s_path.assign(1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path.assign(1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (win_searchpath("gzip.exe",s_path,s_path._width)) path_found = true; - if (!path_found) { - std::strcpy(s_path,".\\gzip.exe"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"gzip.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./gzip"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"gzip"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } - - //! Get/set path to the ImageMagick's \c convert binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c convert binary. - **/ - inline const char* imagemagick_path(const char *const user_path, const bool reinit_path) { - static CImg s_path; - cimg::mutex(7); - if (reinit_path) s_path.assign(); - if (user_path) { - if (!s_path) s_path.assign(1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path.assign(1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (win_searchpath("magick.exe",s_path,s_path._width)) path_found = true; - const char *const pf_path = win_programfiles_path(); - for (int l = 0; l<2 && !path_found; ++l) { - const char *const s_exe = l?"convert":"magick"; - cimg_snprintf(s_path,s_path._width,".\\%s.exe",s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%.2d-\\%s.exe",pf_path,k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d-Q\\%s.exe",pf_path,k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d\\%s.exe",pf_path,k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\%s.exe",pf_path,k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\%s.exe",pf_path,k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"%s\\IMAGEM~1.%d\\VISUA~1\\BIN\\%s.exe",pf_path,k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%.2d-\\%s.exe",k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d-Q\\%s.exe",k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d\\%s.exe",k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\%s.exe",k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\%s.exe",k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"C:\\IMAGEM~1.%d\\VISUA~1\\BIN\\%s.exe",k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%.2d-\\%s.exe",k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d-Q\\%s.exe",k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d\\%s.exe",k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=10 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%.2d-\\VISUA~1\\BIN\\%s.exe",k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 9; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d-Q\\VISUA~1\\BIN\\%s.exe",k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - for (int k = 32; k>=0 && !path_found; --k) { - cimg_snprintf(s_path,s_path._width,"D:\\IMAGEM~1.%d\\VISUA~1\\BIN\\%s.exe",k,s_exe); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) cimg_snprintf(s_path,s_path._width,"%s.exe",s_exe); - } -#else - std::strcpy(s_path,"./magick"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - if (!path_found) { - std::strcpy(s_path,"./convert"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"convert"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } - - //! Get/set path to the Medcon's \c medcon binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c medcon binary. - **/ - inline const char* medcon_path(const char *const user_path, const bool reinit_path) { - static CImg s_path; - cimg::mutex(7); - if (reinit_path) s_path.assign(); - if (user_path) { - if (!s_path) s_path.assign(1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path.assign(1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (win_searchpath("medcon.exe",s_path,s_path._width)) path_found = true; - const char *const pf_path = win_programfiles_path(); - if (!path_found) { - std::strcpy(s_path,".\\medcon.exe"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) { - cimg_snprintf(s_path,s_path._width,"%s\\XMedCon\\bin\\medcon.bat",pf_path); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) { - cimg_snprintf(s_path,s_path._width,"%s\\XMedCon\\bin\\medcon.exe",pf_path); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) { - std::strcpy(s_path,"C:\\XMedCon\\bin\\medcon.exe"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"medcon.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./medcon"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"medcon"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } - - //! Get/set path to store temporary files. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path where temporary files can be saved. - **/ - inline const char* temporary_path(const char *const user_path, const bool reinit_path) { -#define _cimg_test_temporary_path(p) \ - if (!path_found) { \ - cimg_snprintf(s_path,s_path._width,"%s",p); \ - cimg_snprintf(tmp,tmp._width,"%s%c%s",s_path.data(),cimg_file_separator,filename_tmp._data); \ - if ((file=cimg::std_fopen(tmp,"wb"))!=0) { cimg::fclose(file); std::remove(tmp); path_found = true; } \ - } - static CImg s_path; - cimg::mutex(7); - if (reinit_path) s_path.assign(); - if (user_path) { - if (!s_path) s_path.assign(1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path.assign(1024); - bool path_found = false; - CImg tmp(1024), filename_tmp(256); - std::FILE *file = 0; - cimg_snprintf(filename_tmp,filename_tmp._width,"%s.tmp",cimg::filenamerand()); - char *tmpPath = std::getenv("TMP"); - if (!tmpPath) { tmpPath = std::getenv("TEMP"); winformat_string(tmpPath); } - if (tmpPath) _cimg_test_temporary_path(tmpPath); -#if cimg_OS==2 - _cimg_test_temporary_path("C:\\WINNT\\Temp"); - _cimg_test_temporary_path("C:\\WINDOWS\\Temp"); - _cimg_test_temporary_path("C:\\Temp"); - _cimg_test_temporary_path("C:"); - _cimg_test_temporary_path("D:\\WINNT\\Temp"); - _cimg_test_temporary_path("D:\\WINDOWS\\Temp"); - _cimg_test_temporary_path("D:\\Temp"); - _cimg_test_temporary_path("D:"); -#else - _cimg_test_temporary_path("/tmp"); - _cimg_test_temporary_path("/var/tmp"); -#endif - if (!path_found) { - *s_path = 0; - std::strncpy(tmp,filename_tmp,tmp._width - 1); - if ((file=cimg::std_fopen(tmp,"wb"))!=0) { cimg::fclose(file); std::remove(tmp); path_found = true; } - } - if (!path_found) { - cimg::mutex(7,0); - throw CImgIOException("cimg::temporary_path(): Failed to locate path for writing temporary files.\n"); - } - } - cimg::mutex(7,0); - return s_path; - } - - //! Get/set path to the \c wget binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c wget binary. - **/ - inline const char *wget_path(const char *const user_path, const bool reinit_path) { - static CImg s_path; - cimg::mutex(7); - if (reinit_path) s_path.assign(); - if (user_path) { - if (!s_path) s_path.assign(1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path.assign(1024); - bool path_found = false; - std::FILE *file = 0; -#if cimg_OS==2 - if (win_searchpath("wget.exe",s_path,s_path._width)) path_found = true; - if (!path_found) { - std::strcpy(s_path,".\\wget.exe"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"wget.exe"); -#else - if (!path_found) { - std::strcpy(s_path,"./wget"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"wget"); -#endif - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } - -#if cimg_OS==2 - //! Get/set path to the \c powershell binary. - /** - \param user_path Specified path, or \c 0 to get the path currently used. - \param reinit_path Force path to be recalculated (may take some time). - \return Path containing the \c wget binary. - **/ - inline const char *powershell_path(const char *const user_path, const bool reinit_path) { - static CImg s_path; - cimg::mutex(7); - if (reinit_path) s_path.assign(); - if (user_path) { - if (!s_path) s_path.assign(1024); - std::strncpy(s_path,user_path,1023); - } else if (!s_path) { - s_path.assign(1024); - bool path_found = false; - std::FILE *file = 0; - if (win_searchpath("powershell.exe",s_path,s_path._width)) path_found = true; - if (!path_found) { - std::strcpy(s_path,".\\powershell.exe"); - if ((file=cimg::std_fopen(s_path,"r"))!=0) { cimg::fclose(file); path_found = true; } - } - if (!path_found) std::strcpy(s_path,"powershell.exe"); - winformat_string(s_path); - } - cimg::mutex(7,0); - return s_path; - } -#endif - - // [internal] Sorting function, used by cimg::files(). - inline int _sort_files(const void* a, const void* b) { - const CImg &sa = *(CImg*)a, &sb = *(CImg*)b; - return std::strcmp(sa._data,sb._data); - } - - //! Generate a numbered version of a filename. - inline char* number_filename(const char *const filename, const int number, - const unsigned int digits, char *const str) { - if (!filename) { if (str) *str = 0; return 0; } - const unsigned int siz = (unsigned int)std::strlen(filename); - CImg format(16), body(siz + 32); - const char *const ext = cimg::split_filename(filename,body); - if (*ext) cimg_snprintf(format,format._width,"%%s_%%.%ud.%%s",digits); - else cimg_snprintf(format,format._width,"%%s_%%.%ud",digits); - cimg_snprintf(str,1024,format._data,body._data,number,ext); - return str; - } - - //! Return list of files/directories in specified directory. - /** - \param path Path to the directory. Set to 0 for current directory. - \param is_pattern Tell if specified path has a matching pattern in it. - \param mode Output type, can be primary { 0=files only | 1=folders only | 2=files + folders }. - \param include_path Tell if \c path must be included in resulting filenames. - \return A list of filenames. - **/ - inline CImgList files(const char *const path, const bool is_pattern=false, - const unsigned int mode=2, const bool include_path=false) { - if (!path || !*path) return files("*",true,mode,include_path); - CImgList res; - - // If path is a valid folder name, ignore argument 'is_pattern'. - const bool _is_pattern = is_pattern && !cimg::is_directory(path); - bool is_root = false, is_current = false; - cimg::unused(is_root,is_current); - - // Clean format of input path. - CImg pattern, _path = CImg::string(path); -#if cimg_OS==2 - for (char *ps = _path; *ps; ++ps) if (*ps=='\\') *ps='/'; -#endif - char *pd = _path; - for (char *ps = pd; *ps; ++ps) { if (*ps!='/' || *ps!=*(ps+1)) *(pd++) = *ps; } - *pd = 0; - unsigned int lp = (unsigned int)std::strlen(_path); - if (!_is_pattern && lp && _path[lp - 1]=='/') { - _path[lp - 1] = 0; --lp; -#if cimg_OS!=2 - is_root = !*_path; -#endif - } - - // Separate folder path and matching pattern. - if (_is_pattern) { - const unsigned int bpos = (unsigned int)(cimg::basename(_path,'/') - _path.data()); - CImg::string(_path).move_to(pattern); - if (bpos) { - _path[bpos - 1] = 0; // End 'path' at last slash -#if cimg_OS!=2 - is_root = !*_path; -#endif - } else { // No path to folder specified, assuming current folder - is_current = true; *_path = 0; - } - lp = (unsigned int)std::strlen(_path); - } - - // Windows version. -#if cimg_OS==2 - if (!_is_pattern) { - pattern.assign(lp + 3); - std::memcpy(pattern,_path,lp); - pattern[lp] = '/'; pattern[lp + 1] = '*'; pattern[lp + 2] = 0; - } - WIN32_FIND_DATAA file_data; - const HANDLE dir = FindFirstFileA(pattern.data(),&file_data); - if (dir==INVALID_HANDLE_VALUE) return CImgList::const_empty(); - do { - const char *const filename = file_data.cFileName; - if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) { - const unsigned int lf = (unsigned int)std::strlen(filename); - const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)!=0; - if ((!mode && !is_directory) || (mode==1 && is_directory) || mode>=2) { - if (include_path) { - CImg full_filename((lp?lp+1:0) + lf + 1); - if (lp) { std::memcpy(full_filename,_path,lp); full_filename[lp] = '/'; } - std::memcpy(full_filename._data + (lp?lp + 1:0),filename,lf + 1); - full_filename.move_to(res); - } else CImg(filename,lf + 1).move_to(res); - } - } - } while (FindNextFileA(dir,&file_data)); - FindClose(dir); - - // Unix version (posix). -#elif cimg_OS == 1 - DIR *const dir = opendir(is_root?"/":is_current?".":_path.data()); - if (!dir) return CImgList::const_empty(); - struct dirent *ent; - while ((ent=readdir(dir))!=0) { - const char *const filename = ent->d_name; - if (*filename!='.' || (filename[1] && (filename[1]!='.' || filename[2]))) { - const unsigned int lf = (unsigned int)std::strlen(filename); - CImg full_filename(lp + lf + 2); - - if (!is_current) { - full_filename.assign(lp + lf + 2); - if (lp) std::memcpy(full_filename,_path,lp); - full_filename[lp] = '/'; - std::memcpy(full_filename._data + lp + 1,filename,lf + 1); - } else full_filename.assign(filename,lf + 1); - - struct stat st; - if (stat(full_filename,&st)==-1) continue; - const bool is_directory = (st.st_mode & S_IFDIR)!=0; - if ((!mode && !is_directory) || (mode==1 && is_directory) || mode==2) { - if (include_path) { - if (!_is_pattern || (_is_pattern && !fnmatch(pattern,full_filename,0))) - full_filename.move_to(res); - } else { - if (!_is_pattern || (_is_pattern && !fnmatch(pattern,full_filename,0))) - CImg(filename,lf + 1).move_to(res); - } - } - } - } - closedir(dir); -#endif - - // Sort resulting list by lexicographic order. - if (res._width>=2) std::qsort(res._data,res._width,sizeof(CImg),_sort_files); - - return res; - } - - //! Try to guess format from an image file. - /** - \param file Input file (can be \c 0 if \c filename is set). - \param filename Filename, as a C-string (can be \c 0 if \c file is set). - \return C-string containing the guessed file format, or \c 0 if nothing has been guessed. - **/ - inline const char *ftype(std::FILE *const file, const char *const filename) { - if (!file && !filename) - throw CImgArgumentException("cimg::ftype(): Specified filename is (null)."); - static const char - *const _bmp = "bmp", - *const _cr2 = "cr2", - *const _dcm = "dcm", - *const _gif = "gif", - *const _inr = "inr", - *const _jpg = "jpg", - *const _off = "off", - *const _pan = "pan", - *const _pfm = "pfm", - *const _png = "png", - *const _pnm = "pnm", - *const _tif = "tif"; - - const char *f_type = 0; - CImg header; - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - try { - header._load_raw(file,filename,512,1,1,1,false,false,0); - const unsigned char *const uheader = (unsigned char*)header._data; - if (!std::strncmp(header,"OFF\n",4)) f_type = _off; // OFF - else if (!std::strncmp(header,"#INRIMAGE",9)) // INRIMAGE - f_type = _inr; - else if (!std::strncmp(header,"PANDORE",7)) // PANDORE - f_type = _pan; - else if (!std::strncmp(header.data() + 128,"DICM",4)) // DICOM - f_type = _dcm; - else if (uheader[0]==0xFF && uheader[1]==0xD8 && uheader[2]==0xFF) // JPEG - f_type = _jpg; - else if (header[0]=='B' && header[1]=='M') // BMP - f_type = _bmp; - else if (header[0]=='G' && header[1]=='I' && header[2]=='F' && header[3]=='8' && header[5]=='a' && - (header[4]=='7' || header[4]=='9')) // GIF - f_type = _gif; - else if (uheader[0]==0x89 && uheader[1]==0x50 && uheader[2]==0x4E && uheader[3]==0x47 && - uheader[4]==0x0D && uheader[5]==0x0A && uheader[6]==0x1A && uheader[7]==0x0A) // PNG - f_type = _png; - else if (uheader[0]==0x49 && uheader[1]==0x49 && uheader[2]==0x2A && uheader[3]==0x00 && // CR2 - uheader[4]==0x10 && uheader[5]==0x00 && uheader[6]==0x00 && uheader[7]==0x00 && - uheader[8]==0x43 && uheader[9]==0x52) - f_type = _cr2; - else if ((uheader[0]==0x49 && uheader[1]==0x49 && uheader[2]==0x2A && uheader[3]==0x00) || - (uheader[0]==0x4D && uheader[1]==0x4D && uheader[2]==0x00 && uheader[3]==0x2A)) // TIFF - f_type = _tif; - else { // PNM or PFM - CImgList _header = header.get_split(CImg::vector('\n'),0,false); - cimglist_for(_header,l) { - if (_header(l,0)=='#') continue; - if (_header[l]._width==2 && _header(l,0)=='P') { - const char c = _header(l,1); - if (c=='f' || c=='F') { f_type = _pfm; break; } - if (c>='1' && c<='9') { f_type = _pnm; break; } - } - f_type = 0; break; - } - } - } catch (CImgIOException&) { } - cimg::exception_mode(omode); - return f_type; - } - - //! Load file from network as a local temporary file. - /** - \param url URL of the filename, as a C-string. - \param[out] filename_local C-string containing the path to a local copy of \c filename. - \param timeout Maximum time (in seconds) authorized for downloading the file from the URL. - \param try_fallback When using libcurl, tells using system calls as fallbacks in case of libcurl failure. - \param referer Referer used, as a C-string. - \return Value of \c filename_local. - \note Use the \c libcurl library, or the external binaries \c wget or \c curl to perform the download. - **/ - inline char *load_network(const char *const url, char *const filename_local, - const unsigned int timeout, const bool try_fallback, - const char *const referer) { - if (!url) - throw CImgArgumentException("cimg::load_network(): Specified URL is (null)."); - if (!filename_local) - throw CImgArgumentException("cimg::load_network(): Specified destination string is (null)."); - if (!network_mode()) - throw CImgIOException("cimg::load_network(): Loading files from network is disabled."); - - const char *const __ext = cimg::split_filename(url), *const _ext = (*__ext && __ext>url)?__ext - 1:__ext; - CImg ext = CImg::string(_ext); - std::FILE *file = 0; - *filename_local = 0; - if (ext._width>16 || !cimg::strncasecmp(ext,"cgi",3)) *ext = 0; - else cimg::strwindows_reserved(ext); - do { - cimg_snprintf(filename_local,256,"%s%c%s%s", - cimg::temporary_path(),cimg_file_separator,cimg::filenamerand(),ext._data); - if ((file=cimg::std_fopen(filename_local,"rb"))!=0) cimg::fclose(file); - } while (file); - -#ifdef cimg_use_curl - const unsigned int omode = cimg::exception_mode(); - cimg::exception_mode(0); - try { - CURL *curl = 0; - CURLcode res; - curl = curl_easy_init(); - if (curl) { - file = cimg::fopen(filename_local,"wb"); - curl_easy_setopt(curl,CURLOPT_URL,url); - curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,0); - curl_easy_setopt(curl,CURLOPT_WRITEDATA,file); - curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,0L); - curl_easy_setopt(curl,CURLOPT_SSL_VERIFYHOST,0L); - curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,1L); - if (timeout) curl_easy_setopt(curl,CURLOPT_TIMEOUT,(long)timeout); - if (std::strchr(url,'?')) curl_easy_setopt(curl,CURLOPT_HTTPGET,1L); - if (referer) curl_easy_setopt(curl,CURLOPT_REFERER,referer); - res = curl_easy_perform(curl); - curl_easy_cleanup(curl); - cimg::fseek(file,0,SEEK_END); // Check if file size is 0 - const cimg_ulong siz = cimg::ftell(file); - cimg::fclose(file); - if (siz>0 && res==CURLE_OK) { - cimg::exception_mode(omode); - return filename_local; - } else std::remove(filename_local); - } - } catch (...) { } - cimg::exception_mode(omode); - if (!try_fallback) throw CImgIOException("cimg::load_network(): Failed to load file '%s' with libcurl.",url); -#endif - - CImg command((unsigned int)std::strlen(url) + 512); - cimg::unused(try_fallback); - - // Try with 'curl' first. - if (timeout) { - if (referer) - cimg_snprintf(command,command._width,"\"%s\" -e %s -m %u -f --silent --compressed -o \"%s\" \"%s\"", - cimg::curl_path(),referer,timeout,filename_local, - CImg::string(url)._system_strescape().data()); - else - cimg_snprintf(command,command._width,"\"%s\" -m %u -f --silent --compressed -o \"%s\" \"%s\"", - cimg::curl_path(),timeout,filename_local, - CImg::string(url)._system_strescape().data()); - } else { - if (referer) - cimg_snprintf(command,command._width,"\"%s\" -e %s -f --silent --compressed -o \"%s\" \"%s\"", - cimg::curl_path(),referer,filename_local, - CImg::string(url)._system_strescape().data()); - else - cimg_snprintf(command,command._width,"\"%s\" -f --silent --compressed -o \"%s\" \"%s\"", - cimg::curl_path(),filename_local, - CImg::string(url)._system_strescape().data()); - } - cimg::system(command, cimg::curl_path()); - -#if cimg_OS==2 - if (!(file=cimg::std_fopen(filename_local,"rb"))) { - - // Try with 'powershell' otherwise. - if (timeout) { - if (referer) - cimg_snprintf(command,command._width, - "\"%s\" -NonInteractive -Command Invoke-WebRequest -Headers @{'Referer'='%s'} " - "-TimeoutSec %u -OutFile \"%s\" -Uri \"%s\"", - cimg::powershell_path(),referer,timeout,filename_local, - CImg::string(url)._system_strescape().data()); - else - cimg_snprintf(command,command._width, - "\"%s\" -NonInteractive -Command Invoke-WebRequest " - "-TimeoutSec %u -OutFile \"%s\" -Uri \"%s\"", - cimg::powershell_path(),timeout,filename_local, - CImg::string(url)._system_strescape().data()); - } else { - if (referer) - cimg_snprintf(command,command._width,"\"%s\" -NonInteractive -Command Invoke-WebRequest " - "-Headers @{'Referer'='%s'} -OutFile \"%s\" -Uri \"%s\"", - cimg::powershell_path(),referer,filename_local, - CImg::string(url)._system_strescape().data()); - else - cimg_snprintf(command,command._width,"\"%s\" -NonInteractive -Command Invoke-WebRequest " - "-OutFile \"%s\" -Uri \"%s\"", - cimg::powershell_path(),filename_local, - CImg::string(url)._system_strescape().data()); - } - cimg::system(command, cimg::powershell_path()); - } -#endif - - if (!(file=cimg::std_fopen(filename_local,"rb"))) { - - // Try with 'wget' otherwise. - if (timeout) { - if (referer) - cimg_snprintf(command,command._width,"\"%s\" --referer=%s -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"", - cimg::wget_path(),referer,timeout,filename_local, - CImg::string(url)._system_strescape().data()); - else - cimg_snprintf(command,command._width,"\"%s\" -T %u -q -r -l 0 --no-cache -O \"%s\" \"%s\"", - cimg::wget_path(),timeout,filename_local, - CImg::string(url)._system_strescape().data()); - } else { - if (referer) - cimg_snprintf(command,command._width,"\"%s\" --referer=%s -q -r -l 0 --no-cache -O \"%s\" \"%s\"", - cimg::wget_path(),referer,filename_local, - CImg::string(url)._system_strescape().data()); - else - cimg_snprintf(command,command._width,"\"%s\" -q -r -l 0 --no-cache -O \"%s\" \"%s\"", - cimg::wget_path(),filename_local, - CImg::string(url)._system_strescape().data()); - } - cimg::system(command, cimg::wget_path()); - - if (!(file=cimg::std_fopen(filename_local,"rb"))) - throw CImgIOException("cimg::load_network(): Failed to load file '%s' with external commands " -#if cimg_OS==2 - "'wget', 'curl', or 'powershell'.",url); -#else - "'wget' or 'curl'.",url); -#endif - cimg::fclose(file); - - // Try gunzip it. - cimg_snprintf(command,command._width,"%s.gz",filename_local); - std::rename(filename_local,command); - cimg_snprintf(command,command._width,"\"%s\" --quiet \"%s.gz\"", - gunzip_path(),filename_local); - cimg::system(command, gunzip_path()); - file = cimg::std_fopen(filename_local,"rb"); - if (!file) { - cimg_snprintf(command,command._width,"%s.gz",filename_local); - std::rename(command,filename_local); - file = cimg::std_fopen(filename_local,"rb"); - } - } - cimg::fseek(file,0,SEEK_END); // Check if file size is 0 - if (std::ftell(file)<=0) - throw CImgIOException("cimg::load_network(): Failed to load URL '%s' with external commands " - "'wget' or 'curl'.",url); - cimg::fclose(file); - return filename_local; - } - - // Implement a tic/toc mechanism to display elapsed time of algorithms. - inline cimg_uint64 tictoc(const bool is_tic) { - cimg::mutex(2); - static CImg times(64); - static unsigned int pos = 0; - const cimg_uint64 t1 = cimg::time(); - if (is_tic) { - // Tic - times[pos++] = t1; - if (pos>=times._width) - throw CImgArgumentException("cimg::tic(): Too much calls to 'cimg::tic()' without calls to 'cimg::toc()'."); - cimg::mutex(2,0); - return t1; - } - - // Toc - if (!pos) - throw CImgArgumentException("cimg::toc(): No previous call to 'cimg::tic()' has been made."); - const cimg_uint64 - t0 = times[--pos], - dt = t1>=t0?(t1 - t0):cimg::type::max(); - const unsigned int - edays = (unsigned int)(dt/86400000.), - ehours = (unsigned int)((dt - edays*86400000.)/3600000.), - emin = (unsigned int)((dt - edays*86400000. - ehours*3600000.)/60000.), - esec = (unsigned int)((dt - edays*86400000. - ehours*3600000. - emin*60000.)/1000.), - ems = (unsigned int)(dt - edays*86400000. - ehours*3600000. - emin*60000. - esec*1000.); - if (!edays && !ehours && !emin && !esec) - std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u ms%s\n", - cimg::t_red,1 + 2*pos,"",ems,cimg::t_normal); - else { - if (!edays && !ehours && !emin) - std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u sec %u ms%s\n", - cimg::t_red,1 + 2*pos,"",esec,ems,cimg::t_normal); - else { - if (!edays && !ehours) - std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u min %u sec %u ms%s\n", - cimg::t_red,1 + 2*pos,"",emin,esec,ems,cimg::t_normal); - else{ - if (!edays) - std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u hours %u min %u sec %u ms%s\n", - cimg::t_red,1 + 2*pos,"",ehours,emin,esec,ems,cimg::t_normal); - else{ - std::fprintf(cimg::output(),"%s[CImg]%*sElapsed time: %u days %u hours %u min %u sec %u ms%s\n", - cimg::t_red,1 + 2*pos,"",edays,ehours,emin,esec,ems,cimg::t_normal); - } - } - } - } - cimg::mutex(2,0); - return dt; - } - - // Return a temporary string describing the size of a memory buffer. - inline const char *strbuffersize(const cimg_ulong size) { - static CImg res(256); - cimg::mutex(5); - if (size<1024LU) cimg_snprintf(res,res._width,"%lu byte%s",(unsigned long)size,size>1?"s":""); - else if (size<1024*1024LU) { const float nsize = size/1024.f; cimg_snprintf(res,res._width,"%.1f Kio",nsize); } - else if (size<1024*1024*1024LU) { - const float nsize = size/(1024*1024.f); cimg_snprintf(res,res._width,"%.1f Mio",nsize); - } else { const float nsize = size/(1024*1024*1024.f); cimg_snprintf(res,res._width,"%.1f Gio",nsize); } - cimg::mutex(5,0); - return res; - } - - //! Display a simple dialog box, and wait for the user's response. - /** - \param title Title of the dialog window. - \param msg Main message displayed inside the dialog window. - \param button1_label Label of the 1st button. - \param button2_label Label of the 2nd button (\c 0 to hide button). - \param button3_label Label of the 3rd button (\c 0 to hide button). - \param button4_label Label of the 4th button (\c 0 to hide button). - \param button5_label Label of the 5th button (\c 0 to hide button). - \param button6_label Label of the 6th button (\c 0 to hide button). - \param logo Image logo displayed at the left of the main message. - \param is_centered Tells if the dialog window must be centered on the screen. - \return Index of clicked button (from \c 0 to \c 5), or \c -1 if the dialog window has been closed by the user. - \note - - Up to 6 buttons can be defined in the dialog window. - - The function returns when a user clicked one of the button or closed the dialog window. - - If a button text is set to 0, the corresponding button (and the following) will not appear in the dialog box. - At least one button must be specified. - **/ - template - inline int dialog(const char *const title, const char *const msg, - const char *const button1_label, const char *const button2_label, - const char *const button3_label, const char *const button4_label, - const char *const button5_label, const char *const button6_label, - const CImg& logo, const bool is_centered=false) { -#if cimg_display==0 - cimg::unused(title,msg,button1_label,button2_label,button3_label,button4_label,button5_label,button6_label, - logo._data,is_centered); - throw CImgIOException("cimg::dialog(): No display available."); -#else - static const unsigned char - black[] = { 0,0,0 }, white[] = { 255,255,255 }, gray[] = { 200,200,200 }, gray2[] = { 150,150,150 }; - - // Create buttons and canvas graphics - CImgList buttons, cbuttons, sbuttons; - if (button1_label) { - CImg().draw_text(0,0,button1_label,black,gray,1,13).move_to(buttons); - if (button2_label) { - CImg().draw_text(0,0,button2_label,black,gray,1,13).move_to(buttons); - if (button3_label) { - CImg().draw_text(0,0,button3_label,black,gray,1,13).move_to(buttons); - if (button4_label) { - CImg().draw_text(0,0,button4_label,black,gray,1,13).move_to(buttons); - if (button5_label) { - CImg().draw_text(0,0,button5_label,black,gray,1,13).move_to(buttons); - if (button6_label) { - CImg().draw_text(0,0,button6_label,black,gray,1,13).move_to(buttons); - }}}}}} - if (!buttons._width) - throw CImgArgumentException("cimg::dialog(): No buttons have been defined."); - cimglist_for(buttons,l) buttons[l].resize(-100,-100,1,3); - - unsigned int bw = 0, bh = 0; - cimglist_for(buttons,l) { bw = std::max(bw,buttons[l]._width); bh = std::max(bh,buttons[l]._height); } - bw+=8; bh+=8; - if (bw<64) bw = 64; - if (bw>128) bw = 128; - if (bh<24) bh = 24; - if (bh>48) bh = 48; - - CImg button(bw,bh,1,3); - button.draw_rectangle(0,0,bw - 1,bh - 1,gray); - button.draw_line(0,0,bw - 1,0,white).draw_line(0,bh - 1,0,0,white); - button.draw_line(bw - 1,0,bw - 1,bh - 1,black).draw_line(bw - 1,bh - 1,0,bh - 1,black); - button.draw_line(1,bh - 2,bw - 2,bh - 2,gray2).draw_line(bw - 2,bh - 2,bw - 2,1,gray2); - CImg sbutton(bw,bh,1,3); - sbutton.draw_rectangle(0,0,bw - 1,bh - 1,gray); - sbutton.draw_line(0,0,bw - 1,0,black).draw_line(bw - 1,0,bw - 1,bh - 1,black); - sbutton.draw_line(bw - 1,bh - 1,0,bh - 1,black).draw_line(0,bh - 1,0,0,black); - sbutton.draw_line(1,1,bw - 2,1,white).draw_line(1,bh - 2,1,1,white); - sbutton.draw_line(bw - 2,1,bw - 2,bh - 2,black).draw_line(bw - 2,bh - 2,1,bh - 2,black); - sbutton.draw_line(2,bh - 3,bw - 3,bh - 3,gray2).draw_line(bw - 3,bh - 3,bw - 3,2,gray2); - sbutton.draw_line(4,4,bw - 5,4,black,1,0xAAAAAAAA,true). - draw_line(bw - 5,4,bw - 5,bh - 5,black,1,0xAAAAAAAA,false); - sbutton.draw_line(bw - 5,bh - 5,4,bh - 5,black,1,0xAAAAAAAA,false). - draw_line(4,bh - 5,4,4,black,1,0xAAAAAAAA,false); - CImg cbutton(bw,bh,1,3); - cbutton.draw_rectangle(0,0,bw - 1,bh - 1,black).draw_rectangle(1,1,bw - 2,bh - 2,gray2). - draw_rectangle(2,2,bw - 3,bh - 3,gray); - cbutton.draw_line(4,4,bw - 5,4,black,1,0xAAAAAAAA,true). - draw_line(bw - 5,4,bw - 5,bh - 5,black,1,0xAAAAAAAA,false); - cbutton.draw_line(bw - 5,bh - 5,4,bh - 5,black,1,0xAAAAAAAA,false). - draw_line(4,bh - 5,4,4,black,1,0xAAAAAAAA,false); - - cimglist_for(buttons,ll) { - CImg(cbutton). - draw_image(1 + (bw -buttons[ll].width())/2,1 + (bh - buttons[ll].height())/2,buttons[ll]). - move_to(cbuttons); - CImg(sbutton). - draw_image((bw - buttons[ll].width())/2,(bh - buttons[ll].height())/2,buttons[ll]). - move_to(sbuttons); - CImg(button). - draw_image((bw - buttons[ll].width())/2,(bh - buttons[ll].height())/2,buttons[ll]). - move_to(buttons[ll]); - } - - CImg canvas; - if (msg) - ((CImg().draw_text(0,0,"%s",gray,0,1,13,msg)*=-1)+=200).resize(-100,-100,1,3).move_to(canvas); - - const unsigned int - bwall = (buttons._width - 1)*(12 + bw) + bw, - w = cimg::max(196U,36 + logo._width + canvas._width,24 + bwall), - h = cimg::max(96U,36 + canvas._height + bh,36 + logo._height + bh), - lx = 12 + (canvas._data?0:((w - 24 - logo._width)/2)), - ly = (h - 12 - bh - logo._height)/2, - tx = lx + logo._width + 12, - ty = (h - 12 - bh - canvas._height)/2, - bx = (w - bwall)/2, - by = h - 12 - bh; - - if (canvas._data) - canvas = CImg(w,h,1,3). - draw_rectangle(0,0,w - 1,h - 1,gray). - draw_line(0,0,w - 1,0,white).draw_line(0,h - 1,0,0,white). - draw_line(w - 1,0,w - 1,h - 1,black).draw_line(w - 1,h - 1,0,h - 1,black). - draw_image(tx,ty,canvas); - else - canvas = CImg(w,h,1,3). - draw_rectangle(0,0,w - 1,h - 1,gray). - draw_line(0,0,w - 1,0,white).draw_line(0,h - 1,0,0,white). - draw_line(w - 1,0,w - 1,h - 1,black).draw_line(w - 1,h - 1,0,h - 1,black); - if (logo._data) canvas.draw_image(lx,ly,logo); - - unsigned int xbuttons[6] = { 0 }; - cimglist_for(buttons,lll) { - xbuttons[lll] = bx + (bw + 12)*lll; - canvas.draw_image(xbuttons[lll],by,buttons[lll]); - } - - // Open window and enter events loop - CImgDisplay disp(canvas,title?title:" ",0,false,is_centered?true:false); - if (is_centered) disp.move((CImgDisplay::screen_width() - disp.width())/2, - (CImgDisplay::screen_height() - disp.height())/2); - bool stop_flag = false, refresh = false; - int oselected = -1, oclicked = -1, selected = -1, clicked = -1; - while (!disp.is_closed() && !stop_flag) { - if (refresh) { - if (clicked>=0) - CImg(canvas).draw_image(xbuttons[clicked],by,cbuttons[clicked]).display(disp); - else { - if (selected>=0) - CImg(canvas).draw_image(xbuttons[selected],by,sbuttons[selected]).display(disp); - else canvas.display(disp); - } - refresh = false; - } - disp.wait(15); - if (disp.is_resized()) disp.resize(disp,false); - - if (disp.button()&1) { - oclicked = clicked; - clicked = -1; - cimglist_for(buttons,l) - if (disp.mouse_y()>=(int)by && disp.mouse_y()<(int)(by + bh) && - disp.mouse_x()>=(int)xbuttons[l] && disp.mouse_x()<(int)(xbuttons[l] + bw)) { - clicked = selected = l; - refresh = true; - } - if (clicked!=oclicked) refresh = true; - } else if (clicked>=0) stop_flag = true; - - if (disp.key()) { - oselected = selected; - switch (disp.key()) { - case cimg::keyESC : selected = -1; stop_flag = true; break; - case cimg::keyENTER : if (selected<0) selected = 0; stop_flag = true; break; - case cimg::keyTAB : - case cimg::keyARROWRIGHT : - case cimg::keyARROWDOWN : selected = (selected + 1)%buttons.width(); break; - case cimg::keyARROWLEFT : - case cimg::keyARROWUP : selected = (selected + buttons.width() - 1)%buttons.width(); break; - } - disp.set_key(); - if (selected!=oselected) refresh = true; - } - } - if (!disp) selected = -1; - return selected; -#endif - } - - //! Display a simple dialog box, and wait for the user's response \specialization. - inline int dialog(const char *const title, const char *const msg, - const char *const button1_label, const char *const button2_label, - const char *const button3_label, const char *const button4_label, - const char *const button5_label, const char *const button6_label, - const bool is_centered) { - return dialog(title,msg,button1_label,button2_label,button3_label,button4_label,button5_label,button6_label, - CImg::_logo40x38(),is_centered); - } - - //! Evaluate math expression. - /** - \param expression C-string describing the formula to evaluate. - \param x Value of the pre-defined variable \c x. - \param y Value of the pre-defined variable \c y. - \param z Value of the pre-defined variable \c z. - \param c Value of the pre-defined variable \c c. - \return Result of the formula evaluation. - \note Set \c expression to \c 0 to keep evaluating the last specified \c expression. - \par Example - \code - const double - res1 = cimg::eval("cos(x)^2 + sin(y)^2",2,2), // will return '1' - res2 = cimg::eval(0,1,1); // will return '1' too - \endcode - **/ - inline double eval(const char *const expression, const double x, const double y, const double z, const double c) { - static const CImg empty; - return empty.eval(expression,x,y,z,c); - } - - template - inline CImg::type> eval(const char *const expression, const CImg& xyzc) { - static const CImg empty; - return empty.eval(expression,xyzc); - } - - } // namespace cimg { ... -} // namespace cimg_library { ... - -//! Short alias name. -namespace cil = cimg_library_suffixed; - -#ifdef _cimg_redefine_False -#define False 0 -#endif -#ifdef _cimg_redefine_True -#define True 1 -#endif -#ifdef _cimg_redefine_Status -#define Status int -#endif -#ifdef _cimg_redefine_Success -#define Success 0 -#endif -#ifdef _cimg_redefine_min -#define min(a,b) (((a)<(b))?(a):(b)) -#endif -#ifdef _cimg_redefine_max -#define max(a,b) (((a)>(b))?(a):(b)) -#endif -#ifdef _cimg_redefine_PI -#define PI 3.141592653589793238462643383 -#endif -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#endif - -// Local Variables: -// mode: c++ -// End: diff --git a/deps/doctest b/deps/doctest deleted file mode 160000 index 86892fc48..000000000 --- a/deps/doctest +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 86892fc480f80fb57d9a3926cb506c0e974489d8 diff --git a/deps/eigen b/deps/eigen deleted file mode 160000 index 39142904c..000000000 --- a/deps/eigen +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 39142904cc2301628931481e8b331cc2d567e22f diff --git a/deps/highs b/deps/highs deleted file mode 160000 index adfb2cf39..000000000 --- a/deps/highs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit adfb2cf394cd6fe5c78711c537b9caf7d16373f0 diff --git a/deps/json b/deps/json deleted file mode 160000 index db78ac1d7..000000000 --- a/deps/json +++ /dev/null @@ -1 +0,0 @@ -Subproject commit db78ac1d7716f56fc9f1b030b715f872f93964e4 diff --git a/deps/lemon/.hg_archival.txt b/deps/lemon/.hg_archival.txt deleted file mode 100644 index f834209f3..000000000 --- a/deps/lemon/.hg_archival.txt +++ /dev/null @@ -1,5 +0,0 @@ -repo: 6ed5fe0ea387ba9808e21048f02c665b16aa8c23 -node: bdabbf66b2ad131199059736178664f44c69adaf -branch: 1.3 -latesttag: r1.3 -latesttagdistance: 11 diff --git a/deps/lemon/.hgignore b/deps/lemon/.hgignore deleted file mode 100644 index 73230edfd..000000000 --- a/deps/lemon/.hgignore +++ /dev/null @@ -1,53 +0,0 @@ -syntax: glob -*.obj -*.orig -*.rej -*~ -*.o -*.log -*.lo -*.tar.* -*.bak -Makefile.in -aclocal.m4 -config.h.in -configure -Makefile -config.h -config.log -config.status -libtool -stamp-h1 -lemon/lemon.pc -lemon/libemon.la -lemon/stamp-h2 -doc/Doxyfile -doc/references.dox -cmake/version.cmake -.dirstamp -.libs/* -.deps/* -demo/*.eps -m4/libtool.m4 -m4/ltoptions.m4 -m4/ltsugar.m4 -m4/ltversion.m4 -m4/lt~obsolete.m4 - -syntax: regexp -(.*/)?\#[^/]*\#$ -(.*/)?\.\#[^/]*$ -^doc/html/.* -^doc/.*\.tag -^autom4te.cache/.* -^build-aux/.* -^.*objs.*/.* -^test/[a-z_]*$ -^tools/[a-z-_]*$ -^demo/.*_demo$ -^.*build.*/.* -^doc/gen-images/.* -CMakeFiles -DartTestfile.txt -cmake_install.cmake -CMakeCache.txt diff --git a/deps/lemon/.hgtags b/deps/lemon/.hgtags deleted file mode 100644 index b5eb130dc..000000000 --- a/deps/lemon/.hgtags +++ /dev/null @@ -1 +0,0 @@ -57ab090b6109902536ee34b1e8d4d123474311e3 r1.3 diff --git a/deps/lemon/AUTHORS b/deps/lemon/AUTHORS deleted file mode 100644 index 4019ca621..000000000 --- a/deps/lemon/AUTHORS +++ /dev/null @@ -1,26 +0,0 @@ -The main developers of release series 1.x are - - * Balazs Dezso - * Alpar Juttner - * Peter Kovacs - * Akos Ladanyi - -For more complete list of contributors, please visit the history of -the LEMON source code repository: http://lemon.cs.elte.hu/hg/lemon - -Moreover, this version is heavily based on version 0.x of LEMON. Here -is the list of people who contributed to those versions. - - * Mihaly Barasz - * Johanna Becker - * Attila Bernath - * Balazs Dezso - * Peter Hegyi - * Alpar Juttner - * Peter Kovacs - * Akos Ladanyi - * Marton Makai - * Jacint Szabo - -Again, please visit the history of the old LEMON repository for more -details: http://lemon.cs.elte.hu/hg/lemon-0.x \ No newline at end of file diff --git a/deps/lemon/CMakeLists.txt b/deps/lemon/CMakeLists.txt deleted file mode 100644 index b8f9d9f93..000000000 --- a/deps/lemon/CMakeLists.txt +++ /dev/null @@ -1,375 +0,0 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) - -CMAKE_POLICY(SET CMP0048 OLD) - -SET(PROJECT_NAME "LEMON") -PROJECT(${PROJECT_NAME}) - -INCLUDE(FindPythonInterp) -INCLUDE(FindWget) - -IF(EXISTS ${PROJECT_SOURCE_DIR}/cmake/version.cmake) - INCLUDE(${PROJECT_SOURCE_DIR}/cmake/version.cmake) -ELSEIF(DEFINED ENV{LEMON_VERSION}) - SET(LEMON_VERSION $ENV{LEMON_VERSION} CACHE STRING "LEMON version string.") -ELSE() - EXECUTE_PROCESS( - COMMAND - hg log -r. --template "{latesttag}" - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - OUTPUT_VARIABLE HG_REVISION_TAG - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - EXECUTE_PROCESS( - COMMAND - hg log -r. --template "{latesttagdistance}" - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - OUTPUT_VARIABLE HG_REVISION_DIST - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - EXECUTE_PROCESS( - COMMAND - hg log -r. --template "{node|short}" - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - OUTPUT_VARIABLE HG_REVISION_ID - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - IF(HG_REVISION_TAG STREQUAL "") - SET(HG_REVISION_ID "hg-tip") - ELSE() - IF(HG_REVISION_TAG STREQUAL "null") - SET(HG_REVISION_TAG "trunk") - ELSEIF(HG_REVISION_TAG MATCHES "^r") - STRING(SUBSTRING ${HG_REVISION_TAG} 1 -1 HG_REVISION_TAG) - ENDIF() - IF(HG_REVISION_DIST STREQUAL "0") - SET(HG_REVISION ${HG_REVISION_TAG}) - ELSE() - SET(HG_REVISION - "${HG_REVISION_TAG}+${HG_REVISION_DIST}-${HG_REVISION_ID}") - ENDIF() - ENDIF() - - SET(LEMON_VERSION ${HG_REVISION} CACHE STRING "LEMON version string.") -ENDIF() - -SET(PROJECT_VERSION ${LEMON_VERSION}) - -SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) - -FIND_PACKAGE(Doxygen) -FIND_PACKAGE(Ghostscript) - -SET(LEMON_ENABLE_GLPK YES CACHE STRING "Enable GLPK solver backend.") -SET(LEMON_ENABLE_ILOG YES CACHE STRING "Enable ILOG (CPLEX) solver backend.") -SET(LEMON_ENABLE_COIN YES CACHE STRING "Enable COIN solver backend.") -SET(LEMON_ENABLE_SOPLEX YES CACHE STRING "Enable SoPlex solver backend.") - -IF(LEMON_ENABLE_GLPK) - FIND_PACKAGE(GLPK 4.33) -ENDIF(LEMON_ENABLE_GLPK) -IF(LEMON_ENABLE_ILOG) - FIND_PACKAGE(ILOG) -ENDIF(LEMON_ENABLE_ILOG) -IF(LEMON_ENABLE_COIN) - FIND_PACKAGE(COIN) -ENDIF(LEMON_ENABLE_COIN) -IF(LEMON_ENABLE_SOPLEX) - FIND_PACKAGE(SOPLEX) -ENDIF(LEMON_ENABLE_SOPLEX) - -IF(GLPK_FOUND) - SET(LEMON_HAVE_LP TRUE) - SET(LEMON_HAVE_MIP TRUE) - SET(LEMON_HAVE_GLPK TRUE) -ENDIF(GLPK_FOUND) -IF(ILOG_FOUND) - SET(LEMON_HAVE_LP TRUE) - SET(LEMON_HAVE_MIP TRUE) - SET(LEMON_HAVE_CPLEX TRUE) -ENDIF(ILOG_FOUND) -IF(COIN_FOUND) - SET(LEMON_HAVE_LP TRUE) - SET(LEMON_HAVE_MIP TRUE) - SET(LEMON_HAVE_CLP TRUE) - SET(LEMON_HAVE_CBC TRUE) -ENDIF(COIN_FOUND) -IF(SOPLEX_FOUND) - SET(LEMON_HAVE_LP TRUE) - SET(LEMON_HAVE_SOPLEX TRUE) -ENDIF(SOPLEX_FOUND) - -IF(ILOG_FOUND) - SET(DEFAULT_LP "CPLEX") - SET(DEFAULT_MIP "CPLEX") -ELSEIF(COIN_FOUND) - SET(DEFAULT_LP "CLP") - SET(DEFAULT_MIP "CBC") -ELSEIF(GLPK_FOUND) - SET(DEFAULT_LP "GLPK") - SET(DEFAULT_MIP "GLPK") -ELSEIF(SOPLEX_FOUND) - SET(DEFAULT_LP "SOPLEX") -ENDIF() - -IF(NOT LEMON_DEFAULT_LP OR - (NOT ILOG_FOUND AND (LEMON_DEFAULT_LP STREQUAL "CPLEX")) OR - (NOT COIN_FOUND AND (LEMON_DEFAULT_LP STREQUAL "CLP")) OR - (NOT GLPK_FOUND AND (LEMON_DEFAULT_LP STREQUAL "GLPK")) OR - (NOT SOPLEX_FOUND AND (LEMON_DEFAULT_LP STREQUAL "SOPLEX"))) - SET(LEMON_DEFAULT_LP ${DEFAULT_LP} CACHE STRING - "Default LP solver backend (GLPK, CPLEX, CLP or SOPLEX)" FORCE) -ELSE() - SET(LEMON_DEFAULT_LP ${DEFAULT_LP} CACHE STRING - "Default LP solver backend (GLPK, CPLEX, CLP or SOPLEX)") -ENDIF() -IF(NOT LEMON_DEFAULT_MIP OR - (NOT ILOG_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "CPLEX")) OR - (NOT COIN_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "CBC")) OR - (NOT GLPK_FOUND AND (LEMON_DEFAULT_MIP STREQUAL "GLPK"))) - SET(LEMON_DEFAULT_MIP ${DEFAULT_MIP} CACHE STRING - "Default MIP solver backend (GLPK, CPLEX or CBC)" FORCE) -ELSE() - SET(LEMON_DEFAULT_MIP ${DEFAULT_MIP} CACHE STRING - "Default MIP solver backend (GLPK, CPLEX or CBC)") -ENDIF() - - -IF(DEFINED ENV{LEMON_CXX_WARNING}) - SET(CXX_WARNING $ENV{LEMON_CXX_WARNING}) -ELSE() - IF(CMAKE_COMPILER_IS_GNUCXX) - SET(CXX_WARNING "-Wall -W -Wunused -Wformat=2 -Wctor-dtor-privacy -Wnon-virtual-dtor -Wno-char-subscripts -Wwrite-strings -Wno-char-subscripts -Wreturn-type -Wcast-qual -Wcast-align -Wsign-promo -Woverloaded-virtual -fno-strict-aliasing -Wold-style-cast -Wno-unknown-pragmas") - SET(CMAKE_CXX_FLAGS_DEBUG CACHE STRING "-ggdb") - SET(CMAKE_C_FLAGS_DEBUG CACHE STRING "-ggdb") - ELSEIF(MSVC) - # This part is unnecessary 'casue the same is set by the lemon/core.h. - # Still keep it as an example. - SET(CXX_WARNING "/wd4250 /wd4355 /wd4503 /wd4800 /wd4996") - # Suppressed warnings: - # C4250: 'class1' : inherits 'class2::member' via dominance - # C4355: 'this' : used in base member initializer list - # C4503: 'function' : decorated name length exceeded, name was truncated - # C4800: 'type' : forcing value to bool 'true' or 'false' - # (performance warning) - # C4996: 'function': was declared deprecated - ELSE() - SET(CXX_WARNING "-Wall") - ENDIF() -ENDIF() -SET(LEMON_CXX_WARNING_FLAGS ${CXX_WARNING} CACHE STRING "LEMON warning flags.") - -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LEMON_CXX_WARNING_FLAGS} -fPIC") - -IF(MSVC) - SET( CMAKE_CXX_FLAGS_MAINTAINER "/WX ${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING - "Flags used by the C++ compiler during maintainer builds." - ) - SET( CMAKE_C_FLAGS_MAINTAINER "/WX ${CMAKE_CXX_FLAGS_DEBUG}" CACHE STRING - "Flags used by the C compiler during maintainer builds." - ) - SET( CMAKE_EXE_LINKER_FLAGS_MAINTAINER - "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING - "Flags used for linking binaries during maintainer builds." - ) - SET( CMAKE_SHARED_LINKER_FLAGS_MAINTAINER - "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING - "Flags used by the shared libraries linker during maintainer builds." - ) -ELSE() - SET( CMAKE_CXX_FLAGS_MAINTAINER "-Werror -ggdb -O0" CACHE STRING - "Flags used by the C++ compiler during maintainer builds." - ) - SET( CMAKE_C_FLAGS_MAINTAINER "-Werror -O0" CACHE STRING - "Flags used by the C compiler during maintainer builds." - ) - SET( CMAKE_EXE_LINKER_FLAGS_MAINTAINER - "${CMAKE_EXE_LINKER_FLAGS_DEBUG}" CACHE STRING - "Flags used for linking binaries during maintainer builds." - ) - SET( CMAKE_SHARED_LINKER_FLAGS_MAINTAINER - "${CMAKE_SHARED_LINKER_FLAGS_DEBUG}" CACHE STRING - "Flags used by the shared libraries linker during maintainer builds." - ) -ENDIF() - -MARK_AS_ADVANCED( - CMAKE_CXX_FLAGS_MAINTAINER - CMAKE_C_FLAGS_MAINTAINER - CMAKE_EXE_LINKER_FLAGS_MAINTAINER - CMAKE_SHARED_LINKER_FLAGS_MAINTAINER ) - -IF(CMAKE_CONFIGURATION_TYPES) - LIST(APPEND CMAKE_CONFIGURATION_TYPES Maintainer) - LIST(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES) - SET(CMAKE_CONFIGURATION_TYPES "${CMAKE_CONFIGURATION_TYPES}" CACHE STRING - "Add the configurations that we need" - FORCE) - endif() - -IF(NOT CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE "Release") -ENDIF() - -SET( CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING - "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel Maintainer." - FORCE ) - - -INCLUDE(CheckTypeSize) -CHECK_TYPE_SIZE("long long" LONG_LONG) -SET(LEMON_HAVE_LONG_LONG ${HAVE_LONG_LONG}) - -INCLUDE(FindThreads) - -IF(NOT LEMON_THREADING) - IF(CMAKE_USE_PTHREADS_INIT) - SET(LEMON_THREADING "Pthread") - ELSEIF(CMAKE_USE_WIN32_THREADS_INIT) - SET(LEMON_THREADING "Win32") - ELSE() - SET(LEMON_THREADING "None") - ENDIF() -ENDIF() - -SET( LEMON_THREADING "${LEMON_THREADING}" CACHE STRING - "Choose the threading library, options are: Pthread Win32 None." - FORCE ) - -IF(LEMON_THREADING STREQUAL "Pthread") - SET(LEMON_USE_PTHREAD TRUE) -ELSEIF(LEMON_THREADING STREQUAL "Win32") - SET(LEMON_USE_WIN32_THREADS TRUE) -ENDIF() - -ENABLE_TESTING() - -IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer") - ADD_CUSTOM_TARGET(check ALL COMMAND ${CMAKE_CTEST_COMMAND}) -ELSE() - ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND}) -ENDIF() - -ADD_SUBDIRECTORY(lemon) -IF(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR}) - ADD_SUBDIRECTORY(contrib) - ADD_SUBDIRECTORY(demo) - ADD_SUBDIRECTORY(tools) - ADD_SUBDIRECTORY(doc) - ADD_SUBDIRECTORY(test) -ENDIF() - -CONFIGURE_FILE( - ${PROJECT_SOURCE_DIR}/cmake/LEMONConfig.cmake.in - ${PROJECT_BINARY_DIR}/cmake/LEMONConfig.cmake - @ONLY -) -IF(UNIX) - INSTALL( - FILES ${PROJECT_BINARY_DIR}/cmake/LEMONConfig.cmake - DESTINATION share/lemon/cmake - ) -ELSEIF(WIN32) - INSTALL( - FILES ${PROJECT_BINARY_DIR}/cmake/LEMONConfig.cmake - DESTINATION cmake - ) -ENDIF() - -CONFIGURE_FILE( - ${PROJECT_SOURCE_DIR}/cmake/version.cmake.in - ${PROJECT_BINARY_DIR}/cmake/version.cmake - @ONLY -) - -SET(ARCHIVE_BASE_NAME ${CMAKE_PROJECT_NAME}) -STRING(TOLOWER ${ARCHIVE_BASE_NAME} ARCHIVE_BASE_NAME) -SET(ARCHIVE_NAME ${ARCHIVE_BASE_NAME}-${PROJECT_VERSION}) -ADD_CUSTOM_TARGET(dist - COMMAND cmake -E remove_directory ${ARCHIVE_NAME} - COMMAND hg archive ${ARCHIVE_NAME} - COMMAND cmake -E copy cmake/version.cmake ${ARCHIVE_NAME}/cmake/version.cmake - COMMAND tar -czf ${ARCHIVE_BASE_NAME}-nodoc-${PROJECT_VERSION}.tar.gz ${ARCHIVE_NAME} - COMMAND zip -r ${ARCHIVE_BASE_NAME}-nodoc-${PROJECT_VERSION}.zip ${ARCHIVE_NAME} - COMMAND cmake -E copy_directory doc/html ${ARCHIVE_NAME}/doc/html - COMMAND tar -czf ${ARCHIVE_NAME}.tar.gz ${ARCHIVE_NAME} - COMMAND zip -r ${ARCHIVE_NAME}.zip ${ARCHIVE_NAME} - COMMAND cmake -E copy_directory doc/html ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} - COMMAND tar -czf ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}.tar.gz ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} - COMMAND zip -r ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION}.zip ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} - COMMAND cmake -E remove_directory ${ARCHIVE_NAME} - COMMAND cmake -E remove_directory ${ARCHIVE_BASE_NAME}-doc-${PROJECT_VERSION} - DEPENDS html - WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) - -# CPACK config (Basically for NSIS) -IF(${CMAKE_SOURCE_DIR} STREQUAL ${PROJECT_SOURCE_DIR}) - SET(CPACK_PACKAGE_NAME ${PROJECT_NAME}) - SET(CPACK_PACKAGE_VENDOR "EGRES") - SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY - "LEMON - Library for Efficient Modeling and Optimization in Networks") - SET(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") - - SET(CPACK_PACKAGE_VERSION ${PROJECT_VERSION}) - - SET(CPACK_PACKAGE_INSTALL_DIRECTORY - "${PROJECT_NAME} ${PROJECT_VERSION}") - SET(CPACK_PACKAGE_INSTALL_REGISTRY_KEY - "${PROJECT_NAME} ${PROJECT_VERSION}") - - SET(CPACK_COMPONENTS_ALL headers library html_documentation bin) - - SET(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C++ headers") - SET(CPACK_COMPONENT_LIBRARY_DISPLAY_NAME "Dynamic-link library") - SET(CPACK_COMPONENT_BIN_DISPLAY_NAME "Command line utilities") - SET(CPACK_COMPONENT_HTML_DOCUMENTATION_DISPLAY_NAME "HTML documentation") - - SET(CPACK_COMPONENT_HEADERS_DESCRIPTION - "C++ header files") - SET(CPACK_COMPONENT_LIBRARY_DESCRIPTION - "DLL and import library") - SET(CPACK_COMPONENT_BIN_DESCRIPTION - "Command line utilities") - SET(CPACK_COMPONENT_HTML_DOCUMENTATION_DESCRIPTION - "Doxygen generated documentation") - - SET(CPACK_COMPONENT_HEADERS_DEPENDS library) - - SET(CPACK_COMPONENT_HEADERS_GROUP "Development") - SET(CPACK_COMPONENT_LIBRARY_GROUP "Development") - SET(CPACK_COMPONENT_HTML_DOCUMENTATION_GROUP "Documentation") - - SET(CPACK_COMPONENT_GROUP_DEVELOPMENT_DESCRIPTION - "Components needed to develop software using LEMON") - SET(CPACK_COMPONENT_GROUP_DOCUMENTATION_DESCRIPTION - "Documentation of LEMON") - - SET(CPACK_ALL_INSTALL_TYPES Full Developer) - - SET(CPACK_COMPONENT_HEADERS_INSTALL_TYPES Developer Full) - SET(CPACK_COMPONENT_LIBRARY_INSTALL_TYPES Developer Full) - SET(CPACK_COMPONENT_HTML_DOCUMENTATION_INSTALL_TYPES Full) - - SET(CPACK_GENERATOR "NSIS") - SET(CPACK_NSIS_MUI_ICON "${PROJECT_SOURCE_DIR}/cmake/nsis/lemon.ico") - SET(CPACK_NSIS_MUI_UNIICON "${PROJECT_SOURCE_DIR}/cmake/nsis/uninstall.ico") - #SET(CPACK_PACKAGE_ICON "${PROJECT_SOURCE_DIR}/cmake/nsis\\\\installer.bmp") - SET(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\lemon.ico") - SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_INSTALL_DIRECTORY} ${PROJECT_NAME}") - SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\lemon.cs.elte.hu") - SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\lemon.cs.elte.hu") - SET(CPACK_NSIS_CONTACT "lemon-user@lemon.cs.elte.hu") - SET(CPACK_NSIS_CREATE_ICONS_EXTRA " - CreateShortCut \\\"$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Documentation.lnk\\\" \\\"$INSTDIR\\\\share\\\\doc\\\\index.html\\\" - ") - SET(CPACK_NSIS_DELETE_ICONS_EXTRA " - !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP - Delete \\\"$SMPROGRAMS\\\\$MUI_TEMP\\\\Documentation.lnk\\\" - ") - - INCLUDE(CPack) -ENDIF() diff --git a/deps/lemon/INSTALL b/deps/lemon/INSTALL deleted file mode 100644 index 3fba5b263..000000000 --- a/deps/lemon/INSTALL +++ /dev/null @@ -1,167 +0,0 @@ -Installation Instructions -========================= - -This file contains instructions for building and installing LEMON from -source on Linux. The process on Windows is similar. - -Note that it is not necessary to install LEMON in order to use -it. Instead, you can easily integrate it with your own code -directly. For instructions, see -https://lemon.cs.elte.hu/trac/lemon/wiki/HowToCompile - - -In order to install LEMON from the extracted source tarball you have to -issue the following commands: - - 1. Step into the root of the source directory. - - $ cd lemon-x.y.z - - 2. Create a build subdirectory and step into it. - - $ mkdir build - $ cd build - - 3. Perform system checks and create the makefiles. - - $ cmake .. - - 4. Build LEMON. - - $ make - - This command compiles the non-template part of LEMON into - libemon.a file. It also compiles the programs in the 'tools' and - 'demo' subdirectories. - - 5. [Optional] Compile and run the self-tests. - - $ make check - - 5. [Optional] Generate the user documentation. - - $ make html - - The release tarballs already include the documentation. - - Note that for this step you need to have the following tools - installed: Python, Doxygen, Graphviz, Ghostscript, LaTeX. - - 6. [Optional] Install LEMON - - $ make install - - This command installs LEMON under /usr/local (you will need root - privileges to be able to do that). If you want to install it to - some other location, then pass the - -DCMAKE_INSTALL_PREFIX=DIRECTORY flag to cmake in Step 3. - For example: - - $ cmake -DCMAKE_INSTALL_PREFIX=/home/username/lemon' - -Configure Options and Variables -=============================== - -In Step 3, you can customize the build process by passing options to CMAKE. - -$ cmake [OPTIONS] .. - -You find a list of the most useful options below. - --DCMAKE_INSTALL_PREFIX=PREFIX - - Set the installation prefix to PREFIX. By default it is /usr/local. - --DCMAKE_BUILD_TYPE=[Release|Debug|Maintainer|...] - - This sets the compiler options. The choices are the following - - 'Release': A strong optimization is turned on (-O3 with gcc). This - is the default setting and we strongly recommend using this for - the final compilation. - - 'Debug': Optimization is turned off and debug info is added (-O0 - -ggdb with gcc). If is recommended during the development. - - 'Maintainer': The same as 'Debug' but the compiler warnings are - converted to errors (-Werror with gcc). In addition, 'make' will - also automatically compile and execute the test codes. It is the - best way of ensuring that LEMON codebase is clean and safe. - - 'RelWithDebInfo': Optimized build with debug info. - - 'MinSizeRel': Size optimized build (-Os with gcc) - --DTEST_WITH_VALGRIND=YES - - Using this, the test codes will be executed using valgrind. It is a - very effective way of identifying indexing problems and memory leaks. - --DCMAKE_CXX_COMPILER=path-to-compiler - - Change the compiler to be used. - --DBUILD_SHARED_LIBS=TRUE - - Build shared library instead of static one. Think twice if you - really want to use this option. - --DLEMON_DOC_SOURCE_BROWSER=YES - - Include the browsable cross referenced LEMON source code into the - doc. It makes the doc quite bloated, but may be useful for - developing LEMON itself. - --DLEMON_DOC_USE_MATHJAX=YES - - Use MathJax (http://mathjax.org) for rendering the math formulae in - the doc. It of much higher quality compared to the default LaTeX - generated static images and it allows copy&paste of the formulae to - LaTeX, Open Office, MS Word etc. documents. - - On the other hand, it needs either Internet access or a locally - installed version of MathJax to properly render the doc. - --DLEMON_DOC_MATHJAX_RELPATH=DIRECTORY - - The location of the MathJax library. It defaults to - http://www.mathjax.org/mathjax, which necessitates Internet access - for proper rendering. The easiest way to make it usable offline is - to set this parameter to 'mathjax' and copy all files of the MathJax - library into the 'doc/html/mathjax' subdirectory of the build - location. - - See http://docs.mathjax.org/en/latest/installation.html for more details. - - --DLEMON_ENABLE_GLPK=NO --DLEMON_ENABLE_COIN=NO --DLEMON_ENABLE_ILOG=NO - - Enable optional third party libraries. They are all enabled by default. - --DLEMON_DEFAULT_LP=GLPK - - Sets the default LP solver backend. The supported values are - CPLEX, CLP and GLPK. By default, it is set to the first one which - is enabled and succesfully discovered. - --DLEMON_DEFAULT_MIP=GLPK - - Sets the default MIP solver backend. The supported values are - CPLEX, CBC and GLPK. By default, it is set to the first one which - is enabled and succesfully discovered. - --DGLPK_ROOT_DIR=DIRECTORY --DCOIN_ROOT_DIR=DIRECTORY --DILOG_ROOT_DIR=DIRECTORY - - Root directory prefixes of optional third party libraries. - -Makefile Variables -================== - -make VERBOSE=1 - - This results in a more verbose output by showing the full - compiler and linker commands. \ No newline at end of file diff --git a/deps/lemon/LICENSE b/deps/lemon/LICENSE deleted file mode 100644 index 5b1c42550..000000000 --- a/deps/lemon/LICENSE +++ /dev/null @@ -1,32 +0,0 @@ -LEMON code without an explicit copyright notice is covered by the following -copyright/license. - -Copyright (C) 2003-2012 Egervary Jeno Kombinatorikus Optimalizalasi -Kutatocsoport (Egervary Combinatorial Optimization Research Group, -EGRES). - -=========================================================================== -Boost Software License, Version 1.0 -=========================================================================== - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/deps/lemon/NEWS b/deps/lemon/NEWS deleted file mode 100644 index 7908ca3a4..000000000 --- a/deps/lemon/NEWS +++ /dev/null @@ -1,337 +0,0 @@ -2014-07-07 Version 1.3.1 released - - Bugfix release. - - #484: Require CMAKE 2.8 - #471, #472, #480: Various clang compatibility fixes - #481, #482: Fix shared lib build and versioning - #476: Fix invalid map query in NearestNeighborTsp - #478: Bugfix in debug checking and lower bound handling - in min cost flow algorithms - #479, #465: Bugfix in default LP/MIP backend settings - #476: Bugfix in tsp_test - #487: Add missing include header and std:: namespace spec. - #474: Fix division by zero error in NetworkSimplex - -2013-08-10 Version 1.3 released - - This is major feature release - - * New data structures - - #69 : Bipartite graph concepts and implementations - - * New algorithms - - #177: Port Edmonds-Karp algorithm - #380, #405: Heuristic algorithm for the max clique problem - #386: Heuristic algorithms for symmetric TSP - ----: Nagamochi-Ibaraki algorithm [5087694945e4] - #397, #56: Max. cardinality search - - * Other new features - - #223: Thread safe graph and graph map implementations - #442: Different TimeStamp print formats - #457: File export functionality to LpBase - #362: Bidirectional iterator support for radixSort() - - * Implementation improvements - - ----: Network Simplex - #391: Better update process, pivot rule and arc mixing - #435: Improved Altering List pivot rule - #417: Various fine tunings in CostScaling - #438: Optional iteration limit in HowardMmc - #436: Ensure strongly polynomial running time for CycleCanceling - while keeping the same performance - ----: Make the CBC interface be compatible with latest CBC releases - [ee581a0ecfbf] - - * CMAKE has become the default build environment (#434) - - ----: Autotool support has been dropped - ----: Improved LP/MIP configuration - #465: Enable/disable options for LP/MIP backends - #446: Better CPLEX discovery - #460: Add cmake config to find SoPlex - ----: Allow CPACK configuration on all platforms - #390: Add 'Maintainer' CMAKE build type - #388: Add 'check' target. - #401: Add contrib dir - #389: Better version string setting in CMAKE - #433: Support shared library build - #416: Support testing with valgrind - - * Doc improvements - - #395: SOURCE_BROWSER Doxygen switch is configurable from CMAKE - update-external-tags CMAKE target - #455: Optionally use MathJax for rendering the math formulae - #402, #437, #459, #456, #463: Various doc improvements - - * Bugfixes (compared to release 1.2): - - #432: Add missing doc/template.h and doc/references.bib to release - tarball - ----: Intel C++ compatibility fixes - #441: Fix buggy reinitialization in _solver_bits::VarIndex::clear() - #444: Bugfix in path copy constructors and assignment operators - #447: Bugfix in AllArcLookUp<> - #448: Bugfix in adaptor_test.cc - #449: Fix clang compilation warnings and errors - #440: Fix a bug + remove redundant typedefs in dimacs-solver - #453: Avoid GCC 4.7 compiler warnings - #445: Fix missing initialization in CplexEnv::CplexEnv() - #428: Add missing lemon/lemon.pc.cmake to the release tarball - #393: Create and install lemon.pc - #429: Fix VS warnings - #430: Fix LpBase::Constr two-side limit bug - #392: Bug fix in Dfs::start(s,t) - #414: Fix wrong initialization in Preflow - #418: Better Win CodeBlock/MinGW support - #419: Build environment improvements - - Build of mip_test and lp_test precede the running of the tests - - Also search for coin libs under ${COIN_ROOT_DIR}/lib/coin - - Do not look for COIN_VOL libraries - #382: Allow lgf file without Arc maps - #417: Bug fix in CostScaling - #366: Fix Pred[Matrix]MapPath::empty() - #371: Bug fix in (di)graphCopy() - The target graph is cleared before adding nodes and arcs/edges. - #364: Add missing UndirectedTags - #368: Fix the usage of std::numeric_limits<>::min() in Network Simplex - #372: Fix a critical bug in preflow - #461: Bugfix in assert.h - #470: Fix compilation issues related to various gcc versions - #446: Fix #define indicating CPLEX availability - #294: Add explicit namespace to - ignore_unused_variable_warning() usages - #420: Bugfix in IterableValueMap - #439: Bugfix in biNodeConnected() - - -2010-03-19 Version 1.2 released - - This is major feature release - - * New algorithms - * Bellman-Ford algorithm (#51) - * Minimum mean cycle algorithms (#179) - * Karp, Hartman-Orlin and Howard algorithms - * New minimum cost flow algorithms (#180) - * Cost Scaling algorithms - * Capacity Scaling algorithm - * Cycle-Canceling algorithms - * Planarity related algorithms (#62) - * Planarity checking algorithm - * Planar embedding algorithm - * Schnyder's planar drawing algorithm - * Coloring planar graphs with five or six colors - * Fractional matching algorithms (#314) - * New data structures - * StaticDigraph structure (#68) - * Several new priority queue structures (#50, #301) - * Fibonacci, Radix, Bucket, Pairing, Binomial - D-ary and fourary heaps (#301) - * Iterable map structures (#73) - * Other new tools and functionality - * Map utility functions (#320) - * Reserve functions are added to ListGraph and SmartGraph (#311) - * A resize() function is added to HypercubeGraph (#311) - * A count() function is added to CrossRefMap (#302) - * Support for multiple targets in Suurballe using fullInit() (#181) - * Traits class and named parameters for Suurballe (#323) - * Separate reset() and resetParams() functions in NetworkSimplex - to handle graph changes (#327) - * tolerance() functions are added to HaoOrlin (#306) - * Implementation improvements - * Improvements in weighted matching algorithms (#314) - * Jumpstart initialization - * ArcIt iteration is based on out-arc lists instead of in-arc lists - in ListDigraph (#311) - * Faster add row operation in CbcMip (#203) - * Better implementation for split() in ListDigraph (#311) - * ArgParser can also throw exception instead of exit(1) (#332) - * Miscellaneous - * A simple interactive bootstrap script - * Doc improvements (#62,#180,#299,#302,#303,#304,#307,#311,#331,#315, - #316,#319) - * BibTeX references in the doc (#184) - * Optionally use valgrind when running tests - * Also check ReferenceMapTag in concept checks (#312) - * dimacs-solver uses long long type by default. - * Several bugfixes (compared to release 1.1): - #295: Suppress MSVC warnings using pragmas - ----: Various CMAKE related improvements - * Remove duplications from doc/CMakeLists.txt - * Rename documentation install folder from 'docs' to 'html' - * Add tools/CMakeLists.txt to the tarball - * Generate and install LEMONConfig.cmake - * Change the label of the html project in Visual Studio - * Fix the check for the 'long long' type - * Put the version string into config.h - * Minor CMake improvements - * Set the version to 'hg-tip' if everything fails - #311: Add missing 'explicit' keywords - #302: Fix the implementation and doc of CrossRefMap - #308: Remove duplicate list_graph.h entry from source list - #307: Bugfix in Preflow and Circulation - #305: Bugfix and extension in the rename script - #312: Also check ReferenceMapTag in concept checks - #250: Bugfix in pathSource() and pathTarget() - #321: Use pathCopy(from,to) instead of copyPath(to,from) - #322: Distribure LEMONConfig.cmake.in - #330: Bug fix in map_extender.h - #336: Fix the date field comment of graphToEps() output - #323: Bug fix in Suurballe - #335: Fix clear() function in ExtendFindEnum - #337: Use void* as the LPX object pointer - #317: Fix (and improve) error message in mip_test.cc - Remove unnecessary OsiCbc dependency - #356: Allow multiple executions of weighted matching algorithms (#356) - -2009-05-13 Version 1.1 released - - This is the second stable release of the 1.x series. It - features a better coverage of the tools available in the 0.x - series, a thoroughly reworked LP/MIP interface plus various - improvements in the existing tools. - - * Much improved M$ Windows support - * Various improvements in the CMAKE build system - * Compilation warnings are fixed/suppressed - * Support IBM xlC compiler - * New algorithms - * Connectivity related algorithms (#61) - * Euler walks (#65) - * Preflow push-relabel max. flow algorithm (#176) - * Circulation algorithm (push-relabel based) (#175) - * Suurballe algorithm (#47) - * Gomory-Hu algorithm (#66) - * Hao-Orlin algorithm (#58) - * Edmond's maximum cardinality and weighted matching algorithms - in general graphs (#48,#265) - * Minimum cost arborescence/branching (#60) - * Network Simplex min. cost flow algorithm (#234) - * New data structures - * Full graph structure (#57) - * Grid graph structure (#57) - * Hypercube graph structure (#57) - * Graph adaptors (#67) - * ArcSet and EdgeSet classes (#67) - * Elevator class (#174) - * Other new tools - * LP/MIP interface (#44) - * Support for GLPK, CPLEX, Soplex, COIN-OR CLP and CBC - * Reader for the Nauty file format (#55) - * DIMACS readers (#167) - * Radix sort algorithms (#72) - * RangeIdMap and CrossRefMap (#160) - * New command line tools - * DIMACS to LGF converter (#182) - * lgf-gen - a graph generator (#45) - * DIMACS solver utility (#226) - * Other code improvements - * Lognormal distribution added to Random (#102) - * Better (i.e. O(1) time) item counting in SmartGraph (#3) - * The standard maps of graphs are guaranteed to be - reference maps (#190) - * Miscellaneous - * Various doc improvements - * Improved 0.x -> 1.x converter script - - * Several bugfixes (compared to release 1.0): - #170: Bugfix SmartDigraph::split() - #171: Bugfix in SmartGraph::restoreSnapshot() - #172: Extended test cases for graphs and digraphs - #173: Bugfix in Random - * operator()s always return a double now - * the faulty real(Num) and real(Num,Num) - have been removed - #187: Remove DijkstraWidestPathOperationTraits - #61: Bugfix in DfsVisit - #193: Bugfix in GraphReader::skipSection() - #195: Bugfix in ConEdgeIt() - #197: Bugfix in heap unionfind - * This bug affects Edmond's general matching algorithms - #207: Fix 'make install' without 'make html' using CMAKE - #208: Suppress or fix VS2008 compilation warnings - ----: Update the LEMON icon - ----: Enable the component-based installer - (in installers made by CPACK) - ----: Set the proper version for CMAKE in the tarballs - (made by autotools) - ----: Minor clarification in the LICENSE file - ----: Add missing unistd.h include to time_measure.h - #204: Compilation bug fixed in graph_to_eps.h with VS2005 - #214,#215: windows.h should never be included by LEMON headers - #230: Build systems check the availability of 'long long' type - #229: Default implementation of Tolerance<> is used for integer types - #211,#212: Various fixes for compiling on AIX - ----: Improvements in CMAKE config - - docs is installed in share/doc/ - - detects newer versions of Ghostscript - #239: Fix missing 'inline' specifier in time_measure.h - #274,#280: Install lemon/config.h - #275: Prefix macro names with LEMON_ in lemon/config.h - ----: Small script for making the release tarballs added - ----: Minor improvement in unify-sources.sh (a76f55d7d397) - -2009-03-27 LEMON joins to the COIN-OR initiative - - COIN-OR (Computational Infrastructure for Operations Research, - http://www.coin-or.org) project is an initiative to spur the - development of open-source software for the operations research - community. - -2008-10-13 Version 1.0 released - - This is the first stable release of LEMON. Compared to the 0.x - release series, it features a considerably smaller but more - matured set of tools. The API has also completely revised and - changed in several places. - - * The major name changes compared to the 0.x series (see the - Migration Guide in the doc for more details) - * Graph -> Digraph, UGraph -> Graph - * Edge -> Arc, UEdge -> Edge - * source(UEdge)/target(UEdge) -> u(Edge)/v(Edge) - * Other improvements - * Better documentation - * Reviewed and cleaned up codebase - * CMake based build system (along with the autotools based one) - * Contents of the library (ported from 0.x) - * Algorithms - * breadth-first search (bfs.h) - * depth-first search (dfs.h) - * Dijkstra's algorithm (dijkstra.h) - * Kruskal's algorithm (kruskal.h) - * Data structures - * graph data structures (list_graph.h, smart_graph.h) - * path data structures (path.h) - * binary heap data structure (bin_heap.h) - * union-find data structures (unionfind.h) - * miscellaneous property maps (maps.h) - * two dimensional vector and bounding box (dim2.h) - * Concepts - * graph structure concepts (concepts/digraph.h, concepts/graph.h, - concepts/graph_components.h) - * concepts for other structures (concepts/heap.h, concepts/maps.h, - concepts/path.h) - * Tools - * Mersenne twister random number generator (random.h) - * tools for measuring cpu and wall clock time (time_measure.h) - * tools for counting steps and events (counter.h) - * tool for parsing command line arguments (arg_parser.h) - * tool for visualizing graphs (graph_to_eps.h) - * tools for reading and writing data in LEMON Graph Format - (lgf_reader.h, lgf_writer.h) - * tools to handle the anomalies of calculations with - floating point numbers (tolerance.h) - * tools to manage RGB colors (color.h) - * Infrastructure - * extended assertion handling (assert.h) - * exception classes and error handling (error.h) - * concept checking (concept_check.h) - * commonly used mathematical constants (math.h) diff --git a/deps/lemon/README b/deps/lemon/README deleted file mode 100644 index 52a768c39..000000000 --- a/deps/lemon/README +++ /dev/null @@ -1,50 +0,0 @@ -===================================================================== -LEMON - a Library for Efficient Modeling and Optimization in Networks -===================================================================== - -LEMON is an open source library written in C++. It provides -easy-to-use implementations of common data structures and algorithms -in the area of optimization and helps implementing new ones. The main -focus is on graphs and graph algorithms, thus it is especially -suitable for solving design and optimization problems of -telecommunication networks. To achieve wide usability its data -structures and algorithms provide generic interfaces. - -Contents -======== - -LICENSE - - Copying, distribution and modification conditions and terms. - -NEWS - - News and version history. - -INSTALL - - General building and installation instructions. - -lemon/ - - Source code of LEMON library. - -doc/ - - Documentation of LEMON. The starting page is doc/html/index.html. - -demo/ - - Some example programs to make you easier to get familiar with LEMON. - -scripts/ - - Scripts that make it easier to develop LEMON. - -test/ - - Programs to check the integrity and correctness of LEMON. - -tools/ - - Various utilities related to LEMON. diff --git a/deps/lemon/cmake/FindCOIN.cmake b/deps/lemon/cmake/FindCOIN.cmake deleted file mode 100644 index d4ed735df..000000000 --- a/deps/lemon/cmake/FindCOIN.cmake +++ /dev/null @@ -1,110 +0,0 @@ -SET(COIN_ROOT_DIR "" CACHE PATH "COIN root directory") - -FIND_PATH(COIN_INCLUDE_DIR coin/CoinUtilsConfig.h - HINTS ${COIN_ROOT_DIR}/include -) -FIND_LIBRARY(COIN_CBC_LIBRARY - NAMES Cbc libCbc - HINTS ${COIN_ROOT_DIR}/lib/coin - HINTS ${COIN_ROOT_DIR}/lib -) -FIND_LIBRARY(COIN_CBC_SOLVER_LIBRARY - NAMES CbcSolver libCbcSolver - HINTS ${COIN_ROOT_DIR}/lib/coin - HINTS ${COIN_ROOT_DIR}/lib -) -FIND_LIBRARY(COIN_CGL_LIBRARY - NAMES Cgl libCgl - HINTS ${COIN_ROOT_DIR}/lib/coin - HINTS ${COIN_ROOT_DIR}/lib -) -FIND_LIBRARY(COIN_CLP_LIBRARY - NAMES Clp libClp - HINTS ${COIN_ROOT_DIR}/lib/coin - HINTS ${COIN_ROOT_DIR}/lib -) -FIND_LIBRARY(COIN_COIN_UTILS_LIBRARY - NAMES CoinUtils libCoinUtils - HINTS ${COIN_ROOT_DIR}/lib/coin - HINTS ${COIN_ROOT_DIR}/lib -) -FIND_LIBRARY(COIN_OSI_LIBRARY - NAMES Osi libOsi - HINTS ${COIN_ROOT_DIR}/lib/coin - HINTS ${COIN_ROOT_DIR}/lib -) -FIND_LIBRARY(COIN_OSI_CBC_LIBRARY - NAMES OsiCbc libOsiCbc - HINTS ${COIN_ROOT_DIR}/lib/coin - HINTS ${COIN_ROOT_DIR}/lib -) -FIND_LIBRARY(COIN_OSI_CLP_LIBRARY - NAMES OsiClp libOsiClp - HINTS ${COIN_ROOT_DIR}/lib/coin - HINTS ${COIN_ROOT_DIR}/lib -) -FIND_LIBRARY(COIN_OSI_VOL_LIBRARY - NAMES OsiVol libOsiVol - HINTS ${COIN_ROOT_DIR}/lib/coin - HINTS ${COIN_ROOT_DIR}/lib -) -FIND_LIBRARY(COIN_VOL_LIBRARY - NAMES Vol libVol - HINTS ${COIN_ROOT_DIR}/lib/coin - HINTS ${COIN_ROOT_DIR}/lib -) - -FIND_LIBRARY(COIN_ZLIB_LIBRARY - NAMES z libz - HINTS ${COIN_ROOT_DIR}/lib/coin - HINTS ${COIN_ROOT_DIR}/lib -) -FIND_LIBRARY(COIN_BZ2_LIBRARY - NAMES bz2 libbz2 - HINTS ${COIN_ROOT_DIR}/lib/coin - HINTS ${COIN_ROOT_DIR}/lib -) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(COIN DEFAULT_MSG - COIN_INCLUDE_DIR - COIN_CBC_LIBRARY - COIN_CBC_SOLVER_LIBRARY - COIN_CGL_LIBRARY - COIN_CLP_LIBRARY - COIN_COIN_UTILS_LIBRARY - COIN_OSI_LIBRARY - COIN_OSI_CBC_LIBRARY - COIN_OSI_CLP_LIBRARY - # COIN_OSI_VOL_LIBRARY - # COIN_VOL_LIBRARY -) - -IF(COIN_FOUND) - SET(COIN_INCLUDE_DIRS ${COIN_INCLUDE_DIR}) - SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARY};${COIN_COIN_UTILS_LIBRARY};${COIN_ZLIB_LIBRARY};${COIN_BZ2_LIBRARY}") - IF(COIN_ZLIB_LIBRARY) - SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARIES};${COIN_ZLIB_LIBRARY}") - ENDIF(COIN_ZLIB_LIBRARY) - IF(COIN_BZ2_LIBRARY) - SET(COIN_CLP_LIBRARIES "${COIN_CLP_LIBRARIES};${COIN_BZ2_LIBRARY}") - ENDIF(COIN_BZ2_LIBRARY) - SET(COIN_CBC_LIBRARIES "${COIN_CBC_LIBRARY};${COIN_CBC_SOLVER_LIBRARY};${COIN_CGL_LIBRARY};${COIN_OSI_LIBRARY};${COIN_OSI_CBC_LIBRARY};${COIN_OSI_CLP_LIBRARY};${COIN_ZLIB_LIBRARY};${COIN_BZ2_LIBRARY};${COIN_CLP_LIBRARIES}") - SET(COIN_LIBRARIES ${COIN_CBC_LIBRARIES}) -ENDIF(COIN_FOUND) - -MARK_AS_ADVANCED( - COIN_INCLUDE_DIR - COIN_CBC_LIBRARY - COIN_CBC_SOLVER_LIBRARY - COIN_CGL_LIBRARY - COIN_CLP_LIBRARY - COIN_COIN_UTILS_LIBRARY - COIN_OSI_LIBRARY - COIN_OSI_CBC_LIBRARY - COIN_OSI_CLP_LIBRARY - COIN_OSI_VOL_LIBRARY - COIN_VOL_LIBRARY - COIN_ZLIB_LIBRARY - COIN_BZ2_LIBRARY -) diff --git a/deps/lemon/cmake/FindGLPK.cmake b/deps/lemon/cmake/FindGLPK.cmake deleted file mode 100644 index 55e5e3ee0..000000000 --- a/deps/lemon/cmake/FindGLPK.cmake +++ /dev/null @@ -1,55 +0,0 @@ -SET(GLPK_ROOT_DIR "" CACHE PATH "GLPK root directory") - -SET(GLPK_REGKEY "[HKEY_LOCAL_MACHINE\\SOFTWARE\\GnuWin32\\Glpk;InstallPath]") -GET_FILENAME_COMPONENT(GLPK_ROOT_PATH ${GLPK_REGKEY} ABSOLUTE) - -FIND_PATH(GLPK_INCLUDE_DIR - glpk.h - PATHS ${GLPK_REGKEY}/include - HINTS ${GLPK_ROOT_DIR}/include -) -FIND_LIBRARY(GLPK_LIBRARY - glpk - PATHS ${GLPK_REGKEY}/lib - HINTS ${GLPK_ROOT_DIR}/lib -) - -IF(GLPK_INCLUDE_DIR AND GLPK_LIBRARY) - FILE(READ ${GLPK_INCLUDE_DIR}/glpk.h GLPK_GLPK_H) - - STRING(REGEX MATCH "define[ ]+GLP_MAJOR_VERSION[ ]+[0-9]+" GLPK_MAJOR_VERSION_LINE "${GLPK_GLPK_H}") - STRING(REGEX REPLACE "define[ ]+GLP_MAJOR_VERSION[ ]+([0-9]+)" "\\1" GLPK_VERSION_MAJOR "${GLPK_MAJOR_VERSION_LINE}") - - STRING(REGEX MATCH "define[ ]+GLP_MINOR_VERSION[ ]+[0-9]+" GLPK_MINOR_VERSION_LINE "${GLPK_GLPK_H}") - STRING(REGEX REPLACE "define[ ]+GLP_MINOR_VERSION[ ]+([0-9]+)" "\\1" GLPK_VERSION_MINOR "${GLPK_MINOR_VERSION_LINE}") - - SET(GLPK_VERSION_STRING "${GLPK_VERSION_MAJOR}.${GLPK_VERSION_MINOR}") - - IF(GLPK_FIND_VERSION) - IF(GLPK_FIND_VERSION_COUNT GREATER 2) - MESSAGE(SEND_ERROR "unexpected version string") - ENDIF(GLPK_FIND_VERSION_COUNT GREATER 2) - - MATH(EXPR GLPK_REQUESTED_VERSION "${GLPK_FIND_VERSION_MAJOR}*100 + ${GLPK_FIND_VERSION_MINOR}") - MATH(EXPR GLPK_FOUND_VERSION "${GLPK_VERSION_MAJOR}*100 + ${GLPK_VERSION_MINOR}") - - IF(GLPK_FOUND_VERSION LESS GLPK_REQUESTED_VERSION) - SET(GLPK_PROPER_VERSION_FOUND FALSE) - ELSE(GLPK_FOUND_VERSION LESS GLPK_REQUESTED_VERSION) - SET(GLPK_PROPER_VERSION_FOUND TRUE) - ENDIF(GLPK_FOUND_VERSION LESS GLPK_REQUESTED_VERSION) - ELSE(GLPK_FIND_VERSION) - SET(GLPK_PROPER_VERSION_FOUND TRUE) - ENDIF(GLPK_FIND_VERSION) -ENDIF(GLPK_INCLUDE_DIR AND GLPK_LIBRARY) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLPK DEFAULT_MSG GLPK_LIBRARY GLPK_INCLUDE_DIR GLPK_PROPER_VERSION_FOUND) - -IF(GLPK_FOUND) - SET(GLPK_INCLUDE_DIRS ${GLPK_INCLUDE_DIR}) - SET(GLPK_LIBRARIES ${GLPK_LIBRARY}) - SET(GLPK_BIN_DIR ${GLPK_ROOT_PATH}/bin) -ENDIF(GLPK_FOUND) - -MARK_AS_ADVANCED(GLPK_LIBRARY GLPK_INCLUDE_DIR GLPK_BIN_DIR) diff --git a/deps/lemon/cmake/FindGhostscript.cmake b/deps/lemon/cmake/FindGhostscript.cmake deleted file mode 100644 index 3366a000e..000000000 --- a/deps/lemon/cmake/FindGhostscript.cmake +++ /dev/null @@ -1,10 +0,0 @@ -INCLUDE(FindPackageHandleStandardArgs) - -FIND_PROGRAM(GHOSTSCRIPT_EXECUTABLE - NAMES gs gswin32c - PATHS "$ENV{ProgramFiles}/gs" - PATH_SUFFIXES gs8.61/bin gs8.62/bin gs8.63/bin gs8.64/bin gs8.65/bin - DOC "Ghostscript: PostScript and PDF language interpreter and previewer." -) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Ghostscript DEFAULT_MSG GHOSTSCRIPT_EXECUTABLE) diff --git a/deps/lemon/cmake/FindILOG.cmake b/deps/lemon/cmake/FindILOG.cmake deleted file mode 100644 index a09fc9a27..000000000 --- a/deps/lemon/cmake/FindILOG.cmake +++ /dev/null @@ -1,102 +0,0 @@ -FIND_PATH(ILOG_ROOT_DIR - NAMES cplex - DOC "CPLEX STUDIO root directory" - PATHS /opt/ibm/ILOG /usr/local/ibm/ILOG /usr/local/ILOG /usr/local/ilog - PATHS "$ENV{HOME}/ILOG" "$ENV{HOME}/.local/ILOG" - PATHS "$ENV{HOME}/ibm/ILOG" "$ENV{HOME}/.local/ibm/ILOG" - PATHS "C:/Program Files/IBM/ILOG" - PATH_SUFFIXES "CPLEX_Studio126" "CPLEX_Studio125" - "CPLEX_Studio124" "CPLEX_Studio123" "CPLEX_Studio122" - NO_DEFAULT_PATH -) - -IF(WIN32) - IF(MSVC_VERSION STREQUAL "1400") - SET(ILOG_WIN_COMPILER "windows_vs2005") - ELSEIF(MSVC_VERSION STREQUAL "1500") - SET(ILOG_WIN_COMPILER "windows_vs2008") - ELSEIF(MSVC_VERSION STREQUAL "1600") - SET(ILOG_WIN_COMPILER "windows_vs2010") - ELSE() - SET(ILOG_WIN_COMPILER "windows_vs2008") - ENDIF() - IF(CMAKE_CL_64) - SET(ILOG_WIN_COMPILER "x64_${ILOG_WIN_COMPILER}") - SET(ILOG_WIN_PLATFORM "x64_win32") - ELSE() - SET(ILOG_WIN_COMPILER "x86_${ILOG_WIN_COMPILER}") - SET(ILOG_WIN_PLATFORM "x86_win32") - ENDIF() -ENDIF() - -FIND_PATH(ILOG_CPLEX_ROOT_DIR - NAMES include/ilcplex - HINTS ${ILOG_ROOT_DIR}/cplex ${ILOG_ROOT_DIR}/cplex121 - ${ILOG_ROOT_DIR}/cplex122 ${ILOG_ROOT_DIR}/cplex123 - DOC "CPLEX root directory" - NO_DEFAULT_PATH -) - -FIND_PATH(ILOG_CONCERT_ROOT_DIR - NAMES include/ilconcert - HINTS ${ILOG_ROOT_DIR}/concert ${ILOG_ROOT_DIR}/concert29 - DOC "CONCERT root directory" - NO_DEFAULT_PATH -) - -FIND_PATH(ILOG_CPLEX_INCLUDE_DIR - ilcplex/cplex.h - HINTS ${ILOG_CPLEX_ROOT_DIR}/include - NO_DEFAULT_PATH -) - -FIND_PATH(ILOG_CONCERT_INCLUDE_DIR - ilconcert/ilobasic.h - HINTS ${ILOG_CONCERT_ROOT_DIR}/include - NO_DEFAULT_PATH -) - -FIND_LIBRARY(ILOG_CPLEX_LIBRARY - cplex cplex121 cplex122 cplex123 cplex124 - HINTS ${ILOG_CPLEX_ROOT_DIR}/lib/x86_sles10_4.1/static_pic - ${ILOG_CPLEX_ROOT_DIR}/lib/x86-64_sles10_4.1/static_pic - ${ILOG_CPLEX_ROOT_DIR}/lib/x86_debian4.0_4.1/static_pic - ${ILOG_CPLEX_ROOT_DIR}/lib/x86-64_debian4.0_4.1/static_pic - ${ILOG_CPLEX_ROOT_DIR}/lib/${ILOG_WIN_COMPILER}/stat_mda - NO_DEFAULT_PATH - ) - -FIND_LIBRARY(ILOG_CONCERT_LIBRARY - concert - HINTS ${ILOG_CONCERT_ROOT_DIR}/lib/x86_sles10_4.1/static_pic - ${ILOG_CONCERT_ROOT_DIR}/lib/x86-64_sles10_4.1/static_pic - ${ILOG_CONCERT_ROOT_DIR}/lib/x86_debian4.0_4.1/static_pic - ${ILOG_CONCERT_ROOT_DIR}/lib/x86-64_debian4.0_4.1/static_pic - ${ILOG_CONCERT_ROOT_DIR}/lib/${ILOG_WIN_COMPILER}/stat_mda - NO_DEFAULT_PATH - ) - -FIND_FILE(ILOG_CPLEX_DLL - cplex121.dll cplex122.dll cplex123.dll cplex124.dll - HINTS ${ILOG_CPLEX_ROOT_DIR}/bin/${ILOG_WIN_PLATFORM} - NO_DEFAULT_PATH - ) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(ILOG - DEFAULT_MSG ILOG_CPLEX_LIBRARY ILOG_CPLEX_INCLUDE_DIR - ) - -IF(ILOG_FOUND) - SET(ILOG_INCLUDE_DIRS ${ILOG_CPLEX_INCLUDE_DIR} ${ILOG_CONCERT_INCLUDE_DIR}) - SET(ILOG_LIBRARIES ${ILOG_CPLEX_LIBRARY} ${ILOG_CONCERT_LIBRARY}) - IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") - # SET(CPLEX_LIBRARIES "${CPLEX_LIBRARIES};m;pthread") - SET(ILOG_LIBRARIES ${ILOG_LIBRARIES} "m" "pthread") - ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux") -ENDIF(ILOG_FOUND) - -MARK_AS_ADVANCED( - ILOG_CPLEX_LIBRARY ILOG_CPLEX_INCLUDE_DIR ILOG_CPLEX_DLL - ILOG_CONCERT_LIBRARY ILOG_CONCERT_INCLUDE_DIR ILOG_CONCERT_DLL - ) diff --git a/deps/lemon/cmake/FindSOPLEX.cmake b/deps/lemon/cmake/FindSOPLEX.cmake deleted file mode 100644 index d27cff0f3..000000000 --- a/deps/lemon/cmake/FindSOPLEX.cmake +++ /dev/null @@ -1,23 +0,0 @@ -SET(SOPLEX_ROOT_DIR "" CACHE PATH "SoPlex root directory") - -FIND_PATH(SOPLEX_INCLUDE_DIR - soplex.h - HINTS ${SOPLEX_ROOT_DIR}/src -) -FIND_LIBRARY(SOPLEX_LIBRARY - soplex - HINTS ${SOPLEX_ROOT_DIR}/lib -) - -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SOPLEX DEFAULT_MSG SOPLEX_LIBRARY SOPLEX_INCLUDE_DIR) - -IF(SOPLEX_FOUND) - SET(SOPLEX_INCLUDE_DIRS ${SOPLEX_INCLUDE_DIR}) - SET(SOPLEX_LIBRARIES ${SOPLEX_LIBRARY}) - IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") - SET(SOPLEX_LIBRARIES "${SOPLEX_LIBRARIES};z") - ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux") -ENDIF(SOPLEX_FOUND) - -MARK_AS_ADVANCED(SOPLEX_LIBRARY SOPLEX_INCLUDE_DIR) diff --git a/deps/lemon/cmake/LEMONConfig.cmake.in b/deps/lemon/cmake/LEMONConfig.cmake.in deleted file mode 100644 index b0d2d8b4c..000000000 --- a/deps/lemon/cmake/LEMONConfig.cmake.in +++ /dev/null @@ -1,13 +0,0 @@ -SET(LEMON_INCLUDE_DIR "@CMAKE_INSTALL_PREFIX@/include" CACHE PATH "LEMON include directory") -SET(LEMON_INCLUDE_DIRS "${LEMON_INCLUDE_DIR}") - -IF(UNIX) - SET(LEMON_LIB_NAME "libemon.a") -ELSEIF(WIN32) - SET(LEMON_LIB_NAME "lemon.lib") -ENDIF(UNIX) - -SET(LEMON_LIBRARY "@CMAKE_INSTALL_PREFIX@/lib/${LEMON_LIB_NAME}" CACHE FILEPATH "LEMON library") -SET(LEMON_LIBRARIES "${LEMON_LIBRARY}") - -MARK_AS_ADVANCED(LEMON_LIBRARY LEMON_INCLUDE_DIR) diff --git a/deps/lemon/cmake/nsis/lemon.ico b/deps/lemon/cmake/nsis/lemon.ico deleted file mode 100644 index bbfd8c143..000000000 Binary files a/deps/lemon/cmake/nsis/lemon.ico and /dev/null differ diff --git a/deps/lemon/cmake/nsis/uninstall.ico b/deps/lemon/cmake/nsis/uninstall.ico deleted file mode 100644 index 7495f7c3c..000000000 Binary files a/deps/lemon/cmake/nsis/uninstall.ico and /dev/null differ diff --git a/deps/lemon/cmake/version.cmake b/deps/lemon/cmake/version.cmake deleted file mode 100644 index 91369e1ca..000000000 --- a/deps/lemon/cmake/version.cmake +++ /dev/null @@ -1 +0,0 @@ -SET(LEMON_VERSION "1.3.1" CACHE STRING "LEMON version string.") diff --git a/deps/lemon/cmake/version.cmake.in b/deps/lemon/cmake/version.cmake.in deleted file mode 100644 index 7cd4b6899..000000000 --- a/deps/lemon/cmake/version.cmake.in +++ /dev/null @@ -1 +0,0 @@ -SET(LEMON_VERSION "@LEMON_VERSION@" CACHE STRING "LEMON version string.") diff --git a/deps/lemon/contrib/CMakeLists.txt b/deps/lemon/contrib/CMakeLists.txt deleted file mode 100644 index b6c11e2aa..000000000 --- a/deps/lemon/contrib/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -INCLUDE_DIRECTORIES( - ${PROJECT_SOURCE_DIR} - ${PROJECT_BINARY_DIR} -) - -LINK_DIRECTORIES( - ${PROJECT_BINARY_DIR}/lemon -) - -# Uncomment (and adjust) the following two lines. 'myprog' is the name -# of the final executable ('.exe' will automatically be added to the -# name on Windows) and 'myprog-main.cc' is the source code it is -# compiled from. You can add more source files separated by -# whitespaces. Moreover, you can add multiple similar blocks if you -# want to build more than one executables. - -# ADD_EXECUTABLE(myprog myprog-main.cc) -# TARGET_LINK_LIBRARIES(myprog lemon) - diff --git a/deps/lemon/demo/CMakeLists.txt b/deps/lemon/demo/CMakeLists.txt deleted file mode 100644 index e0566f407..000000000 --- a/deps/lemon/demo/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -INCLUDE_DIRECTORIES( - ${PROJECT_SOURCE_DIR} - ${PROJECT_BINARY_DIR} -) - -LINK_DIRECTORIES( - ${PROJECT_BINARY_DIR}/lemon -) - -SET(DEMOS - arg_parser_demo - graph_to_eps_demo - lgf_demo -) - -FOREACH(DEMO_NAME ${DEMOS}) - ADD_EXECUTABLE(${DEMO_NAME} ${DEMO_NAME}.cc) - TARGET_LINK_LIBRARIES(${DEMO_NAME} lemon) -ENDFOREACH() diff --git a/deps/lemon/demo/arg_parser_demo.cc b/deps/lemon/demo/arg_parser_demo.cc deleted file mode 100644 index 1bafac0c8..000000000 --- a/deps/lemon/demo/arg_parser_demo.cc +++ /dev/null @@ -1,112 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2010 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\ingroup demos -///\file -///\brief Argument parser demo -/// -/// This example shows how the argument parser can be used. -/// -/// \include arg_parser_demo.cc - -#include - -using namespace lemon; -int main(int argc, char **argv) -{ - // Initialize the argument parser - ArgParser ap(argc, argv); - int i; - std::string s; - double d = 1.0; - bool b, nh; - bool g1, g2, g3; - - // Add a mandatory integer option with storage reference - ap.refOption("n", "An integer input.", i, true); - // Add a double option with storage reference (the default value is 1.0) - ap.refOption("val", "A double input.", d); - // Add a double option without storage reference (the default value is 3.14) - ap.doubleOption("val2", "A double input.", 3.14); - // Set synonym for -val option - ap.synonym("vals", "val"); - // Add a string option - ap.refOption("name", "A string input.", s); - // Add bool options - ap.refOption("f", "A switch.", b) - .refOption("nohelp", "", nh) - .refOption("gra", "Choice A", g1) - .refOption("grb", "Choice B", g2) - .refOption("grc", "Choice C", g3); - // Bundle -gr* options into a group - ap.optionGroup("gr", "gra") - .optionGroup("gr", "grb") - .optionGroup("gr", "grc"); - // Set the group mandatory - ap.mandatoryGroup("gr"); - // Set the options of the group exclusive (only one option can be given) - ap.onlyOneGroup("gr"); - // Add non-parsed arguments (e.g. input files) - ap.other("infile", "The input file.") - .other("..."); - - // Throw an exception when problems occurs. The default behavior is to - // exit(1) on these cases, but this makes Valgrind falsely warn - // about memory leaks. - ap.throwOnProblems(); - - // Perform the parsing process - // (in case of any error it terminates the program) - // The try {} construct is necessary only if the ap.trowOnProblems() - // setting is in use. - try { - ap.parse(); - } catch (ArgParserException &) { return 1; } - - // Check each option if it has been given and print its value - std::cout << "Parameters of '" << ap.commandName() << "':\n"; - - std::cout << " Value of -n: " << i << std::endl; - if(ap.given("val")) std::cout << " Value of -val: " << d << std::endl; - if(ap.given("val2")) { - d = ap["val2"]; - std::cout << " Value of -val2: " << d << std::endl; - } - if(ap.given("name")) std::cout << " Value of -name: " << s << std::endl; - if(ap.given("f")) std::cout << " -f is given\n"; - if(ap.given("nohelp")) std::cout << " Value of -nohelp: " << nh << std::endl; - if(ap.given("gra")) std::cout << " -gra is given\n"; - if(ap.given("grb")) std::cout << " -grb is given\n"; - if(ap.given("grc")) std::cout << " -grc is given\n"; - - switch(ap.files().size()) { - case 0: - std::cout << " No file argument was given.\n"; - break; - case 1: - std::cout << " 1 file argument was given. It is:\n"; - break; - default: - std::cout << " " - << ap.files().size() << " file arguments were given. They are:\n"; - } - for(unsigned int i=0;i.eps files demonstrating the capability of \ref -/// graphToEps(), and showing how to draw directed graphs, -/// how to handle parallel egdes, how to change the properties (like -/// color, shape, size, title etc.) of nodes and arcs individually -/// using appropriate graph maps. -/// -/// \include graph_to_eps_demo.cc - -#include -#include -#include - -using namespace std; -using namespace lemon; - -int main() -{ - Palette palette; - Palette paletteW(true); - - // Create a small digraph - ListDigraph g; - typedef ListDigraph::Node Node; - typedef ListDigraph::NodeIt NodeIt; - typedef ListDigraph::Arc Arc; - typedef dim2::Point Point; - - Node n1=g.addNode(); - Node n2=g.addNode(); - Node n3=g.addNode(); - Node n4=g.addNode(); - Node n5=g.addNode(); - - ListDigraph::NodeMap coords(g); - ListDigraph::NodeMap sizes(g); - ListDigraph::NodeMap colors(g); - ListDigraph::NodeMap shapes(g); - ListDigraph::ArcMap acolors(g); - ListDigraph::ArcMap widths(g); - - coords[n1]=Point(50,50); sizes[n1]=1; colors[n1]=1; shapes[n1]=0; - coords[n2]=Point(50,70); sizes[n2]=2; colors[n2]=2; shapes[n2]=2; - coords[n3]=Point(70,70); sizes[n3]=1; colors[n3]=3; shapes[n3]=0; - coords[n4]=Point(70,50); sizes[n4]=2; colors[n4]=4; shapes[n4]=1; - coords[n5]=Point(85,60); sizes[n5]=3; colors[n5]=5; shapes[n5]=2; - - Arc a; - - a=g.addArc(n1,n2); acolors[a]=0; widths[a]=1; - a=g.addArc(n2,n3); acolors[a]=0; widths[a]=1; - a=g.addArc(n3,n5); acolors[a]=0; widths[a]=3; - a=g.addArc(n5,n4); acolors[a]=0; widths[a]=1; - a=g.addArc(n4,n1); acolors[a]=0; widths[a]=1; - a=g.addArc(n2,n4); acolors[a]=1; widths[a]=2; - a=g.addArc(n3,n4); acolors[a]=2; widths[a]=1; - - IdMap id(g); - - // Create .eps files showing the digraph with different options - cout << "Create 'graph_to_eps_demo_out_1_pure.eps'" << endl; - graphToEps(g,"graph_to_eps_demo_out_1_pure.eps"). - coords(coords). - title("Sample .eps figure"). - copyright("(C) 2003-2009 LEMON Project"). - run(); - - cout << "Create 'graph_to_eps_demo_out_2.eps'" << endl; - graphToEps(g,"graph_to_eps_demo_out_2.eps"). - coords(coords). - title("Sample .eps figure"). - copyright("(C) 2003-2009 LEMON Project"). - absoluteNodeSizes().absoluteArcWidths(). - nodeScale(2).nodeSizes(sizes). - nodeShapes(shapes). - nodeColors(composeMap(palette,colors)). - arcColors(composeMap(palette,acolors)). - arcWidthScale(.4).arcWidths(widths). - nodeTexts(id).nodeTextSize(3). - run(); - - cout << "Create 'graph_to_eps_demo_out_3_arr.eps'" << endl; - graphToEps(g,"graph_to_eps_demo_out_3_arr.eps"). - title("Sample .eps figure (with arrowheads)"). - copyright("(C) 2003-2009 LEMON Project"). - absoluteNodeSizes().absoluteArcWidths(). - nodeColors(composeMap(palette,colors)). - coords(coords). - nodeScale(2).nodeSizes(sizes). - nodeShapes(shapes). - arcColors(composeMap(palette,acolors)). - arcWidthScale(.4).arcWidths(widths). - nodeTexts(id).nodeTextSize(3). - drawArrows().arrowWidth(2).arrowLength(2). - run(); - - // Add more arcs to the digraph - a=g.addArc(n1,n4); acolors[a]=2; widths[a]=1; - a=g.addArc(n4,n1); acolors[a]=1; widths[a]=2; - - a=g.addArc(n1,n2); acolors[a]=1; widths[a]=1; - a=g.addArc(n1,n2); acolors[a]=2; widths[a]=1; - a=g.addArc(n1,n2); acolors[a]=3; widths[a]=1; - a=g.addArc(n1,n2); acolors[a]=4; widths[a]=1; - a=g.addArc(n1,n2); acolors[a]=5; widths[a]=1; - a=g.addArc(n1,n2); acolors[a]=6; widths[a]=1; - a=g.addArc(n1,n2); acolors[a]=7; widths[a]=1; - - cout << "Create 'graph_to_eps_demo_out_4_par.eps'" << endl; - graphToEps(g,"graph_to_eps_demo_out_4_par.eps"). - title("Sample .eps figure (parallel arcs)"). - copyright("(C) 2003-2009 LEMON Project"). - absoluteNodeSizes().absoluteArcWidths(). - nodeShapes(shapes). - coords(coords). - nodeScale(2).nodeSizes(sizes). - nodeColors(composeMap(palette,colors)). - arcColors(composeMap(palette,acolors)). - arcWidthScale(.4).arcWidths(widths). - nodeTexts(id).nodeTextSize(3). - enableParallel().parArcDist(1.5). - run(); - - cout << "Create 'graph_to_eps_demo_out_5_par_arr.eps'" << endl; - graphToEps(g,"graph_to_eps_demo_out_5_par_arr.eps"). - title("Sample .eps figure (parallel arcs and arrowheads)"). - copyright("(C) 2003-2009 LEMON Project"). - absoluteNodeSizes().absoluteArcWidths(). - nodeScale(2).nodeSizes(sizes). - coords(coords). - nodeShapes(shapes). - nodeColors(composeMap(palette,colors)). - arcColors(composeMap(palette,acolors)). - arcWidthScale(.3).arcWidths(widths). - nodeTexts(id).nodeTextSize(3). - enableParallel().parArcDist(1). - drawArrows().arrowWidth(1).arrowLength(1). - run(); - - cout << "Create 'graph_to_eps_demo_out_6_par_arr_a4.eps'" << endl; - graphToEps(g,"graph_to_eps_demo_out_6_par_arr_a4.eps"). - title("Sample .eps figure (fits to A4)"). - copyright("(C) 2003-2009 LEMON Project"). - scaleToA4(). - absoluteNodeSizes().absoluteArcWidths(). - nodeScale(2).nodeSizes(sizes). - coords(coords). - nodeShapes(shapes). - nodeColors(composeMap(palette,colors)). - arcColors(composeMap(palette,acolors)). - arcWidthScale(.3).arcWidths(widths). - nodeTexts(id).nodeTextSize(3). - enableParallel().parArcDist(1). - drawArrows().arrowWidth(1).arrowLength(1). - run(); - - // Create an .eps file showing the colors of a default Palette - ListDigraph h; - ListDigraph::NodeMap hcolors(h); - ListDigraph::NodeMap hcoords(h); - - int cols=int(std::sqrt(double(palette.size()))); - for(int i=0;i -#include -#include -#include - -using namespace lemon; - -int main() { - SmartDigraph g; - SmartDigraph::ArcMap cap(g); - SmartDigraph::Node s, t; - - try { - digraphReader(g, "digraph.lgf"). // read the directed graph into g - arcMap("capacity", cap). // read the 'capacity' arc map into cap - node("source", s). // read 'source' node to s - node("target", t). // read 'target' node to t - run(); - } catch (Exception& error) { // check if there was any error - std::cerr << "Error: " << error.what() << std::endl; - return -1; - } - - std::cout << "A digraph is read from 'digraph.lgf'." << std::endl; - std::cout << "Number of nodes: " << countNodes(g) << std::endl; - std::cout << "Number of arcs: " << countArcs(g) << std::endl; - - std::cout << "We can write it to the standard output:" << std::endl; - - digraphWriter(g). // write g to the standard output - arcMap("capacity", cap). // write cap into 'capacity' - node("source", s). // write s to 'source' - node("target", t). // write t to 'target' - run(); - - return 0; -} diff --git a/deps/lemon/lemon/CMakeLists.txt b/deps/lemon/lemon/CMakeLists.txt deleted file mode 100644 index f7b90536a..000000000 --- a/deps/lemon/lemon/CMakeLists.txt +++ /dev/null @@ -1,95 +0,0 @@ -INCLUDE_DIRECTORIES( - ${PROJECT_SOURCE_DIR} - ${PROJECT_BINARY_DIR} -) - -CONFIGURE_FILE( - ${CMAKE_CURRENT_SOURCE_DIR}/config.h.in - ${CMAKE_CURRENT_BINARY_DIR}/config.h -) - -CONFIGURE_FILE( - ${CMAKE_CURRENT_SOURCE_DIR}/lemon.pc.in - ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc - @ONLY -) - -SET(LEMON_SOURCES - arg_parser.cc - base.cc - color.cc - lp_base.cc - lp_skeleton.cc - random.cc - bits/windows.cc -) - -IF(LEMON_HAVE_GLPK) - SET(LEMON_SOURCES ${LEMON_SOURCES} glpk.cc) - INCLUDE_DIRECTORIES(${GLPK_INCLUDE_DIRS}) - IF(WIN32 AND NOT DEFINED WITHOUT_GLPK_INSTALL) - INSTALL(FILES ${GLPK_BIN_DIR}/glpk.dll DESTINATION bin) - INSTALL(FILES ${GLPK_BIN_DIR}/libltdl3.dll DESTINATION bin) - INSTALL(FILES ${GLPK_BIN_DIR}/zlib1.dll DESTINATION bin) - ENDIF() -ENDIF() - -IF(LEMON_HAVE_CPLEX) - SET(LEMON_SOURCES ${LEMON_SOURCES} cplex.cc) - INCLUDE_DIRECTORIES(${ILOG_INCLUDE_DIRS}) -ENDIF() - -IF(LEMON_HAVE_CLP) - SET(LEMON_SOURCES ${LEMON_SOURCES} clp.cc) - INCLUDE_DIRECTORIES(${COIN_INCLUDE_DIRS}) -ENDIF() - -IF(LEMON_HAVE_CBC) - SET(LEMON_SOURCES ${LEMON_SOURCES} cbc.cc) - INCLUDE_DIRECTORIES(${COIN_INCLUDE_DIRS}) -ENDIF() - -IF(LEMON_HAVE_SOPLEX) - SET(LEMON_SOURCES ${LEMON_SOURCES} soplex.cc) - INCLUDE_DIRECTORIES(${SOPLEX_INCLUDE_DIRS}) -ENDIF() - -ADD_LIBRARY(lemon ${LEMON_SOURCES}) - -TARGET_COMPILE_DEFINITIONS(lemon PRIVATE BUILDING_LEMON) - -TARGET_LINK_LIBRARIES(lemon - ${GLPK_LIBRARIES} ${COIN_LIBRARIES} ${ILOG_LIBRARIES} ${SOPLEX_LIBRARIES} - ) - -IF(UNIX) - SET_TARGET_PROPERTIES(lemon PROPERTIES OUTPUT_NAME emon VERSION ${LEMON_VERSION} SOVERSION ${LEMON_VERSION}) -ENDIF() - -INCLUDE(GNUInstallDirs) - -INSTALL( - TARGETS lemon - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" - LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" - COMPONENT library -) - -INSTALL( - DIRECTORY . bits concepts - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/lemon" - COMPONENT headers - FILES_MATCHING PATTERN "*.h" -) - -INSTALL( - FILES ${CMAKE_CURRENT_BINARY_DIR}/config.h - DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/lemon" - COMPONENT headers -) - -INSTALL( - FILES ${CMAKE_CURRENT_BINARY_DIR}/lemon.pc - DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig" -) - diff --git a/deps/lemon/lemon/adaptors.h b/deps/lemon/lemon/adaptors.h deleted file mode 100644 index 1a40f8ea2..000000000 --- a/deps/lemon/lemon/adaptors.h +++ /dev/null @@ -1,3638 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_ADAPTORS_H -#define LEMON_ADAPTORS_H - -/// \ingroup graph_adaptors -/// \file -/// \brief Adaptor classes for digraphs and graphs -/// -/// This file contains several useful adaptors for digraphs and graphs. - -#include -#include -#include - -#include -#include -#include - -#include - -namespace lemon { - -#ifdef _MSC_VER -#define LEMON_SCOPE_FIX(OUTER, NESTED) OUTER::NESTED -#else -#define LEMON_SCOPE_FIX(OUTER, NESTED) typename OUTER::template NESTED -#endif - - template - class DigraphAdaptorBase { - public: - typedef DGR Digraph; - typedef DigraphAdaptorBase Adaptor; - - protected: - DGR* _digraph; - DigraphAdaptorBase() : _digraph(0) { } - void initialize(DGR& digraph) { _digraph = &digraph; } - - public: - DigraphAdaptorBase(DGR& digraph) : _digraph(&digraph) { } - - typedef typename DGR::Node Node; - typedef typename DGR::Arc Arc; - - void first(Node& i) const { _digraph->first(i); } - void first(Arc& i) const { _digraph->first(i); } - void firstIn(Arc& i, const Node& n) const { _digraph->firstIn(i, n); } - void firstOut(Arc& i, const Node& n ) const { _digraph->firstOut(i, n); } - - void next(Node& i) const { _digraph->next(i); } - void next(Arc& i) const { _digraph->next(i); } - void nextIn(Arc& i) const { _digraph->nextIn(i); } - void nextOut(Arc& i) const { _digraph->nextOut(i); } - - Node source(const Arc& a) const { return _digraph->source(a); } - Node target(const Arc& a) const { return _digraph->target(a); } - - typedef NodeNumTagIndicator NodeNumTag; - int nodeNum() const { return _digraph->nodeNum(); } - - typedef ArcNumTagIndicator ArcNumTag; - int arcNum() const { return _digraph->arcNum(); } - - typedef FindArcTagIndicator FindArcTag; - Arc findArc(const Node& u, const Node& v, const Arc& prev = INVALID) const { - return _digraph->findArc(u, v, prev); - } - - Node addNode() { return _digraph->addNode(); } - Arc addArc(const Node& u, const Node& v) { return _digraph->addArc(u, v); } - - void erase(const Node& n) { _digraph->erase(n); } - void erase(const Arc& a) { _digraph->erase(a); } - - void clear() { _digraph->clear(); } - - int id(const Node& n) const { return _digraph->id(n); } - int id(const Arc& a) const { return _digraph->id(a); } - - Node nodeFromId(int ix) const { return _digraph->nodeFromId(ix); } - Arc arcFromId(int ix) const { return _digraph->arcFromId(ix); } - - int maxNodeId() const { return _digraph->maxNodeId(); } - int maxArcId() const { return _digraph->maxArcId(); } - - typedef typename ItemSetTraits::ItemNotifier NodeNotifier; - NodeNotifier& notifier(Node) const { return _digraph->notifier(Node()); } - - typedef typename ItemSetTraits::ItemNotifier ArcNotifier; - ArcNotifier& notifier(Arc) const { return _digraph->notifier(Arc()); } - - template - class NodeMap : public DGR::template NodeMap { - typedef typename DGR::template NodeMap Parent; - - public: - explicit NodeMap(const Adaptor& adaptor) - : Parent(*adaptor._digraph) {} - NodeMap(const Adaptor& adaptor, const V& value) - : Parent(*adaptor._digraph, value) { } - - private: - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - template - class ArcMap : public DGR::template ArcMap { - typedef typename DGR::template ArcMap Parent; - - public: - explicit ArcMap(const DigraphAdaptorBase& adaptor) - : Parent(*adaptor._digraph) {} - ArcMap(const DigraphAdaptorBase& adaptor, const V& value) - : Parent(*adaptor._digraph, value) {} - - private: - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - }; - - template - class GraphAdaptorBase { - public: - typedef GR Graph; - - protected: - GR* _graph; - - GraphAdaptorBase() : _graph(0) {} - - void initialize(GR& graph) { _graph = &graph; } - - public: - GraphAdaptorBase(GR& graph) : _graph(&graph) {} - - typedef typename GR::Node Node; - typedef typename GR::Arc Arc; - typedef typename GR::Edge Edge; - - void first(Node& i) const { _graph->first(i); } - void first(Arc& i) const { _graph->first(i); } - void first(Edge& i) const { _graph->first(i); } - void firstIn(Arc& i, const Node& n) const { _graph->firstIn(i, n); } - void firstOut(Arc& i, const Node& n ) const { _graph->firstOut(i, n); } - void firstInc(Edge &i, bool &d, const Node &n) const { - _graph->firstInc(i, d, n); - } - - void next(Node& i) const { _graph->next(i); } - void next(Arc& i) const { _graph->next(i); } - void next(Edge& i) const { _graph->next(i); } - void nextIn(Arc& i) const { _graph->nextIn(i); } - void nextOut(Arc& i) const { _graph->nextOut(i); } - void nextInc(Edge &i, bool &d) const { _graph->nextInc(i, d); } - - Node u(const Edge& e) const { return _graph->u(e); } - Node v(const Edge& e) const { return _graph->v(e); } - - Node source(const Arc& a) const { return _graph->source(a); } - Node target(const Arc& a) const { return _graph->target(a); } - - typedef NodeNumTagIndicator NodeNumTag; - int nodeNum() const { return _graph->nodeNum(); } - - typedef ArcNumTagIndicator ArcNumTag; - int arcNum() const { return _graph->arcNum(); } - - typedef EdgeNumTagIndicator EdgeNumTag; - int edgeNum() const { return _graph->edgeNum(); } - - typedef FindArcTagIndicator FindArcTag; - Arc findArc(const Node& u, const Node& v, - const Arc& prev = INVALID) const { - return _graph->findArc(u, v, prev); - } - - typedef FindEdgeTagIndicator FindEdgeTag; - Edge findEdge(const Node& u, const Node& v, - const Edge& prev = INVALID) const { - return _graph->findEdge(u, v, prev); - } - - Node addNode() { return _graph->addNode(); } - Edge addEdge(const Node& u, const Node& v) { return _graph->addEdge(u, v); } - - void erase(const Node& i) { _graph->erase(i); } - void erase(const Edge& i) { _graph->erase(i); } - - void clear() { _graph->clear(); } - - bool direction(const Arc& a) const { return _graph->direction(a); } - Arc direct(const Edge& e, bool d) const { return _graph->direct(e, d); } - - int id(const Node& v) const { return _graph->id(v); } - int id(const Arc& a) const { return _graph->id(a); } - int id(const Edge& e) const { return _graph->id(e); } - - Node nodeFromId(int ix) const { return _graph->nodeFromId(ix); } - Arc arcFromId(int ix) const { return _graph->arcFromId(ix); } - Edge edgeFromId(int ix) const { return _graph->edgeFromId(ix); } - - int maxNodeId() const { return _graph->maxNodeId(); } - int maxArcId() const { return _graph->maxArcId(); } - int maxEdgeId() const { return _graph->maxEdgeId(); } - - typedef typename ItemSetTraits::ItemNotifier NodeNotifier; - NodeNotifier& notifier(Node) const { return _graph->notifier(Node()); } - - typedef typename ItemSetTraits::ItemNotifier ArcNotifier; - ArcNotifier& notifier(Arc) const { return _graph->notifier(Arc()); } - - typedef typename ItemSetTraits::ItemNotifier EdgeNotifier; - EdgeNotifier& notifier(Edge) const { return _graph->notifier(Edge()); } - - template - class NodeMap : public GR::template NodeMap { - typedef typename GR::template NodeMap Parent; - - public: - explicit NodeMap(const GraphAdaptorBase& adapter) - : Parent(*adapter._graph) {} - NodeMap(const GraphAdaptorBase& adapter, const V& value) - : Parent(*adapter._graph, value) {} - - private: - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - template - class ArcMap : public GR::template ArcMap { - typedef typename GR::template ArcMap Parent; - - public: - explicit ArcMap(const GraphAdaptorBase& adapter) - : Parent(*adapter._graph) {} - ArcMap(const GraphAdaptorBase& adapter, const V& value) - : Parent(*adapter._graph, value) {} - - private: - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - template - class EdgeMap : public GR::template EdgeMap { - typedef typename GR::template EdgeMap Parent; - - public: - explicit EdgeMap(const GraphAdaptorBase& adapter) - : Parent(*adapter._graph) {} - EdgeMap(const GraphAdaptorBase& adapter, const V& value) - : Parent(*adapter._graph, value) {} - - private: - EdgeMap& operator=(const EdgeMap& cmap) { - return operator=(cmap); - } - - template - EdgeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - }; - - template - class ReverseDigraphBase : public DigraphAdaptorBase { - typedef DigraphAdaptorBase Parent; - public: - typedef DGR Digraph; - protected: - ReverseDigraphBase() : Parent() { } - public: - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - - void firstIn(Arc& a, const Node& n) const { Parent::firstOut(a, n); } - void firstOut(Arc& a, const Node& n ) const { Parent::firstIn(a, n); } - - void nextIn(Arc& a) const { Parent::nextOut(a); } - void nextOut(Arc& a) const { Parent::nextIn(a); } - - Node source(const Arc& a) const { return Parent::target(a); } - Node target(const Arc& a) const { return Parent::source(a); } - - Arc addArc(const Node& u, const Node& v) { return Parent::addArc(v, u); } - - typedef FindArcTagIndicator FindArcTag; - Arc findArc(const Node& u, const Node& v, - const Arc& prev = INVALID) const { - return Parent::findArc(v, u, prev); - } - - }; - - /// \ingroup graph_adaptors - /// - /// \brief Adaptor class for reversing the orientation of the arcs in - /// a digraph. - /// - /// ReverseDigraph can be used for reversing the arcs in a digraph. - /// It conforms to the \ref concepts::Digraph "Digraph" concept. - /// - /// The adapted digraph can also be modified through this adaptor - /// by adding or removing nodes or arcs, unless the \c GR template - /// parameter is set to be \c const. - /// - /// This class provides item counting in the same time as the adapted - /// digraph structure. - /// - /// \tparam DGR The type of the adapted digraph. - /// It must conform to the \ref concepts::Digraph "Digraph" concept. - /// It can also be specified to be \c const. - /// - /// \note The \c Node and \c Arc types of this adaptor and the adapted - /// digraph are convertible to each other. - template -#ifdef DOXYGEN - class ReverseDigraph { -#else - class ReverseDigraph : - public DigraphAdaptorExtender > { -#endif - typedef DigraphAdaptorExtender > Parent; - public: - /// The type of the adapted digraph. - typedef DGR Digraph; - protected: - ReverseDigraph() { } - public: - - /// \brief Constructor - /// - /// Creates a reverse digraph adaptor for the given digraph. - explicit ReverseDigraph(DGR& digraph) { - Parent::initialize(digraph); - } - }; - - /// \brief Returns a read-only ReverseDigraph adaptor - /// - /// This function just returns a read-only \ref ReverseDigraph adaptor. - /// \ingroup graph_adaptors - /// \relates ReverseDigraph - template - ReverseDigraph reverseDigraph(const DGR& digraph) { - return ReverseDigraph(digraph); - } - - - template - class SubDigraphBase : public DigraphAdaptorBase { - typedef DigraphAdaptorBase Parent; - public: - typedef DGR Digraph; - typedef NF NodeFilterMap; - typedef AF ArcFilterMap; - - typedef SubDigraphBase Adaptor; - protected: - NF* _node_filter; - AF* _arc_filter; - SubDigraphBase() - : Parent(), _node_filter(0), _arc_filter(0) { } - - void initialize(DGR& digraph, NF& node_filter, AF& arc_filter) { - Parent::initialize(digraph); - _node_filter = &node_filter; - _arc_filter = &arc_filter; - } - - public: - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - - void first(Node& i) const { - Parent::first(i); - while (i != INVALID && !(*_node_filter)[i]) Parent::next(i); - } - - void first(Arc& i) const { - Parent::first(i); - while (i != INVALID && (!(*_arc_filter)[i] - || !(*_node_filter)[Parent::source(i)] - || !(*_node_filter)[Parent::target(i)])) - Parent::next(i); - } - - void firstIn(Arc& i, const Node& n) const { - Parent::firstIn(i, n); - while (i != INVALID && (!(*_arc_filter)[i] - || !(*_node_filter)[Parent::source(i)])) - Parent::nextIn(i); - } - - void firstOut(Arc& i, const Node& n) const { - Parent::firstOut(i, n); - while (i != INVALID && (!(*_arc_filter)[i] - || !(*_node_filter)[Parent::target(i)])) - Parent::nextOut(i); - } - - void next(Node& i) const { - Parent::next(i); - while (i != INVALID && !(*_node_filter)[i]) Parent::next(i); - } - - void next(Arc& i) const { - Parent::next(i); - while (i != INVALID && (!(*_arc_filter)[i] - || !(*_node_filter)[Parent::source(i)] - || !(*_node_filter)[Parent::target(i)])) - Parent::next(i); - } - - void nextIn(Arc& i) const { - Parent::nextIn(i); - while (i != INVALID && (!(*_arc_filter)[i] - || !(*_node_filter)[Parent::source(i)])) - Parent::nextIn(i); - } - - void nextOut(Arc& i) const { - Parent::nextOut(i); - while (i != INVALID && (!(*_arc_filter)[i] - || !(*_node_filter)[Parent::target(i)])) - Parent::nextOut(i); - } - - void status(const Node& n, bool v) const { _node_filter->set(n, v); } - void status(const Arc& a, bool v) const { _arc_filter->set(a, v); } - - bool status(const Node& n) const { return (*_node_filter)[n]; } - bool status(const Arc& a) const { return (*_arc_filter)[a]; } - - typedef False NodeNumTag; - typedef False ArcNumTag; - - typedef FindArcTagIndicator FindArcTag; - Arc findArc(const Node& source, const Node& target, - const Arc& prev = INVALID) const { - if (!(*_node_filter)[source] || !(*_node_filter)[target]) { - return INVALID; - } - Arc arc = Parent::findArc(source, target, prev); - while (arc != INVALID && !(*_arc_filter)[arc]) { - arc = Parent::findArc(source, target, arc); - } - return arc; - } - - public: - - template - class NodeMap - : public SubMapExtender, - LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> { - typedef SubMapExtender, - LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> Parent; - - public: - typedef V Value; - - NodeMap(const SubDigraphBase& adaptor) - : Parent(adaptor) {} - NodeMap(const SubDigraphBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - template - class ArcMap - : public SubMapExtender, - LEMON_SCOPE_FIX(DigraphAdaptorBase, ArcMap)> { - typedef SubMapExtender, - LEMON_SCOPE_FIX(DigraphAdaptorBase, ArcMap)> Parent; - - public: - typedef V Value; - - ArcMap(const SubDigraphBase& adaptor) - : Parent(adaptor) {} - ArcMap(const SubDigraphBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - }; - - template - class SubDigraphBase - : public DigraphAdaptorBase { - typedef DigraphAdaptorBase Parent; - public: - typedef DGR Digraph; - typedef NF NodeFilterMap; - typedef AF ArcFilterMap; - - typedef SubDigraphBase Adaptor; - protected: - NF* _node_filter; - AF* _arc_filter; - SubDigraphBase() - : Parent(), _node_filter(0), _arc_filter(0) { } - - void initialize(DGR& digraph, NF& node_filter, AF& arc_filter) { - Parent::initialize(digraph); - _node_filter = &node_filter; - _arc_filter = &arc_filter; - } - - public: - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - - void first(Node& i) const { - Parent::first(i); - while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i); - } - - void first(Arc& i) const { - Parent::first(i); - while (i!=INVALID && !(*_arc_filter)[i]) Parent::next(i); - } - - void firstIn(Arc& i, const Node& n) const { - Parent::firstIn(i, n); - while (i!=INVALID && !(*_arc_filter)[i]) Parent::nextIn(i); - } - - void firstOut(Arc& i, const Node& n) const { - Parent::firstOut(i, n); - while (i!=INVALID && !(*_arc_filter)[i]) Parent::nextOut(i); - } - - void next(Node& i) const { - Parent::next(i); - while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i); - } - void next(Arc& i) const { - Parent::next(i); - while (i!=INVALID && !(*_arc_filter)[i]) Parent::next(i); - } - void nextIn(Arc& i) const { - Parent::nextIn(i); - while (i!=INVALID && !(*_arc_filter)[i]) Parent::nextIn(i); - } - - void nextOut(Arc& i) const { - Parent::nextOut(i); - while (i!=INVALID && !(*_arc_filter)[i]) Parent::nextOut(i); - } - - void status(const Node& n, bool v) const { _node_filter->set(n, v); } - void status(const Arc& a, bool v) const { _arc_filter->set(a, v); } - - bool status(const Node& n) const { return (*_node_filter)[n]; } - bool status(const Arc& a) const { return (*_arc_filter)[a]; } - - typedef False NodeNumTag; - typedef False ArcNumTag; - - typedef FindArcTagIndicator FindArcTag; - Arc findArc(const Node& source, const Node& target, - const Arc& prev = INVALID) const { - if (!(*_node_filter)[source] || !(*_node_filter)[target]) { - return INVALID; - } - Arc arc = Parent::findArc(source, target, prev); - while (arc != INVALID && !(*_arc_filter)[arc]) { - arc = Parent::findArc(source, target, arc); - } - return arc; - } - - template - class NodeMap - : public SubMapExtender, - LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> { - typedef SubMapExtender, - LEMON_SCOPE_FIX(DigraphAdaptorBase, NodeMap)> Parent; - - public: - typedef V Value; - - NodeMap(const SubDigraphBase& adaptor) - : Parent(adaptor) {} - NodeMap(const SubDigraphBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - template - class ArcMap - : public SubMapExtender, - LEMON_SCOPE_FIX(DigraphAdaptorBase, ArcMap)> { - typedef SubMapExtender, - LEMON_SCOPE_FIX(DigraphAdaptorBase, ArcMap)> Parent; - - public: - typedef V Value; - - ArcMap(const SubDigraphBase& adaptor) - : Parent(adaptor) {} - ArcMap(const SubDigraphBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - }; - - /// \ingroup graph_adaptors - /// - /// \brief Adaptor class for hiding nodes and arcs in a digraph - /// - /// SubDigraph can be used for hiding nodes and arcs in a digraph. - /// A \c bool node map and a \c bool arc map must be specified, which - /// define the filters for nodes and arcs. - /// Only the nodes and arcs with \c true filter value are - /// shown in the subdigraph. The arcs that are incident to hidden - /// nodes are also filtered out. - /// This adaptor conforms to the \ref concepts::Digraph "Digraph" concept. - /// - /// The adapted digraph can also be modified through this adaptor - /// by adding or removing nodes or arcs, unless the \c GR template - /// parameter is set to be \c const. - /// - /// This class provides only linear time counting for nodes and arcs. - /// - /// \tparam DGR The type of the adapted digraph. - /// It must conform to the \ref concepts::Digraph "Digraph" concept. - /// It can also be specified to be \c const. - /// \tparam NF The type of the node filter map. - /// It must be a \c bool (or convertible) node map of the - /// adapted digraph. The default type is - /// \ref concepts::Digraph::NodeMap "DGR::NodeMap". - /// \tparam AF The type of the arc filter map. - /// It must be \c bool (or convertible) arc map of the - /// adapted digraph. The default type is - /// \ref concepts::Digraph::ArcMap "DGR::ArcMap". - /// - /// \note The \c Node and \c Arc types of this adaptor and the adapted - /// digraph are convertible to each other. - /// - /// \see FilterNodes - /// \see FilterArcs -#ifdef DOXYGEN - template - class SubDigraph { -#else - template, - typename AF = typename DGR::template ArcMap > - class SubDigraph : - public DigraphAdaptorExtender > { -#endif - public: - /// The type of the adapted digraph. - typedef DGR Digraph; - /// The type of the node filter map. - typedef NF NodeFilterMap; - /// The type of the arc filter map. - typedef AF ArcFilterMap; - - typedef DigraphAdaptorExtender > - Parent; - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - - protected: - SubDigraph() { } - public: - - /// \brief Constructor - /// - /// Creates a subdigraph for the given digraph with the - /// given node and arc filter maps. - SubDigraph(DGR& digraph, NF& node_filter, AF& arc_filter) { - Parent::initialize(digraph, node_filter, arc_filter); - } - - /// \brief Sets the status of the given node - /// - /// This function sets the status of the given node. - /// It is done by simply setting the assigned value of \c n - /// to \c v in the node filter map. - void status(const Node& n, bool v) const { Parent::status(n, v); } - - /// \brief Sets the status of the given arc - /// - /// This function sets the status of the given arc. - /// It is done by simply setting the assigned value of \c a - /// to \c v in the arc filter map. - void status(const Arc& a, bool v) const { Parent::status(a, v); } - - /// \brief Returns the status of the given node - /// - /// This function returns the status of the given node. - /// It is \c true if the given node is enabled (i.e. not hidden). - bool status(const Node& n) const { return Parent::status(n); } - - /// \brief Returns the status of the given arc - /// - /// This function returns the status of the given arc. - /// It is \c true if the given arc is enabled (i.e. not hidden). - bool status(const Arc& a) const { return Parent::status(a); } - - /// \brief Disables the given node - /// - /// This function disables the given node in the subdigraph, - /// so the iteration jumps over it. - /// It is the same as \ref status() "status(n, false)". - void disable(const Node& n) const { Parent::status(n, false); } - - /// \brief Disables the given arc - /// - /// This function disables the given arc in the subdigraph, - /// so the iteration jumps over it. - /// It is the same as \ref status() "status(a, false)". - void disable(const Arc& a) const { Parent::status(a, false); } - - /// \brief Enables the given node - /// - /// This function enables the given node in the subdigraph. - /// It is the same as \ref status() "status(n, true)". - void enable(const Node& n) const { Parent::status(n, true); } - - /// \brief Enables the given arc - /// - /// This function enables the given arc in the subdigraph. - /// It is the same as \ref status() "status(a, true)". - void enable(const Arc& a) const { Parent::status(a, true); } - - }; - - /// \brief Returns a read-only SubDigraph adaptor - /// - /// This function just returns a read-only \ref SubDigraph adaptor. - /// \ingroup graph_adaptors - /// \relates SubDigraph - template - SubDigraph - subDigraph(const DGR& digraph, - NF& node_filter, AF& arc_filter) { - return SubDigraph - (digraph, node_filter, arc_filter); - } - - template - SubDigraph - subDigraph(const DGR& digraph, - const NF& node_filter, AF& arc_filter) { - return SubDigraph - (digraph, node_filter, arc_filter); - } - - template - SubDigraph - subDigraph(const DGR& digraph, - NF& node_filter, const AF& arc_filter) { - return SubDigraph - (digraph, node_filter, arc_filter); - } - - template - SubDigraph - subDigraph(const DGR& digraph, - const NF& node_filter, const AF& arc_filter) { - return SubDigraph - (digraph, node_filter, arc_filter); - } - - - template - class SubGraphBase : public GraphAdaptorBase { - typedef GraphAdaptorBase Parent; - public: - typedef GR Graph; - typedef NF NodeFilterMap; - typedef EF EdgeFilterMap; - - typedef SubGraphBase Adaptor; - protected: - - NF* _node_filter; - EF* _edge_filter; - - SubGraphBase() - : Parent(), _node_filter(0), _edge_filter(0) { } - - void initialize(GR& graph, NF& node_filter, EF& edge_filter) { - Parent::initialize(graph); - _node_filter = &node_filter; - _edge_filter = &edge_filter; - } - - public: - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - typedef typename Parent::Edge Edge; - - void first(Node& i) const { - Parent::first(i); - while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i); - } - - void first(Arc& i) const { - Parent::first(i); - while (i!=INVALID && (!(*_edge_filter)[i] - || !(*_node_filter)[Parent::source(i)] - || !(*_node_filter)[Parent::target(i)])) - Parent::next(i); - } - - void first(Edge& i) const { - Parent::first(i); - while (i!=INVALID && (!(*_edge_filter)[i] - || !(*_node_filter)[Parent::u(i)] - || !(*_node_filter)[Parent::v(i)])) - Parent::next(i); - } - - void firstIn(Arc& i, const Node& n) const { - Parent::firstIn(i, n); - while (i!=INVALID && (!(*_edge_filter)[i] - || !(*_node_filter)[Parent::source(i)])) - Parent::nextIn(i); - } - - void firstOut(Arc& i, const Node& n) const { - Parent::firstOut(i, n); - while (i!=INVALID && (!(*_edge_filter)[i] - || !(*_node_filter)[Parent::target(i)])) - Parent::nextOut(i); - } - - void firstInc(Edge& i, bool& d, const Node& n) const { - Parent::firstInc(i, d, n); - while (i!=INVALID && (!(*_edge_filter)[i] - || !(*_node_filter)[Parent::u(i)] - || !(*_node_filter)[Parent::v(i)])) - Parent::nextInc(i, d); - } - - void next(Node& i) const { - Parent::next(i); - while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i); - } - - void next(Arc& i) const { - Parent::next(i); - while (i!=INVALID && (!(*_edge_filter)[i] - || !(*_node_filter)[Parent::source(i)] - || !(*_node_filter)[Parent::target(i)])) - Parent::next(i); - } - - void next(Edge& i) const { - Parent::next(i); - while (i!=INVALID && (!(*_edge_filter)[i] - || !(*_node_filter)[Parent::u(i)] - || !(*_node_filter)[Parent::v(i)])) - Parent::next(i); - } - - void nextIn(Arc& i) const { - Parent::nextIn(i); - while (i!=INVALID && (!(*_edge_filter)[i] - || !(*_node_filter)[Parent::source(i)])) - Parent::nextIn(i); - } - - void nextOut(Arc& i) const { - Parent::nextOut(i); - while (i!=INVALID && (!(*_edge_filter)[i] - || !(*_node_filter)[Parent::target(i)])) - Parent::nextOut(i); - } - - void nextInc(Edge& i, bool& d) const { - Parent::nextInc(i, d); - while (i!=INVALID && (!(*_edge_filter)[i] - || !(*_node_filter)[Parent::u(i)] - || !(*_node_filter)[Parent::v(i)])) - Parent::nextInc(i, d); - } - - void status(const Node& n, bool v) const { _node_filter->set(n, v); } - void status(const Edge& e, bool v) const { _edge_filter->set(e, v); } - - bool status(const Node& n) const { return (*_node_filter)[n]; } - bool status(const Edge& e) const { return (*_edge_filter)[e]; } - - typedef False NodeNumTag; - typedef False ArcNumTag; - typedef False EdgeNumTag; - - typedef FindArcTagIndicator FindArcTag; - Arc findArc(const Node& u, const Node& v, - const Arc& prev = INVALID) const { - if (!(*_node_filter)[u] || !(*_node_filter)[v]) { - return INVALID; - } - Arc arc = Parent::findArc(u, v, prev); - while (arc != INVALID && !(*_edge_filter)[arc]) { - arc = Parent::findArc(u, v, arc); - } - return arc; - } - - typedef FindEdgeTagIndicator FindEdgeTag; - Edge findEdge(const Node& u, const Node& v, - const Edge& prev = INVALID) const { - if (!(*_node_filter)[u] || !(*_node_filter)[v]) { - return INVALID; - } - Edge edge = Parent::findEdge(u, v, prev); - while (edge != INVALID && !(*_edge_filter)[edge]) { - edge = Parent::findEdge(u, v, edge); - } - return edge; - } - - template - class NodeMap - : public SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, NodeMap)> { - typedef SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, NodeMap)> Parent; - - public: - typedef V Value; - - NodeMap(const SubGraphBase& adaptor) - : Parent(adaptor) {} - NodeMap(const SubGraphBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - template - class ArcMap - : public SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, ArcMap)> { - typedef SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, ArcMap)> Parent; - - public: - typedef V Value; - - ArcMap(const SubGraphBase& adaptor) - : Parent(adaptor) {} - ArcMap(const SubGraphBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - template - class EdgeMap - : public SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> { - typedef SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> Parent; - - public: - typedef V Value; - - EdgeMap(const SubGraphBase& adaptor) - : Parent(adaptor) {} - - EdgeMap(const SubGraphBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - EdgeMap& operator=(const EdgeMap& cmap) { - return operator=(cmap); - } - - template - EdgeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - }; - - template - class SubGraphBase - : public GraphAdaptorBase { - typedef GraphAdaptorBase Parent; - public: - typedef GR Graph; - typedef NF NodeFilterMap; - typedef EF EdgeFilterMap; - - typedef SubGraphBase Adaptor; - protected: - NF* _node_filter; - EF* _edge_filter; - SubGraphBase() - : Parent(), _node_filter(0), _edge_filter(0) { } - - void initialize(GR& graph, NF& node_filter, EF& edge_filter) { - Parent::initialize(graph); - _node_filter = &node_filter; - _edge_filter = &edge_filter; - } - - public: - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - typedef typename Parent::Edge Edge; - - void first(Node& i) const { - Parent::first(i); - while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i); - } - - void first(Arc& i) const { - Parent::first(i); - while (i!=INVALID && !(*_edge_filter)[i]) Parent::next(i); - } - - void first(Edge& i) const { - Parent::first(i); - while (i!=INVALID && !(*_edge_filter)[i]) Parent::next(i); - } - - void firstIn(Arc& i, const Node& n) const { - Parent::firstIn(i, n); - while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextIn(i); - } - - void firstOut(Arc& i, const Node& n) const { - Parent::firstOut(i, n); - while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextOut(i); - } - - void firstInc(Edge& i, bool& d, const Node& n) const { - Parent::firstInc(i, d, n); - while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextInc(i, d); - } - - void next(Node& i) const { - Parent::next(i); - while (i!=INVALID && !(*_node_filter)[i]) Parent::next(i); - } - void next(Arc& i) const { - Parent::next(i); - while (i!=INVALID && !(*_edge_filter)[i]) Parent::next(i); - } - void next(Edge& i) const { - Parent::next(i); - while (i!=INVALID && !(*_edge_filter)[i]) Parent::next(i); - } - void nextIn(Arc& i) const { - Parent::nextIn(i); - while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextIn(i); - } - - void nextOut(Arc& i) const { - Parent::nextOut(i); - while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextOut(i); - } - void nextInc(Edge& i, bool& d) const { - Parent::nextInc(i, d); - while (i!=INVALID && !(*_edge_filter)[i]) Parent::nextInc(i, d); - } - - void status(const Node& n, bool v) const { _node_filter->set(n, v); } - void status(const Edge& e, bool v) const { _edge_filter->set(e, v); } - - bool status(const Node& n) const { return (*_node_filter)[n]; } - bool status(const Edge& e) const { return (*_edge_filter)[e]; } - - typedef False NodeNumTag; - typedef False ArcNumTag; - typedef False EdgeNumTag; - - typedef FindArcTagIndicator FindArcTag; - Arc findArc(const Node& u, const Node& v, - const Arc& prev = INVALID) const { - Arc arc = Parent::findArc(u, v, prev); - while (arc != INVALID && !(*_edge_filter)[arc]) { - arc = Parent::findArc(u, v, arc); - } - return arc; - } - - typedef FindEdgeTagIndicator FindEdgeTag; - Edge findEdge(const Node& u, const Node& v, - const Edge& prev = INVALID) const { - Edge edge = Parent::findEdge(u, v, prev); - while (edge != INVALID && !(*_edge_filter)[edge]) { - edge = Parent::findEdge(u, v, edge); - } - return edge; - } - - template - class NodeMap - : public SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, NodeMap)> { - typedef SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, NodeMap)> Parent; - - public: - typedef V Value; - - NodeMap(const SubGraphBase& adaptor) - : Parent(adaptor) {} - NodeMap(const SubGraphBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - template - class ArcMap - : public SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, ArcMap)> { - typedef SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, ArcMap)> Parent; - - public: - typedef V Value; - - ArcMap(const SubGraphBase& adaptor) - : Parent(adaptor) {} - ArcMap(const SubGraphBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - template - class EdgeMap - : public SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> { - typedef SubMapExtender, - LEMON_SCOPE_FIX(GraphAdaptorBase, EdgeMap)> Parent; - - public: - typedef V Value; - - EdgeMap(const SubGraphBase& adaptor) - : Parent(adaptor) {} - - EdgeMap(const SubGraphBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - EdgeMap& operator=(const EdgeMap& cmap) { - return operator=(cmap); - } - - template - EdgeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - }; - - /// \ingroup graph_adaptors - /// - /// \brief Adaptor class for hiding nodes and edges in an undirected - /// graph. - /// - /// SubGraph can be used for hiding nodes and edges in a graph. - /// A \c bool node map and a \c bool edge map must be specified, which - /// define the filters for nodes and edges. - /// Only the nodes and edges with \c true filter value are - /// shown in the subgraph. The edges that are incident to hidden - /// nodes are also filtered out. - /// This adaptor conforms to the \ref concepts::Graph "Graph" concept. - /// - /// The adapted graph can also be modified through this adaptor - /// by adding or removing nodes or edges, unless the \c GR template - /// parameter is set to be \c const. - /// - /// This class provides only linear time counting for nodes, edges and arcs. - /// - /// \tparam GR The type of the adapted graph. - /// It must conform to the \ref concepts::Graph "Graph" concept. - /// It can also be specified to be \c const. - /// \tparam NF The type of the node filter map. - /// It must be a \c bool (or convertible) node map of the - /// adapted graph. The default type is - /// \ref concepts::Graph::NodeMap "GR::NodeMap". - /// \tparam EF The type of the edge filter map. - /// It must be a \c bool (or convertible) edge map of the - /// adapted graph. The default type is - /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". - /// - /// \note The \c Node, \c Edge and \c Arc types of this adaptor and the - /// adapted graph are convertible to each other. - /// - /// \see FilterNodes - /// \see FilterEdges -#ifdef DOXYGEN - template - class SubGraph { -#else - template, - typename EF = typename GR::template EdgeMap > - class SubGraph : - public GraphAdaptorExtender > { -#endif - public: - /// The type of the adapted graph. - typedef GR Graph; - /// The type of the node filter map. - typedef NF NodeFilterMap; - /// The type of the edge filter map. - typedef EF EdgeFilterMap; - - typedef GraphAdaptorExtender > - Parent; - - typedef typename Parent::Node Node; - typedef typename Parent::Edge Edge; - - protected: - SubGraph() { } - public: - - /// \brief Constructor - /// - /// Creates a subgraph for the given graph with the given node - /// and edge filter maps. - SubGraph(GR& graph, NF& node_filter, EF& edge_filter) { - this->initialize(graph, node_filter, edge_filter); - } - - /// \brief Sets the status of the given node - /// - /// This function sets the status of the given node. - /// It is done by simply setting the assigned value of \c n - /// to \c v in the node filter map. - void status(const Node& n, bool v) const { Parent::status(n, v); } - - /// \brief Sets the status of the given edge - /// - /// This function sets the status of the given edge. - /// It is done by simply setting the assigned value of \c e - /// to \c v in the edge filter map. - void status(const Edge& e, bool v) const { Parent::status(e, v); } - - /// \brief Returns the status of the given node - /// - /// This function returns the status of the given node. - /// It is \c true if the given node is enabled (i.e. not hidden). - bool status(const Node& n) const { return Parent::status(n); } - - /// \brief Returns the status of the given edge - /// - /// This function returns the status of the given edge. - /// It is \c true if the given edge is enabled (i.e. not hidden). - bool status(const Edge& e) const { return Parent::status(e); } - - /// \brief Disables the given node - /// - /// This function disables the given node in the subdigraph, - /// so the iteration jumps over it. - /// It is the same as \ref status() "status(n, false)". - void disable(const Node& n) const { Parent::status(n, false); } - - /// \brief Disables the given edge - /// - /// This function disables the given edge in the subgraph, - /// so the iteration jumps over it. - /// It is the same as \ref status() "status(e, false)". - void disable(const Edge& e) const { Parent::status(e, false); } - - /// \brief Enables the given node - /// - /// This function enables the given node in the subdigraph. - /// It is the same as \ref status() "status(n, true)". - void enable(const Node& n) const { Parent::status(n, true); } - - /// \brief Enables the given edge - /// - /// This function enables the given edge in the subgraph. - /// It is the same as \ref status() "status(e, true)". - void enable(const Edge& e) const { Parent::status(e, true); } - - }; - - /// \brief Returns a read-only SubGraph adaptor - /// - /// This function just returns a read-only \ref SubGraph adaptor. - /// \ingroup graph_adaptors - /// \relates SubGraph - template - SubGraph - subGraph(const GR& graph, NF& node_filter, EF& edge_filter) { - return SubGraph - (graph, node_filter, edge_filter); - } - - template - SubGraph - subGraph(const GR& graph, const NF& node_filter, EF& edge_filter) { - return SubGraph - (graph, node_filter, edge_filter); - } - - template - SubGraph - subGraph(const GR& graph, NF& node_filter, const EF& edge_filter) { - return SubGraph - (graph, node_filter, edge_filter); - } - - template - SubGraph - subGraph(const GR& graph, const NF& node_filter, const EF& edge_filter) { - return SubGraph - (graph, node_filter, edge_filter); - } - - - /// \ingroup graph_adaptors - /// - /// \brief Adaptor class for hiding nodes in a digraph or a graph. - /// - /// FilterNodes adaptor can be used for hiding nodes in a digraph or a - /// graph. A \c bool node map must be specified, which defines the filter - /// for the nodes. Only the nodes with \c true filter value and the - /// arcs/edges incident to nodes both with \c true filter value are shown - /// in the subgraph. This adaptor conforms to the \ref concepts::Digraph - /// "Digraph" concept or the \ref concepts::Graph "Graph" concept - /// depending on the \c GR template parameter. - /// - /// The adapted (di)graph can also be modified through this adaptor - /// by adding or removing nodes or arcs/edges, unless the \c GR template - /// parameter is set to be \c const. - /// - /// This class provides only linear time item counting. - /// - /// \tparam GR The type of the adapted digraph or graph. - /// It must conform to the \ref concepts::Digraph "Digraph" concept - /// or the \ref concepts::Graph "Graph" concept. - /// It can also be specified to be \c const. - /// \tparam NF The type of the node filter map. - /// It must be a \c bool (or convertible) node map of the - /// adapted (di)graph. The default type is - /// \ref concepts::Graph::NodeMap "GR::NodeMap". - /// - /// \note The \c Node and Arc/Edge types of this adaptor and the - /// adapted (di)graph are convertible to each other. -#ifdef DOXYGEN - template - class FilterNodes { -#else - template, - typename Enable = void> - class FilterNodes : - public DigraphAdaptorExtender< - SubDigraphBase >, - true> > { -#endif - typedef DigraphAdaptorExtender< - SubDigraphBase >, - true> > Parent; - - public: - - typedef GR Digraph; - typedef NF NodeFilterMap; - - typedef typename Parent::Node Node; - - protected: - ConstMap > const_true_map; - - FilterNodes() : const_true_map() {} - - public: - - /// \brief Constructor - /// - /// Creates a subgraph for the given digraph or graph with the - /// given node filter map. - FilterNodes(GR& graph, NF& node_filter) - : Parent(), const_true_map() - { - Parent::initialize(graph, node_filter, const_true_map); - } - - /// \brief Sets the status of the given node - /// - /// This function sets the status of the given node. - /// It is done by simply setting the assigned value of \c n - /// to \c v in the node filter map. - void status(const Node& n, bool v) const { Parent::status(n, v); } - - /// \brief Returns the status of the given node - /// - /// This function returns the status of the given node. - /// It is \c true if the given node is enabled (i.e. not hidden). - bool status(const Node& n) const { return Parent::status(n); } - - /// \brief Disables the given node - /// - /// This function disables the given node, so the iteration - /// jumps over it. - /// It is the same as \ref status() "status(n, false)". - void disable(const Node& n) const { Parent::status(n, false); } - - /// \brief Enables the given node - /// - /// This function enables the given node. - /// It is the same as \ref status() "status(n, true)". - void enable(const Node& n) const { Parent::status(n, true); } - - }; - - template - class FilterNodes >::type> : - public GraphAdaptorExtender< - SubGraphBase >, - true> > { - - typedef GraphAdaptorExtender< - SubGraphBase >, - true> > Parent; - - public: - - typedef GR Graph; - typedef NF NodeFilterMap; - - typedef typename Parent::Node Node; - - protected: - ConstMap > const_true_map; - - FilterNodes() : const_true_map() {} - - public: - - FilterNodes(GR& graph, NodeFilterMap& node_filter) : - Parent(), const_true_map() { - Parent::initialize(graph, node_filter, const_true_map); - } - - void status(const Node& n, bool v) const { Parent::status(n, v); } - bool status(const Node& n) const { return Parent::status(n); } - void disable(const Node& n) const { Parent::status(n, false); } - void enable(const Node& n) const { Parent::status(n, true); } - - }; - - - /// \brief Returns a read-only FilterNodes adaptor - /// - /// This function just returns a read-only \ref FilterNodes adaptor. - /// \ingroup graph_adaptors - /// \relates FilterNodes - template - FilterNodes - filterNodes(const GR& graph, NF& node_filter) { - return FilterNodes(graph, node_filter); - } - - template - FilterNodes - filterNodes(const GR& graph, const NF& node_filter) { - return FilterNodes(graph, node_filter); - } - - /// \ingroup graph_adaptors - /// - /// \brief Adaptor class for hiding arcs in a digraph. - /// - /// FilterArcs adaptor can be used for hiding arcs in a digraph. - /// A \c bool arc map must be specified, which defines the filter for - /// the arcs. Only the arcs with \c true filter value are shown in the - /// subdigraph. This adaptor conforms to the \ref concepts::Digraph - /// "Digraph" concept. - /// - /// The adapted digraph can also be modified through this adaptor - /// by adding or removing nodes or arcs, unless the \c GR template - /// parameter is set to be \c const. - /// - /// This class provides only linear time counting for nodes and arcs. - /// - /// \tparam DGR The type of the adapted digraph. - /// It must conform to the \ref concepts::Digraph "Digraph" concept. - /// It can also be specified to be \c const. - /// \tparam AF The type of the arc filter map. - /// It must be a \c bool (or convertible) arc map of the - /// adapted digraph. The default type is - /// \ref concepts::Digraph::ArcMap "DGR::ArcMap". - /// - /// \note The \c Node and \c Arc types of this adaptor and the adapted - /// digraph are convertible to each other. -#ifdef DOXYGEN - template - class FilterArcs { -#else - template > - class FilterArcs : - public DigraphAdaptorExtender< - SubDigraphBase >, - AF, false> > { -#endif - typedef DigraphAdaptorExtender< - SubDigraphBase >, - AF, false> > Parent; - - public: - - /// The type of the adapted digraph. - typedef DGR Digraph; - /// The type of the arc filter map. - typedef AF ArcFilterMap; - - typedef typename Parent::Arc Arc; - - protected: - ConstMap > const_true_map; - - FilterArcs() : const_true_map() {} - - public: - - /// \brief Constructor - /// - /// Creates a subdigraph for the given digraph with the given arc - /// filter map. - FilterArcs(DGR& digraph, ArcFilterMap& arc_filter) - : Parent(), const_true_map() { - Parent::initialize(digraph, const_true_map, arc_filter); - } - - /// \brief Sets the status of the given arc - /// - /// This function sets the status of the given arc. - /// It is done by simply setting the assigned value of \c a - /// to \c v in the arc filter map. - void status(const Arc& a, bool v) const { Parent::status(a, v); } - - /// \brief Returns the status of the given arc - /// - /// This function returns the status of the given arc. - /// It is \c true if the given arc is enabled (i.e. not hidden). - bool status(const Arc& a) const { return Parent::status(a); } - - /// \brief Disables the given arc - /// - /// This function disables the given arc in the subdigraph, - /// so the iteration jumps over it. - /// It is the same as \ref status() "status(a, false)". - void disable(const Arc& a) const { Parent::status(a, false); } - - /// \brief Enables the given arc - /// - /// This function enables the given arc in the subdigraph. - /// It is the same as \ref status() "status(a, true)". - void enable(const Arc& a) const { Parent::status(a, true); } - - }; - - /// \brief Returns a read-only FilterArcs adaptor - /// - /// This function just returns a read-only \ref FilterArcs adaptor. - /// \ingroup graph_adaptors - /// \relates FilterArcs - template - FilterArcs - filterArcs(const DGR& digraph, AF& arc_filter) { - return FilterArcs(digraph, arc_filter); - } - - template - FilterArcs - filterArcs(const DGR& digraph, const AF& arc_filter) { - return FilterArcs(digraph, arc_filter); - } - - /// \ingroup graph_adaptors - /// - /// \brief Adaptor class for hiding edges in a graph. - /// - /// FilterEdges adaptor can be used for hiding edges in a graph. - /// A \c bool edge map must be specified, which defines the filter for - /// the edges. Only the edges with \c true filter value are shown in the - /// subgraph. This adaptor conforms to the \ref concepts::Graph - /// "Graph" concept. - /// - /// The adapted graph can also be modified through this adaptor - /// by adding or removing nodes or edges, unless the \c GR template - /// parameter is set to be \c const. - /// - /// This class provides only linear time counting for nodes, edges and arcs. - /// - /// \tparam GR The type of the adapted graph. - /// It must conform to the \ref concepts::Graph "Graph" concept. - /// It can also be specified to be \c const. - /// \tparam EF The type of the edge filter map. - /// It must be a \c bool (or convertible) edge map of the - /// adapted graph. The default type is - /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". - /// - /// \note The \c Node, \c Edge and \c Arc types of this adaptor and the - /// adapted graph are convertible to each other. -#ifdef DOXYGEN - template - class FilterEdges { -#else - template > - class FilterEdges : - public GraphAdaptorExtender< - SubGraphBase >, - EF, false> > { -#endif - typedef GraphAdaptorExtender< - SubGraphBase >, - EF, false> > Parent; - - public: - - /// The type of the adapted graph. - typedef GR Graph; - /// The type of the edge filter map. - typedef EF EdgeFilterMap; - - typedef typename Parent::Edge Edge; - - protected: - ConstMap > const_true_map; - - FilterEdges() : const_true_map(true) { - Parent::setNodeFilterMap(const_true_map); - } - - public: - - /// \brief Constructor - /// - /// Creates a subgraph for the given graph with the given edge - /// filter map. - FilterEdges(GR& graph, EF& edge_filter) - : Parent(), const_true_map() { - Parent::initialize(graph, const_true_map, edge_filter); - } - - /// \brief Sets the status of the given edge - /// - /// This function sets the status of the given edge. - /// It is done by simply setting the assigned value of \c e - /// to \c v in the edge filter map. - void status(const Edge& e, bool v) const { Parent::status(e, v); } - - /// \brief Returns the status of the given edge - /// - /// This function returns the status of the given edge. - /// It is \c true if the given edge is enabled (i.e. not hidden). - bool status(const Edge& e) const { return Parent::status(e); } - - /// \brief Disables the given edge - /// - /// This function disables the given edge in the subgraph, - /// so the iteration jumps over it. - /// It is the same as \ref status() "status(e, false)". - void disable(const Edge& e) const { Parent::status(e, false); } - - /// \brief Enables the given edge - /// - /// This function enables the given edge in the subgraph. - /// It is the same as \ref status() "status(e, true)". - void enable(const Edge& e) const { Parent::status(e, true); } - - }; - - /// \brief Returns a read-only FilterEdges adaptor - /// - /// This function just returns a read-only \ref FilterEdges adaptor. - /// \ingroup graph_adaptors - /// \relates FilterEdges - template - FilterEdges - filterEdges(const GR& graph, EF& edge_filter) { - return FilterEdges(graph, edge_filter); - } - - template - FilterEdges - filterEdges(const GR& graph, const EF& edge_filter) { - return FilterEdges(graph, edge_filter); - } - - - template - class UndirectorBase { - public: - typedef DGR Digraph; - typedef UndirectorBase Adaptor; - - typedef True UndirectedTag; - - typedef typename Digraph::Arc Edge; - typedef typename Digraph::Node Node; - - class Arc { - friend class UndirectorBase; - protected: - Edge _edge; - bool _forward; - - Arc(const Edge& edge, bool forward) - : _edge(edge), _forward(forward) {} - - public: - Arc() {} - - Arc(Invalid) : _edge(INVALID), _forward(true) {} - - operator const Edge&() const { return _edge; } - - bool operator==(const Arc &other) const { - return _forward == other._forward && _edge == other._edge; - } - bool operator!=(const Arc &other) const { - return _forward != other._forward || _edge != other._edge; - } - bool operator<(const Arc &other) const { - return _forward < other._forward || - (_forward == other._forward && _edge < other._edge); - } - }; - - void first(Node& n) const { - _digraph->first(n); - } - - void next(Node& n) const { - _digraph->next(n); - } - - void first(Arc& a) const { - _digraph->first(a._edge); - a._forward = true; - } - - void next(Arc& a) const { - if (a._forward) { - a._forward = false; - } else { - _digraph->next(a._edge); - a._forward = true; - } - } - - void first(Edge& e) const { - _digraph->first(e); - } - - void next(Edge& e) const { - _digraph->next(e); - } - - void firstOut(Arc& a, const Node& n) const { - _digraph->firstIn(a._edge, n); - if (a._edge != INVALID ) { - a._forward = false; - } else { - _digraph->firstOut(a._edge, n); - a._forward = true; - } - } - void nextOut(Arc &a) const { - if (!a._forward) { - Node n = _digraph->target(a._edge); - _digraph->nextIn(a._edge); - if (a._edge == INVALID) { - _digraph->firstOut(a._edge, n); - a._forward = true; - } - } - else { - _digraph->nextOut(a._edge); - } - } - - void firstIn(Arc &a, const Node &n) const { - _digraph->firstOut(a._edge, n); - if (a._edge != INVALID ) { - a._forward = false; - } else { - _digraph->firstIn(a._edge, n); - a._forward = true; - } - } - void nextIn(Arc &a) const { - if (!a._forward) { - Node n = _digraph->source(a._edge); - _digraph->nextOut(a._edge); - if (a._edge == INVALID ) { - _digraph->firstIn(a._edge, n); - a._forward = true; - } - } - else { - _digraph->nextIn(a._edge); - } - } - - void firstInc(Edge &e, bool &d, const Node &n) const { - d = true; - _digraph->firstOut(e, n); - if (e != INVALID) return; - d = false; - _digraph->firstIn(e, n); - } - - void nextInc(Edge &e, bool &d) const { - if (d) { - Node s = _digraph->source(e); - _digraph->nextOut(e); - if (e != INVALID) return; - d = false; - _digraph->firstIn(e, s); - } else { - _digraph->nextIn(e); - } - } - - Node u(const Edge& e) const { - return _digraph->source(e); - } - - Node v(const Edge& e) const { - return _digraph->target(e); - } - - Node source(const Arc &a) const { - return a._forward ? _digraph->source(a._edge) : _digraph->target(a._edge); - } - - Node target(const Arc &a) const { - return a._forward ? _digraph->target(a._edge) : _digraph->source(a._edge); - } - - static Arc direct(const Edge &e, bool d) { - return Arc(e, d); - } - - static bool direction(const Arc &a) { return a._forward; } - - Node nodeFromId(int ix) const { return _digraph->nodeFromId(ix); } - Arc arcFromId(int ix) const { - return direct(_digraph->arcFromId(ix >> 1), bool(ix & 1)); - } - Edge edgeFromId(int ix) const { return _digraph->arcFromId(ix); } - - int id(const Node &n) const { return _digraph->id(n); } - int id(const Arc &a) const { - return (_digraph->id(a) << 1) | (a._forward ? 1 : 0); - } - int id(const Edge &e) const { return _digraph->id(e); } - - int maxNodeId() const { return _digraph->maxNodeId(); } - int maxArcId() const { return (_digraph->maxArcId() << 1) | 1; } - int maxEdgeId() const { return _digraph->maxArcId(); } - - Node addNode() { return _digraph->addNode(); } - Edge addEdge(const Node& u, const Node& v) { - return _digraph->addArc(u, v); - } - - void erase(const Node& i) { _digraph->erase(i); } - void erase(const Edge& i) { _digraph->erase(i); } - - void clear() { _digraph->clear(); } - - typedef NodeNumTagIndicator NodeNumTag; - int nodeNum() const { return _digraph->nodeNum(); } - - typedef ArcNumTagIndicator ArcNumTag; - int arcNum() const { return 2 * _digraph->arcNum(); } - - typedef ArcNumTag EdgeNumTag; - int edgeNum() const { return _digraph->arcNum(); } - - typedef FindArcTagIndicator FindArcTag; - Arc findArc(Node s, Node t, Arc p = INVALID) const { - if (p == INVALID) { - Edge arc = _digraph->findArc(s, t); - if (arc != INVALID) return direct(arc, true); - arc = _digraph->findArc(t, s); - if (arc != INVALID) return direct(arc, false); - } else if (direction(p)) { - Edge arc = _digraph->findArc(s, t, p); - if (arc != INVALID) return direct(arc, true); - arc = _digraph->findArc(t, s); - if (arc != INVALID) return direct(arc, false); - } else { - Edge arc = _digraph->findArc(t, s, p); - if (arc != INVALID) return direct(arc, false); - } - return INVALID; - } - - typedef FindArcTag FindEdgeTag; - Edge findEdge(Node s, Node t, Edge p = INVALID) const { - if (s != t) { - if (p == INVALID) { - Edge arc = _digraph->findArc(s, t); - if (arc != INVALID) return arc; - arc = _digraph->findArc(t, s); - if (arc != INVALID) return arc; - } else if (_digraph->source(p) == s) { - Edge arc = _digraph->findArc(s, t, p); - if (arc != INVALID) return arc; - arc = _digraph->findArc(t, s); - if (arc != INVALID) return arc; - } else { - Edge arc = _digraph->findArc(t, s, p); - if (arc != INVALID) return arc; - } - } else { - return _digraph->findArc(s, t, p); - } - return INVALID; - } - - private: - - template - class ArcMapBase { - private: - - typedef typename DGR::template ArcMap MapImpl; - - public: - - typedef typename MapTraits::ReferenceMapTag ReferenceMapTag; - - typedef V Value; - typedef Arc Key; - typedef typename MapTraits::ConstReturnValue ConstReturnValue; - typedef typename MapTraits::ReturnValue ReturnValue; - typedef typename MapTraits::ConstReturnValue ConstReference; - typedef typename MapTraits::ReturnValue Reference; - - ArcMapBase(const UndirectorBase& adaptor) : - _forward(*adaptor._digraph), _backward(*adaptor._digraph) {} - - ArcMapBase(const UndirectorBase& adaptor, const V& value) - : _forward(*adaptor._digraph, value), - _backward(*adaptor._digraph, value) {} - - void set(const Arc& a, const V& value) { - if (direction(a)) { - _forward.set(a, value); - } else { - _backward.set(a, value); - } - } - - ConstReturnValue operator[](const Arc& a) const { - if (direction(a)) { - return _forward[a]; - } else { - return _backward[a]; - } - } - - ReturnValue operator[](const Arc& a) { - if (direction(a)) { - return _forward[a]; - } else { - return _backward[a]; - } - } - - protected: - - MapImpl _forward, _backward; - - }; - - public: - - template - class NodeMap : public DGR::template NodeMap { - typedef typename DGR::template NodeMap Parent; - - public: - typedef V Value; - - explicit NodeMap(const UndirectorBase& adaptor) - : Parent(*adaptor._digraph) {} - - NodeMap(const UndirectorBase& adaptor, const V& value) - : Parent(*adaptor._digraph, value) { } - - private: - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - template - class ArcMap - : public SubMapExtender, ArcMapBase > { - typedef SubMapExtender, ArcMapBase > Parent; - - public: - typedef V Value; - - explicit ArcMap(const UndirectorBase& adaptor) - : Parent(adaptor) {} - - ArcMap(const UndirectorBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - template - class EdgeMap : public Digraph::template ArcMap { - typedef typename Digraph::template ArcMap Parent; - - public: - typedef V Value; - - explicit EdgeMap(const UndirectorBase& adaptor) - : Parent(*adaptor._digraph) {} - - EdgeMap(const UndirectorBase& adaptor, const V& value) - : Parent(*adaptor._digraph, value) {} - - private: - EdgeMap& operator=(const EdgeMap& cmap) { - return operator=(cmap); - } - - template - EdgeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - typedef typename ItemSetTraits::ItemNotifier NodeNotifier; - NodeNotifier& notifier(Node) const { return _digraph->notifier(Node()); } - - typedef typename ItemSetTraits::ItemNotifier EdgeNotifier; - EdgeNotifier& notifier(Edge) const { return _digraph->notifier(Edge()); } - - typedef EdgeNotifier ArcNotifier; - ArcNotifier& notifier(Arc) const { return _digraph->notifier(Edge()); } - - protected: - - UndirectorBase() : _digraph(0) {} - - DGR* _digraph; - - void initialize(DGR& digraph) { - _digraph = &digraph; - } - - }; - - /// \ingroup graph_adaptors - /// - /// \brief Adaptor class for viewing a digraph as an undirected graph. - /// - /// Undirector adaptor can be used for viewing a digraph as an undirected - /// graph. All arcs of the underlying digraph are showed in the - /// adaptor as an edge (and also as a pair of arcs, of course). - /// This adaptor conforms to the \ref concepts::Graph "Graph" concept. - /// - /// The adapted digraph can also be modified through this adaptor - /// by adding or removing nodes or edges, unless the \c GR template - /// parameter is set to be \c const. - /// - /// This class provides item counting in the same time as the adapted - /// digraph structure. - /// - /// \tparam DGR The type of the adapted digraph. - /// It must conform to the \ref concepts::Digraph "Digraph" concept. - /// It can also be specified to be \c const. - /// - /// \note The \c Node type of this adaptor and the adapted digraph are - /// convertible to each other, moreover the \c Edge type of the adaptor - /// and the \c Arc type of the adapted digraph are also convertible to - /// each other. - /// (Thus the \c Arc type of the adaptor is convertible to the \c Arc type - /// of the adapted digraph.) - template -#ifdef DOXYGEN - class Undirector { -#else - class Undirector : - public GraphAdaptorExtender > { -#endif - typedef GraphAdaptorExtender > Parent; - public: - /// The type of the adapted digraph. - typedef DGR Digraph; - protected: - Undirector() { } - public: - - /// \brief Constructor - /// - /// Creates an undirected graph from the given digraph. - Undirector(DGR& digraph) { - this->initialize(digraph); - } - - /// \brief Arc map combined from two original arc maps - /// - /// This map adaptor class adapts two arc maps of the underlying - /// digraph to get an arc map of the undirected graph. - /// Its value type is inherited from the first arc map type (\c FW). - /// \tparam FW The type of the "foward" arc map. - /// \tparam BK The type of the "backward" arc map. - template - class CombinedArcMap { - public: - - /// The key type of the map - typedef typename Parent::Arc Key; - /// The value type of the map - typedef typename FW::Value Value; - - typedef typename MapTraits::ReferenceMapTag ReferenceMapTag; - - typedef typename MapTraits::ReturnValue ReturnValue; - typedef typename MapTraits::ConstReturnValue ConstReturnValue; - typedef typename MapTraits::ReturnValue Reference; - typedef typename MapTraits::ConstReturnValue ConstReference; - - /// Constructor - CombinedArcMap(FW& forward, BK& backward) - : _forward(&forward), _backward(&backward) {} - - /// Sets the value associated with the given key. - void set(const Key& e, const Value& a) { - if (Parent::direction(e)) { - _forward->set(e, a); - } else { - _backward->set(e, a); - } - } - - /// Returns the value associated with the given key. - ConstReturnValue operator[](const Key& e) const { - if (Parent::direction(e)) { - return (*_forward)[e]; - } else { - return (*_backward)[e]; - } - } - - /// Returns a reference to the value associated with the given key. - ReturnValue operator[](const Key& e) { - if (Parent::direction(e)) { - return (*_forward)[e]; - } else { - return (*_backward)[e]; - } - } - - protected: - - FW* _forward; - BK* _backward; - - }; - - /// \brief Returns a combined arc map - /// - /// This function just returns a combined arc map. - template - static CombinedArcMap - combinedArcMap(FW& forward, BK& backward) { - return CombinedArcMap(forward, backward); - } - - template - static CombinedArcMap - combinedArcMap(const FW& forward, BK& backward) { - return CombinedArcMap(forward, backward); - } - - template - static CombinedArcMap - combinedArcMap(FW& forward, const BK& backward) { - return CombinedArcMap(forward, backward); - } - - template - static CombinedArcMap - combinedArcMap(const FW& forward, const BK& backward) { - return CombinedArcMap(forward, backward); - } - - }; - - /// \brief Returns a read-only Undirector adaptor - /// - /// This function just returns a read-only \ref Undirector adaptor. - /// \ingroup graph_adaptors - /// \relates Undirector - template - Undirector undirector(const DGR& digraph) { - return Undirector(digraph); - } - - - template - class OrienterBase { - public: - - typedef GR Graph; - typedef DM DirectionMap; - - typedef typename GR::Node Node; - typedef typename GR::Edge Arc; - - void reverseArc(const Arc& arc) { - _direction->set(arc, !(*_direction)[arc]); - } - - void first(Node& i) const { _graph->first(i); } - void first(Arc& i) const { _graph->first(i); } - void firstIn(Arc& i, const Node& n) const { - bool d = true; - _graph->firstInc(i, d, n); - while (i != INVALID && d == (*_direction)[i]) _graph->nextInc(i, d); - } - void firstOut(Arc& i, const Node& n ) const { - bool d = true; - _graph->firstInc(i, d, n); - while (i != INVALID && d != (*_direction)[i]) _graph->nextInc(i, d); - } - - void next(Node& i) const { _graph->next(i); } - void next(Arc& i) const { _graph->next(i); } - void nextIn(Arc& i) const { - bool d = !(*_direction)[i]; - _graph->nextInc(i, d); - while (i != INVALID && d == (*_direction)[i]) _graph->nextInc(i, d); - } - void nextOut(Arc& i) const { - bool d = (*_direction)[i]; - _graph->nextInc(i, d); - while (i != INVALID && d != (*_direction)[i]) _graph->nextInc(i, d); - } - - Node source(const Arc& e) const { - return (*_direction)[e] ? _graph->u(e) : _graph->v(e); - } - Node target(const Arc& e) const { - return (*_direction)[e] ? _graph->v(e) : _graph->u(e); - } - - typedef NodeNumTagIndicator NodeNumTag; - int nodeNum() const { return _graph->nodeNum(); } - - typedef EdgeNumTagIndicator ArcNumTag; - int arcNum() const { return _graph->edgeNum(); } - - typedef FindEdgeTagIndicator FindArcTag; - Arc findArc(const Node& u, const Node& v, - const Arc& prev = INVALID) const { - Arc arc = _graph->findEdge(u, v, prev); - while (arc != INVALID && source(arc) != u) { - arc = _graph->findEdge(u, v, arc); - } - return arc; - } - - Node addNode() { - return Node(_graph->addNode()); - } - - Arc addArc(const Node& u, const Node& v) { - Arc arc = _graph->addEdge(u, v); - _direction->set(arc, _graph->u(arc) == u); - return arc; - } - - void erase(const Node& i) { _graph->erase(i); } - void erase(const Arc& i) { _graph->erase(i); } - - void clear() { _graph->clear(); } - - int id(const Node& v) const { return _graph->id(v); } - int id(const Arc& e) const { return _graph->id(e); } - - Node nodeFromId(int idx) const { return _graph->nodeFromId(idx); } - Arc arcFromId(int idx) const { return _graph->edgeFromId(idx); } - - int maxNodeId() const { return _graph->maxNodeId(); } - int maxArcId() const { return _graph->maxEdgeId(); } - - typedef typename ItemSetTraits::ItemNotifier NodeNotifier; - NodeNotifier& notifier(Node) const { return _graph->notifier(Node()); } - - typedef typename ItemSetTraits::ItemNotifier ArcNotifier; - ArcNotifier& notifier(Arc) const { return _graph->notifier(Arc()); } - - template - class NodeMap : public GR::template NodeMap { - typedef typename GR::template NodeMap Parent; - - public: - - explicit NodeMap(const OrienterBase& adapter) - : Parent(*adapter._graph) {} - - NodeMap(const OrienterBase& adapter, const V& value) - : Parent(*adapter._graph, value) {} - - private: - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - template - class ArcMap : public GR::template EdgeMap { - typedef typename Graph::template EdgeMap Parent; - - public: - - explicit ArcMap(const OrienterBase& adapter) - : Parent(*adapter._graph) { } - - ArcMap(const OrienterBase& adapter, const V& value) - : Parent(*adapter._graph, value) { } - - private: - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - - - protected: - Graph* _graph; - DM* _direction; - - void initialize(GR& graph, DM& direction) { - _graph = &graph; - _direction = &direction; - } - - }; - - /// \ingroup graph_adaptors - /// - /// \brief Adaptor class for orienting the edges of a graph to get a digraph - /// - /// Orienter adaptor can be used for orienting the edges of a graph to - /// get a digraph. A \c bool edge map of the underlying graph must be - /// specified, which define the direction of the arcs in the adaptor. - /// The arcs can be easily reversed by the \c reverseArc() member function - /// of the adaptor. - /// This class conforms to the \ref concepts::Digraph "Digraph" concept. - /// - /// The adapted graph can also be modified through this adaptor - /// by adding or removing nodes or arcs, unless the \c GR template - /// parameter is set to be \c const. - /// - /// This class provides item counting in the same time as the adapted - /// graph structure. - /// - /// \tparam GR The type of the adapted graph. - /// It must conform to the \ref concepts::Graph "Graph" concept. - /// It can also be specified to be \c const. - /// \tparam DM The type of the direction map. - /// It must be a \c bool (or convertible) edge map of the - /// adapted graph. The default type is - /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". - /// - /// \note The \c Node type of this adaptor and the adapted graph are - /// convertible to each other, moreover the \c Arc type of the adaptor - /// and the \c Edge type of the adapted graph are also convertible to - /// each other. -#ifdef DOXYGEN - template - class Orienter { -#else - template > - class Orienter : - public DigraphAdaptorExtender > { -#endif - typedef DigraphAdaptorExtender > Parent; - public: - - /// The type of the adapted graph. - typedef GR Graph; - /// The type of the direction edge map. - typedef DM DirectionMap; - - typedef typename Parent::Arc Arc; - - protected: - Orienter() { } - - public: - - /// \brief Constructor - /// - /// Constructor of the adaptor. - Orienter(GR& graph, DM& direction) { - Parent::initialize(graph, direction); - } - - /// \brief Reverses the given arc - /// - /// This function reverses the given arc. - /// It is done by simply negate the assigned value of \c a - /// in the direction map. - void reverseArc(const Arc& a) { - Parent::reverseArc(a); - } - }; - - /// \brief Returns a read-only Orienter adaptor - /// - /// This function just returns a read-only \ref Orienter adaptor. - /// \ingroup graph_adaptors - /// \relates Orienter - template - Orienter - orienter(const GR& graph, DM& direction) { - return Orienter(graph, direction); - } - - template - Orienter - orienter(const GR& graph, const DM& direction) { - return Orienter(graph, direction); - } - - namespace _adaptor_bits { - - template - class ResForwardFilter { - public: - - typedef typename DGR::Arc Key; - typedef bool Value; - - private: - - const CM* _capacity; - const FM* _flow; - TL _tolerance; - - public: - - ResForwardFilter(const CM& capacity, const FM& flow, - const TL& tolerance = TL()) - : _capacity(&capacity), _flow(&flow), _tolerance(tolerance) { } - - bool operator[](const typename DGR::Arc& a) const { - return _tolerance.positive((*_capacity)[a] - (*_flow)[a]); - } - }; - - template - class ResBackwardFilter { - public: - - typedef typename DGR::Arc Key; - typedef bool Value; - - private: - - const CM* _capacity; - const FM* _flow; - TL _tolerance; - - public: - - ResBackwardFilter(const CM& capacity, const FM& flow, - const TL& tolerance = TL()) - : _capacity(&capacity), _flow(&flow), _tolerance(tolerance) { } - - bool operator[](const typename DGR::Arc& a) const { - return _tolerance.positive((*_flow)[a]); - } - }; - - } - - /// \ingroup graph_adaptors - /// - /// \brief Adaptor class for composing the residual digraph for directed - /// flow and circulation problems. - /// - /// ResidualDigraph can be used for composing the \e residual digraph - /// for directed flow and circulation problems. Let \f$ G=(V, A) \f$ - /// be a directed graph and let \f$ F \f$ be a number type. - /// Let \f$ flow, cap: A\to F \f$ be functions on the arcs. - /// This adaptor implements a digraph structure with node set \f$ V \f$ - /// and arc set \f$ A_{forward}\cup A_{backward} \f$, - /// where \f$ A_{forward}=\{uv : uv\in A, flow(uv)0\} \f$, i.e. the so - /// called residual digraph. - /// When the union \f$ A_{forward}\cup A_{backward} \f$ is taken, - /// multiplicities are counted, i.e. the adaptor has exactly - /// \f$ |A_{forward}| + |A_{backward}|\f$ arcs (it may have parallel - /// arcs). - /// This class conforms to the \ref concepts::Digraph "Digraph" concept. - /// - /// This class provides only linear time counting for nodes and arcs. - /// - /// \tparam DGR The type of the adapted digraph. - /// It must conform to the \ref concepts::Digraph "Digraph" concept. - /// It is implicitly \c const. - /// \tparam CM The type of the capacity map. - /// It must be an arc map of some numerical type, which defines - /// the capacities in the flow problem. It is implicitly \c const. - /// The default type is - /// \ref concepts::Digraph::ArcMap "GR::ArcMap". - /// \tparam FM The type of the flow map. - /// It must be an arc map of some numerical type, which defines - /// the flow values in the flow problem. The default type is \c CM. - /// \tparam TL The tolerance type for handling inexact computation. - /// The default tolerance type depends on the value type of the - /// capacity map. - /// - /// \note This adaptor is implemented using Undirector and FilterArcs - /// adaptors. - /// - /// \note The \c Node type of this adaptor and the adapted digraph are - /// convertible to each other, moreover the \c Arc type of the adaptor - /// is convertible to the \c Arc type of the adapted digraph. -#ifdef DOXYGEN - template - class ResidualDigraph -#else - template, - typename FM = CM, - typename TL = Tolerance > - class ResidualDigraph - : public SubDigraph< - Undirector, - ConstMap >, - typename Undirector::template CombinedArcMap< - _adaptor_bits::ResForwardFilter, - _adaptor_bits::ResBackwardFilter > > -#endif - { - public: - - /// The type of the underlying digraph. - typedef DGR Digraph; - /// The type of the capacity map. - typedef CM CapacityMap; - /// The type of the flow map. - typedef FM FlowMap; - /// The tolerance type. - typedef TL Tolerance; - - typedef typename CapacityMap::Value Value; - typedef ResidualDigraph Adaptor; - - protected: - - typedef Undirector Undirected; - - typedef ConstMap > NodeFilter; - - typedef _adaptor_bits::ResForwardFilter ForwardFilter; - - typedef _adaptor_bits::ResBackwardFilter BackwardFilter; - - typedef typename Undirected:: - template CombinedArcMap ArcFilter; - - typedef SubDigraph Parent; - - const CapacityMap* _capacity; - FlowMap* _flow; - - Undirected _graph; - NodeFilter _node_filter; - ForwardFilter _forward_filter; - BackwardFilter _backward_filter; - ArcFilter _arc_filter; - - public: - - /// \brief Constructor - /// - /// Constructor of the residual digraph adaptor. The parameters are the - /// digraph, the capacity map, the flow map, and a tolerance object. - ResidualDigraph(const DGR& digraph, const CM& capacity, - FM& flow, const TL& tolerance = Tolerance()) - : Parent(), _capacity(&capacity), _flow(&flow), - _graph(digraph), _node_filter(), - _forward_filter(capacity, flow, tolerance), - _backward_filter(capacity, flow, tolerance), - _arc_filter(_forward_filter, _backward_filter) - { - Parent::initialize(_graph, _node_filter, _arc_filter); - } - - typedef typename Parent::Arc Arc; - - /// \brief Returns the residual capacity of the given arc. - /// - /// Returns the residual capacity of the given arc. - Value residualCapacity(const Arc& a) const { - if (Undirected::direction(a)) { - return (*_capacity)[a] - (*_flow)[a]; - } else { - return (*_flow)[a]; - } - } - - /// \brief Augments on the given arc in the residual digraph. - /// - /// Augments on the given arc in the residual digraph. It increases - /// or decreases the flow value on the original arc according to the - /// direction of the residual arc. - void augment(const Arc& a, const Value& v) const { - if (Undirected::direction(a)) { - _flow->set(a, (*_flow)[a] + v); - } else { - _flow->set(a, (*_flow)[a] - v); - } - } - - /// \brief Returns \c true if the given residual arc is a forward arc. - /// - /// Returns \c true if the given residual arc has the same orientation - /// as the original arc, i.e. it is a so called forward arc. - static bool forward(const Arc& a) { - return Undirected::direction(a); - } - - /// \brief Returns \c true if the given residual arc is a backward arc. - /// - /// Returns \c true if the given residual arc has the opposite orientation - /// than the original arc, i.e. it is a so called backward arc. - static bool backward(const Arc& a) { - return !Undirected::direction(a); - } - - /// \brief Returns the forward oriented residual arc. - /// - /// Returns the forward oriented residual arc related to the given - /// arc of the underlying digraph. - static Arc forward(const typename Digraph::Arc& a) { - return Undirected::direct(a, true); - } - - /// \brief Returns the backward oriented residual arc. - /// - /// Returns the backward oriented residual arc related to the given - /// arc of the underlying digraph. - static Arc backward(const typename Digraph::Arc& a) { - return Undirected::direct(a, false); - } - - /// \brief Residual capacity map. - /// - /// This map adaptor class can be used for obtaining the residual - /// capacities as an arc map of the residual digraph. - /// Its value type is inherited from the capacity map. - class ResidualCapacity { - protected: - const Adaptor* _adaptor; - public: - /// The key type of the map - typedef Arc Key; - /// The value type of the map - typedef typename CapacityMap::Value Value; - - /// Constructor - ResidualCapacity(const ResidualDigraph& adaptor) - : _adaptor(&adaptor) {} - - /// Returns the value associated with the given residual arc - Value operator[](const Arc& a) const { - return _adaptor->residualCapacity(a); - } - - }; - - /// \brief Returns a residual capacity map - /// - /// This function just returns a residual capacity map. - ResidualCapacity residualCapacity() const { - return ResidualCapacity(*this); - } - - }; - - /// \brief Returns a (read-only) Residual adaptor - /// - /// This function just returns a (read-only) \ref ResidualDigraph adaptor. - /// \ingroup graph_adaptors - /// \relates ResidualDigraph - template - ResidualDigraph - residualDigraph(const DGR& digraph, const CM& capacity_map, FM& flow_map) { - return ResidualDigraph (digraph, capacity_map, flow_map); - } - - - template - class SplitNodesBase { - typedef DigraphAdaptorBase Parent; - - public: - - typedef DGR Digraph; - typedef SplitNodesBase Adaptor; - - typedef typename DGR::Node DigraphNode; - typedef typename DGR::Arc DigraphArc; - - class Node; - class Arc; - - private: - - template class NodeMapBase; - template class ArcMapBase; - - public: - - class Node : public DigraphNode { - friend class SplitNodesBase; - template friend class NodeMapBase; - private: - - bool _in; - Node(DigraphNode node, bool in) - : DigraphNode(node), _in(in) {} - - public: - - Node() {} - Node(Invalid) : DigraphNode(INVALID), _in(true) {} - - bool operator==(const Node& node) const { - return DigraphNode::operator==(node) && _in == node._in; - } - - bool operator!=(const Node& node) const { - return !(*this == node); - } - - bool operator<(const Node& node) const { - return DigraphNode::operator<(node) || - (DigraphNode::operator==(node) && _in < node._in); - } - }; - - class Arc { - friend class SplitNodesBase; - template friend class ArcMapBase; - private: - typedef BiVariant ArcImpl; - - explicit Arc(const DigraphArc& arc) : _item(arc) {} - explicit Arc(const DigraphNode& node) : _item(node) {} - - ArcImpl _item; - - public: - Arc() {} - Arc(Invalid) : _item(DigraphArc(INVALID)) {} - - bool operator==(const Arc& arc) const { - if (_item.firstState()) { - if (arc._item.firstState()) { - return _item.first() == arc._item.first(); - } - } else { - if (arc._item.secondState()) { - return _item.second() == arc._item.second(); - } - } - return false; - } - - bool operator!=(const Arc& arc) const { - return !(*this == arc); - } - - bool operator<(const Arc& arc) const { - if (_item.firstState()) { - if (arc._item.firstState()) { - return _item.first() < arc._item.first(); - } - return false; - } else { - if (arc._item.secondState()) { - return _item.second() < arc._item.second(); - } - return true; - } - } - - operator DigraphArc() const { return _item.first(); } - operator DigraphNode() const { return _item.second(); } - - }; - - void first(Node& n) const { - _digraph->first(n); - n._in = true; - } - - void next(Node& n) const { - if (n._in) { - n._in = false; - } else { - n._in = true; - _digraph->next(n); - } - } - - void first(Arc& e) const { - e._item.setSecond(); - _digraph->first(e._item.second()); - if (e._item.second() == INVALID) { - e._item.setFirst(); - _digraph->first(e._item.first()); - } - } - - void next(Arc& e) const { - if (e._item.secondState()) { - _digraph->next(e._item.second()); - if (e._item.second() == INVALID) { - e._item.setFirst(); - _digraph->first(e._item.first()); - } - } else { - _digraph->next(e._item.first()); - } - } - - void firstOut(Arc& e, const Node& n) const { - if (n._in) { - e._item.setSecond(n); - } else { - e._item.setFirst(); - _digraph->firstOut(e._item.first(), n); - } - } - - void nextOut(Arc& e) const { - if (!e._item.firstState()) { - e._item.setFirst(INVALID); - } else { - _digraph->nextOut(e._item.first()); - } - } - - void firstIn(Arc& e, const Node& n) const { - if (!n._in) { - e._item.setSecond(n); - } else { - e._item.setFirst(); - _digraph->firstIn(e._item.first(), n); - } - } - - void nextIn(Arc& e) const { - if (!e._item.firstState()) { - e._item.setFirst(INVALID); - } else { - _digraph->nextIn(e._item.first()); - } - } - - Node source(const Arc& e) const { - if (e._item.firstState()) { - return Node(_digraph->source(e._item.first()), false); - } else { - return Node(e._item.second(), true); - } - } - - Node target(const Arc& e) const { - if (e._item.firstState()) { - return Node(_digraph->target(e._item.first()), true); - } else { - return Node(e._item.second(), false); - } - } - - int id(const Node& n) const { - return (_digraph->id(n) << 1) | (n._in ? 0 : 1); - } - Node nodeFromId(int ix) const { - return Node(_digraph->nodeFromId(ix >> 1), (ix & 1) == 0); - } - int maxNodeId() const { - return 2 * _digraph->maxNodeId() + 1; - } - - int id(const Arc& e) const { - if (e._item.firstState()) { - return _digraph->id(e._item.first()) << 1; - } else { - return (_digraph->id(e._item.second()) << 1) | 1; - } - } - Arc arcFromId(int ix) const { - if ((ix & 1) == 0) { - return Arc(_digraph->arcFromId(ix >> 1)); - } else { - return Arc(_digraph->nodeFromId(ix >> 1)); - } - } - int maxArcId() const { - return std::max(_digraph->maxNodeId() << 1, - (_digraph->maxArcId() << 1) | 1); - } - - static bool inNode(const Node& n) { - return n._in; - } - - static bool outNode(const Node& n) { - return !n._in; - } - - static bool origArc(const Arc& e) { - return e._item.firstState(); - } - - static bool bindArc(const Arc& e) { - return e._item.secondState(); - } - - static Node inNode(const DigraphNode& n) { - return Node(n, true); - } - - static Node outNode(const DigraphNode& n) { - return Node(n, false); - } - - static Arc arc(const DigraphNode& n) { - return Arc(n); - } - - static Arc arc(const DigraphArc& e) { - return Arc(e); - } - - typedef True NodeNumTag; - int nodeNum() const { - return 2 * countNodes(*_digraph); - } - - typedef True ArcNumTag; - int arcNum() const { - return countArcs(*_digraph) + countNodes(*_digraph); - } - - typedef True FindArcTag; - Arc findArc(const Node& u, const Node& v, - const Arc& prev = INVALID) const { - if (inNode(u) && outNode(v)) { - if (static_cast(u) == - static_cast(v) && prev == INVALID) { - return Arc(u); - } - } - else if (outNode(u) && inNode(v)) { - return Arc(::lemon::findArc(*_digraph, u, v, prev)); - } - return INVALID; - } - - private: - - template - class NodeMapBase - : public MapTraits > { - typedef typename Parent::template NodeMap NodeImpl; - public: - typedef Node Key; - typedef V Value; - typedef typename MapTraits::ReferenceMapTag ReferenceMapTag; - typedef typename MapTraits::ReturnValue ReturnValue; - typedef typename MapTraits::ConstReturnValue ConstReturnValue; - typedef typename MapTraits::ReturnValue Reference; - typedef typename MapTraits::ConstReturnValue ConstReference; - - NodeMapBase(const SplitNodesBase& adaptor) - : _in_map(*adaptor._digraph), _out_map(*adaptor._digraph) {} - NodeMapBase(const SplitNodesBase& adaptor, const V& value) - : _in_map(*adaptor._digraph, value), - _out_map(*adaptor._digraph, value) {} - - void set(const Node& key, const V& val) { - if (SplitNodesBase::inNode(key)) { _in_map.set(key, val); } - else {_out_map.set(key, val); } - } - - ReturnValue operator[](const Node& key) { - if (SplitNodesBase::inNode(key)) { return _in_map[key]; } - else { return _out_map[key]; } - } - - ConstReturnValue operator[](const Node& key) const { - if (Adaptor::inNode(key)) { return _in_map[key]; } - else { return _out_map[key]; } - } - - private: - NodeImpl _in_map, _out_map; - }; - - template - class ArcMapBase - : public MapTraits > { - typedef typename Parent::template ArcMap ArcImpl; - typedef typename Parent::template NodeMap NodeImpl; - public: - typedef Arc Key; - typedef V Value; - typedef typename MapTraits::ReferenceMapTag ReferenceMapTag; - typedef typename MapTraits::ReturnValue ReturnValue; - typedef typename MapTraits::ConstReturnValue ConstReturnValue; - typedef typename MapTraits::ReturnValue Reference; - typedef typename MapTraits::ConstReturnValue ConstReference; - - ArcMapBase(const SplitNodesBase& adaptor) - : _arc_map(*adaptor._digraph), _node_map(*adaptor._digraph) {} - ArcMapBase(const SplitNodesBase& adaptor, const V& value) - : _arc_map(*adaptor._digraph, value), - _node_map(*adaptor._digraph, value) {} - - void set(const Arc& key, const V& val) { - if (SplitNodesBase::origArc(key)) { - _arc_map.set(static_cast(key), val); - } else { - _node_map.set(static_cast(key), val); - } - } - - ReturnValue operator[](const Arc& key) { - if (SplitNodesBase::origArc(key)) { - return _arc_map[static_cast(key)]; - } else { - return _node_map[static_cast(key)]; - } - } - - ConstReturnValue operator[](const Arc& key) const { - if (SplitNodesBase::origArc(key)) { - return _arc_map[static_cast(key)]; - } else { - return _node_map[static_cast(key)]; - } - } - - private: - ArcImpl _arc_map; - NodeImpl _node_map; - }; - - public: - - template - class NodeMap - : public SubMapExtender, NodeMapBase > { - typedef SubMapExtender, NodeMapBase > Parent; - - public: - typedef V Value; - - NodeMap(const SplitNodesBase& adaptor) - : Parent(adaptor) {} - - NodeMap(const SplitNodesBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - template - class ArcMap - : public SubMapExtender, ArcMapBase > { - typedef SubMapExtender, ArcMapBase > Parent; - - public: - typedef V Value; - - ArcMap(const SplitNodesBase& adaptor) - : Parent(adaptor) {} - - ArcMap(const SplitNodesBase& adaptor, const V& value) - : Parent(adaptor, value) {} - - private: - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - protected: - - SplitNodesBase() : _digraph(0) {} - - DGR* _digraph; - - void initialize(Digraph& digraph) { - _digraph = &digraph; - } - - }; - - /// \ingroup graph_adaptors - /// - /// \brief Adaptor class for splitting the nodes of a digraph. - /// - /// SplitNodes adaptor can be used for splitting each node into an - /// \e in-node and an \e out-node in a digraph. Formaly, the adaptor - /// replaces each node \f$ u \f$ in the digraph with two nodes, - /// namely node \f$ u_{in} \f$ and node \f$ u_{out} \f$. - /// If there is a \f$ (v, u) \f$ arc in the original digraph, then the - /// new target of the arc will be \f$ u_{in} \f$ and similarly the - /// source of each original \f$ (u, v) \f$ arc will be \f$ u_{out} \f$. - /// The adaptor adds an additional \e bind \e arc from \f$ u_{in} \f$ - /// to \f$ u_{out} \f$ for each node \f$ u \f$ of the original digraph. - /// - /// The aim of this class is running an algorithm with respect to node - /// costs or capacities if the algorithm considers only arc costs or - /// capacities directly. - /// In this case you can use \c SplitNodes adaptor, and set the node - /// costs/capacities of the original digraph to the \e bind \e arcs - /// in the adaptor. - /// - /// This class provides item counting in the same time as the adapted - /// digraph structure. - /// - /// \tparam DGR The type of the adapted digraph. - /// It must conform to the \ref concepts::Digraph "Digraph" concept. - /// It is implicitly \c const. - /// - /// \note The \c Node type of this adaptor is converible to the \c Node - /// type of the adapted digraph. - template -#ifdef DOXYGEN - class SplitNodes { -#else - class SplitNodes - : public DigraphAdaptorExtender > { -#endif - typedef DigraphAdaptorExtender > Parent; - - public: - typedef DGR Digraph; - - typedef typename DGR::Node DigraphNode; - typedef typename DGR::Arc DigraphArc; - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - - /// \brief Constructor - /// - /// Constructor of the adaptor. - SplitNodes(const DGR& g) { - Parent::initialize(g); - } - - /// \brief Returns \c true if the given node is an in-node. - /// - /// Returns \c true if the given node is an in-node. - static bool inNode(const Node& n) { - return Parent::inNode(n); - } - - /// \brief Returns \c true if the given node is an out-node. - /// - /// Returns \c true if the given node is an out-node. - static bool outNode(const Node& n) { - return Parent::outNode(n); - } - - /// \brief Returns \c true if the given arc is an original arc. - /// - /// Returns \c true if the given arc is one of the arcs in the - /// original digraph. - static bool origArc(const Arc& a) { - return Parent::origArc(a); - } - - /// \brief Returns \c true if the given arc is a bind arc. - /// - /// Returns \c true if the given arc is a bind arc, i.e. it connects - /// an in-node and an out-node. - static bool bindArc(const Arc& a) { - return Parent::bindArc(a); - } - - /// \brief Returns the in-node created from the given original node. - /// - /// Returns the in-node created from the given original node. - static Node inNode(const DigraphNode& n) { - return Parent::inNode(n); - } - - /// \brief Returns the out-node created from the given original node. - /// - /// Returns the out-node created from the given original node. - static Node outNode(const DigraphNode& n) { - return Parent::outNode(n); - } - - /// \brief Returns the bind arc that corresponds to the given - /// original node. - /// - /// Returns the bind arc in the adaptor that corresponds to the given - /// original node, i.e. the arc connecting the in-node and out-node - /// of \c n. - static Arc arc(const DigraphNode& n) { - return Parent::arc(n); - } - - /// \brief Returns the arc that corresponds to the given original arc. - /// - /// Returns the arc in the adaptor that corresponds to the given - /// original arc. - static Arc arc(const DigraphArc& a) { - return Parent::arc(a); - } - - /// \brief Node map combined from two original node maps - /// - /// This map adaptor class adapts two node maps of the original digraph - /// to get a node map of the split digraph. - /// Its value type is inherited from the first node map type (\c IN). - /// \tparam IN The type of the node map for the in-nodes. - /// \tparam OUT The type of the node map for the out-nodes. - template - class CombinedNodeMap { - public: - - /// The key type of the map - typedef Node Key; - /// The value type of the map - typedef typename IN::Value Value; - - typedef typename MapTraits::ReferenceMapTag ReferenceMapTag; - typedef typename MapTraits::ReturnValue ReturnValue; - typedef typename MapTraits::ConstReturnValue ConstReturnValue; - typedef typename MapTraits::ReturnValue Reference; - typedef typename MapTraits::ConstReturnValue ConstReference; - - /// Constructor - CombinedNodeMap(IN& in_map, OUT& out_map) - : _in_map(in_map), _out_map(out_map) {} - - /// Returns the value associated with the given key. - Value operator[](const Key& key) const { - if (SplitNodesBase::inNode(key)) { - return _in_map[key]; - } else { - return _out_map[key]; - } - } - - /// Returns a reference to the value associated with the given key. - Value& operator[](const Key& key) { - if (SplitNodesBase::inNode(key)) { - return _in_map[key]; - } else { - return _out_map[key]; - } - } - - /// Sets the value associated with the given key. - void set(const Key& key, const Value& value) { - if (SplitNodesBase::inNode(key)) { - _in_map.set(key, value); - } else { - _out_map.set(key, value); - } - } - - private: - - IN& _in_map; - OUT& _out_map; - - }; - - - /// \brief Returns a combined node map - /// - /// This function just returns a combined node map. - template - static CombinedNodeMap - combinedNodeMap(IN& in_map, OUT& out_map) { - return CombinedNodeMap(in_map, out_map); - } - - template - static CombinedNodeMap - combinedNodeMap(const IN& in_map, OUT& out_map) { - return CombinedNodeMap(in_map, out_map); - } - - template - static CombinedNodeMap - combinedNodeMap(IN& in_map, const OUT& out_map) { - return CombinedNodeMap(in_map, out_map); - } - - template - static CombinedNodeMap - combinedNodeMap(const IN& in_map, const OUT& out_map) { - return CombinedNodeMap(in_map, out_map); - } - - /// \brief Arc map combined from an arc map and a node map of the - /// original digraph. - /// - /// This map adaptor class adapts an arc map and a node map of the - /// original digraph to get an arc map of the split digraph. - /// Its value type is inherited from the original arc map type (\c AM). - /// \tparam AM The type of the arc map. - /// \tparam NM the type of the node map. - template - class CombinedArcMap { - public: - - /// The key type of the map - typedef Arc Key; - /// The value type of the map - typedef typename AM::Value Value; - - typedef typename MapTraits::ReferenceMapTag ReferenceMapTag; - typedef typename MapTraits::ReturnValue ReturnValue; - typedef typename MapTraits::ConstReturnValue ConstReturnValue; - typedef typename MapTraits::ReturnValue Reference; - typedef typename MapTraits::ConstReturnValue ConstReference; - - /// Constructor - CombinedArcMap(AM& arc_map, NM& node_map) - : _arc_map(arc_map), _node_map(node_map) {} - - /// Returns the value associated with the given key. - Value operator[](const Key& arc) const { - if (SplitNodesBase::origArc(arc)) { - return _arc_map[arc]; - } else { - return _node_map[arc]; - } - } - - /// Returns a reference to the value associated with the given key. - Value& operator[](const Key& arc) { - if (SplitNodesBase::origArc(arc)) { - return _arc_map[arc]; - } else { - return _node_map[arc]; - } - } - - /// Sets the value associated with the given key. - void set(const Arc& arc, const Value& val) { - if (SplitNodesBase::origArc(arc)) { - _arc_map.set(arc, val); - } else { - _node_map.set(arc, val); - } - } - - private: - - AM& _arc_map; - NM& _node_map; - - }; - - /// \brief Returns a combined arc map - /// - /// This function just returns a combined arc map. - template - static CombinedArcMap - combinedArcMap(ArcMap& arc_map, NodeMap& node_map) { - return CombinedArcMap(arc_map, node_map); - } - - template - static CombinedArcMap - combinedArcMap(const ArcMap& arc_map, NodeMap& node_map) { - return CombinedArcMap(arc_map, node_map); - } - - template - static CombinedArcMap - combinedArcMap(ArcMap& arc_map, const NodeMap& node_map) { - return CombinedArcMap(arc_map, node_map); - } - - template - static CombinedArcMap - combinedArcMap(const ArcMap& arc_map, const NodeMap& node_map) { - return CombinedArcMap(arc_map, node_map); - } - - }; - - /// \brief Returns a (read-only) SplitNodes adaptor - /// - /// This function just returns a (read-only) \ref SplitNodes adaptor. - /// \ingroup graph_adaptors - /// \relates SplitNodes - template - SplitNodes - splitNodes(const DGR& digraph) { - return SplitNodes(digraph); - } - -#undef LEMON_SCOPE_FIX - -} //namespace lemon - -#endif //LEMON_ADAPTORS_H diff --git a/deps/lemon/lemon/arg_parser.cc b/deps/lemon/lemon/arg_parser.cc deleted file mode 100644 index 0eeba8ab6..000000000 --- a/deps/lemon/lemon/arg_parser.cc +++ /dev/null @@ -1,473 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2010 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -namespace lemon { - - void ArgParser::_terminate(ArgParserException::Reason reason) const - { - if(_exit_on_problems) - exit(1); - else throw(ArgParserException(reason)); - } - - - void ArgParser::_showHelp(void *p) - { - (static_cast(p))->showHelp(); - (static_cast(p))->_terminate(ArgParserException::HELP); - } - - ArgParser::ArgParser(int argc, const char * const *argv) - :_argc(argc), _argv(argv), _command_name(argv[0]), - _exit_on_problems(true) { - funcOption("-help","Print a short help message",_showHelp,this); - synonym("help","-help"); - synonym("h","-help"); - } - - ArgParser::~ArgParser() - { - for(Opts::iterator i=_opts.begin();i!=_opts.end();++i) - if(i->second.self_delete) - switch(i->second.type) { - case BOOL: - delete i->second.bool_p; - break; - case STRING: - delete i->second.string_p; - break; - case DOUBLE: - delete i->second.double_p; - break; - case INTEGER: - delete i->second.int_p; - break; - case UNKNOWN: - break; - case FUNC: - break; - } - } - - - ArgParser &ArgParser::intOption(const std::string &name, - const std::string &help, - int value, bool obl) - { - ParData p; - p.int_p=new int(value); - p.self_delete=true; - p.help=help; - p.type=INTEGER; - p.mandatory=obl; - _opts[name]=p; - return *this; - } - - ArgParser &ArgParser::doubleOption(const std::string &name, - const std::string &help, - double value, bool obl) - { - ParData p; - p.double_p=new double(value); - p.self_delete=true; - p.help=help; - p.type=DOUBLE; - p.mandatory=obl; - _opts[name]=p; - return *this; - } - - ArgParser &ArgParser::boolOption(const std::string &name, - const std::string &help, - bool value, bool obl) - { - ParData p; - p.bool_p=new bool(value); - p.self_delete=true; - p.help=help; - p.type=BOOL; - p.mandatory=obl; - _opts[name]=p; - return *this; - } - - ArgParser &ArgParser::stringOption(const std::string &name, - const std::string &help, - std::string value, bool obl) - { - ParData p; - p.string_p=new std::string(value); - p.self_delete=true; - p.help=help; - p.type=STRING; - p.mandatory=obl; - _opts[name]=p; - return *this; - } - - ArgParser &ArgParser::refOption(const std::string &name, - const std::string &help, - int &ref, bool obl) - { - ParData p; - p.int_p=&ref; - p.self_delete=false; - p.help=help; - p.type=INTEGER; - p.mandatory=obl; - _opts[name]=p; - return *this; - } - - ArgParser &ArgParser::refOption(const std::string &name, - const std::string &help, - double &ref, bool obl) - { - ParData p; - p.double_p=&ref; - p.self_delete=false; - p.help=help; - p.type=DOUBLE; - p.mandatory=obl; - _opts[name]=p; - return *this; - } - - ArgParser &ArgParser::refOption(const std::string &name, - const std::string &help, - bool &ref, bool obl) - { - ParData p; - p.bool_p=&ref; - p.self_delete=false; - p.help=help; - p.type=BOOL; - p.mandatory=obl; - _opts[name]=p; - - ref = false; - - return *this; - } - - ArgParser &ArgParser::refOption(const std::string &name, - const std::string &help, - std::string &ref, bool obl) - { - ParData p; - p.string_p=&ref; - p.self_delete=false; - p.help=help; - p.type=STRING; - p.mandatory=obl; - _opts[name]=p; - return *this; - } - - ArgParser &ArgParser::funcOption(const std::string &name, - const std::string &help, - void (*func)(void *),void *data) - { - ParData p; - p.func_p.p=func; - p.func_p.data=data; - p.self_delete=false; - p.help=help; - p.type=FUNC; - p.mandatory=false; - _opts[name]=p; - return *this; - } - - ArgParser &ArgParser::optionGroup(const std::string &group, - const std::string &opt) - { - Opts::iterator i = _opts.find(opt); - LEMON_ASSERT(i!=_opts.end(), "Unknown option: '"+opt+"'"); - LEMON_ASSERT(!(i->second.ingroup), - "Option already in option group: '"+opt+"'"); - GroupData &g=_groups[group]; - g.opts.push_back(opt); - i->second.ingroup=true; - return *this; - } - - ArgParser &ArgParser::onlyOneGroup(const std::string &group) - { - GroupData &g=_groups[group]; - g.only_one=true; - return *this; - } - - ArgParser &ArgParser::synonym(const std::string &syn, - const std::string &opt) - { - Opts::iterator o = _opts.find(opt); - LEMON_ASSERT(o!=_opts.end(), "Unknown option: '"+opt+"'"); - LEMON_ASSERT(_opts.find(syn)==_opts.end(), "Option already used: '"+syn+"'"); - ParData p; - p.help=opt; - p.mandatory=false; - p.syn=true; - _opts[syn]=p; - o->second.has_syn=true; - return *this; - } - - ArgParser &ArgParser::mandatoryGroup(const std::string &group) - { - GroupData &g=_groups[group]; - g.mandatory=true; - return *this; - } - - ArgParser &ArgParser::other(const std::string &name, - const std::string &help) - { - _others_help.push_back(OtherArg(name,help)); - return *this; - } - - void ArgParser::show(std::ostream &os,Opts::const_iterator i) const - { - os << "-" << i->first; - if(i->second.has_syn) - for(Opts::const_iterator j=_opts.begin();j!=_opts.end();++j) - if(j->second.syn&&j->second.help==i->first) - os << "|-" << j->first; - switch(i->second.type) { - case STRING: - os << " str"; - break; - case INTEGER: - os << " int"; - break; - case DOUBLE: - os << " num"; - break; - default: - break; - } - } - - void ArgParser::show(std::ostream &os,Groups::const_iterator i) const - { - GroupData::Opts::const_iterator o=i->second.opts.begin(); - while(o!=i->second.opts.end()) { - show(os,_opts.find(*o)); - ++o; - if(o!=i->second.opts.end()) os<<'|'; - } - } - - void ArgParser::showHelp(Opts::const_iterator i) const - { - if(i->second.help.size()==0||i->second.syn) return; - std::cerr << " "; - show(std::cerr,i); - std::cerr << std::endl; - std::cerr << " " << i->second.help << std::endl; - } - void ArgParser::showHelp(std::vector::const_iterator i) - const - { - if(i->help.size()==0) return; - std::cerr << " " << i->name << std::endl - << " " << i->help << std::endl; - } - - void ArgParser::shortHelp() const - { - const unsigned int LINE_LEN=77; - const std::string indent(" "); - std::cerr << "Usage:\n " << _command_name; - int pos=_command_name.size()+2; - for(Groups::const_iterator g=_groups.begin();g!=_groups.end();++g) { - std::ostringstream cstr; - cstr << ' '; - if(!g->second.mandatory) cstr << '['; - show(cstr,g); - if(!g->second.mandatory) cstr << ']'; - if(pos+cstr.str().size()>LINE_LEN) { - std::cerr << std::endl << indent; - pos=indent.size(); - } - std::cerr << cstr.str(); - pos+=cstr.str().size(); - } - for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i) - if(!i->second.ingroup&&!i->second.syn) { - std::ostringstream cstr; - cstr << ' '; - if(!i->second.mandatory) cstr << '['; - show(cstr,i); - if(!i->second.mandatory) cstr << ']'; - if(pos+cstr.str().size()>LINE_LEN) { - std::cerr << std::endl << indent; - pos=indent.size(); - } - std::cerr << cstr.str(); - pos+=cstr.str().size(); - } - for(std::vector::const_iterator i=_others_help.begin(); - i!=_others_help.end();++i) - { - std::ostringstream cstr; - cstr << ' ' << i->name; - - if(pos+cstr.str().size()>LINE_LEN) { - std::cerr << std::endl << indent; - pos=indent.size(); - } - std::cerr << cstr.str(); - pos+=cstr.str().size(); - } - std::cerr << std::endl; - } - - void ArgParser::showHelp() const - { - shortHelp(); - std::cerr << "Where:\n"; - for(std::vector::const_iterator i=_others_help.begin(); - i!=_others_help.end();++i) showHelp(i); - for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i) showHelp(i); - _terminate(ArgParserException::HELP); - } - - - void ArgParser::unknownOpt(std::string arg) const - { - std::cerr << "\nUnknown option: " << arg << "\n"; - std::cerr << "\nType '" << _command_name << - " --help' to obtain a short summary on the usage.\n\n"; - _terminate(ArgParserException::UNKNOWN_OPT); - } - - void ArgParser::requiresValue(std::string arg, OptType t) const - { - std::cerr << "Argument '" << arg << "' requires a"; - switch(t) { - case STRING: - std::cerr << " string"; - break; - case INTEGER: - std::cerr << "n integer"; - break; - case DOUBLE: - std::cerr << " floating point"; - break; - default: - break; - } - std::cerr << " value\n\n"; - showHelp(); - } - - - void ArgParser::checkMandatories() const - { - bool ok=true; - for(Opts::const_iterator i=_opts.begin();i!=_opts.end();++i) - if(i->second.mandatory&&!i->second.set) - { - if(ok) - std::cerr << _command_name - << ": The following mandatory arguments are missing.\n"; - ok=false; - showHelp(i); - } - for(Groups::const_iterator i=_groups.begin();i!=_groups.end();++i) - if(i->second.mandatory||i->second.only_one) - { - int set=0; - for(GroupData::Opts::const_iterator o=i->second.opts.begin(); - o!=i->second.opts.end();++o) - if(_opts.find(*o)->second.set) ++set; - if(i->second.mandatory&&!set) { - std::cerr << _command_name << - ": At least one of the following arguments is mandatory.\n"; - ok=false; - for(GroupData::Opts::const_iterator o=i->second.opts.begin(); - o!=i->second.opts.end();++o) - showHelp(_opts.find(*o)); - } - if(i->second.only_one&&set>1) { - std::cerr << _command_name << - ": At most one of the following arguments can be given.\n"; - ok=false; - for(GroupData::Opts::const_iterator o=i->second.opts.begin(); - o!=i->second.opts.end();++o) - showHelp(_opts.find(*o)); - } - } - if(!ok) { - std::cerr << "\nType '" << _command_name << - " --help' to obtain a short summary on the usage.\n\n"; - _terminate(ArgParserException::INVALID_OPT); - } - } - - ArgParser &ArgParser::parse() - { - for(int ar=1; ar<_argc; ++ar) { - std::string arg(_argv[ar]); - if (arg[0] != '-' || arg.size() == 1) { - _file_args.push_back(arg); - } - else { - Opts::iterator i = _opts.find(arg.substr(1)); - if(i==_opts.end()) unknownOpt(arg); - else { - if(i->second.syn) i=_opts.find(i->second.help); - ParData &p(i->second); - if (p.type==BOOL) *p.bool_p=true; - else if (p.type==FUNC) p.func_p.p(p.func_p.data); - else if(++ar==_argc) requiresValue(arg, p.type); - else { - std::string val(_argv[ar]); - std::istringstream vals(val); - switch(p.type) { - case STRING: - *p.string_p=val; - break; - case INTEGER: - vals >> *p.int_p; - break; - case DOUBLE: - vals >> *p.double_p; - break; - default: - break; - } - if(p.type!=STRING&&(!vals||!vals.eof())) - requiresValue(arg, p.type); - } - p.set = true; - } - } - } - checkMandatories(); - - return *this; - } - -} diff --git a/deps/lemon/lemon/arg_parser.h b/deps/lemon/lemon/arg_parser.h deleted file mode 100644 index 3fbe75c97..000000000 --- a/deps/lemon/lemon/arg_parser.h +++ /dev/null @@ -1,440 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2010 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_ARG_PARSER_H -#define LEMON_ARG_PARSER_H - -#include -#include -#include -#include -#include -#include -#include -#include - -///\ingroup misc -///\file -///\brief A tool to parse command line arguments. - -namespace lemon { - - ///Exception used by ArgParser - - ///Exception used by ArgParser. - /// - class ArgParserException : public Exception { - public: - /// Reasons for failure - - /// Reasons for failure. - /// - enum Reason { - HELP, ///< --help option was given. - UNKNOWN_OPT, ///< Unknown option was given. - INVALID_OPT ///< Invalid combination of options. - }; - - private: - Reason _reason; - - public: - ///Constructor - ArgParserException(Reason r) throw() : _reason(r) {} - ///Virtual destructor - virtual ~ArgParserException() throw() {} - ///A short description of the exception - virtual const char* what() const throw() { - switch(_reason) - { - case HELP: - return "lemon::ArgParseException: ask for help"; - break; - case UNKNOWN_OPT: - return "lemon::ArgParseException: unknown option"; - break; - case INVALID_OPT: - return "lemon::ArgParseException: invalid combination of options"; - break; - } - return ""; - } - ///Return the reason for the failure - Reason reason() const {return _reason; } - }; - - - ///Command line arguments parser - - ///\ingroup misc - ///Command line arguments parser. - /// - ///For a complete example see the \ref arg_parser_demo.cc demo file. - class ArgParser { - - static void _showHelp(void *p); - protected: - - int _argc; - const char * const *_argv; - - enum OptType { UNKNOWN=0, BOOL=1, STRING=2, DOUBLE=3, INTEGER=4, FUNC=5 }; - - class ParData { - public: - union { - bool *bool_p; - int *int_p; - double *double_p; - std::string *string_p; - struct { - void (*p)(void *); - void *data; - } func_p; - - }; - std::string help; - bool mandatory; - OptType type; - bool set; - bool ingroup; - bool has_syn; - bool syn; - bool self_delete; - ParData() : mandatory(false), type(UNKNOWN), set(false), ingroup(false), - has_syn(false), syn(false), self_delete(false) {} - }; - - typedef std::map Opts; - Opts _opts; - - class GroupData - { - public: - typedef std::list Opts; - Opts opts; - bool only_one; - bool mandatory; - GroupData() :only_one(false), mandatory(false) {} - }; - - typedef std::map Groups; - Groups _groups; - - struct OtherArg - { - std::string name; - std::string help; - OtherArg(std::string n, std::string h) :name(n), help(h) {} - - }; - - std::vector _others_help; - std::vector _file_args; - std::string _command_name; - - - private: - //Bind a function to an option. - - //\param name The name of the option. The leading '-' must be omitted. - //\param help A help string. - //\retval func The function to be called when the option is given. It - // must be of type "void f(void *)" - //\param data Data to be passed to \c func - ArgParser &funcOption(const std::string &name, - const std::string &help, - void (*func)(void *),void *data); - - bool _exit_on_problems; - - void _terminate(ArgParserException::Reason reason) const; - - public: - - ///Constructor - ArgParser(int argc, const char * const *argv); - - ~ArgParser(); - - ///\name Options - /// - - ///@{ - - ///Add a new integer type option - - ///Add a new integer type option. - ///\param name The name of the option. The leading '-' must be omitted. - ///\param help A help string. - ///\param value A default value for the option. - ///\param obl Indicate if the option is mandatory. - ArgParser &intOption(const std::string &name, - const std::string &help, - int value=0, bool obl=false); - - ///Add a new floating point type option - - ///Add a new floating point type option. - ///\param name The name of the option. The leading '-' must be omitted. - ///\param help A help string. - ///\param value A default value for the option. - ///\param obl Indicate if the option is mandatory. - ArgParser &doubleOption(const std::string &name, - const std::string &help, - double value=0, bool obl=false); - - ///Add a new bool type option - - ///Add a new bool type option. - ///\param name The name of the option. The leading '-' must be omitted. - ///\param help A help string. - ///\param value A default value for the option. - ///\param obl Indicate if the option is mandatory. - ///\note A mandatory bool obtion is of very little use. - ArgParser &boolOption(const std::string &name, - const std::string &help, - bool value=false, bool obl=false); - - ///Add a new string type option - - ///Add a new string type option. - ///\param name The name of the option. The leading '-' must be omitted. - ///\param help A help string. - ///\param value A default value for the option. - ///\param obl Indicate if the option is mandatory. - ArgParser &stringOption(const std::string &name, - const std::string &help, - std::string value="", bool obl=false); - - ///Give help string for non-parsed arguments. - - ///With this function you can give help string for non-parsed arguments. - ///The parameter \c name will be printed in the short usage line, while - ///\c help gives a more detailed description. - ArgParser &other(const std::string &name, - const std::string &help=""); - - ///@} - - ///\name Options with External Storage - ///Using this functions, the value of the option will be directly written - ///into a variable once the option appears in the command line. - - ///@{ - - ///Add a new integer type option with a storage reference - - ///Add a new integer type option with a storage reference. - ///\param name The name of the option. The leading '-' must be omitted. - ///\param help A help string. - ///\param obl Indicate if the option is mandatory. - ///\retval ref The value of the argument will be written to this variable. - ArgParser &refOption(const std::string &name, - const std::string &help, - int &ref, bool obl=false); - - ///Add a new floating type option with a storage reference - - ///Add a new floating type option with a storage reference. - ///\param name The name of the option. The leading '-' must be omitted. - ///\param help A help string. - ///\param obl Indicate if the option is mandatory. - ///\retval ref The value of the argument will be written to this variable. - ArgParser &refOption(const std::string &name, - const std::string &help, - double &ref, bool obl=false); - - ///Add a new bool type option with a storage reference - - ///Add a new bool type option with a storage reference. - ///\param name The name of the option. The leading '-' must be omitted. - ///\param help A help string. - ///\param obl Indicate if the option is mandatory. - ///\retval ref The value of the argument will be written to this variable. - ///\note A mandatory bool obtion is of very little use. - ArgParser &refOption(const std::string &name, - const std::string &help, - bool &ref, bool obl=false); - - ///Add a new string type option with a storage reference - - ///Add a new string type option with a storage reference. - ///\param name The name of the option. The leading '-' must be omitted. - ///\param help A help string. - ///\param obl Indicate if the option is mandatory. - ///\retval ref The value of the argument will be written to this variable. - ArgParser &refOption(const std::string &name, - const std::string &help, - std::string &ref, bool obl=false); - - ///@} - - ///\name Option Groups and Synonyms - /// - - ///@{ - - ///Bundle some options into a group - - /// You can group some option by calling this function repeatedly for each - /// option to be grouped with the same groupname. - ///\param group The group name. - ///\param opt The option name. - ArgParser &optionGroup(const std::string &group, - const std::string &opt); - - ///Make the members of a group exclusive - - ///If you call this function for a group, than at most one of them can be - ///given at the same time. - ArgParser &onlyOneGroup(const std::string &group); - - ///Make a group mandatory - - ///Using this function, at least one of the members of \c group - ///must be given. - ArgParser &mandatoryGroup(const std::string &group); - - ///Create synonym to an option - - ///With this function you can create a synonym \c syn of the - ///option \c opt. - ArgParser &synonym(const std::string &syn, - const std::string &opt); - - ///@} - - private: - void show(std::ostream &os,Opts::const_iterator i) const; - void show(std::ostream &os,Groups::const_iterator i) const; - void showHelp(Opts::const_iterator i) const; - void showHelp(std::vector::const_iterator i) const; - - void unknownOpt(std::string arg) const; - - void requiresValue(std::string arg, OptType t) const; - void checkMandatories() const; - - void shortHelp() const; - void showHelp() const; - public: - - ///Start the parsing process - ArgParser &parse(); - - /// Synonym for parse() - ArgParser &run() - { - return parse(); - } - - ///Give back the command name (the 0th argument) - const std::string &commandName() const { return _command_name; } - - ///Check if an opion has been given to the command. - bool given(std::string op) const - { - Opts::const_iterator i = _opts.find(op); - return i!=_opts.end()?i->second.set:false; - } - - - ///Magic type for operator[] - - ///This is the type of the return value of ArgParser::operator[](). - ///It automatically converts to \c int, \c double, \c bool or - ///\c std::string if the type of the option matches, which is checked - ///with an \ref LEMON_ASSERT "assertion" (i.e. it performs runtime - ///type checking). - class RefType - { - const ArgParser &_parser; - std::string _name; - public: - ///\e - RefType(const ArgParser &p,const std::string &n) :_parser(p),_name(n) {} - ///\e - operator bool() - { - Opts::const_iterator i = _parser._opts.find(_name); - LEMON_ASSERT(i!=_parser._opts.end(), - std::string()+"Unkown option: '"+_name+"'"); - LEMON_ASSERT(i->second.type==ArgParser::BOOL, - std::string()+"'"+_name+"' is a bool option"); - return *(i->second.bool_p); - } - ///\e - operator std::string() - { - Opts::const_iterator i = _parser._opts.find(_name); - LEMON_ASSERT(i!=_parser._opts.end(), - std::string()+"Unkown option: '"+_name+"'"); - LEMON_ASSERT(i->second.type==ArgParser::STRING, - std::string()+"'"+_name+"' is a string option"); - return *(i->second.string_p); - } - ///\e - operator double() - { - Opts::const_iterator i = _parser._opts.find(_name); - LEMON_ASSERT(i!=_parser._opts.end(), - std::string()+"Unkown option: '"+_name+"'"); - LEMON_ASSERT(i->second.type==ArgParser::DOUBLE || - i->second.type==ArgParser::INTEGER, - std::string()+"'"+_name+"' is a floating point option"); - return i->second.type==ArgParser::DOUBLE ? - *(i->second.double_p) : *(i->second.int_p); - } - ///\e - operator int() - { - Opts::const_iterator i = _parser._opts.find(_name); - LEMON_ASSERT(i!=_parser._opts.end(), - std::string()+"Unkown option: '"+_name+"'"); - LEMON_ASSERT(i->second.type==ArgParser::INTEGER, - std::string()+"'"+_name+"' is an integer option"); - return *(i->second.int_p); - } - - }; - - ///Give back the value of an option - - ///Give back the value of an option. - ///\sa RefType - RefType operator[](const std::string &n) const - { - return RefType(*this, n); - } - - ///Give back the non-option type arguments. - - ///Give back a reference to a vector consisting of the program arguments - ///not starting with a '-' character. - const std::vector &files() const { return _file_args; } - - ///Throw instead of exit in case of problems - void throwOnProblems() - { - _exit_on_problems=false; - } - }; -} - -#endif // LEMON_ARG_PARSER_H diff --git a/deps/lemon/lemon/assert.h b/deps/lemon/lemon/assert.h deleted file mode 100644 index f6c1dfc8e..000000000 --- a/deps/lemon/lemon/assert.h +++ /dev/null @@ -1,214 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_ASSERT_H -#define LEMON_ASSERT_H - -/// \ingroup exceptions -/// \file -/// \brief Extended assertion handling - -#include - -namespace lemon { - - inline void assert_fail_abort(const char *file, int line, - const char *function, const char* message, - const char *assertion) - { - std::cerr << file << ":" << line << ": "; - if (function) - std::cerr << function << ": "; - std::cerr << message; - if (assertion) - std::cerr << " (assertion '" << assertion << "' failed)"; - std::cerr << std::endl; - std::abort(); - } - - namespace _assert_bits { - - - inline const char* cstringify(const std::string& str) { - return str.c_str(); - } - - inline const char* cstringify(const char* str) { - return str; - } - } -} - -#endif // LEMON_ASSERT_H - -#undef LEMON_ASSERT -#undef LEMON_DEBUG - -#if (defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \ - (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1 -#error "LEMON assertion system is not set properly" -#endif - -#if ((defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \ - (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 || \ - defined(LEMON_ENABLE_ASSERTS)) && \ - (defined(LEMON_DISABLE_ASSERTS) || \ - defined(NDEBUG)) -#error "LEMON assertion system is not set properly" -#endif - - -#if defined LEMON_ASSERT_ABORT -# undef LEMON_ASSERT_HANDLER -# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort -#elif defined LEMON_ASSERT_CUSTOM -# undef LEMON_ASSERT_HANDLER -# ifndef LEMON_CUSTOM_ASSERT_HANDLER -# error "LEMON_CUSTOM_ASSERT_HANDLER is not set" -# endif -# define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER -#elif defined LEMON_DISABLE_ASSERTS -# undef LEMON_ASSERT_HANDLER -#elif defined NDEBUG -# undef LEMON_ASSERT_HANDLER -#else -# define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort -#endif - -#ifndef LEMON_FUNCTION_NAME -# if defined __GNUC__ -# define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__) -# elif defined _MSC_VER -# define LEMON_FUNCTION_NAME (__FUNCSIG__) -# elif __STDC_VERSION__ >= 199901L -# define LEMON_FUNCTION_NAME (__func__) -# else -# define LEMON_FUNCTION_NAME ("") -# endif -#endif - -#ifdef DOXYGEN - -/// \ingroup exceptions -/// -/// \brief Macro for assertion with customizable message -/// -/// Macro for assertion with customizable message. -/// \param exp An expression that must be convertible to \c bool. If it is \c -/// false, then an assertion is raised. The concrete behaviour depends on the -/// settings of the assertion system. -/// \param msg A const char* parameter, which can be used to provide -/// information about the circumstances of the failed assertion. -/// -/// The assertions are enabled in the default behaviour. -/// You can disable them with the following code: -/// \code -/// #define LEMON_DISABLE_ASSERTS -/// \endcode -/// or with compilation parameters: -/// \code -/// g++ -DLEMON_DISABLE_ASSERTS -/// make CXXFLAGS='-DLEMON_DISABLE_ASSERTS' -/// \endcode -/// The checking is also disabled when the standard macro \c NDEBUG is defined. -/// -/// As a default behaviour the failed assertion prints a short log message to -/// the standard error and aborts the execution. -/// -/// However, the following modes can be used in the assertion system: -/// - \c LEMON_ASSERT_ABORT The failed assertion prints a short log message to -/// the standard error and aborts the program. It is the default behaviour. -/// - \c LEMON_ASSERT_CUSTOM The user can define own assertion handler -/// function. -/// \code -/// void custom_assert_handler(const char* file, int line, -/// const char* function, const char* message, -/// const char* assertion); -/// \endcode -/// The name of the function should be defined as the \c -/// LEMON_CUSTOM_ASSERT_HANDLER macro name. -/// \code -/// #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler -/// \endcode -/// Whenever an assertion is occured, the custom assertion -/// handler is called with appropiate parameters. -/// -/// The assertion mode can also be changed within one compilation unit. -/// If the macros are redefined with other settings and the -/// \ref lemon/assert.h "assert.h" file is reincluded, then the -/// behaviour is changed appropiately to the new settings. -# define LEMON_ASSERT(exp, msg) \ - (static_cast (!!(exp) ? 0 : ( \ - LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ - LEMON_FUNCTION_NAME, \ - ::lemon::_assert_bits::cstringify(msg), #exp), 0))) - -/// \ingroup exceptions -/// -/// \brief Macro for internal assertions -/// -/// Macro for internal assertions, it is used in the library to check -/// the consistency of results of algorithms, several pre- and -/// postconditions and invariants. The checking is disabled by -/// default, but it can be turned on with the macro \c -/// LEMON_ENABLE_DEBUG. -/// \code -/// #define LEMON_ENABLE_DEBUG -/// \endcode -/// or with compilation parameters: -/// \code -/// g++ -DLEMON_ENABLE_DEBUG -/// make CXXFLAGS='-DLEMON_ENABLE_DEBUG' -/// \endcode -/// -/// This macro works like the \c LEMON_ASSERT macro, therefore the -/// current behaviour depends on the settings of \c LEMON_ASSERT -/// macro. -/// -/// \see LEMON_ASSERT -# define LEMON_DEBUG(exp, msg) \ - (static_cast (!!(exp) ? 0 : ( \ - LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ - LEMON_FUNCTION_NAME, \ - ::lemon::_assert_bits::cstringify(msg), #exp), 0))) - -#else - -# ifndef LEMON_ASSERT_HANDLER -# define LEMON_ASSERT(exp, msg) (static_cast(0)) -# define LEMON_DEBUG(exp, msg) (static_cast(0)) -# else -# define LEMON_ASSERT(exp, msg) \ - (static_cast (!!(exp) ? 0 : ( \ - LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ - LEMON_FUNCTION_NAME, \ - ::lemon::_assert_bits::cstringify(msg), \ - #exp), 0))) -# if defined LEMON_ENABLE_DEBUG -# define LEMON_DEBUG(exp, msg) \ - (static_cast (!!(exp) ? 0 : ( \ - LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ - LEMON_FUNCTION_NAME, \ - ::lemon::_assert_bits::cstringify(msg), \ - #exp), 0))) -# else -# define LEMON_DEBUG(exp, msg) (static_cast(0)) -# endif -# endif - -#endif diff --git a/deps/lemon/lemon/base.cc b/deps/lemon/lemon/base.cc deleted file mode 100644 index 3a7dcb595..000000000 --- a/deps/lemon/lemon/base.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\file -///\brief Some basic non-inline functions and static global data. - -#include -#include -#include -namespace lemon { - - float Tolerance::def_epsilon = static_cast(1e-4); - double Tolerance::def_epsilon = 1e-10; - long double Tolerance::def_epsilon = 1e-14; - - TimeStamp::Format TimeStamp::_format = TimeStamp::NORMAL; - -} //namespace lemon diff --git a/deps/lemon/lemon/bellman_ford.h b/deps/lemon/lemon/bellman_ford.h deleted file mode 100644 index 310758ebb..000000000 --- a/deps/lemon/lemon/bellman_ford.h +++ /dev/null @@ -1,1116 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BELLMAN_FORD_H -#define LEMON_BELLMAN_FORD_H - -/// \ingroup shortest_path -/// \file -/// \brief Bellman-Ford algorithm. - -#include -#include -#include -#include -#include -#include - -#include - -namespace lemon { - - /// \brief Default OperationTraits for the BellmanFord algorithm class. - /// - /// This operation traits class defines all computational operations - /// and constants that are used in the Bellman-Ford algorithm. - /// The default implementation is based on the \c numeric_limits class. - /// If the numeric type does not have infinity value, then the maximum - /// value is used as extremal infinity value. - template < - typename V, - bool has_inf = std::numeric_limits::has_infinity> - struct BellmanFordDefaultOperationTraits { - /// \e - typedef V Value; - /// \brief Gives back the zero value of the type. - static Value zero() { - return static_cast(0); - } - /// \brief Gives back the positive infinity value of the type. - static Value infinity() { - return std::numeric_limits::infinity(); - } - /// \brief Gives back the sum of the given two elements. - static Value plus(const Value& left, const Value& right) { - return left + right; - } - /// \brief Gives back \c true only if the first value is less than - /// the second. - static bool less(const Value& left, const Value& right) { - return left < right; - } - }; - - template - struct BellmanFordDefaultOperationTraits { - typedef V Value; - static Value zero() { - return static_cast(0); - } - static Value infinity() { - return std::numeric_limits::max(); - } - static Value plus(const Value& left, const Value& right) { - if (left == infinity() || right == infinity()) return infinity(); - return left + right; - } - static bool less(const Value& left, const Value& right) { - return left < right; - } - }; - - /// \brief Default traits class of BellmanFord class. - /// - /// Default traits class of BellmanFord class. - /// \param GR The type of the digraph. - /// \param LEN The type of the length map. - template - struct BellmanFordDefaultTraits { - /// The type of the digraph the algorithm runs on. - typedef GR Digraph; - - /// \brief The type of the map that stores the arc lengths. - /// - /// The type of the map that stores the arc lengths. - /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. - typedef LEN LengthMap; - - /// The type of the arc lengths. - typedef typename LEN::Value Value; - - /// \brief Operation traits for Bellman-Ford algorithm. - /// - /// It defines the used operations and the infinity value for the - /// given \c Value type. - /// \see BellmanFordDefaultOperationTraits - typedef BellmanFordDefaultOperationTraits OperationTraits; - - /// \brief The type of the map that stores the last arcs of the - /// shortest paths. - /// - /// The type of the map that stores the last - /// arcs of the shortest paths. - /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename GR::template NodeMap PredMap; - - /// \brief Instantiates a \c PredMap. - /// - /// This function instantiates a \ref PredMap. - /// \param g is the digraph to which we would like to define the - /// \ref PredMap. - static PredMap *createPredMap(const GR& g) { - return new PredMap(g); - } - - /// \brief The type of the map that stores the distances of the nodes. - /// - /// The type of the map that stores the distances of the nodes. - /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename GR::template NodeMap DistMap; - - /// \brief Instantiates a \c DistMap. - /// - /// This function instantiates a \ref DistMap. - /// \param g is the digraph to which we would like to define the - /// \ref DistMap. - static DistMap *createDistMap(const GR& g) { - return new DistMap(g); - } - - }; - - /// \brief %BellmanFord algorithm class. - /// - /// \ingroup shortest_path - /// This class provides an efficient implementation of the Bellman-Ford - /// algorithm. The maximum time complexity of the algorithm is - /// O(nm). - /// - /// The Bellman-Ford algorithm solves the single-source shortest path - /// problem when the arcs can have negative lengths, but the digraph - /// should not contain directed cycles with negative total length. - /// If all arc costs are non-negative, consider to use the Dijkstra - /// algorithm instead, since it is more efficient. - /// - /// The arc lengths are passed to the algorithm using a - /// \ref concepts::ReadMap "ReadMap", so it is easy to change it to any - /// kind of length. The type of the length values is determined by the - /// \ref concepts::ReadMap::Value "Value" type of the length map. - /// - /// There is also a \ref bellmanFord() "function-type interface" for the - /// Bellman-Ford algorithm, which is convenient in the simplier cases and - /// it can be used easier. - /// - /// \tparam GR The type of the digraph the algorithm runs on. - /// The default type is \ref ListDigraph. - /// \tparam LEN A \ref concepts::ReadMap "readable" arc map that specifies - /// the lengths of the arcs. The default map type is - /// \ref concepts::Digraph::ArcMap "GR::ArcMap". - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref BellmanFordDefaultTraits - /// "BellmanFordDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template , - typename TR=BellmanFordDefaultTraits > -#endif - class BellmanFord { - public: - - ///The type of the underlying digraph. - typedef typename TR::Digraph Digraph; - - /// \brief The type of the arc lengths. - typedef typename TR::LengthMap::Value Value; - /// \brief The type of the map that stores the arc lengths. - typedef typename TR::LengthMap LengthMap; - /// \brief The type of the map that stores the last - /// arcs of the shortest paths. - typedef typename TR::PredMap PredMap; - /// \brief The type of the map that stores the distances of the nodes. - typedef typename TR::DistMap DistMap; - /// The type of the paths. - typedef PredMapPath Path; - ///\brief The \ref lemon::BellmanFordDefaultOperationTraits - /// "operation traits class" of the algorithm. - typedef typename TR::OperationTraits OperationTraits; - - ///\brief The \ref lemon::BellmanFordDefaultTraits "traits class" - ///of the algorithm. - typedef TR Traits; - - private: - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::OutArcIt OutArcIt; - - // Pointer to the underlying digraph. - const Digraph *_gr; - // Pointer to the length map - const LengthMap *_length; - // Pointer to the map of predecessors arcs. - PredMap *_pred; - // Indicates if _pred is locally allocated (true) or not. - bool _local_pred; - // Pointer to the map of distances. - DistMap *_dist; - // Indicates if _dist is locally allocated (true) or not. - bool _local_dist; - - typedef typename Digraph::template NodeMap MaskMap; - MaskMap *_mask; - - std::vector _process; - - // Creates the maps if necessary. - void create_maps() { - if(!_pred) { - _local_pred = true; - _pred = Traits::createPredMap(*_gr); - } - if(!_dist) { - _local_dist = true; - _dist = Traits::createDistMap(*_gr); - } - if(!_mask) { - _mask = new MaskMap(*_gr); - } - } - - public : - - typedef BellmanFord Create; - - /// \name Named Template Parameters - - ///@{ - - template - struct SetPredMapTraits : public Traits { - typedef T PredMap; - static PredMap *createPredMap(const Digraph&) { - LEMON_ASSERT(false, "PredMap is not initialized"); - return 0; // ignore warnings - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c PredMap type. - /// - /// \ref named-templ-param "Named parameter" for setting - /// \c PredMap type. - /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. - template - struct SetPredMap - : public BellmanFord< Digraph, LengthMap, SetPredMapTraits > { - typedef BellmanFord< Digraph, LengthMap, SetPredMapTraits > Create; - }; - - template - struct SetDistMapTraits : public Traits { - typedef T DistMap; - static DistMap *createDistMap(const Digraph&) { - LEMON_ASSERT(false, "DistMap is not initialized"); - return 0; // ignore warnings - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c DistMap type. - /// - /// \ref named-templ-param "Named parameter" for setting - /// \c DistMap type. - /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. - template - struct SetDistMap - : public BellmanFord< Digraph, LengthMap, SetDistMapTraits > { - typedef BellmanFord< Digraph, LengthMap, SetDistMapTraits > Create; - }; - - template - struct SetOperationTraitsTraits : public Traits { - typedef T OperationTraits; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c OperationTraits type. - /// - /// \ref named-templ-param "Named parameter" for setting - /// \c OperationTraits type. - /// For more information, see \ref BellmanFordDefaultOperationTraits. - template - struct SetOperationTraits - : public BellmanFord< Digraph, LengthMap, SetOperationTraitsTraits > { - typedef BellmanFord< Digraph, LengthMap, SetOperationTraitsTraits > - Create; - }; - - ///@} - - protected: - - BellmanFord() {} - - public: - - /// \brief Constructor. - /// - /// Constructor. - /// \param g The digraph the algorithm runs on. - /// \param length The length map used by the algorithm. - BellmanFord(const Digraph& g, const LengthMap& length) : - _gr(&g), _length(&length), - _pred(0), _local_pred(false), - _dist(0), _local_dist(false), _mask(0) {} - - ///Destructor. - ~BellmanFord() { - if(_local_pred) delete _pred; - if(_local_dist) delete _dist; - if(_mask) delete _mask; - } - - /// \brief Sets the length map. - /// - /// Sets the length map. - /// \return (*this) - BellmanFord &lengthMap(const LengthMap &map) { - _length = ↦ - return *this; - } - - /// \brief Sets the map that stores the predecessor arcs. - /// - /// Sets the map that stores the predecessor arcs. - /// If you don't use this function before calling \ref run() - /// or \ref init(), an instance will be allocated automatically. - /// The destructor deallocates this automatically allocated map, - /// of course. - /// \return (*this) - BellmanFord &predMap(PredMap &map) { - if(_local_pred) { - delete _pred; - _local_pred=false; - } - _pred = ↦ - return *this; - } - - /// \brief Sets the map that stores the distances of the nodes. - /// - /// Sets the map that stores the distances of the nodes calculated - /// by the algorithm. - /// If you don't use this function before calling \ref run() - /// or \ref init(), an instance will be allocated automatically. - /// The destructor deallocates this automatically allocated map, - /// of course. - /// \return (*this) - BellmanFord &distMap(DistMap &map) { - if(_local_dist) { - delete _dist; - _local_dist=false; - } - _dist = ↦ - return *this; - } - - /// \name Execution Control - /// The simplest way to execute the Bellman-Ford algorithm is to use - /// one of the member functions called \ref run().\n - /// If you need better control on the execution, you have to call - /// \ref init() first, then you can add several source nodes - /// with \ref addSource(). Finally the actual path computation can be - /// performed with \ref start(), \ref checkedStart() or - /// \ref limitedStart(). - - ///@{ - - /// \brief Initializes the internal data structures. - /// - /// Initializes the internal data structures. The optional parameter - /// is the initial distance of each node. - void init(const Value value = OperationTraits::infinity()) { - create_maps(); - for (NodeIt it(*_gr); it != INVALID; ++it) { - _pred->set(it, INVALID); - _dist->set(it, value); - } - _process.clear(); - if (OperationTraits::less(value, OperationTraits::infinity())) { - for (NodeIt it(*_gr); it != INVALID; ++it) { - _process.push_back(it); - _mask->set(it, true); - } - } else { - for (NodeIt it(*_gr); it != INVALID; ++it) { - _mask->set(it, false); - } - } - } - - /// \brief Adds a new source node. - /// - /// This function adds a new source node. The optional second parameter - /// is the initial distance of the node. - void addSource(Node source, Value dst = OperationTraits::zero()) { - _dist->set(source, dst); - if (!(*_mask)[source]) { - _process.push_back(source); - _mask->set(source, true); - } - } - - /// \brief Executes one round from the Bellman-Ford algorithm. - /// - /// If the algoritm calculated the distances in the previous round - /// exactly for the paths of at most \c k arcs, then this function - /// will calculate the distances exactly for the paths of at most - /// k+1 arcs. Performing \c k iterations using this function - /// calculates the shortest path distances exactly for the paths - /// consisting of at most \c k arcs. - /// - /// \warning The paths with limited arc number cannot be retrieved - /// easily with \ref path() or \ref predArc() functions. If you also - /// need the shortest paths and not only the distances, you should - /// store the \ref predMap() "predecessor map" after each iteration - /// and build the path manually. - /// - /// \return \c true when the algorithm have not found more shorter - /// paths. - /// - /// \see ActiveIt - bool processNextRound() { - for (int i = 0; i < int(_process.size()); ++i) { - _mask->set(_process[i], false); - } - std::vector nextProcess; - std::vector values(_process.size()); - for (int i = 0; i < int(_process.size()); ++i) { - values[i] = (*_dist)[_process[i]]; - } - for (int i = 0; i < int(_process.size()); ++i) { - for (OutArcIt it(*_gr, _process[i]); it != INVALID; ++it) { - Node target = _gr->target(it); - Value relaxed = OperationTraits::plus(values[i], (*_length)[it]); - if (OperationTraits::less(relaxed, (*_dist)[target])) { - _pred->set(target, it); - _dist->set(target, relaxed); - if (!(*_mask)[target]) { - _mask->set(target, true); - nextProcess.push_back(target); - } - } - } - } - _process.swap(nextProcess); - return _process.empty(); - } - - /// \brief Executes one weak round from the Bellman-Ford algorithm. - /// - /// If the algorithm calculated the distances in the previous round - /// at least for the paths of at most \c k arcs, then this function - /// will calculate the distances at least for the paths of at most - /// k+1 arcs. - /// This function does not make it possible to calculate the shortest - /// path distances exactly for paths consisting of at most \c k arcs, - /// this is why it is called weak round. - /// - /// \return \c true when the algorithm have not found more shorter - /// paths. - /// - /// \see ActiveIt - bool processNextWeakRound() { - for (int i = 0; i < int(_process.size()); ++i) { - _mask->set(_process[i], false); - } - std::vector nextProcess; - for (int i = 0; i < int(_process.size()); ++i) { - for (OutArcIt it(*_gr, _process[i]); it != INVALID; ++it) { - Node target = _gr->target(it); - Value relaxed = - OperationTraits::plus((*_dist)[_process[i]], (*_length)[it]); - if (OperationTraits::less(relaxed, (*_dist)[target])) { - _pred->set(target, it); - _dist->set(target, relaxed); - if (!(*_mask)[target]) { - _mask->set(target, true); - nextProcess.push_back(target); - } - } - } - } - _process.swap(nextProcess); - return _process.empty(); - } - - /// \brief Executes the algorithm. - /// - /// Executes the algorithm. - /// - /// This method runs the Bellman-Ford algorithm from the root node(s) - /// in order to compute the shortest path to each node. - /// - /// The algorithm computes - /// - the shortest path tree (forest), - /// - the distance of each node from the root(s). - /// - /// \pre init() must be called and at least one root node should be - /// added with addSource() before using this function. - void start() { - int num = countNodes(*_gr) - 1; - for (int i = 0; i < num; ++i) { - if (processNextWeakRound()) break; - } - } - - /// \brief Executes the algorithm and checks the negative cycles. - /// - /// Executes the algorithm and checks the negative cycles. - /// - /// This method runs the Bellman-Ford algorithm from the root node(s) - /// in order to compute the shortest path to each node and also checks - /// if the digraph contains cycles with negative total length. - /// - /// The algorithm computes - /// - the shortest path tree (forest), - /// - the distance of each node from the root(s). - /// - /// \return \c false if there is a negative cycle in the digraph. - /// - /// \pre init() must be called and at least one root node should be - /// added with addSource() before using this function. - bool checkedStart() { - int num = countNodes(*_gr); - for (int i = 0; i < num; ++i) { - if (processNextWeakRound()) return true; - } - return _process.empty(); - } - - /// \brief Executes the algorithm with arc number limit. - /// - /// Executes the algorithm with arc number limit. - /// - /// This method runs the Bellman-Ford algorithm from the root node(s) - /// in order to compute the shortest path distance for each node - /// using only the paths consisting of at most \c num arcs. - /// - /// The algorithm computes - /// - the limited distance of each node from the root(s), - /// - the predecessor arc for each node. - /// - /// \warning The paths with limited arc number cannot be retrieved - /// easily with \ref path() or \ref predArc() functions. If you also - /// need the shortest paths and not only the distances, you should - /// store the \ref predMap() "predecessor map" after each iteration - /// and build the path manually. - /// - /// \pre init() must be called and at least one root node should be - /// added with addSource() before using this function. - void limitedStart(int num) { - for (int i = 0; i < num; ++i) { - if (processNextRound()) break; - } - } - - /// \brief Runs the algorithm from the given root node. - /// - /// This method runs the Bellman-Ford algorithm from the given root - /// node \c s in order to compute the shortest path to each node. - /// - /// The algorithm computes - /// - the shortest path tree (forest), - /// - the distance of each node from the root(s). - /// - /// \note bf.run(s) is just a shortcut of the following code. - /// \code - /// bf.init(); - /// bf.addSource(s); - /// bf.start(); - /// \endcode - void run(Node s) { - init(); - addSource(s); - start(); - } - - /// \brief Runs the algorithm from the given root node with arc - /// number limit. - /// - /// This method runs the Bellman-Ford algorithm from the given root - /// node \c s in order to compute the shortest path distance for each - /// node using only the paths consisting of at most \c num arcs. - /// - /// The algorithm computes - /// - the limited distance of each node from the root(s), - /// - the predecessor arc for each node. - /// - /// \warning The paths with limited arc number cannot be retrieved - /// easily with \ref path() or \ref predArc() functions. If you also - /// need the shortest paths and not only the distances, you should - /// store the \ref predMap() "predecessor map" after each iteration - /// and build the path manually. - /// - /// \note bf.run(s, num) is just a shortcut of the following code. - /// \code - /// bf.init(); - /// bf.addSource(s); - /// bf.limitedStart(num); - /// \endcode - void run(Node s, int num) { - init(); - addSource(s); - limitedStart(num); - } - - ///@} - - /// \brief LEMON iterator for getting the active nodes. - /// - /// This class provides a common style LEMON iterator that traverses - /// the active nodes of the Bellman-Ford algorithm after the last - /// phase. These nodes should be checked in the next phase to - /// find augmenting arcs outgoing from them. - class ActiveIt { - public: - - /// \brief Constructor. - /// - /// Constructor for getting the active nodes of the given BellmanFord - /// instance. - ActiveIt(const BellmanFord& algorithm) : _algorithm(&algorithm) - { - _index = _algorithm->_process.size() - 1; - } - - /// \brief Invalid constructor. - /// - /// Invalid constructor. - ActiveIt(Invalid) : _algorithm(0), _index(-1) {} - - /// \brief Conversion to \c Node. - /// - /// Conversion to \c Node. - operator Node() const { - return _index >= 0 ? _algorithm->_process[_index] : INVALID; - } - - /// \brief Increment operator. - /// - /// Increment operator. - ActiveIt& operator++() { - --_index; - return *this; - } - - bool operator==(const ActiveIt& it) const { - return static_cast(*this) == static_cast(it); - } - bool operator!=(const ActiveIt& it) const { - return static_cast(*this) != static_cast(it); - } - bool operator<(const ActiveIt& it) const { - return static_cast(*this) < static_cast(it); - } - - private: - const BellmanFord* _algorithm; - int _index; - }; - - /// \name Query Functions - /// The result of the Bellman-Ford algorithm can be obtained using these - /// functions.\n - /// Either \ref run() or \ref init() should be called before using them. - - ///@{ - - /// \brief The shortest path to the given node. - /// - /// Gives back the shortest path to the given node from the root(s). - /// - /// \warning \c t should be reached from the root(s). - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - Path path(Node t) const - { - return Path(*_gr, *_pred, t); - } - - /// \brief The distance of the given node from the root(s). - /// - /// Returns the distance of the given node from the root(s). - /// - /// \warning If node \c v is not reached from the root(s), then - /// the return value of this function is undefined. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - Value dist(Node v) const { return (*_dist)[v]; } - - /// \brief Returns the 'previous arc' of the shortest path tree for - /// the given node. - /// - /// This function returns the 'previous arc' of the shortest path - /// tree for node \c v, i.e. it returns the last arc of a - /// shortest path from a root to \c v. It is \c INVALID if \c v - /// is not reached from the root(s) or if \c v is a root. - /// - /// The shortest path tree used here is equal to the shortest path - /// tree used in \ref predNode() and \ref predMap(). - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - Arc predArc(Node v) const { return (*_pred)[v]; } - - /// \brief Returns the 'previous node' of the shortest path tree for - /// the given node. - /// - /// This function returns the 'previous node' of the shortest path - /// tree for node \c v, i.e. it returns the last but one node of - /// a shortest path from a root to \c v. It is \c INVALID if \c v - /// is not reached from the root(s) or if \c v is a root. - /// - /// The shortest path tree used here is equal to the shortest path - /// tree used in \ref predArc() and \ref predMap(). - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - Node predNode(Node v) const { - return (*_pred)[v] == INVALID ? INVALID : _gr->source((*_pred)[v]); - } - - /// \brief Returns a const reference to the node map that stores the - /// distances of the nodes. - /// - /// Returns a const reference to the node map that stores the distances - /// of the nodes calculated by the algorithm. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - const DistMap &distMap() const { return *_dist;} - - /// \brief Returns a const reference to the node map that stores the - /// predecessor arcs. - /// - /// Returns a const reference to the node map that stores the predecessor - /// arcs, which form the shortest path tree (forest). - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - const PredMap &predMap() const { return *_pred; } - - /// \brief Checks if a node is reached from the root(s). - /// - /// Returns \c true if \c v is reached from the root(s). - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - bool reached(Node v) const { - return (*_dist)[v] != OperationTraits::infinity(); - } - - /// \brief Gives back a negative cycle. - /// - /// This function gives back a directed cycle with negative total - /// length if the algorithm has already found one. - /// Otherwise it gives back an empty path. - lemon::Path negativeCycle() const { - typename Digraph::template NodeMap state(*_gr, -1); - lemon::Path cycle; - for (int i = 0; i < int(_process.size()); ++i) { - if (state[_process[i]] != -1) continue; - for (Node v = _process[i]; (*_pred)[v] != INVALID; - v = _gr->source((*_pred)[v])) { - if (state[v] == i) { - cycle.addFront((*_pred)[v]); - for (Node u = _gr->source((*_pred)[v]); u != v; - u = _gr->source((*_pred)[u])) { - cycle.addFront((*_pred)[u]); - } - return cycle; - } - else if (state[v] >= 0) { - break; - } - state[v] = i; - } - } - return cycle; - } - - ///@} - }; - - /// \brief Default traits class of bellmanFord() function. - /// - /// Default traits class of bellmanFord() function. - /// \tparam GR The type of the digraph. - /// \tparam LEN The type of the length map. - template - struct BellmanFordWizardDefaultTraits { - /// The type of the digraph the algorithm runs on. - typedef GR Digraph; - - /// \brief The type of the map that stores the arc lengths. - /// - /// The type of the map that stores the arc lengths. - /// It must meet the \ref concepts::ReadMap "ReadMap" concept. - typedef LEN LengthMap; - - /// The type of the arc lengths. - typedef typename LEN::Value Value; - - /// \brief Operation traits for Bellman-Ford algorithm. - /// - /// It defines the used operations and the infinity value for the - /// given \c Value type. - /// \see BellmanFordDefaultOperationTraits - typedef BellmanFordDefaultOperationTraits OperationTraits; - - /// \brief The type of the map that stores the last - /// arcs of the shortest paths. - /// - /// The type of the map that stores the last arcs of the shortest paths. - /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename GR::template NodeMap PredMap; - - /// \brief Instantiates a \c PredMap. - /// - /// This function instantiates a \ref PredMap. - /// \param g is the digraph to which we would like to define the - /// \ref PredMap. - static PredMap *createPredMap(const GR &g) { - return new PredMap(g); - } - - /// \brief The type of the map that stores the distances of the nodes. - /// - /// The type of the map that stores the distances of the nodes. - /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename GR::template NodeMap DistMap; - - /// \brief Instantiates a \c DistMap. - /// - /// This function instantiates a \ref DistMap. - /// \param g is the digraph to which we would like to define the - /// \ref DistMap. - static DistMap *createDistMap(const GR &g) { - return new DistMap(g); - } - - ///The type of the shortest paths. - - ///The type of the shortest paths. - ///It must meet the \ref concepts::Path "Path" concept. - typedef lemon::Path Path; - }; - - /// \brief Default traits class used by BellmanFordWizard. - /// - /// Default traits class used by BellmanFordWizard. - /// \tparam GR The type of the digraph. - /// \tparam LEN The type of the length map. - template - class BellmanFordWizardBase - : public BellmanFordWizardDefaultTraits { - - typedef BellmanFordWizardDefaultTraits Base; - protected: - // Type of the nodes in the digraph. - typedef typename Base::Digraph::Node Node; - - // Pointer to the underlying digraph. - void *_graph; - // Pointer to the length map - void *_length; - // Pointer to the map of predecessors arcs. - void *_pred; - // Pointer to the map of distances. - void *_dist; - //Pointer to the shortest path to the target node. - void *_path; - //Pointer to the distance of the target node. - void *_di; - - public: - /// Constructor. - - /// This constructor does not require parameters, it initiates - /// all of the attributes to default values \c 0. - BellmanFordWizardBase() : - _graph(0), _length(0), _pred(0), _dist(0), _path(0), _di(0) {} - - /// Constructor. - - /// This constructor requires two parameters, - /// others are initiated to \c 0. - /// \param gr The digraph the algorithm runs on. - /// \param len The length map. - BellmanFordWizardBase(const GR& gr, - const LEN& len) : - _graph(reinterpret_cast(const_cast(&gr))), - _length(reinterpret_cast(const_cast(&len))), - _pred(0), _dist(0), _path(0), _di(0) {} - - }; - - /// \brief Auxiliary class for the function-type interface of the - /// \ref BellmanFord "Bellman-Ford" algorithm. - /// - /// This auxiliary class is created to implement the - /// \ref bellmanFord() "function-type interface" of the - /// \ref BellmanFord "Bellman-Ford" algorithm. - /// It does not have own \ref run() method, it uses the - /// functions and features of the plain \ref BellmanFord. - /// - /// This class should only be used through the \ref bellmanFord() - /// function, which makes it easier to use the algorithm. - /// - /// \tparam TR The traits class that defines various types used by the - /// algorithm. - template - class BellmanFordWizard : public TR { - typedef TR Base; - - typedef typename TR::Digraph Digraph; - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::OutArcIt ArcIt; - - typedef typename TR::LengthMap LengthMap; - typedef typename LengthMap::Value Value; - typedef typename TR::PredMap PredMap; - typedef typename TR::DistMap DistMap; - typedef typename TR::Path Path; - - public: - /// Constructor. - BellmanFordWizard() : TR() {} - - /// \brief Constructor that requires parameters. - /// - /// Constructor that requires parameters. - /// These parameters will be the default values for the traits class. - /// \param gr The digraph the algorithm runs on. - /// \param len The length map. - BellmanFordWizard(const Digraph& gr, const LengthMap& len) - : TR(gr, len) {} - - /// \brief Copy constructor - BellmanFordWizard(const TR &b) : TR(b) {} - - ~BellmanFordWizard() {} - - /// \brief Runs the Bellman-Ford algorithm from the given source node. - /// - /// This method runs the Bellman-Ford algorithm from the given source - /// node in order to compute the shortest path to each node. - void run(Node s) { - BellmanFord - bf(*reinterpret_cast(Base::_graph), - *reinterpret_cast(Base::_length)); - if (Base::_pred) bf.predMap(*reinterpret_cast(Base::_pred)); - if (Base::_dist) bf.distMap(*reinterpret_cast(Base::_dist)); - bf.run(s); - } - - /// \brief Runs the Bellman-Ford algorithm to find the shortest path - /// between \c s and \c t. - /// - /// This method runs the Bellman-Ford algorithm from node \c s - /// in order to compute the shortest path to node \c t. - /// Actually, it computes the shortest path to each node, but using - /// this function you can retrieve the distance and the shortest path - /// for a single target node easier. - /// - /// \return \c true if \c t is reachable form \c s. - bool run(Node s, Node t) { - BellmanFord - bf(*reinterpret_cast(Base::_graph), - *reinterpret_cast(Base::_length)); - if (Base::_pred) bf.predMap(*reinterpret_cast(Base::_pred)); - if (Base::_dist) bf.distMap(*reinterpret_cast(Base::_dist)); - bf.run(s); - if (Base::_path) *reinterpret_cast(Base::_path) = bf.path(t); - if (Base::_di) *reinterpret_cast(Base::_di) = bf.dist(t); - return bf.reached(t); - } - - template - struct SetPredMapBase : public Base { - typedef T PredMap; - static PredMap *createPredMap(const Digraph &) { return 0; }; - SetPredMapBase(const TR &b) : TR(b) {} - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// the predecessor map. - /// - /// \ref named-templ-param "Named parameter" for setting - /// the map that stores the predecessor arcs of the nodes. - template - BellmanFordWizard > predMap(const T &t) { - Base::_pred=reinterpret_cast(const_cast(&t)); - return BellmanFordWizard >(*this); - } - - template - struct SetDistMapBase : public Base { - typedef T DistMap; - static DistMap *createDistMap(const Digraph &) { return 0; }; - SetDistMapBase(const TR &b) : TR(b) {} - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// the distance map. - /// - /// \ref named-templ-param "Named parameter" for setting - /// the map that stores the distances of the nodes calculated - /// by the algorithm. - template - BellmanFordWizard > distMap(const T &t) { - Base::_dist=reinterpret_cast(const_cast(&t)); - return BellmanFordWizard >(*this); - } - - template - struct SetPathBase : public Base { - typedef T Path; - SetPathBase(const TR &b) : TR(b) {} - }; - - /// \brief \ref named-func-param "Named parameter" for getting - /// the shortest path to the target node. - /// - /// \ref named-func-param "Named parameter" for getting - /// the shortest path to the target node. - template - BellmanFordWizard > path(const T &t) - { - Base::_path=reinterpret_cast(const_cast(&t)); - return BellmanFordWizard >(*this); - } - - /// \brief \ref named-func-param "Named parameter" for getting - /// the distance of the target node. - /// - /// \ref named-func-param "Named parameter" for getting - /// the distance of the target node. - BellmanFordWizard dist(const Value &d) - { - Base::_di=reinterpret_cast(const_cast(&d)); - return *this; - } - - }; - - /// \brief Function type interface for the \ref BellmanFord "Bellman-Ford" - /// algorithm. - /// - /// \ingroup shortest_path - /// Function type interface for the \ref BellmanFord "Bellman-Ford" - /// algorithm. - /// - /// This function also has several \ref named-templ-func-param - /// "named parameters", they are declared as the members of class - /// \ref BellmanFordWizard. - /// The following examples show how to use these parameters. - /// \code - /// // Compute shortest path from node s to each node - /// bellmanFord(g,length).predMap(preds).distMap(dists).run(s); - /// - /// // Compute shortest path from s to t - /// bool reached = bellmanFord(g,length).path(p).dist(d).run(s,t); - /// \endcode - /// \warning Don't forget to put the \ref BellmanFordWizard::run() "run()" - /// to the end of the parameter list. - /// \sa BellmanFordWizard - /// \sa BellmanFord - template - BellmanFordWizard > - bellmanFord(const GR& digraph, - const LEN& length) - { - return BellmanFordWizard >(digraph, length); - } - -} //END OF NAMESPACE LEMON - -#endif - diff --git a/deps/lemon/lemon/bfs.h b/deps/lemon/lemon/bfs.h deleted file mode 100644 index e5f4e5c5a..000000000 --- a/deps/lemon/lemon/bfs.h +++ /dev/null @@ -1,1754 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BFS_H -#define LEMON_BFS_H - -///\ingroup search -///\file -///\brief BFS algorithm. - -#include -#include -#include -#include -#include -#include - -namespace lemon { - - ///Default traits class of Bfs class. - - ///Default traits class of Bfs class. - ///\tparam GR Digraph type. - template - struct BfsDefaultTraits - { - ///The type of the digraph the algorithm runs on. - typedef GR Digraph; - - ///\brief The type of the map that stores the predecessor - ///arcs of the shortest paths. - /// - ///The type of the map that stores the predecessor - ///arcs of the shortest paths. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap PredMap; - ///Instantiates a \c PredMap. - - ///This function instantiates a \ref PredMap. - ///\param g is the digraph, to which we would like to define the - ///\ref PredMap. - static PredMap *createPredMap(const Digraph &g) - { - return new PredMap(g); - } - - ///The type of the map that indicates which nodes are processed. - - ///The type of the map that indicates which nodes are processed. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - ///By default, it is a NullMap. - typedef NullMap ProcessedMap; - ///Instantiates a \c ProcessedMap. - - ///This function instantiates a \ref ProcessedMap. - ///\param g is the digraph, to which - ///we would like to define the \ref ProcessedMap -#ifdef DOXYGEN - static ProcessedMap *createProcessedMap(const Digraph &g) -#else - static ProcessedMap *createProcessedMap(const Digraph &) -#endif - { - return new ProcessedMap(); - } - - ///The type of the map that indicates which nodes are reached. - - ///The type of the map that indicates which nodes are reached. - ///It must conform to - ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. - typedef typename Digraph::template NodeMap ReachedMap; - ///Instantiates a \c ReachedMap. - - ///This function instantiates a \ref ReachedMap. - ///\param g is the digraph, to which - ///we would like to define the \ref ReachedMap. - static ReachedMap *createReachedMap(const Digraph &g) - { - return new ReachedMap(g); - } - - ///The type of the map that stores the distances of the nodes. - - ///The type of the map that stores the distances of the nodes. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap DistMap; - ///Instantiates a \c DistMap. - - ///This function instantiates a \ref DistMap. - ///\param g is the digraph, to which we would like to define the - ///\ref DistMap. - static DistMap *createDistMap(const Digraph &g) - { - return new DistMap(g); - } - }; - - ///%BFS algorithm class. - - ///\ingroup search - ///This class provides an efficient implementation of the %BFS algorithm. - /// - ///There is also a \ref bfs() "function-type interface" for the BFS - ///algorithm, which is convenient in the simplier cases and it can be - ///used easier. - /// - ///\tparam GR The type of the digraph the algorithm runs on. - ///The default type is \ref ListDigraph. - ///\tparam TR The traits class that defines various types used by the - ///algorithm. By default, it is \ref BfsDefaultTraits - ///"BfsDefaultTraits". - ///In most cases, this parameter should not be set directly, - ///consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template > -#endif - class Bfs { - public: - - ///The type of the digraph the algorithm runs on. - typedef typename TR::Digraph Digraph; - - ///\brief The type of the map that stores the predecessor arcs of the - ///shortest paths. - typedef typename TR::PredMap PredMap; - ///The type of the map that stores the distances of the nodes. - typedef typename TR::DistMap DistMap; - ///The type of the map that indicates which nodes are reached. - typedef typename TR::ReachedMap ReachedMap; - ///The type of the map that indicates which nodes are processed. - typedef typename TR::ProcessedMap ProcessedMap; - ///The type of the paths. - typedef PredMapPath Path; - - ///The \ref lemon::BfsDefaultTraits "traits class" of the algorithm. - typedef TR Traits; - - private: - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::OutArcIt OutArcIt; - - //Pointer to the underlying digraph. - const Digraph *G; - //Pointer to the map of predecessor arcs. - PredMap *_pred; - //Indicates if _pred is locally allocated (true) or not. - bool local_pred; - //Pointer to the map of distances. - DistMap *_dist; - //Indicates if _dist is locally allocated (true) or not. - bool local_dist; - //Pointer to the map of reached status of the nodes. - ReachedMap *_reached; - //Indicates if _reached is locally allocated (true) or not. - bool local_reached; - //Pointer to the map of processed status of the nodes. - ProcessedMap *_processed; - //Indicates if _processed is locally allocated (true) or not. - bool local_processed; - - std::vector _queue; - int _queue_head,_queue_tail,_queue_next_dist; - int _curr_dist; - - //Creates the maps if necessary. - void create_maps() - { - if(!_pred) { - local_pred = true; - _pred = Traits::createPredMap(*G); - } - if(!_dist) { - local_dist = true; - _dist = Traits::createDistMap(*G); - } - if(!_reached) { - local_reached = true; - _reached = Traits::createReachedMap(*G); - } - if(!_processed) { - local_processed = true; - _processed = Traits::createProcessedMap(*G); - } - } - - protected: - - Bfs() {} - - public: - - typedef Bfs Create; - - ///\name Named Template Parameters - - ///@{ - - template - struct SetPredMapTraits : public Traits { - typedef T PredMap; - static PredMap *createPredMap(const Digraph &) - { - LEMON_ASSERT(false, "PredMap is not initialized"); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c PredMap type. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c PredMap type. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - template - struct SetPredMap : public Bfs< Digraph, SetPredMapTraits > { - typedef Bfs< Digraph, SetPredMapTraits > Create; - }; - - template - struct SetDistMapTraits : public Traits { - typedef T DistMap; - static DistMap *createDistMap(const Digraph &) - { - LEMON_ASSERT(false, "DistMap is not initialized"); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c DistMap type. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c DistMap type. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - template - struct SetDistMap : public Bfs< Digraph, SetDistMapTraits > { - typedef Bfs< Digraph, SetDistMapTraits > Create; - }; - - template - struct SetReachedMapTraits : public Traits { - typedef T ReachedMap; - static ReachedMap *createReachedMap(const Digraph &) - { - LEMON_ASSERT(false, "ReachedMap is not initialized"); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c ReachedMap type. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c ReachedMap type. - ///It must conform to - ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. - template - struct SetReachedMap : public Bfs< Digraph, SetReachedMapTraits > { - typedef Bfs< Digraph, SetReachedMapTraits > Create; - }; - - template - struct SetProcessedMapTraits : public Traits { - typedef T ProcessedMap; - static ProcessedMap *createProcessedMap(const Digraph &) - { - LEMON_ASSERT(false, "ProcessedMap is not initialized"); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c ProcessedMap type. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c ProcessedMap type. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - template - struct SetProcessedMap : public Bfs< Digraph, SetProcessedMapTraits > { - typedef Bfs< Digraph, SetProcessedMapTraits > Create; - }; - - struct SetStandardProcessedMapTraits : public Traits { - typedef typename Digraph::template NodeMap ProcessedMap; - static ProcessedMap *createProcessedMap(const Digraph &g) - { - return new ProcessedMap(g); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c ProcessedMap type to be Digraph::NodeMap. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c ProcessedMap type to be Digraph::NodeMap. - ///If you don't set it explicitly, it will be automatically allocated. - struct SetStandardProcessedMap : - public Bfs< Digraph, SetStandardProcessedMapTraits > { - typedef Bfs< Digraph, SetStandardProcessedMapTraits > Create; - }; - - ///@} - - public: - - ///Constructor. - - ///Constructor. - ///\param g The digraph the algorithm runs on. - Bfs(const Digraph &g) : - G(&g), - _pred(NULL), local_pred(false), - _dist(NULL), local_dist(false), - _reached(NULL), local_reached(false), - _processed(NULL), local_processed(false) - { } - - ///Destructor. - ~Bfs() - { - if(local_pred) delete _pred; - if(local_dist) delete _dist; - if(local_reached) delete _reached; - if(local_processed) delete _processed; - } - - ///Sets the map that stores the predecessor arcs. - - ///Sets the map that stores the predecessor arcs. - ///If you don't use this function before calling \ref run(Node) "run()" - ///or \ref init(), an instance will be allocated automatically. - ///The destructor deallocates this automatically allocated map, - ///of course. - ///\return (*this) - Bfs &predMap(PredMap &m) - { - if(local_pred) { - delete _pred; - local_pred=false; - } - _pred = &m; - return *this; - } - - ///Sets the map that indicates which nodes are reached. - - ///Sets the map that indicates which nodes are reached. - ///If you don't use this function before calling \ref run(Node) "run()" - ///or \ref init(), an instance will be allocated automatically. - ///The destructor deallocates this automatically allocated map, - ///of course. - ///\return (*this) - Bfs &reachedMap(ReachedMap &m) - { - if(local_reached) { - delete _reached; - local_reached=false; - } - _reached = &m; - return *this; - } - - ///Sets the map that indicates which nodes are processed. - - ///Sets the map that indicates which nodes are processed. - ///If you don't use this function before calling \ref run(Node) "run()" - ///or \ref init(), an instance will be allocated automatically. - ///The destructor deallocates this automatically allocated map, - ///of course. - ///\return (*this) - Bfs &processedMap(ProcessedMap &m) - { - if(local_processed) { - delete _processed; - local_processed=false; - } - _processed = &m; - return *this; - } - - ///Sets the map that stores the distances of the nodes. - - ///Sets the map that stores the distances of the nodes calculated by - ///the algorithm. - ///If you don't use this function before calling \ref run(Node) "run()" - ///or \ref init(), an instance will be allocated automatically. - ///The destructor deallocates this automatically allocated map, - ///of course. - ///\return (*this) - Bfs &distMap(DistMap &m) - { - if(local_dist) { - delete _dist; - local_dist=false; - } - _dist = &m; - return *this; - } - - public: - - ///\name Execution Control - ///The simplest way to execute the BFS algorithm is to use one of the - ///member functions called \ref run(Node) "run()".\n - ///If you need better control on the execution, you have to call - ///\ref init() first, then you can add several source nodes with - ///\ref addSource(). Finally the actual path computation can be - ///performed with one of the \ref start() functions. - - ///@{ - - ///\brief Initializes the internal data structures. - /// - ///Initializes the internal data structures. - void init() - { - create_maps(); - _queue.resize(countNodes(*G)); - _queue_head=_queue_tail=0; - _curr_dist=1; - for ( NodeIt u(*G) ; u!=INVALID ; ++u ) { - _pred->set(u,INVALID); - _reached->set(u,false); - _processed->set(u,false); - } - } - - ///Adds a new source node. - - ///Adds a new source node to the set of nodes to be processed. - /// - void addSource(Node s) - { - if(!(*_reached)[s]) - { - _reached->set(s,true); - _pred->set(s,INVALID); - _dist->set(s,0); - _queue[_queue_head++]=s; - _queue_next_dist=_queue_head; - } - } - - ///Processes the next node. - - ///Processes the next node. - /// - ///\return The processed node. - /// - ///\pre The queue must not be empty. - Node processNextNode() - { - if(_queue_tail==_queue_next_dist) { - _curr_dist++; - _queue_next_dist=_queue_head; - } - Node n=_queue[_queue_tail++]; - _processed->set(n,true); - Node m; - for(OutArcIt e(*G,n);e!=INVALID;++e) - if(!(*_reached)[m=G->target(e)]) { - _queue[_queue_head++]=m; - _reached->set(m,true); - _pred->set(m,e); - _dist->set(m,_curr_dist); - } - return n; - } - - ///Processes the next node. - - ///Processes the next node and checks if the given target node - ///is reached. If the target node is reachable from the processed - ///node, then the \c reach parameter will be set to \c true. - /// - ///\param target The target node. - ///\retval reach Indicates if the target node is reached. - ///It should be initially \c false. - /// - ///\return The processed node. - /// - ///\pre The queue must not be empty. - Node processNextNode(Node target, bool& reach) - { - if(_queue_tail==_queue_next_dist) { - _curr_dist++; - _queue_next_dist=_queue_head; - } - Node n=_queue[_queue_tail++]; - _processed->set(n,true); - Node m; - for(OutArcIt e(*G,n);e!=INVALID;++e) - if(!(*_reached)[m=G->target(e)]) { - _queue[_queue_head++]=m; - _reached->set(m,true); - _pred->set(m,e); - _dist->set(m,_curr_dist); - reach = reach || (target == m); - } - return n; - } - - ///Processes the next node. - - ///Processes the next node and checks if at least one of reached - ///nodes has \c true value in the \c nm node map. If one node - ///with \c true value is reachable from the processed node, then the - ///\c rnode parameter will be set to the first of such nodes. - /// - ///\param nm A \c bool (or convertible) node map that indicates the - ///possible targets. - ///\retval rnode The reached target node. - ///It should be initially \c INVALID. - /// - ///\return The processed node. - /// - ///\pre The queue must not be empty. - template - Node processNextNode(const NM& nm, Node& rnode) - { - if(_queue_tail==_queue_next_dist) { - _curr_dist++; - _queue_next_dist=_queue_head; - } - Node n=_queue[_queue_tail++]; - _processed->set(n,true); - Node m; - for(OutArcIt e(*G,n);e!=INVALID;++e) - if(!(*_reached)[m=G->target(e)]) { - _queue[_queue_head++]=m; - _reached->set(m,true); - _pred->set(m,e); - _dist->set(m,_curr_dist); - if (nm[m] && rnode == INVALID) rnode = m; - } - return n; - } - - ///The next node to be processed. - - ///Returns the next node to be processed or \c INVALID if the queue - ///is empty. - Node nextNode() const - { - return _queue_tail<_queue_head?_queue[_queue_tail]:INVALID; - } - - ///Returns \c false if there are nodes to be processed. - - ///Returns \c false if there are nodes to be processed - ///in the queue. - bool emptyQueue() const { return _queue_tail==_queue_head; } - - ///Returns the number of the nodes to be processed. - - ///Returns the number of the nodes to be processed - ///in the queue. - int queueSize() const { return _queue_head-_queue_tail; } - - ///Executes the algorithm. - - ///Executes the algorithm. - /// - ///This method runs the %BFS algorithm from the root node(s) - ///in order to compute the shortest path to each node. - /// - ///The algorithm computes - ///- the shortest path tree (forest), - ///- the distance of each node from the root(s). - /// - ///\pre init() must be called and at least one root node should be - ///added with addSource() before using this function. - /// - ///\note b.start() is just a shortcut of the following code. - ///\code - /// while ( !b.emptyQueue() ) { - /// b.processNextNode(); - /// } - ///\endcode - void start() - { - while ( !emptyQueue() ) processNextNode(); - } - - ///Executes the algorithm until the given target node is reached. - - ///Executes the algorithm until the given target node is reached. - /// - ///This method runs the %BFS algorithm from the root node(s) - ///in order to compute the shortest path to \c t. - /// - ///The algorithm computes - ///- the shortest path to \c t, - ///- the distance of \c t from the root(s). - /// - ///\pre init() must be called and at least one root node should be - ///added with addSource() before using this function. - /// - ///\note b.start(t) is just a shortcut of the following code. - ///\code - /// bool reach = false; - /// while ( !b.emptyQueue() && !reach ) { - /// b.processNextNode(t, reach); - /// } - ///\endcode - void start(Node t) - { - bool reach = false; - while ( !emptyQueue() && !reach ) processNextNode(t, reach); - } - - ///Executes the algorithm until a condition is met. - - ///Executes the algorithm until a condition is met. - /// - ///This method runs the %BFS algorithm from the root node(s) in - ///order to compute the shortest path to a node \c v with - /// nm[v] true, if such a node can be found. - /// - ///\param nm A \c bool (or convertible) node map. The algorithm - ///will stop when it reaches a node \c v with nm[v] true. - /// - ///\return The reached node \c v with nm[v] true or - ///\c INVALID if no such node was found. - /// - ///\pre init() must be called and at least one root node should be - ///added with addSource() before using this function. - /// - ///\note b.start(nm) is just a shortcut of the following code. - ///\code - /// Node rnode = INVALID; - /// while ( !b.emptyQueue() && rnode == INVALID ) { - /// b.processNextNode(nm, rnode); - /// } - /// return rnode; - ///\endcode - template - Node start(const NodeBoolMap &nm) - { - Node rnode = INVALID; - while ( !emptyQueue() && rnode == INVALID ) { - processNextNode(nm, rnode); - } - return rnode; - } - - ///Runs the algorithm from the given source node. - - ///This method runs the %BFS algorithm from node \c s - ///in order to compute the shortest path to each node. - /// - ///The algorithm computes - ///- the shortest path tree, - ///- the distance of each node from the root. - /// - ///\note b.run(s) is just a shortcut of the following code. - ///\code - /// b.init(); - /// b.addSource(s); - /// b.start(); - ///\endcode - void run(Node s) { - init(); - addSource(s); - start(); - } - - ///Finds the shortest path between \c s and \c t. - - ///This method runs the %BFS algorithm from node \c s - ///in order to compute the shortest path to node \c t - ///(it stops searching when \c t is processed). - /// - ///\return \c true if \c t is reachable form \c s. - /// - ///\note Apart from the return value, b.run(s,t) is just a - ///shortcut of the following code. - ///\code - /// b.init(); - /// b.addSource(s); - /// b.start(t); - ///\endcode - bool run(Node s,Node t) { - init(); - addSource(s); - start(t); - return reached(t); - } - - ///Runs the algorithm to visit all nodes in the digraph. - - ///This method runs the %BFS algorithm in order to visit all nodes - ///in the digraph. - /// - ///\note b.run(s) is just a shortcut of the following code. - ///\code - /// b.init(); - /// for (NodeIt n(gr); n != INVALID; ++n) { - /// if (!b.reached(n)) { - /// b.addSource(n); - /// b.start(); - /// } - /// } - ///\endcode - void run() { - init(); - for (NodeIt n(*G); n != INVALID; ++n) { - if (!reached(n)) { - addSource(n); - start(); - } - } - } - - ///@} - - ///\name Query Functions - ///The results of the BFS algorithm can be obtained using these - ///functions.\n - ///Either \ref run(Node) "run()" or \ref start() should be called - ///before using them. - - ///@{ - - ///The shortest path to the given node. - - ///Returns the shortest path to the given node from the root(s). - /// - ///\warning \c t should be reached from the root(s). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - Path path(Node t) const { return Path(*G, *_pred, t); } - - ///The distance of the given node from the root(s). - - ///Returns the distance of the given node from the root(s). - /// - ///\warning If node \c v is not reached from the root(s), then - ///the return value of this function is undefined. - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - int dist(Node v) const { return (*_dist)[v]; } - - ///\brief Returns the 'previous arc' of the shortest path tree for - ///the given node. - /// - ///This function returns the 'previous arc' of the shortest path - ///tree for the node \c v, i.e. it returns the last arc of a - ///shortest path from a root to \c v. It is \c INVALID if \c v - ///is not reached from the root(s) or if \c v is a root. - /// - ///The shortest path tree used here is equal to the shortest path - ///tree used in \ref predNode() and \ref predMap(). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - Arc predArc(Node v) const { return (*_pred)[v];} - - ///\brief Returns the 'previous node' of the shortest path tree for - ///the given node. - /// - ///This function returns the 'previous node' of the shortest path - ///tree for the node \c v, i.e. it returns the last but one node - ///of a shortest path from a root to \c v. It is \c INVALID - ///if \c v is not reached from the root(s) or if \c v is a root. - /// - ///The shortest path tree used here is equal to the shortest path - ///tree used in \ref predArc() and \ref predMap(). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - Node predNode(Node v) const { return (*_pred)[v]==INVALID ? INVALID: - G->source((*_pred)[v]); } - - ///\brief Returns a const reference to the node map that stores the - /// distances of the nodes. - /// - ///Returns a const reference to the node map that stores the distances - ///of the nodes calculated by the algorithm. - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - const DistMap &distMap() const { return *_dist;} - - ///\brief Returns a const reference to the node map that stores the - ///predecessor arcs. - /// - ///Returns a const reference to the node map that stores the predecessor - ///arcs, which form the shortest path tree (forest). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - const PredMap &predMap() const { return *_pred;} - - ///Checks if the given node is reached from the root(s). - - ///Returns \c true if \c v is reached from the root(s). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - bool reached(Node v) const { return (*_reached)[v]; } - - ///@} - }; - - ///Default traits class of bfs() function. - - ///Default traits class of bfs() function. - ///\tparam GR Digraph type. - template - struct BfsWizardDefaultTraits - { - ///The type of the digraph the algorithm runs on. - typedef GR Digraph; - - ///\brief The type of the map that stores the predecessor - ///arcs of the shortest paths. - /// - ///The type of the map that stores the predecessor - ///arcs of the shortest paths. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap PredMap; - ///Instantiates a PredMap. - - ///This function instantiates a PredMap. - ///\param g is the digraph, to which we would like to define the - ///PredMap. - static PredMap *createPredMap(const Digraph &g) - { - return new PredMap(g); - } - - ///The type of the map that indicates which nodes are processed. - - ///The type of the map that indicates which nodes are processed. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - ///By default, it is a NullMap. - typedef NullMap ProcessedMap; - ///Instantiates a ProcessedMap. - - ///This function instantiates a ProcessedMap. - ///\param g is the digraph, to which - ///we would like to define the ProcessedMap. -#ifdef DOXYGEN - static ProcessedMap *createProcessedMap(const Digraph &g) -#else - static ProcessedMap *createProcessedMap(const Digraph &) -#endif - { - return new ProcessedMap(); - } - - ///The type of the map that indicates which nodes are reached. - - ///The type of the map that indicates which nodes are reached. - ///It must conform to - ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. - typedef typename Digraph::template NodeMap ReachedMap; - ///Instantiates a ReachedMap. - - ///This function instantiates a ReachedMap. - ///\param g is the digraph, to which - ///we would like to define the ReachedMap. - static ReachedMap *createReachedMap(const Digraph &g) - { - return new ReachedMap(g); - } - - ///The type of the map that stores the distances of the nodes. - - ///The type of the map that stores the distances of the nodes. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap DistMap; - ///Instantiates a DistMap. - - ///This function instantiates a DistMap. - ///\param g is the digraph, to which we would like to define - ///the DistMap - static DistMap *createDistMap(const Digraph &g) - { - return new DistMap(g); - } - - ///The type of the shortest paths. - - ///The type of the shortest paths. - ///It must conform to the \ref concepts::Path "Path" concept. - typedef lemon::Path Path; - }; - - /// Default traits class used by BfsWizard - - /// Default traits class used by BfsWizard. - /// \tparam GR The type of the digraph. - template - class BfsWizardBase : public BfsWizardDefaultTraits - { - - typedef BfsWizardDefaultTraits Base; - protected: - //The type of the nodes in the digraph. - typedef typename Base::Digraph::Node Node; - - //Pointer to the digraph the algorithm runs on. - void *_g; - //Pointer to the map of reached nodes. - void *_reached; - //Pointer to the map of processed nodes. - void *_processed; - //Pointer to the map of predecessors arcs. - void *_pred; - //Pointer to the map of distances. - void *_dist; - //Pointer to the shortest path to the target node. - void *_path; - //Pointer to the distance of the target node. - int *_di; - - public: - /// Constructor. - - /// This constructor does not require parameters, it initiates - /// all of the attributes to \c 0. - BfsWizardBase() : _g(0), _reached(0), _processed(0), _pred(0), - _dist(0), _path(0), _di(0) {} - - /// Constructor. - - /// This constructor requires one parameter, - /// others are initiated to \c 0. - /// \param g The digraph the algorithm runs on. - BfsWizardBase(const GR &g) : - _g(reinterpret_cast(const_cast(&g))), - _reached(0), _processed(0), _pred(0), _dist(0), _path(0), _di(0) {} - - }; - - /// Auxiliary class for the function-type interface of BFS algorithm. - - /// This auxiliary class is created to implement the - /// \ref bfs() "function-type interface" of \ref Bfs algorithm. - /// It does not have own \ref run(Node) "run()" method, it uses the - /// functions and features of the plain \ref Bfs. - /// - /// This class should only be used through the \ref bfs() function, - /// which makes it easier to use the algorithm. - /// - /// \tparam TR The traits class that defines various types used by the - /// algorithm. - template - class BfsWizard : public TR - { - typedef TR Base; - - typedef typename TR::Digraph Digraph; - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::OutArcIt OutArcIt; - - typedef typename TR::PredMap PredMap; - typedef typename TR::DistMap DistMap; - typedef typename TR::ReachedMap ReachedMap; - typedef typename TR::ProcessedMap ProcessedMap; - typedef typename TR::Path Path; - - public: - - /// Constructor. - BfsWizard() : TR() {} - - /// Constructor that requires parameters. - - /// Constructor that requires parameters. - /// These parameters will be the default values for the traits class. - /// \param g The digraph the algorithm runs on. - BfsWizard(const Digraph &g) : - TR(g) {} - - ///Copy constructor - BfsWizard(const TR &b) : TR(b) {} - - ~BfsWizard() {} - - ///Runs BFS algorithm from the given source node. - - ///This method runs BFS algorithm from node \c s - ///in order to compute the shortest path to each node. - void run(Node s) - { - Bfs alg(*reinterpret_cast(Base::_g)); - if (Base::_pred) - alg.predMap(*reinterpret_cast(Base::_pred)); - if (Base::_dist) - alg.distMap(*reinterpret_cast(Base::_dist)); - if (Base::_reached) - alg.reachedMap(*reinterpret_cast(Base::_reached)); - if (Base::_processed) - alg.processedMap(*reinterpret_cast(Base::_processed)); - if (s!=INVALID) - alg.run(s); - else - alg.run(); - } - - ///Finds the shortest path between \c s and \c t. - - ///This method runs BFS algorithm from node \c s - ///in order to compute the shortest path to node \c t - ///(it stops searching when \c t is processed). - /// - ///\return \c true if \c t is reachable form \c s. - bool run(Node s, Node t) - { - Bfs alg(*reinterpret_cast(Base::_g)); - if (Base::_pred) - alg.predMap(*reinterpret_cast(Base::_pred)); - if (Base::_dist) - alg.distMap(*reinterpret_cast(Base::_dist)); - if (Base::_reached) - alg.reachedMap(*reinterpret_cast(Base::_reached)); - if (Base::_processed) - alg.processedMap(*reinterpret_cast(Base::_processed)); - alg.run(s,t); - if (Base::_path) - *reinterpret_cast(Base::_path) = alg.path(t); - if (Base::_di) - *Base::_di = alg.dist(t); - return alg.reached(t); - } - - ///Runs BFS algorithm to visit all nodes in the digraph. - - ///This method runs BFS algorithm in order to visit all nodes - ///in the digraph. - void run() - { - run(INVALID); - } - - template - struct SetPredMapBase : public Base { - typedef T PredMap; - static PredMap *createPredMap(const Digraph &) { return 0; }; - SetPredMapBase(const TR &b) : TR(b) {} - }; - - ///\brief \ref named-templ-param "Named parameter" for setting - ///the predecessor map. - /// - ///\ref named-templ-param "Named parameter" function for setting - ///the map that stores the predecessor arcs of the nodes. - template - BfsWizard > predMap(const T &t) - { - Base::_pred=reinterpret_cast(const_cast(&t)); - return BfsWizard >(*this); - } - - template - struct SetReachedMapBase : public Base { - typedef T ReachedMap; - static ReachedMap *createReachedMap(const Digraph &) { return 0; }; - SetReachedMapBase(const TR &b) : TR(b) {} - }; - - ///\brief \ref named-templ-param "Named parameter" for setting - ///the reached map. - /// - ///\ref named-templ-param "Named parameter" function for setting - ///the map that indicates which nodes are reached. - template - BfsWizard > reachedMap(const T &t) - { - Base::_reached=reinterpret_cast(const_cast(&t)); - return BfsWizard >(*this); - } - - template - struct SetDistMapBase : public Base { - typedef T DistMap; - static DistMap *createDistMap(const Digraph &) { return 0; }; - SetDistMapBase(const TR &b) : TR(b) {} - }; - - ///\brief \ref named-templ-param "Named parameter" for setting - ///the distance map. - /// - ///\ref named-templ-param "Named parameter" function for setting - ///the map that stores the distances of the nodes calculated - ///by the algorithm. - template - BfsWizard > distMap(const T &t) - { - Base::_dist=reinterpret_cast(const_cast(&t)); - return BfsWizard >(*this); - } - - template - struct SetProcessedMapBase : public Base { - typedef T ProcessedMap; - static ProcessedMap *createProcessedMap(const Digraph &) { return 0; }; - SetProcessedMapBase(const TR &b) : TR(b) {} - }; - - ///\brief \ref named-func-param "Named parameter" for setting - ///the processed map. - /// - ///\ref named-templ-param "Named parameter" function for setting - ///the map that indicates which nodes are processed. - template - BfsWizard > processedMap(const T &t) - { - Base::_processed=reinterpret_cast(const_cast(&t)); - return BfsWizard >(*this); - } - - template - struct SetPathBase : public Base { - typedef T Path; - SetPathBase(const TR &b) : TR(b) {} - }; - ///\brief \ref named-func-param "Named parameter" - ///for getting the shortest path to the target node. - /// - ///\ref named-func-param "Named parameter" - ///for getting the shortest path to the target node. - template - BfsWizard > path(const T &t) - { - Base::_path=reinterpret_cast(const_cast(&t)); - return BfsWizard >(*this); - } - - ///\brief \ref named-func-param "Named parameter" - ///for getting the distance of the target node. - /// - ///\ref named-func-param "Named parameter" - ///for getting the distance of the target node. - BfsWizard dist(const int &d) - { - Base::_di=const_cast(&d); - return *this; - } - - }; - - ///Function-type interface for BFS algorithm. - - /// \ingroup search - ///Function-type interface for BFS algorithm. - /// - ///This function also has several \ref named-func-param "named parameters", - ///they are declared as the members of class \ref BfsWizard. - ///The following examples show how to use these parameters. - ///\code - /// // Compute shortest path from node s to each node - /// bfs(g).predMap(preds).distMap(dists).run(s); - /// - /// // Compute shortest path from s to t - /// bool reached = bfs(g).path(p).dist(d).run(s,t); - ///\endcode - ///\warning Don't forget to put the \ref BfsWizard::run(Node) "run()" - ///to the end of the parameter list. - ///\sa BfsWizard - ///\sa Bfs - template - BfsWizard > - bfs(const GR &digraph) - { - return BfsWizard >(digraph); - } - -#ifdef DOXYGEN - /// \brief Visitor class for BFS. - /// - /// This class defines the interface of the BfsVisit events, and - /// it could be the base of a real visitor class. - template - struct BfsVisitor { - typedef GR Digraph; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::Node Node; - /// \brief Called for the source node(s) of the BFS. - /// - /// This function is called for the source node(s) of the BFS. - void start(const Node& node) {} - /// \brief Called when a node is reached first time. - /// - /// This function is called when a node is reached first time. - void reach(const Node& node) {} - /// \brief Called when a node is processed. - /// - /// This function is called when a node is processed. - void process(const Node& node) {} - /// \brief Called when an arc reaches a new node. - /// - /// This function is called when the BFS finds an arc whose target node - /// is not reached yet. - void discover(const Arc& arc) {} - /// \brief Called when an arc is examined but its target node is - /// already discovered. - /// - /// This function is called when an arc is examined but its target node is - /// already discovered. - void examine(const Arc& arc) {} - }; -#else - template - struct BfsVisitor { - typedef GR Digraph; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::Node Node; - void start(const Node&) {} - void reach(const Node&) {} - void process(const Node&) {} - void discover(const Arc&) {} - void examine(const Arc&) {} - - template - struct Constraints { - void constraints() { - Arc arc; - Node node; - visitor.start(node); - visitor.reach(node); - visitor.process(node); - visitor.discover(arc); - visitor.examine(arc); - } - _Visitor& visitor; - Constraints() {} - }; - }; -#endif - - /// \brief Default traits class of BfsVisit class. - /// - /// Default traits class of BfsVisit class. - /// \tparam GR The type of the digraph the algorithm runs on. - template - struct BfsVisitDefaultTraits { - - /// \brief The type of the digraph the algorithm runs on. - typedef GR Digraph; - - /// \brief The type of the map that indicates which nodes are reached. - /// - /// The type of the map that indicates which nodes are reached. - /// It must conform to - ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. - typedef typename Digraph::template NodeMap ReachedMap; - - /// \brief Instantiates a ReachedMap. - /// - /// This function instantiates a ReachedMap. - /// \param digraph is the digraph, to which - /// we would like to define the ReachedMap. - static ReachedMap *createReachedMap(const Digraph &digraph) { - return new ReachedMap(digraph); - } - - }; - - /// \ingroup search - /// - /// \brief BFS algorithm class with visitor interface. - /// - /// This class provides an efficient implementation of the BFS algorithm - /// with visitor interface. - /// - /// The BfsVisit class provides an alternative interface to the Bfs - /// class. It works with callback mechanism, the BfsVisit object calls - /// the member functions of the \c Visitor class on every BFS event. - /// - /// This interface of the BFS algorithm should be used in special cases - /// when extra actions have to be performed in connection with certain - /// events of the BFS algorithm. Otherwise consider to use Bfs or bfs() - /// instead. - /// - /// \tparam GR The type of the digraph the algorithm runs on. - /// The default type is \ref ListDigraph. - /// The value of GR is not used directly by \ref BfsVisit, - /// it is only passed to \ref BfsVisitDefaultTraits. - /// \tparam VS The Visitor type that is used by the algorithm. - /// \ref BfsVisitor "BfsVisitor" is an empty visitor, which - /// does not observe the BFS events. If you want to observe the BFS - /// events, you should implement your own visitor class. - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref BfsVisitDefaultTraits - /// "BfsVisitDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template , - typename TR = BfsVisitDefaultTraits > -#endif - class BfsVisit { - public: - - ///The traits class. - typedef TR Traits; - - ///The type of the digraph the algorithm runs on. - typedef typename Traits::Digraph Digraph; - - ///The visitor type used by the algorithm. - typedef VS Visitor; - - ///The type of the map that indicates which nodes are reached. - typedef typename Traits::ReachedMap ReachedMap; - - private: - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::OutArcIt OutArcIt; - - //Pointer to the underlying digraph. - const Digraph *_digraph; - //Pointer to the visitor object. - Visitor *_visitor; - //Pointer to the map of reached status of the nodes. - ReachedMap *_reached; - //Indicates if _reached is locally allocated (true) or not. - bool local_reached; - - std::vector _list; - int _list_front, _list_back; - - //Creates the maps if necessary. - void create_maps() { - if(!_reached) { - local_reached = true; - _reached = Traits::createReachedMap(*_digraph); - } - } - - protected: - - BfsVisit() {} - - public: - - typedef BfsVisit Create; - - /// \name Named Template Parameters - - ///@{ - template - struct SetReachedMapTraits : public Traits { - typedef T ReachedMap; - static ReachedMap *createReachedMap(const Digraph &digraph) { - LEMON_ASSERT(false, "ReachedMap is not initialized"); - return 0; // ignore warnings - } - }; - /// \brief \ref named-templ-param "Named parameter" for setting - /// ReachedMap type. - /// - /// \ref named-templ-param "Named parameter" for setting ReachedMap type. - template - struct SetReachedMap : public BfsVisit< Digraph, Visitor, - SetReachedMapTraits > { - typedef BfsVisit< Digraph, Visitor, SetReachedMapTraits > Create; - }; - ///@} - - public: - - /// \brief Constructor. - /// - /// Constructor. - /// - /// \param digraph The digraph the algorithm runs on. - /// \param visitor The visitor object of the algorithm. - BfsVisit(const Digraph& digraph, Visitor& visitor) - : _digraph(&digraph), _visitor(&visitor), - _reached(0), local_reached(false) {} - - /// \brief Destructor. - ~BfsVisit() { - if(local_reached) delete _reached; - } - - /// \brief Sets the map that indicates which nodes are reached. - /// - /// Sets the map that indicates which nodes are reached. - /// If you don't use this function before calling \ref run(Node) "run()" - /// or \ref init(), an instance will be allocated automatically. - /// The destructor deallocates this automatically allocated map, - /// of course. - /// \return (*this) - BfsVisit &reachedMap(ReachedMap &m) { - if(local_reached) { - delete _reached; - local_reached = false; - } - _reached = &m; - return *this; - } - - public: - - /// \name Execution Control - /// The simplest way to execute the BFS algorithm is to use one of the - /// member functions called \ref run(Node) "run()".\n - /// If you need better control on the execution, you have to call - /// \ref init() first, then you can add several source nodes with - /// \ref addSource(). Finally the actual path computation can be - /// performed with one of the \ref start() functions. - - /// @{ - - /// \brief Initializes the internal data structures. - /// - /// Initializes the internal data structures. - void init() { - create_maps(); - _list.resize(countNodes(*_digraph)); - _list_front = _list_back = -1; - for (NodeIt u(*_digraph) ; u != INVALID ; ++u) { - _reached->set(u, false); - } - } - - /// \brief Adds a new source node. - /// - /// Adds a new source node to the set of nodes to be processed. - void addSource(Node s) { - if(!(*_reached)[s]) { - _reached->set(s,true); - _visitor->start(s); - _visitor->reach(s); - _list[++_list_back] = s; - } - } - - /// \brief Processes the next node. - /// - /// Processes the next node. - /// - /// \return The processed node. - /// - /// \pre The queue must not be empty. - Node processNextNode() { - Node n = _list[++_list_front]; - _visitor->process(n); - Arc e; - for (_digraph->firstOut(e, n); e != INVALID; _digraph->nextOut(e)) { - Node m = _digraph->target(e); - if (!(*_reached)[m]) { - _visitor->discover(e); - _visitor->reach(m); - _reached->set(m, true); - _list[++_list_back] = m; - } else { - _visitor->examine(e); - } - } - return n; - } - - /// \brief Processes the next node. - /// - /// Processes the next node and checks if the given target node - /// is reached. If the target node is reachable from the processed - /// node, then the \c reach parameter will be set to \c true. - /// - /// \param target The target node. - /// \retval reach Indicates if the target node is reached. - /// It should be initially \c false. - /// - /// \return The processed node. - /// - /// \pre The queue must not be empty. - Node processNextNode(Node target, bool& reach) { - Node n = _list[++_list_front]; - _visitor->process(n); - Arc e; - for (_digraph->firstOut(e, n); e != INVALID; _digraph->nextOut(e)) { - Node m = _digraph->target(e); - if (!(*_reached)[m]) { - _visitor->discover(e); - _visitor->reach(m); - _reached->set(m, true); - _list[++_list_back] = m; - reach = reach || (target == m); - } else { - _visitor->examine(e); - } - } - return n; - } - - /// \brief Processes the next node. - /// - /// Processes the next node and checks if at least one of reached - /// nodes has \c true value in the \c nm node map. If one node - /// with \c true value is reachable from the processed node, then the - /// \c rnode parameter will be set to the first of such nodes. - /// - /// \param nm A \c bool (or convertible) node map that indicates the - /// possible targets. - /// \retval rnode The reached target node. - /// It should be initially \c INVALID. - /// - /// \return The processed node. - /// - /// \pre The queue must not be empty. - template - Node processNextNode(const NM& nm, Node& rnode) { - Node n = _list[++_list_front]; - _visitor->process(n); - Arc e; - for (_digraph->firstOut(e, n); e != INVALID; _digraph->nextOut(e)) { - Node m = _digraph->target(e); - if (!(*_reached)[m]) { - _visitor->discover(e); - _visitor->reach(m); - _reached->set(m, true); - _list[++_list_back] = m; - if (nm[m] && rnode == INVALID) rnode = m; - } else { - _visitor->examine(e); - } - } - return n; - } - - /// \brief The next node to be processed. - /// - /// Returns the next node to be processed or \c INVALID if the queue - /// is empty. - Node nextNode() const { - return _list_front != _list_back ? _list[_list_front + 1] : INVALID; - } - - /// \brief Returns \c false if there are nodes - /// to be processed. - /// - /// Returns \c false if there are nodes - /// to be processed in the queue. - bool emptyQueue() const { return _list_front == _list_back; } - - /// \brief Returns the number of the nodes to be processed. - /// - /// Returns the number of the nodes to be processed in the queue. - int queueSize() const { return _list_back - _list_front; } - - /// \brief Executes the algorithm. - /// - /// Executes the algorithm. - /// - /// This method runs the %BFS algorithm from the root node(s) - /// in order to compute the shortest path to each node. - /// - /// The algorithm computes - /// - the shortest path tree (forest), - /// - the distance of each node from the root(s). - /// - /// \pre init() must be called and at least one root node should be added - /// with addSource() before using this function. - /// - /// \note b.start() is just a shortcut of the following code. - /// \code - /// while ( !b.emptyQueue() ) { - /// b.processNextNode(); - /// } - /// \endcode - void start() { - while ( !emptyQueue() ) processNextNode(); - } - - /// \brief Executes the algorithm until the given target node is reached. - /// - /// Executes the algorithm until the given target node is reached. - /// - /// This method runs the %BFS algorithm from the root node(s) - /// in order to compute the shortest path to \c t. - /// - /// The algorithm computes - /// - the shortest path to \c t, - /// - the distance of \c t from the root(s). - /// - /// \pre init() must be called and at least one root node should be - /// added with addSource() before using this function. - /// - /// \note b.start(t) is just a shortcut of the following code. - /// \code - /// bool reach = false; - /// while ( !b.emptyQueue() && !reach ) { - /// b.processNextNode(t, reach); - /// } - /// \endcode - void start(Node t) { - bool reach = false; - while ( !emptyQueue() && !reach ) processNextNode(t, reach); - } - - /// \brief Executes the algorithm until a condition is met. - /// - /// Executes the algorithm until a condition is met. - /// - /// This method runs the %BFS algorithm from the root node(s) in - /// order to compute the shortest path to a node \c v with - /// nm[v] true, if such a node can be found. - /// - /// \param nm must be a bool (or convertible) node map. The - /// algorithm will stop when it reaches a node \c v with - /// nm[v] true. - /// - /// \return The reached node \c v with nm[v] true or - /// \c INVALID if no such node was found. - /// - /// \pre init() must be called and at least one root node should be - /// added with addSource() before using this function. - /// - /// \note b.start(nm) is just a shortcut of the following code. - /// \code - /// Node rnode = INVALID; - /// while ( !b.emptyQueue() && rnode == INVALID ) { - /// b.processNextNode(nm, rnode); - /// } - /// return rnode; - /// \endcode - template - Node start(const NM &nm) { - Node rnode = INVALID; - while ( !emptyQueue() && rnode == INVALID ) { - processNextNode(nm, rnode); - } - return rnode; - } - - /// \brief Runs the algorithm from the given source node. - /// - /// This method runs the %BFS algorithm from node \c s - /// in order to compute the shortest path to each node. - /// - /// The algorithm computes - /// - the shortest path tree, - /// - the distance of each node from the root. - /// - /// \note b.run(s) is just a shortcut of the following code. - ///\code - /// b.init(); - /// b.addSource(s); - /// b.start(); - ///\endcode - void run(Node s) { - init(); - addSource(s); - start(); - } - - /// \brief Finds the shortest path between \c s and \c t. - /// - /// This method runs the %BFS algorithm from node \c s - /// in order to compute the shortest path to node \c t - /// (it stops searching when \c t is processed). - /// - /// \return \c true if \c t is reachable form \c s. - /// - /// \note Apart from the return value, b.run(s,t) is just a - /// shortcut of the following code. - ///\code - /// b.init(); - /// b.addSource(s); - /// b.start(t); - ///\endcode - bool run(Node s,Node t) { - init(); - addSource(s); - start(t); - return reached(t); - } - - /// \brief Runs the algorithm to visit all nodes in the digraph. - /// - /// This method runs the %BFS algorithm in order to visit all nodes - /// in the digraph. - /// - /// \note b.run(s) is just a shortcut of the following code. - ///\code - /// b.init(); - /// for (NodeIt n(gr); n != INVALID; ++n) { - /// if (!b.reached(n)) { - /// b.addSource(n); - /// b.start(); - /// } - /// } - ///\endcode - void run() { - init(); - for (NodeIt it(*_digraph); it != INVALID; ++it) { - if (!reached(it)) { - addSource(it); - start(); - } - } - } - - ///@} - - /// \name Query Functions - /// The results of the BFS algorithm can be obtained using these - /// functions.\n - /// Either \ref run(Node) "run()" or \ref start() should be called - /// before using them. - - ///@{ - - /// \brief Checks if the given node is reached from the root(s). - /// - /// Returns \c true if \c v is reached from the root(s). - /// - /// \pre Either \ref run(Node) "run()" or \ref init() - /// must be called before using this function. - bool reached(Node v) const { return (*_reached)[v]; } - - ///@} - - }; - -} //END OF NAMESPACE LEMON - -#endif diff --git a/deps/lemon/lemon/bin_heap.h b/deps/lemon/lemon/bin_heap.h deleted file mode 100644 index 02c665822..000000000 --- a/deps/lemon/lemon/bin_heap.h +++ /dev/null @@ -1,347 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BIN_HEAP_H -#define LEMON_BIN_HEAP_H - -///\ingroup heaps -///\file -///\brief Binary heap implementation. - -#include -#include -#include - -namespace lemon { - - /// \ingroup heaps - /// - /// \brief Binary heap data structure. - /// - /// This class implements the \e binary \e heap data structure. - /// It fully conforms to the \ref concepts::Heap "heap concept". - /// - /// \tparam PR Type of the priorities of the items. - /// \tparam IM A read-writable item map with \c int values, used - /// internally to handle the cross references. - /// \tparam CMP A functor class for comparing the priorities. - /// The default is \c std::less. -#ifdef DOXYGEN - template -#else - template > -#endif - class BinHeap { - public: - - /// Type of the item-int map. - typedef IM ItemIntMap; - /// Type of the priorities. - typedef PR Prio; - /// Type of the items stored in the heap. - typedef typename ItemIntMap::Key Item; - /// Type of the item-priority pairs. - typedef std::pair Pair; - /// Functor type for comparing the priorities. - typedef CMP Compare; - - /// \brief Type to represent the states of the items. - /// - /// Each item has a state associated to it. It can be "in heap", - /// "pre-heap" or "post-heap". The latter two are indifferent from the - /// heap's point of view, but may be useful to the user. - /// - /// The item-int map must be initialized in such way that it assigns - /// \c PRE_HEAP (-1) to any element to be put in the heap. - enum State { - IN_HEAP = 0, ///< = 0. - PRE_HEAP = -1, ///< = -1. - POST_HEAP = -2 ///< = -2. - }; - - private: - std::vector _data; - Compare _comp; - ItemIntMap &_iim; - - public: - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - explicit BinHeap(ItemIntMap &map) : _iim(map) {} - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - /// \param comp The function object used for comparing the priorities. - BinHeap(ItemIntMap &map, const Compare &comp) - : _iim(map), _comp(comp) {} - - - /// \brief The number of items stored in the heap. - /// - /// This function returns the number of items stored in the heap. - int size() const { return _data.size(); } - - /// \brief Check if the heap is empty. - /// - /// This function returns \c true if the heap is empty. - bool empty() const { return _data.empty(); } - - /// \brief Make the heap empty. - /// - /// This functon makes the heap empty. - /// It does not change the cross reference map. If you want to reuse - /// a heap that is not surely empty, you should first clear it and - /// then you should set the cross reference map to \c PRE_HEAP - /// for each item. - void clear() { - _data.clear(); - } - - private: - static int parent(int i) { return (i-1)/2; } - - static int secondChild(int i) { return 2*i+2; } - bool less(const Pair &p1, const Pair &p2) const { - return _comp(p1.second, p2.second); - } - - int bubbleUp(int hole, Pair p) { - int par = parent(hole); - while( hole>0 && less(p,_data[par]) ) { - move(_data[par],hole); - hole = par; - par = parent(hole); - } - move(p, hole); - return hole; - } - - int bubbleDown(int hole, Pair p, int length) { - int child = secondChild(hole); - while(child < length) { - if( less(_data[child-1], _data[child]) ) { - --child; - } - if( !less(_data[child], p) ) - goto ok; - move(_data[child], hole); - hole = child; - child = secondChild(hole); - } - child--; - if( child 0) { - bubbleDown(0, _data[n], n); - } - _data.pop_back(); - } - - /// \brief Remove the given item from the heap. - /// - /// This function removes the given item from the heap if it is - /// already stored. - /// \param i The item to delete. - /// \pre \e i must be in the heap. - void erase(const Item &i) { - int h = _iim[i]; - int n = _data.size()-1; - _iim.set(_data[h].first, POST_HEAP); - if( h < n ) { - if ( bubbleUp(h, _data[n]) == h) { - bubbleDown(h, _data[n], n); - } - } - _data.pop_back(); - } - - /// \brief The priority of the given item. - /// - /// This function returns the priority of the given item. - /// \param i The item. - /// \pre \e i must be in the heap. - Prio operator[](const Item &i) const { - int idx = _iim[i]; - return _data[idx].second; - } - - /// \brief Set the priority of an item or insert it, if it is - /// not stored in the heap. - /// - /// This method sets the priority of the given item if it is - /// already stored in the heap. Otherwise it inserts the given - /// item into the heap with the given priority. - /// \param i The item. - /// \param p The priority. - void set(const Item &i, const Prio &p) { - int idx = _iim[i]; - if( idx < 0 ) { - push(i,p); - } - else if( _comp(p, _data[idx].second) ) { - bubbleUp(idx, Pair(i,p)); - } - else { - bubbleDown(idx, Pair(i,p), _data.size()); - } - } - - /// \brief Decrease the priority of an item to the given value. - /// - /// This function decreases the priority of an item to the given value. - /// \param i The item. - /// \param p The priority. - /// \pre \e i must be stored in the heap with priority at least \e p. - void decrease(const Item &i, const Prio &p) { - int idx = _iim[i]; - bubbleUp(idx, Pair(i,p)); - } - - /// \brief Increase the priority of an item to the given value. - /// - /// This function increases the priority of an item to the given value. - /// \param i The item. - /// \param p The priority. - /// \pre \e i must be stored in the heap with priority at most \e p. - void increase(const Item &i, const Prio &p) { - int idx = _iim[i]; - bubbleDown(idx, Pair(i,p), _data.size()); - } - - /// \brief Return the state of an item. - /// - /// This method returns \c PRE_HEAP if the given item has never - /// been in the heap, \c IN_HEAP if it is in the heap at the moment, - /// and \c POST_HEAP otherwise. - /// In the latter case it is possible that the item will get back - /// to the heap again. - /// \param i The item. - State state(const Item &i) const { - int s = _iim[i]; - if( s>=0 ) - s=0; - return State(s); - } - - /// \brief Set the state of an item in the heap. - /// - /// This function sets the state of the given item in the heap. - /// It can be used to manually clear the heap when it is important - /// to achive better time complexity. - /// \param i The item. - /// \param st The state. It should not be \c IN_HEAP. - void state(const Item& i, State st) { - switch (st) { - case POST_HEAP: - case PRE_HEAP: - if (state(i) == IN_HEAP) { - erase(i); - } - _iim[i] = st; - break; - case IN_HEAP: - break; - } - } - - /// \brief Replace an item in the heap. - /// - /// This function replaces item \c i with item \c j. - /// Item \c i must be in the heap, while \c j must be out of the heap. - /// After calling this method, item \c i will be out of the - /// heap and \c j will be in the heap with the same prioriority - /// as item \c i had before. - void replace(const Item& i, const Item& j) { - int idx = _iim[i]; - _iim.set(i, _iim[j]); - _iim.set(j, idx); - _data[idx].first = j; - } - - }; // class BinHeap - -} // namespace lemon - -#endif // LEMON_BIN_HEAP_H diff --git a/deps/lemon/lemon/binomial_heap.h b/deps/lemon/lemon/binomial_heap.h deleted file mode 100644 index 5bc137870..000000000 --- a/deps/lemon/lemon/binomial_heap.h +++ /dev/null @@ -1,445 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2010 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BINOMIAL_HEAP_H -#define LEMON_BINOMIAL_HEAP_H - -///\file -///\ingroup heaps -///\brief Binomial Heap implementation. - -#include -#include -#include -#include -#include - -namespace lemon { - - /// \ingroup heaps - /// - ///\brief Binomial heap data structure. - /// - /// This class implements the \e binomial \e heap data structure. - /// It fully conforms to the \ref concepts::Heap "heap concept". - /// - /// The methods \ref increase() and \ref erase() are not efficient - /// in a binomial heap. In case of many calls of these operations, - /// it is better to use other heap structure, e.g. \ref BinHeap - /// "binary heap". - /// - /// \tparam PR Type of the priorities of the items. - /// \tparam IM A read-writable item map with \c int values, used - /// internally to handle the cross references. - /// \tparam CMP A functor class for comparing the priorities. - /// The default is \c std::less. -#ifdef DOXYGEN - template -#else - template > -#endif - class BinomialHeap { - public: - /// Type of the item-int map. - typedef IM ItemIntMap; - /// Type of the priorities. - typedef PR Prio; - /// Type of the items stored in the heap. - typedef typename ItemIntMap::Key Item; - /// Functor type for comparing the priorities. - typedef CMP Compare; - - /// \brief Type to represent the states of the items. - /// - /// Each item has a state associated to it. It can be "in heap", - /// "pre-heap" or "post-heap". The latter two are indifferent from the - /// heap's point of view, but may be useful to the user. - /// - /// The item-int map must be initialized in such way that it assigns - /// \c PRE_HEAP (-1) to any element to be put in the heap. - enum State { - IN_HEAP = 0, ///< = 0. - PRE_HEAP = -1, ///< = -1. - POST_HEAP = -2 ///< = -2. - }; - - private: - class Store; - - std::vector _data; - int _min, _head; - ItemIntMap &_iim; - Compare _comp; - int _num_items; - - public: - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - explicit BinomialHeap(ItemIntMap &map) - : _min(0), _head(-1), _iim(map), _num_items(0) {} - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - /// \param comp The function object used for comparing the priorities. - BinomialHeap(ItemIntMap &map, const Compare &comp) - : _min(0), _head(-1), _iim(map), _comp(comp), _num_items(0) {} - - /// \brief The number of items stored in the heap. - /// - /// This function returns the number of items stored in the heap. - int size() const { return _num_items; } - - /// \brief Check if the heap is empty. - /// - /// This function returns \c true if the heap is empty. - bool empty() const { return _num_items==0; } - - /// \brief Make the heap empty. - /// - /// This functon makes the heap empty. - /// It does not change the cross reference map. If you want to reuse - /// a heap that is not surely empty, you should first clear it and - /// then you should set the cross reference map to \c PRE_HEAP - /// for each item. - void clear() { - _data.clear(); _min=0; _num_items=0; _head=-1; - } - - /// \brief Set the priority of an item or insert it, if it is - /// not stored in the heap. - /// - /// This method sets the priority of the given item if it is - /// already stored in the heap. Otherwise it inserts the given - /// item into the heap with the given priority. - /// \param item The item. - /// \param value The priority. - void set (const Item& item, const Prio& value) { - int i=_iim[item]; - if ( i >= 0 && _data[i].in ) { - if ( _comp(value, _data[i].prio) ) decrease(item, value); - if ( _comp(_data[i].prio, value) ) increase(item, value); - } else push(item, value); - } - - /// \brief Insert an item into the heap with the given priority. - /// - /// This function inserts the given item into the heap with the - /// given priority. - /// \param item The item to insert. - /// \param value The priority of the item. - /// \pre \e item must not be stored in the heap. - void push (const Item& item, const Prio& value) { - int i=_iim[item]; - if ( i<0 ) { - int s=_data.size(); - _iim.set( item,s ); - Store st; - st.name=item; - st.prio=value; - _data.push_back(st); - i=s; - } - else { - _data[i].parent=_data[i].right_neighbor=_data[i].child=-1; - _data[i].degree=0; - _data[i].in=true; - _data[i].prio=value; - } - - if( 0==_num_items ) { - _head=i; - _min=i; - } else { - merge(i); - if( _comp(_data[i].prio, _data[_min].prio) ) _min=i; - } - ++_num_items; - } - - /// \brief Return the item having minimum priority. - /// - /// This function returns the item having minimum priority. - /// \pre The heap must be non-empty. - Item top() const { return _data[_min].name; } - - /// \brief The minimum priority. - /// - /// This function returns the minimum priority. - /// \pre The heap must be non-empty. - Prio prio() const { return _data[_min].prio; } - - /// \brief The priority of the given item. - /// - /// This function returns the priority of the given item. - /// \param item The item. - /// \pre \e item must be in the heap. - const Prio& operator[](const Item& item) const { - return _data[_iim[item]].prio; - } - - /// \brief Remove the item having minimum priority. - /// - /// This function removes the item having minimum priority. - /// \pre The heap must be non-empty. - void pop() { - _data[_min].in=false; - - int head_child=-1; - if ( _data[_min].child!=-1 ) { - int child=_data[_min].child; - int neighb; - while( child!=-1 ) { - neighb=_data[child].right_neighbor; - _data[child].parent=-1; - _data[child].right_neighbor=head_child; - head_child=child; - child=neighb; - } - } - - if ( _data[_head].right_neighbor==-1 ) { - // there was only one root - _head=head_child; - } - else { - // there were more roots - if( _head!=_min ) { unlace(_min); } - else { _head=_data[_head].right_neighbor; } - merge(head_child); - } - _min=findMin(); - --_num_items; - } - - /// \brief Remove the given item from the heap. - /// - /// This function removes the given item from the heap if it is - /// already stored. - /// \param item The item to delete. - /// \pre \e item must be in the heap. - void erase (const Item& item) { - int i=_iim[item]; - if ( i >= 0 && _data[i].in ) { - decrease( item, _data[_min].prio-1 ); - pop(); - } - } - - /// \brief Decrease the priority of an item to the given value. - /// - /// This function decreases the priority of an item to the given value. - /// \param item The item. - /// \param value The priority. - /// \pre \e item must be stored in the heap with priority at least \e value. - void decrease (Item item, const Prio& value) { - int i=_iim[item]; - int p=_data[i].parent; - _data[i].prio=value; - - while( p!=-1 && _comp(value, _data[p].prio) ) { - _data[i].name=_data[p].name; - _data[i].prio=_data[p].prio; - _data[p].name=item; - _data[p].prio=value; - _iim[_data[i].name]=i; - i=p; - p=_data[p].parent; - } - _iim[item]=i; - if ( _comp(value, _data[_min].prio) ) _min=i; - } - - /// \brief Increase the priority of an item to the given value. - /// - /// This function increases the priority of an item to the given value. - /// \param item The item. - /// \param value The priority. - /// \pre \e item must be stored in the heap with priority at most \e value. - void increase (Item item, const Prio& value) { - erase(item); - push(item, value); - } - - /// \brief Return the state of an item. - /// - /// This method returns \c PRE_HEAP if the given item has never - /// been in the heap, \c IN_HEAP if it is in the heap at the moment, - /// and \c POST_HEAP otherwise. - /// In the latter case it is possible that the item will get back - /// to the heap again. - /// \param item The item. - State state(const Item &item) const { - int i=_iim[item]; - if( i>=0 ) { - if ( _data[i].in ) i=0; - else i=-2; - } - return State(i); - } - - /// \brief Set the state of an item in the heap. - /// - /// This function sets the state of the given item in the heap. - /// It can be used to manually clear the heap when it is important - /// to achive better time complexity. - /// \param i The item. - /// \param st The state. It should not be \c IN_HEAP. - void state(const Item& i, State st) { - switch (st) { - case POST_HEAP: - case PRE_HEAP: - if (state(i) == IN_HEAP) { - erase(i); - } - _iim[i] = st; - break; - case IN_HEAP: - break; - } - } - - private: - - // Find the minimum of the roots - int findMin() { - if( _head!=-1 ) { - int min_loc=_head, min_val=_data[_head].prio; - for( int x=_data[_head].right_neighbor; x!=-1; - x=_data[x].right_neighbor ) { - if( _comp( _data[x].prio,min_val ) ) { - min_val=_data[x].prio; - min_loc=x; - } - } - return min_loc; - } - else return -1; - } - - // Merge the heap with another heap starting at the given position - void merge(int a) { - if( _head==-1 || a==-1 ) return; - if( _data[a].right_neighbor==-1 && - _data[a].degree<=_data[_head].degree ) { - _data[a].right_neighbor=_head; - _head=a; - } else { - interleave(a); - } - if( _data[_head].right_neighbor==-1 ) return; - - int x=_head; - int x_prev=-1, x_next=_data[x].right_neighbor; - while( x_next!=-1 ) { - if( _data[x].degree!=_data[x_next].degree || - ( _data[x_next].right_neighbor!=-1 && - _data[_data[x_next].right_neighbor].degree==_data[x].degree ) ) { - x_prev=x; - x=x_next; - } - else { - if( _comp(_data[x_next].prio,_data[x].prio) ) { - if( x_prev==-1 ) { - _head=x_next; - } else { - _data[x_prev].right_neighbor=x_next; - } - fuse(x,x_next); - x=x_next; - } - else { - _data[x].right_neighbor=_data[x_next].right_neighbor; - fuse(x_next,x); - } - } - x_next=_data[x].right_neighbor; - } - } - - // Interleave the elements of the given list into the list of the roots - void interleave(int a) { - int p=_head, q=a; - int curr=_data.size(); - _data.push_back(Store()); - - while( p!=-1 || q!=-1 ) { - if( q==-1 || ( p!=-1 && _data[p].degree<_data[q].degree ) ) { - _data[curr].right_neighbor=p; - curr=p; - p=_data[p].right_neighbor; - } - else { - _data[curr].right_neighbor=q; - curr=q; - q=_data[q].right_neighbor; - } - } - - _head=_data.back().right_neighbor; - _data.pop_back(); - } - - // Lace node a under node b - void fuse(int a, int b) { - _data[a].parent=b; - _data[a].right_neighbor=_data[b].child; - _data[b].child=a; - - ++_data[b].degree; - } - - // Unlace node a (if it has siblings) - void unlace(int a) { - int neighb=_data[a].right_neighbor; - int other=_head; - - while( _data[other].right_neighbor!=a ) - other=_data[other].right_neighbor; - _data[other].right_neighbor=neighb; - } - - private: - - class Store { - friend class BinomialHeap; - - Item name; - int parent; - int right_neighbor; - int child; - int degree; - bool in; - Prio prio; - - Store() : parent(-1), right_neighbor(-1), child(-1), degree(0), - in(true) {} - }; - }; - -} //namespace lemon - -#endif //LEMON_BINOMIAL_HEAP_H - diff --git a/deps/lemon/lemon/bits/alteration_notifier.h b/deps/lemon/lemon/bits/alteration_notifier.h deleted file mode 100644 index d14fe3634..000000000 --- a/deps/lemon/lemon/bits/alteration_notifier.h +++ /dev/null @@ -1,472 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_ALTERATION_NOTIFIER_H -#define LEMON_BITS_ALTERATION_NOTIFIER_H - -#include -#include - -#include -#include - -//\ingroup graphbits -//\file -//\brief Observer notifier for graph alteration observers. - -namespace lemon { - - // \ingroup graphbits - // - // \brief Notifier class to notify observes about alterations in - // a container. - // - // The simple graphs can be refered as two containers: a node container - // and an edge container. But they do not store values directly, they - // are just key continars for more value containers, which are the - // node and edge maps. - // - // The node and edge sets of the graphs can be changed as we add or erase - // nodes and edges in the graph. LEMON would like to handle easily - // that the node and edge maps should contain values for all nodes or - // edges. If we want to check on every indicing if the map contains - // the current indicing key that cause a drawback in the performance - // in the library. We use another solution: we notify all maps about - // an alteration in the graph, which cause only drawback on the - // alteration of the graph. - // - // This class provides an interface to a node or edge container. - // The first() and next() member functions make possible - // to iterate on the keys of the container. - // The id() function returns an integer id for each key. - // The maxId() function gives back an upper bound of the ids. - // - // For the proper functonality of this class, we should notify it - // about each alteration in the container. The alterations have four type: - // add(), erase(), build() and clear(). The add() and - // erase() signal that only one or few items added or erased to or - // from the graph. If all items are erased from the graph or if a new graph - // is built from an empty graph, then it can be signaled with the - // clear() and build() members. Important rule that if we erase items - // from graphs we should first signal the alteration and after that erase - // them from the container, on the other way on item addition we should - // first extend the container and just after that signal the alteration. - // - // The alteration can be observed with a class inherited from the - // ObserverBase nested class. The signals can be handled with - // overriding the virtual functions defined in the base class. The - // observer base can be attached to the notifier with the - // attach() member and can be detached with detach() function. The - // alteration handlers should not call any function which signals - // an other alteration in the same notifier and should not - // detach any observer from the notifier. - // - // Alteration observers try to be exception safe. If an add() or - // a clear() function throws an exception then the remaining - // observeres will not be notified and the fulfilled additions will - // be rolled back by calling the erase() or clear() functions. - // Hence erase() and clear() should not throw exception. - // Actullay, they can throw only \ref ImmediateDetach exception, - // which detach the observer from the notifier. - // - // There are some cases, when the alteration observing is not completly - // reliable. If we want to carry out the node degree in the graph - // as in the \ref InDegMap and we use the reverseArc(), then it cause - // unreliable functionality. Because the alteration observing signals - // only erasing and adding but not the reversing, it will stores bad - // degrees. Apart form that the subgraph adaptors cannot even signal - // the alterations because just a setting in the filter map can modify - // the graph and this cannot be watched in any way. - // - // \param _Container The container which is observed. - // \param _Item The item type which is obserbved. - - template - class AlterationNotifier { - public: - - typedef True Notifier; - - typedef _Container Container; - typedef _Item Item; - - // \brief Exception which can be called from clear() and - // erase(). - // - // From the clear() and erase() function only this - // exception is allowed to throw. The exception immediatly - // detaches the current observer from the notifier. Because the - // clear() and erase() should not throw other exceptions - // it can be used to invalidate the observer. - struct ImmediateDetach {}; - - // \brief ObserverBase is the base class for the observers. - // - // ObserverBase is the abstract base class for the observers. - // It will be notified about an item was inserted into or - // erased from the graph. - // - // The observer interface contains some pure virtual functions - // to override. The add() and erase() functions are - // to notify the oberver when one item is added or erased. - // - // The build() and clear() members are to notify the observer - // about the container is built from an empty container or - // is cleared to an empty container. - class ObserverBase { - protected: - typedef AlterationNotifier Notifier; - - friend class AlterationNotifier; - - // \brief Default constructor. - // - // Default constructor for ObserverBase. - ObserverBase() : _notifier(0) {} - - // \brief Constructor which attach the observer into notifier. - // - // Constructor which attach the observer into notifier. - ObserverBase(AlterationNotifier& nf) { - attach(nf); - } - - // \brief Constructor which attach the obserever to the same notifier. - // - // Constructor which attach the obserever to the same notifier as - // the other observer is attached to. - ObserverBase(const ObserverBase& copy) { - if (copy.attached()) { - attach(*copy.notifier()); - } - } - - // \brief Destructor - virtual ~ObserverBase() { - if (attached()) { - detach(); - } - } - - // \brief Attaches the observer into an AlterationNotifier. - // - // This member attaches the observer into an AlterationNotifier. - void attach(AlterationNotifier& nf) { - nf.attach(*this); - } - - // \brief Detaches the observer into an AlterationNotifier. - // - // This member detaches the observer from an AlterationNotifier. - void detach() { - _notifier->detach(*this); - } - - // \brief Gives back a pointer to the notifier which the map - // attached into. - // - // This function gives back a pointer to the notifier which the map - // attached into. - Notifier* notifier() const { return const_cast(_notifier); } - - // Gives back true when the observer is attached into a notifier. - bool attached() const { return _notifier != 0; } - - private: - - ObserverBase& operator=(const ObserverBase& copy); - - protected: - - Notifier* _notifier; - typename std::list::iterator _index; - - // \brief The member function to notificate the observer about an - // item is added to the container. - // - // The add() member function notificates the observer about an item - // is added to the container. It have to be overrided in the - // subclasses. - virtual void add(const Item&) = 0; - - // \brief The member function to notificate the observer about - // more item is added to the container. - // - // The add() member function notificates the observer about more item - // is added to the container. It have to be overrided in the - // subclasses. - virtual void add(const std::vector& items) = 0; - - // \brief The member function to notificate the observer about an - // item is erased from the container. - // - // The erase() member function notificates the observer about an - // item is erased from the container. It have to be overrided in - // the subclasses. - virtual void erase(const Item&) = 0; - - // \brief The member function to notificate the observer about - // more item is erased from the container. - // - // The erase() member function notificates the observer about more item - // is erased from the container. It have to be overrided in the - // subclasses. - virtual void erase(const std::vector& items) = 0; - - // \brief The member function to notificate the observer about the - // container is built. - // - // The build() member function notificates the observer about the - // container is built from an empty container. It have to be - // overrided in the subclasses. - virtual void build() = 0; - - // \brief The member function to notificate the observer about all - // items are erased from the container. - // - // The clear() member function notificates the observer about all - // items are erased from the container. It have to be overrided in - // the subclasses. - virtual void clear() = 0; - - }; - - protected: - - const Container* container; - - typedef std::list Observers; - Observers _observers; - lemon::bits::Lock _lock; - - public: - - // \brief Default constructor. - // - // The default constructor of the AlterationNotifier. - // It creates an empty notifier. - AlterationNotifier() - : container(0) {} - - // \brief Constructor. - // - // Constructor with the observed container parameter. - AlterationNotifier(const Container& _container) - : container(&_container) {} - - // \brief Copy Constructor of the AlterationNotifier. - // - // Copy constructor of the AlterationNotifier. - // It creates only an empty notifier because the copiable - // notifier's observers have to be registered still into that notifier. - AlterationNotifier(const AlterationNotifier& _notifier) - : container(_notifier.container) {} - - // \brief Destructor. - // - // Destructor of the AlterationNotifier. - ~AlterationNotifier() { - typename Observers::iterator it; - for (it = _observers.begin(); it != _observers.end(); ++it) { - (*it)->_notifier = 0; - } - } - - // \brief Sets the container. - // - // Sets the container. - void setContainer(const Container& _container) { - container = &_container; - } - - protected: - - AlterationNotifier& operator=(const AlterationNotifier&); - - public: - - // \brief First item in the container. - // - // Returns the first item in the container. It is - // for start the iteration on the container. - void first(Item& item) const { - container->first(item); - } - - // \brief Next item in the container. - // - // Returns the next item in the container. It is - // for iterate on the container. - void next(Item& item) const { - container->next(item); - } - - // \brief Returns the id of the item. - // - // Returns the id of the item provided by the container. - int id(const Item& item) const { - return container->id(item); - } - - // \brief Returns the maximum id of the container. - // - // Returns the maximum id of the container. - int maxId() const { - return container->maxId(Item()); - } - - protected: - - void attach(ObserverBase& observer) { - _lock.lock(); - observer._index = _observers.insert(_observers.begin(), &observer); - observer._notifier = this; - _lock.unlock(); - } - - void detach(ObserverBase& observer) { - _lock.lock(); - _observers.erase(observer._index); - observer._index = _observers.end(); - observer._notifier = 0; - _lock.unlock(); - } - - public: - - // \brief Notifies all the registed observers about an item added to - // the container. - // - // It notifies all the registed observers about an item added to - // the container. - void add(const Item& item) { - typename Observers::reverse_iterator it; - try { - for (it = _observers.rbegin(); it != _observers.rend(); ++it) { - (*it)->add(item); - } - } catch (...) { - typename Observers::iterator jt; - for (jt = it.base(); jt != _observers.end(); ++jt) { - (*jt)->erase(item); - } - throw; - } - } - - // \brief Notifies all the registed observers about more item added to - // the container. - // - // It notifies all the registed observers about more item added to - // the container. - void add(const std::vector& items) { - typename Observers::reverse_iterator it; - try { - for (it = _observers.rbegin(); it != _observers.rend(); ++it) { - (*it)->add(items); - } - } catch (...) { - typename Observers::iterator jt; - for (jt = it.base(); jt != _observers.end(); ++jt) { - (*jt)->erase(items); - } - throw; - } - } - - // \brief Notifies all the registed observers about an item erased from - // the container. - // - // It notifies all the registed observers about an item erased from - // the container. - void erase(const Item& item) throw() { - typename Observers::iterator it = _observers.begin(); - while (it != _observers.end()) { - try { - (*it)->erase(item); - ++it; - } catch (const ImmediateDetach&) { - (*it)->_index = _observers.end(); - (*it)->_notifier = 0; - it = _observers.erase(it); - } - } - } - - // \brief Notifies all the registed observers about more item erased - // from the container. - // - // It notifies all the registed observers about more item erased from - // the container. - void erase(const std::vector& items) { - typename Observers::iterator it = _observers.begin(); - while (it != _observers.end()) { - try { - (*it)->erase(items); - ++it; - } catch (const ImmediateDetach&) { - (*it)->_index = _observers.end(); - (*it)->_notifier = 0; - it = _observers.erase(it); - } - } - } - - // \brief Notifies all the registed observers about the container is - // built. - // - // Notifies all the registed observers about the container is built - // from an empty container. - void build() { - typename Observers::reverse_iterator it; - try { - for (it = _observers.rbegin(); it != _observers.rend(); ++it) { - (*it)->build(); - } - } catch (...) { - typename Observers::iterator jt; - for (jt = it.base(); jt != _observers.end(); ++jt) { - (*jt)->clear(); - } - throw; - } - } - - // \brief Notifies all the registed observers about all items are - // erased. - // - // Notifies all the registed observers about all items are erased - // from the container. - void clear() { - typename Observers::iterator it = _observers.begin(); - while (it != _observers.end()) { - try { - (*it)->clear(); - ++it; - } catch (const ImmediateDetach&) { - (*it)->_index = _observers.end(); - (*it)->_notifier = 0; - it = _observers.erase(it); - } - } - } - }; - -} - -#endif diff --git a/deps/lemon/lemon/bits/array_map.h b/deps/lemon/lemon/bits/array_map.h deleted file mode 100644 index 355ee0082..000000000 --- a/deps/lemon/lemon/bits/array_map.h +++ /dev/null @@ -1,351 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_ARRAY_MAP_H -#define LEMON_BITS_ARRAY_MAP_H - -#include - -#include -#include -#include -#include - -// \ingroup graphbits -// \file -// \brief Graph map based on the array storage. - -namespace lemon { - - // \ingroup graphbits - // - // \brief Graph map based on the array storage. - // - // The ArrayMap template class is graph map structure that automatically - // updates the map when a key is added to or erased from the graph. - // This map uses the allocators to implement the container functionality. - // - // The template parameters are the Graph, the current Item type and - // the Value type of the map. - template - class ArrayMap - : public ItemSetTraits<_Graph, _Item>::ItemNotifier::ObserverBase { - public: - // The graph type. - typedef _Graph GraphType; - // The item type. - typedef _Item Item; - // The reference map tag. - typedef True ReferenceMapTag; - - // The key type of the map. - typedef _Item Key; - // The value type of the map. - typedef _Value Value; - - // The const reference type of the map. - typedef const _Value& ConstReference; - // The reference type of the map. - typedef _Value& Reference; - - // The map type. - typedef ArrayMap Map; - - // The notifier type. - typedef typename ItemSetTraits<_Graph, _Item>::ItemNotifier Notifier; - - private: - - // The MapBase of the Map which imlements the core regisitry function. - typedef typename Notifier::ObserverBase Parent; - - typedef std::allocator Allocator; - - public: - - // \brief Graph initialized map constructor. - // - // Graph initialized map constructor. - explicit ArrayMap(const GraphType& graph) { - Parent::attach(graph.notifier(Item())); - allocate_memory(); - Notifier* nf = Parent::notifier(); - Item it; - for (nf->first(it); it != INVALID; nf->next(it)) { - int id = nf->id(it);; - allocator.construct(&(values[id]), Value()); - } - } - - // \brief Constructor to use default value to initialize the map. - // - // It constructs a map and initialize all of the the map. - ArrayMap(const GraphType& graph, const Value& value) { - Parent::attach(graph.notifier(Item())); - allocate_memory(); - Notifier* nf = Parent::notifier(); - Item it; - for (nf->first(it); it != INVALID; nf->next(it)) { - int id = nf->id(it);; - allocator.construct(&(values[id]), value); - } - } - - private: - // \brief Constructor to copy a map of the same map type. - // - // Constructor to copy a map of the same map type. - ArrayMap(const ArrayMap& copy) : Parent() { - if (copy.attached()) { - attach(*copy.notifier()); - } - capacity = copy.capacity; - if (capacity == 0) return; - values = allocator.allocate(capacity); - Notifier* nf = Parent::notifier(); - Item it; - for (nf->first(it); it != INVALID; nf->next(it)) { - int id = nf->id(it);; - allocator.construct(&(values[id]), copy.values[id]); - } - } - - // \brief Assign operator. - // - // This operator assigns for each item in the map the - // value mapped to the same item in the copied map. - // The parameter map should be indiced with the same - // itemset because this assign operator does not change - // the container of the map. - ArrayMap& operator=(const ArrayMap& cmap) { - return operator=(cmap); - } - - - // \brief Template assign operator. - // - // The given parameter should conform to the ReadMap - // concecpt and could be indiced by the current item set of - // the NodeMap. In this case the value for each item - // is assigned by the value of the given ReadMap. - template - ArrayMap& operator=(const CMap& cmap) { - checkConcept, CMap>(); - const typename Parent::Notifier* nf = Parent::notifier(); - Item it; - for (nf->first(it); it != INVALID; nf->next(it)) { - set(it, cmap[it]); - } - return *this; - } - - public: - // \brief The destructor of the map. - // - // The destructor of the map. - virtual ~ArrayMap() { - if (attached()) { - clear(); - detach(); - } - } - - protected: - - using Parent::attach; - using Parent::detach; - using Parent::attached; - - public: - - // \brief The subscript operator. - // - // The subscript operator. The map can be subscripted by the - // actual keys of the graph. - Value& operator[](const Key& key) { - int id = Parent::notifier()->id(key); - return values[id]; - } - - // \brief The const subscript operator. - // - // The const subscript operator. The map can be subscripted by the - // actual keys of the graph. - const Value& operator[](const Key& key) const { - int id = Parent::notifier()->id(key); - return values[id]; - } - - // \brief Setter function of the map. - // - // Setter function of the map. Equivalent with map[key] = val. - // This is a compatibility feature with the not dereferable maps. - void set(const Key& key, const Value& val) { - (*this)[key] = val; - } - - protected: - - // \brief Adds a new key to the map. - // - // It adds a new key to the map. It is called by the observer notifier - // and it overrides the add() member function of the observer base. - virtual void add(const Key& key) { - Notifier* nf = Parent::notifier(); - int id = nf->id(key); - if (id >= capacity) { - int new_capacity = (capacity == 0 ? 1 : capacity); - while (new_capacity <= id) { - new_capacity <<= 1; - } - Value* new_values = allocator.allocate(new_capacity); - Item it; - for (nf->first(it); it != INVALID; nf->next(it)) { - int jd = nf->id(it);; - if (id != jd) { - allocator.construct(&(new_values[jd]), values[jd]); - allocator.destroy(&(values[jd])); - } - } - if (capacity != 0) allocator.deallocate(values, capacity); - values = new_values; - capacity = new_capacity; - } - allocator.construct(&(values[id]), Value()); - } - - // \brief Adds more new keys to the map. - // - // It adds more new keys to the map. It is called by the observer notifier - // and it overrides the add() member function of the observer base. - virtual void add(const std::vector& keys) { - Notifier* nf = Parent::notifier(); - int max_id = -1; - for (int i = 0; i < int(keys.size()); ++i) { - int id = nf->id(keys[i]); - if (id > max_id) { - max_id = id; - } - } - if (max_id >= capacity) { - int new_capacity = (capacity == 0 ? 1 : capacity); - while (new_capacity <= max_id) { - new_capacity <<= 1; - } - Value* new_values = allocator.allocate(new_capacity); - Item it; - for (nf->first(it); it != INVALID; nf->next(it)) { - int id = nf->id(it); - bool found = false; - for (int i = 0; i < int(keys.size()); ++i) { - int jd = nf->id(keys[i]); - if (id == jd) { - found = true; - break; - } - } - if (found) continue; - allocator.construct(&(new_values[id]), values[id]); - allocator.destroy(&(values[id])); - } - if (capacity != 0) allocator.deallocate(values, capacity); - values = new_values; - capacity = new_capacity; - } - for (int i = 0; i < int(keys.size()); ++i) { - int id = nf->id(keys[i]); - allocator.construct(&(values[id]), Value()); - } - } - - // \brief Erase a key from the map. - // - // Erase a key from the map. It is called by the observer notifier - // and it overrides the erase() member function of the observer base. - virtual void erase(const Key& key) { - int id = Parent::notifier()->id(key); - allocator.destroy(&(values[id])); - } - - // \brief Erase more keys from the map. - // - // Erase more keys from the map. It is called by the observer notifier - // and it overrides the erase() member function of the observer base. - virtual void erase(const std::vector& keys) { - for (int i = 0; i < int(keys.size()); ++i) { - int id = Parent::notifier()->id(keys[i]); - allocator.destroy(&(values[id])); - } - } - - // \brief Builds the map. - // - // It builds the map. It is called by the observer notifier - // and it overrides the build() member function of the observer base. - virtual void build() { - Notifier* nf = Parent::notifier(); - allocate_memory(); - Item it; - for (nf->first(it); it != INVALID; nf->next(it)) { - int id = nf->id(it);; - allocator.construct(&(values[id]), Value()); - } - } - - // \brief Clear the map. - // - // It erase all items from the map. It is called by the observer notifier - // and it overrides the clear() member function of the observer base. - virtual void clear() { - Notifier* nf = Parent::notifier(); - if (capacity != 0) { - Item it; - for (nf->first(it); it != INVALID; nf->next(it)) { - int id = nf->id(it); - allocator.destroy(&(values[id])); - } - allocator.deallocate(values, capacity); - capacity = 0; - } - } - - private: - - void allocate_memory() { - int max_id = Parent::notifier()->maxId(); - if (max_id == -1) { - capacity = 0; - values = 0; - return; - } - capacity = 1; - while (capacity <= max_id) { - capacity <<= 1; - } - values = allocator.allocate(capacity); - } - - int capacity; - Value* values; - Allocator allocator; - - }; - -} - -#endif diff --git a/deps/lemon/lemon/bits/bezier.h b/deps/lemon/lemon/bits/bezier.h deleted file mode 100644 index 9d8d1413d..000000000 --- a/deps/lemon/lemon/bits/bezier.h +++ /dev/null @@ -1,174 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BEZIER_H -#define LEMON_BEZIER_H - -//\ingroup misc -//\file -//\brief Classes to compute with Bezier curves. -// -//Up to now this file is used internally by \ref graph_to_eps.h - -#include - -namespace lemon { - namespace dim2 { - -class BezierBase { -public: - typedef lemon::dim2::Point Point; -protected: - static Point conv(Point x,Point y,double t) {return (1-t)*x+t*y;} -}; - -class Bezier1 : public BezierBase -{ -public: - Point p1,p2; - - Bezier1() {} - Bezier1(Point _p1, Point _p2) :p1(_p1), p2(_p2) {} - - Point operator()(double t) const - { - // return conv(conv(p1,p2,t),conv(p2,p3,t),t); - return conv(p1,p2,t); - } - Bezier1 before(double t) const - { - return Bezier1(p1,conv(p1,p2,t)); - } - - Bezier1 after(double t) const - { - return Bezier1(conv(p1,p2,t),p2); - } - - Bezier1 revert() const { return Bezier1(p2,p1);} - Bezier1 operator()(double a,double b) const { return before(b).after(a/b); } - Point grad() const { return p2-p1; } - Point norm() const { return rot90(p2-p1); } - Point grad(double) const { return grad(); } - Point norm(double t) const { return rot90(grad(t)); } -}; - -class Bezier2 : public BezierBase -{ -public: - Point p1,p2,p3; - - Bezier2() {} - Bezier2(Point _p1, Point _p2, Point _p3) :p1(_p1), p2(_p2), p3(_p3) {} - Bezier2(const Bezier1 &b) : p1(b.p1), p2(conv(b.p1,b.p2,.5)), p3(b.p2) {} - Point operator()(double t) const - { - // return conv(conv(p1,p2,t),conv(p2,p3,t),t); - return ((1-t)*(1-t))*p1+(2*(1-t)*t)*p2+(t*t)*p3; - } - Bezier2 before(double t) const - { - Point q(conv(p1,p2,t)); - Point r(conv(p2,p3,t)); - return Bezier2(p1,q,conv(q,r,t)); - } - - Bezier2 after(double t) const - { - Point q(conv(p1,p2,t)); - Point r(conv(p2,p3,t)); - return Bezier2(conv(q,r,t),r,p3); - } - Bezier2 revert() const { return Bezier2(p3,p2,p1);} - Bezier2 operator()(double a,double b) const { return before(b).after(a/b); } - Bezier1 grad() const { return Bezier1(2.0*(p2-p1),2.0*(p3-p2)); } - Bezier1 norm() const { return Bezier1(2.0*rot90(p2-p1),2.0*rot90(p3-p2)); } - Point grad(double t) const { return grad()(t); } - Point norm(double t) const { return rot90(grad(t)); } -}; - -class Bezier3 : public BezierBase -{ -public: - Point p1,p2,p3,p4; - - Bezier3() {} - Bezier3(Point _p1, Point _p2, Point _p3, Point _p4) - : p1(_p1), p2(_p2), p3(_p3), p4(_p4) {} - Bezier3(const Bezier1 &b) : p1(b.p1), p2(conv(b.p1,b.p2,1.0/3.0)), - p3(conv(b.p1,b.p2,2.0/3.0)), p4(b.p2) {} - Bezier3(const Bezier2 &b) : p1(b.p1), p2(conv(b.p1,b.p2,2.0/3.0)), - p3(conv(b.p2,b.p3,1.0/3.0)), p4(b.p3) {} - - Point operator()(double t) const - { - // return Bezier2(conv(p1,p2,t),conv(p2,p3,t),conv(p3,p4,t))(t); - return ((1-t)*(1-t)*(1-t))*p1+(3*t*(1-t)*(1-t))*p2+ - (3*t*t*(1-t))*p3+(t*t*t)*p4; - } - Bezier3 before(double t) const - { - Point p(conv(p1,p2,t)); - Point q(conv(p2,p3,t)); - Point r(conv(p3,p4,t)); - Point a(conv(p,q,t)); - Point b(conv(q,r,t)); - Point c(conv(a,b,t)); - return Bezier3(p1,p,a,c); - } - - Bezier3 after(double t) const - { - Point p(conv(p1,p2,t)); - Point q(conv(p2,p3,t)); - Point r(conv(p3,p4,t)); - Point a(conv(p,q,t)); - Point b(conv(q,r,t)); - Point c(conv(a,b,t)); - return Bezier3(c,b,r,p4); - } - Bezier3 revert() const { return Bezier3(p4,p3,p2,p1);} - Bezier3 operator()(double a,double b) const { return before(b).after(a/b); } - Bezier2 grad() const { return Bezier2(3.0*(p2-p1),3.0*(p3-p2),3.0*(p4-p3)); } - Bezier2 norm() const { return Bezier2(3.0*rot90(p2-p1), - 3.0*rot90(p3-p2), - 3.0*rot90(p4-p3)); } - Point grad(double t) const { return grad()(t); } - Point norm(double t) const { return rot90(grad(t)); } - - template - R recSplit(F &_f,const S &_s,D _d) const - { - const Point a=(p1+p2)/2; - const Point b=(p2+p3)/2; - const Point c=(p3+p4)/2; - const Point d=(a+b)/2; - const Point e=(b+c)/2; - // const Point f=(d+e)/2; - R f1=_f(Bezier3(p1,a,d,e),_d); - R f2=_f(Bezier3(e,d,c,p4),_d); - return _s(f1,f2); - } - -}; - - -} //END OF NAMESPACE dim2 -} //END OF NAMESPACE lemon - -#endif // LEMON_BEZIER_H diff --git a/deps/lemon/lemon/bits/default_map.h b/deps/lemon/lemon/bits/default_map.h deleted file mode 100644 index 23728e427..000000000 --- a/deps/lemon/lemon/bits/default_map.h +++ /dev/null @@ -1,182 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_DEFAULT_MAP_H -#define LEMON_BITS_DEFAULT_MAP_H - -#include -#include -#include -//#include - -//\ingroup graphbits -//\file -//\brief Graph maps that construct and destruct their elements dynamically. - -namespace lemon { - - - //#ifndef LEMON_USE_DEBUG_MAP - - template - struct DefaultMapSelector { - typedef ArrayMap<_Graph, _Item, _Value> Map; - }; - - // bool - template - struct DefaultMapSelector<_Graph, _Item, bool> { - typedef VectorMap<_Graph, _Item, bool> Map; - }; - - // char - template - struct DefaultMapSelector<_Graph, _Item, char> { - typedef VectorMap<_Graph, _Item, char> Map; - }; - - template - struct DefaultMapSelector<_Graph, _Item, signed char> { - typedef VectorMap<_Graph, _Item, signed char> Map; - }; - - template - struct DefaultMapSelector<_Graph, _Item, unsigned char> { - typedef VectorMap<_Graph, _Item, unsigned char> Map; - }; - - - // int - template - struct DefaultMapSelector<_Graph, _Item, signed int> { - typedef VectorMap<_Graph, _Item, signed int> Map; - }; - - template - struct DefaultMapSelector<_Graph, _Item, unsigned int> { - typedef VectorMap<_Graph, _Item, unsigned int> Map; - }; - - - // short - template - struct DefaultMapSelector<_Graph, _Item, signed short> { - typedef VectorMap<_Graph, _Item, signed short> Map; - }; - - template - struct DefaultMapSelector<_Graph, _Item, unsigned short> { - typedef VectorMap<_Graph, _Item, unsigned short> Map; - }; - - - // long - template - struct DefaultMapSelector<_Graph, _Item, signed long> { - typedef VectorMap<_Graph, _Item, signed long> Map; - }; - - template - struct DefaultMapSelector<_Graph, _Item, unsigned long> { - typedef VectorMap<_Graph, _Item, unsigned long> Map; - }; - - -#if defined LEMON_HAVE_LONG_LONG - - // long long - template - struct DefaultMapSelector<_Graph, _Item, signed long long> { - typedef VectorMap<_Graph, _Item, signed long long> Map; - }; - - template - struct DefaultMapSelector<_Graph, _Item, unsigned long long> { - typedef VectorMap<_Graph, _Item, unsigned long long> Map; - }; - -#endif - - - // float - template - struct DefaultMapSelector<_Graph, _Item, float> { - typedef VectorMap<_Graph, _Item, float> Map; - }; - - - // double - template - struct DefaultMapSelector<_Graph, _Item, double> { - typedef VectorMap<_Graph, _Item, double> Map; - }; - - - // long double - template - struct DefaultMapSelector<_Graph, _Item, long double> { - typedef VectorMap<_Graph, _Item, long double> Map; - }; - - - // pointer - template - struct DefaultMapSelector<_Graph, _Item, _Ptr*> { - typedef VectorMap<_Graph, _Item, _Ptr*> Map; - }; - -// #else - -// template -// struct DefaultMapSelector { -// typedef DebugMap<_Graph, _Item, _Value> Map; -// }; - -// #endif - - // DefaultMap class - template - class DefaultMap - : public DefaultMapSelector<_Graph, _Item, _Value>::Map { - typedef typename DefaultMapSelector<_Graph, _Item, _Value>::Map Parent; - - public: - typedef DefaultMap<_Graph, _Item, _Value> Map; - - typedef typename Parent::GraphType GraphType; - typedef typename Parent::Value Value; - - explicit DefaultMap(const GraphType& graph) : Parent(graph) {} - DefaultMap(const GraphType& graph, const Value& value) - : Parent(graph, value) {} - - DefaultMap& operator=(const DefaultMap& cmap) { - return operator=(cmap); - } - - template - DefaultMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - -} - -#endif diff --git a/deps/lemon/lemon/bits/edge_set_extender.h b/deps/lemon/lemon/bits/edge_set_extender.h deleted file mode 100644 index 364ca2ee6..000000000 --- a/deps/lemon/lemon/bits/edge_set_extender.h +++ /dev/null @@ -1,627 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_EDGE_SET_EXTENDER_H -#define LEMON_BITS_EDGE_SET_EXTENDER_H - -#include -#include -#include -#include - -//\ingroup digraphbits -//\file -//\brief Extenders for the arc set types -namespace lemon { - - // \ingroup digraphbits - // - // \brief Extender for the ArcSets - template - class ArcSetExtender : public Base { - typedef Base Parent; - - public: - - typedef ArcSetExtender Digraph; - - // Base extensions - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - - int maxId(Node) const { - return Parent::maxNodeId(); - } - - int maxId(Arc) const { - return Parent::maxArcId(); - } - - Node fromId(int id, Node) const { - return Parent::nodeFromId(id); - } - - Arc fromId(int id, Arc) const { - return Parent::arcFromId(id); - } - - Node oppositeNode(const Node &n, const Arc &e) const { - if (n == Parent::source(e)) - return Parent::target(e); - else if(n==Parent::target(e)) - return Parent::source(e); - else - return INVALID; - } - - - // Alteration notifier extensions - - // The arc observer registry. - typedef AlterationNotifier ArcNotifier; - - protected: - - mutable ArcNotifier arc_notifier; - - public: - - using Parent::notifier; - - // Gives back the arc alteration notifier. - ArcNotifier& notifier(Arc) const { - return arc_notifier; - } - - // Iterable extensions - - class NodeIt : public Node { - const Digraph* digraph; - public: - - NodeIt() {} - - NodeIt(Invalid i) : Node(i) { } - - explicit NodeIt(const Digraph& _graph) : digraph(&_graph) { - _graph.first(static_cast(*this)); - } - - NodeIt(const Digraph& _graph, const Node& node) - : Node(node), digraph(&_graph) {} - - NodeIt& operator++() { - digraph->next(*this); - return *this; - } - - }; - - - class ArcIt : public Arc { - const Digraph* digraph; - public: - - ArcIt() { } - - ArcIt(Invalid i) : Arc(i) { } - - explicit ArcIt(const Digraph& _graph) : digraph(&_graph) { - _graph.first(static_cast(*this)); - } - - ArcIt(const Digraph& _graph, const Arc& e) : - Arc(e), digraph(&_graph) { } - - ArcIt& operator++() { - digraph->next(*this); - return *this; - } - - }; - - - class OutArcIt : public Arc { - const Digraph* digraph; - public: - - OutArcIt() { } - - OutArcIt(Invalid i) : Arc(i) { } - - OutArcIt(const Digraph& _graph, const Node& node) - : digraph(&_graph) { - _graph.firstOut(*this, node); - } - - OutArcIt(const Digraph& _graph, const Arc& arc) - : Arc(arc), digraph(&_graph) {} - - OutArcIt& operator++() { - digraph->nextOut(*this); - return *this; - } - - }; - - - class InArcIt : public Arc { - const Digraph* digraph; - public: - - InArcIt() { } - - InArcIt(Invalid i) : Arc(i) { } - - InArcIt(const Digraph& _graph, const Node& node) - : digraph(&_graph) { - _graph.firstIn(*this, node); - } - - InArcIt(const Digraph& _graph, const Arc& arc) : - Arc(arc), digraph(&_graph) {} - - InArcIt& operator++() { - digraph->nextIn(*this); - return *this; - } - - }; - - // \brief Base node of the iterator - // - // Returns the base node (ie. the source in this case) of the iterator - Node baseNode(const OutArcIt &e) const { - return Parent::source(static_cast(e)); - } - // \brief Running node of the iterator - // - // Returns the running node (ie. the target in this case) of the - // iterator - Node runningNode(const OutArcIt &e) const { - return Parent::target(static_cast(e)); - } - - // \brief Base node of the iterator - // - // Returns the base node (ie. the target in this case) of the iterator - Node baseNode(const InArcIt &e) const { - return Parent::target(static_cast(e)); - } - // \brief Running node of the iterator - // - // Returns the running node (ie. the source in this case) of the - // iterator - Node runningNode(const InArcIt &e) const { - return Parent::source(static_cast(e)); - } - - using Parent::first; - - // Mappable extension - - template - class ArcMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit ArcMap(const Digraph& _g) - : Parent(_g) {} - ArcMap(const Digraph& _g, const _Value& _v) - : Parent(_g, _v) {} - - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - - // Alteration extension - - Arc addArc(const Node& from, const Node& to) { - Arc arc = Parent::addArc(from, to); - notifier(Arc()).add(arc); - return arc; - } - - void clear() { - notifier(Arc()).clear(); - Parent::clear(); - } - - void erase(const Arc& arc) { - notifier(Arc()).erase(arc); - Parent::erase(arc); - } - - ArcSetExtender() { - arc_notifier.setContainer(*this); - } - - ~ArcSetExtender() { - arc_notifier.clear(); - } - - }; - - - // \ingroup digraphbits - // - // \brief Extender for the EdgeSets - template - class EdgeSetExtender : public Base { - typedef Base Parent; - - public: - - typedef EdgeSetExtender Graph; - - typedef True UndirectedTag; - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - typedef typename Parent::Edge Edge; - - int maxId(Node) const { - return Parent::maxNodeId(); - } - - int maxId(Arc) const { - return Parent::maxArcId(); - } - - int maxId(Edge) const { - return Parent::maxEdgeId(); - } - - Node fromId(int id, Node) const { - return Parent::nodeFromId(id); - } - - Arc fromId(int id, Arc) const { - return Parent::arcFromId(id); - } - - Edge fromId(int id, Edge) const { - return Parent::edgeFromId(id); - } - - Node oppositeNode(const Node &n, const Edge &e) const { - if( n == Parent::u(e)) - return Parent::v(e); - else if( n == Parent::v(e)) - return Parent::u(e); - else - return INVALID; - } - - Arc oppositeArc(const Arc &e) const { - return Parent::direct(e, !Parent::direction(e)); - } - - using Parent::direct; - Arc direct(const Edge &e, const Node &s) const { - return Parent::direct(e, Parent::u(e) == s); - } - - typedef AlterationNotifier ArcNotifier; - typedef AlterationNotifier EdgeNotifier; - - - protected: - - mutable ArcNotifier arc_notifier; - mutable EdgeNotifier edge_notifier; - - public: - - using Parent::notifier; - - ArcNotifier& notifier(Arc) const { - return arc_notifier; - } - - EdgeNotifier& notifier(Edge) const { - return edge_notifier; - } - - - class NodeIt : public Node { - const Graph* graph; - public: - - NodeIt() {} - - NodeIt(Invalid i) : Node(i) { } - - explicit NodeIt(const Graph& _graph) : graph(&_graph) { - _graph.first(static_cast(*this)); - } - - NodeIt(const Graph& _graph, const Node& node) - : Node(node), graph(&_graph) {} - - NodeIt& operator++() { - graph->next(*this); - return *this; - } - - }; - - - class ArcIt : public Arc { - const Graph* graph; - public: - - ArcIt() { } - - ArcIt(Invalid i) : Arc(i) { } - - explicit ArcIt(const Graph& _graph) : graph(&_graph) { - _graph.first(static_cast(*this)); - } - - ArcIt(const Graph& _graph, const Arc& e) : - Arc(e), graph(&_graph) { } - - ArcIt& operator++() { - graph->next(*this); - return *this; - } - - }; - - - class OutArcIt : public Arc { - const Graph* graph; - public: - - OutArcIt() { } - - OutArcIt(Invalid i) : Arc(i) { } - - OutArcIt(const Graph& _graph, const Node& node) - : graph(&_graph) { - _graph.firstOut(*this, node); - } - - OutArcIt(const Graph& _graph, const Arc& arc) - : Arc(arc), graph(&_graph) {} - - OutArcIt& operator++() { - graph->nextOut(*this); - return *this; - } - - }; - - - class InArcIt : public Arc { - const Graph* graph; - public: - - InArcIt() { } - - InArcIt(Invalid i) : Arc(i) { } - - InArcIt(const Graph& _graph, const Node& node) - : graph(&_graph) { - _graph.firstIn(*this, node); - } - - InArcIt(const Graph& _graph, const Arc& arc) : - Arc(arc), graph(&_graph) {} - - InArcIt& operator++() { - graph->nextIn(*this); - return *this; - } - - }; - - - class EdgeIt : public Parent::Edge { - const Graph* graph; - public: - - EdgeIt() { } - - EdgeIt(Invalid i) : Edge(i) { } - - explicit EdgeIt(const Graph& _graph) : graph(&_graph) { - _graph.first(static_cast(*this)); - } - - EdgeIt(const Graph& _graph, const Edge& e) : - Edge(e), graph(&_graph) { } - - EdgeIt& operator++() { - graph->next(*this); - return *this; - } - - }; - - class IncEdgeIt : public Parent::Edge { - friend class EdgeSetExtender; - const Graph* graph; - bool direction; - public: - - IncEdgeIt() { } - - IncEdgeIt(Invalid i) : Edge(i), direction(false) { } - - IncEdgeIt(const Graph& _graph, const Node &n) : graph(&_graph) { - _graph.firstInc(*this, direction, n); - } - - IncEdgeIt(const Graph& _graph, const Edge &ue, const Node &n) - : graph(&_graph), Edge(ue) { - direction = (_graph.source(ue) == n); - } - - IncEdgeIt& operator++() { - graph->nextInc(*this, direction); - return *this; - } - }; - - // \brief Base node of the iterator - // - // Returns the base node (ie. the source in this case) of the iterator - Node baseNode(const OutArcIt &e) const { - return Parent::source(static_cast(e)); - } - // \brief Running node of the iterator - // - // Returns the running node (ie. the target in this case) of the - // iterator - Node runningNode(const OutArcIt &e) const { - return Parent::target(static_cast(e)); - } - - // \brief Base node of the iterator - // - // Returns the base node (ie. the target in this case) of the iterator - Node baseNode(const InArcIt &e) const { - return Parent::target(static_cast(e)); - } - // \brief Running node of the iterator - // - // Returns the running node (ie. the source in this case) of the - // iterator - Node runningNode(const InArcIt &e) const { - return Parent::source(static_cast(e)); - } - - // Base node of the iterator - // - // Returns the base node of the iterator - Node baseNode(const IncEdgeIt &e) const { - return e.direction ? this->u(e) : this->v(e); - } - // Running node of the iterator - // - // Returns the running node of the iterator - Node runningNode(const IncEdgeIt &e) const { - return e.direction ? this->v(e) : this->u(e); - } - - - template - class ArcMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit ArcMap(const Graph& _g) - : Parent(_g) {} - ArcMap(const Graph& _g, const _Value& _v) - : Parent(_g, _v) {} - - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - - template - class EdgeMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit EdgeMap(const Graph& _g) - : Parent(_g) {} - - EdgeMap(const Graph& _g, const _Value& _v) - : Parent(_g, _v) {} - - EdgeMap& operator=(const EdgeMap& cmap) { - return operator=(cmap); - } - - template - EdgeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - - // Alteration extension - - Edge addEdge(const Node& from, const Node& to) { - Edge edge = Parent::addEdge(from, to); - notifier(Edge()).add(edge); - std::vector arcs; - arcs.push_back(Parent::direct(edge, true)); - arcs.push_back(Parent::direct(edge, false)); - notifier(Arc()).add(arcs); - return edge; - } - - void clear() { - notifier(Arc()).clear(); - notifier(Edge()).clear(); - Parent::clear(); - } - - void erase(const Edge& edge) { - std::vector arcs; - arcs.push_back(Parent::direct(edge, true)); - arcs.push_back(Parent::direct(edge, false)); - notifier(Arc()).erase(arcs); - notifier(Edge()).erase(edge); - Parent::erase(edge); - } - - - EdgeSetExtender() { - arc_notifier.setContainer(*this); - edge_notifier.setContainer(*this); - } - - ~EdgeSetExtender() { - edge_notifier.clear(); - arc_notifier.clear(); - } - - }; - -} - -#endif diff --git a/deps/lemon/lemon/bits/enable_if.h b/deps/lemon/lemon/bits/enable_if.h deleted file mode 100644 index f0d8de4d3..000000000 --- a/deps/lemon/lemon/bits/enable_if.h +++ /dev/null @@ -1,131 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -// This file contains a modified version of the enable_if library from BOOST. -// See the appropriate copyright notice below. - -// Boost enable_if library - -// Copyright 2003 (c) The Trustees of Indiana University. - -// Use, modification, and distribution is subject to the Boost Software -// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -// Authors: Jaakko Jarvi (jajarvi at osl.iu.edu) -// Jeremiah Willcock (jewillco at osl.iu.edu) -// Andrew Lumsdaine (lums at osl.iu.edu) - - -#ifndef LEMON_BITS_ENABLE_IF_H -#define LEMON_BITS_ENABLE_IF_H - -//\file -//\brief Miscellaneous basic utilities - -namespace lemon -{ - - // Basic type for defining "tags". A "YES" condition for \c enable_if. - - // Basic type for defining "tags". A "YES" condition for \c enable_if. - // - //\sa False - struct True { - //\e - static const bool value = true; - }; - - // Basic type for defining "tags". A "NO" condition for \c enable_if. - - // Basic type for defining "tags". A "NO" condition for \c enable_if. - // - //\sa True - struct False { - //\e - static const bool value = false; - }; - - - - template - struct Wrap { - const T &value; - Wrap(const T &t) : value(t) {} - }; - - /**************** dummy class to avoid ambiguity ****************/ - - template struct dummy { dummy(int) {} }; - - /**************** enable_if from BOOST ****************/ - - template - struct exists { - typedef T type; - }; - - - template - struct enable_if_c { - typedef T type; - }; - - template - struct enable_if_c {}; - - template - struct enable_if : public enable_if_c {}; - - template - struct lazy_enable_if_c { - typedef typename T::type type; - }; - - template - struct lazy_enable_if_c {}; - - template - struct lazy_enable_if : public lazy_enable_if_c {}; - - - template - struct disable_if_c { - typedef T type; - }; - - template - struct disable_if_c {}; - - template - struct disable_if : public disable_if_c {}; - - template - struct lazy_disable_if_c { - typedef typename T::type type; - }; - - template - struct lazy_disable_if_c {}; - - template - struct lazy_disable_if : public lazy_disable_if_c {}; - -} // namespace lemon - -#endif diff --git a/deps/lemon/lemon/bits/graph_adaptor_extender.h b/deps/lemon/lemon/bits/graph_adaptor_extender.h deleted file mode 100644 index c38c8e1d6..000000000 --- a/deps/lemon/lemon/bits/graph_adaptor_extender.h +++ /dev/null @@ -1,401 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_GRAPH_ADAPTOR_EXTENDER_H -#define LEMON_BITS_GRAPH_ADAPTOR_EXTENDER_H - -#include -#include - -namespace lemon { - - template - class DigraphAdaptorExtender : public _Digraph { - typedef _Digraph Parent; - - public: - - typedef _Digraph Digraph; - typedef DigraphAdaptorExtender Adaptor; - - // Base extensions - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - - int maxId(Node) const { - return Parent::maxNodeId(); - } - - int maxId(Arc) const { - return Parent::maxArcId(); - } - - Node fromId(int id, Node) const { - return Parent::nodeFromId(id); - } - - Arc fromId(int id, Arc) const { - return Parent::arcFromId(id); - } - - Node oppositeNode(const Node &n, const Arc &e) const { - if (n == Parent::source(e)) - return Parent::target(e); - else if(n==Parent::target(e)) - return Parent::source(e); - else - return INVALID; - } - - class NodeIt : public Node { - const Adaptor* _adaptor; - public: - - NodeIt() {} - - NodeIt(Invalid i) : Node(i) { } - - explicit NodeIt(const Adaptor& adaptor) : _adaptor(&adaptor) { - _adaptor->first(static_cast(*this)); - } - - NodeIt(const Adaptor& adaptor, const Node& node) - : Node(node), _adaptor(&adaptor) {} - - NodeIt& operator++() { - _adaptor->next(*this); - return *this; - } - - }; - - - class ArcIt : public Arc { - const Adaptor* _adaptor; - public: - - ArcIt() { } - - ArcIt(Invalid i) : Arc(i) { } - - explicit ArcIt(const Adaptor& adaptor) : _adaptor(&adaptor) { - _adaptor->first(static_cast(*this)); - } - - ArcIt(const Adaptor& adaptor, const Arc& e) : - Arc(e), _adaptor(&adaptor) { } - - ArcIt& operator++() { - _adaptor->next(*this); - return *this; - } - - }; - - - class OutArcIt : public Arc { - const Adaptor* _adaptor; - public: - - OutArcIt() { } - - OutArcIt(Invalid i) : Arc(i) { } - - OutArcIt(const Adaptor& adaptor, const Node& node) - : _adaptor(&adaptor) { - _adaptor->firstOut(*this, node); - } - - OutArcIt(const Adaptor& adaptor, const Arc& arc) - : Arc(arc), _adaptor(&adaptor) {} - - OutArcIt& operator++() { - _adaptor->nextOut(*this); - return *this; - } - - }; - - - class InArcIt : public Arc { - const Adaptor* _adaptor; - public: - - InArcIt() { } - - InArcIt(Invalid i) : Arc(i) { } - - InArcIt(const Adaptor& adaptor, const Node& node) - : _adaptor(&adaptor) { - _adaptor->firstIn(*this, node); - } - - InArcIt(const Adaptor& adaptor, const Arc& arc) : - Arc(arc), _adaptor(&adaptor) {} - - InArcIt& operator++() { - _adaptor->nextIn(*this); - return *this; - } - - }; - - Node baseNode(const OutArcIt &e) const { - return Parent::source(e); - } - Node runningNode(const OutArcIt &e) const { - return Parent::target(e); - } - - Node baseNode(const InArcIt &e) const { - return Parent::target(e); - } - Node runningNode(const InArcIt &e) const { - return Parent::source(e); - } - - }; - - template - class GraphAdaptorExtender : public _Graph { - typedef _Graph Parent; - - public: - - typedef _Graph Graph; - typedef GraphAdaptorExtender Adaptor; - - typedef True UndirectedTag; - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - typedef typename Parent::Edge Edge; - - // Graph extension - - int maxId(Node) const { - return Parent::maxNodeId(); - } - - int maxId(Arc) const { - return Parent::maxArcId(); - } - - int maxId(Edge) const { - return Parent::maxEdgeId(); - } - - Node fromId(int id, Node) const { - return Parent::nodeFromId(id); - } - - Arc fromId(int id, Arc) const { - return Parent::arcFromId(id); - } - - Edge fromId(int id, Edge) const { - return Parent::edgeFromId(id); - } - - Node oppositeNode(const Node &n, const Edge &e) const { - if( n == Parent::u(e)) - return Parent::v(e); - else if( n == Parent::v(e)) - return Parent::u(e); - else - return INVALID; - } - - Arc oppositeArc(const Arc &a) const { - return Parent::direct(a, !Parent::direction(a)); - } - - using Parent::direct; - Arc direct(const Edge &e, const Node &s) const { - return Parent::direct(e, Parent::u(e) == s); - } - - - class NodeIt : public Node { - const Adaptor* _adaptor; - public: - - NodeIt() {} - - NodeIt(Invalid i) : Node(i) { } - - explicit NodeIt(const Adaptor& adaptor) : _adaptor(&adaptor) { - _adaptor->first(static_cast(*this)); - } - - NodeIt(const Adaptor& adaptor, const Node& node) - : Node(node), _adaptor(&adaptor) {} - - NodeIt& operator++() { - _adaptor->next(*this); - return *this; - } - - }; - - - class ArcIt : public Arc { - const Adaptor* _adaptor; - public: - - ArcIt() { } - - ArcIt(Invalid i) : Arc(i) { } - - explicit ArcIt(const Adaptor& adaptor) : _adaptor(&adaptor) { - _adaptor->first(static_cast(*this)); - } - - ArcIt(const Adaptor& adaptor, const Arc& e) : - Arc(e), _adaptor(&adaptor) { } - - ArcIt& operator++() { - _adaptor->next(*this); - return *this; - } - - }; - - - class OutArcIt : public Arc { - const Adaptor* _adaptor; - public: - - OutArcIt() { } - - OutArcIt(Invalid i) : Arc(i) { } - - OutArcIt(const Adaptor& adaptor, const Node& node) - : _adaptor(&adaptor) { - _adaptor->firstOut(*this, node); - } - - OutArcIt(const Adaptor& adaptor, const Arc& arc) - : Arc(arc), _adaptor(&adaptor) {} - - OutArcIt& operator++() { - _adaptor->nextOut(*this); - return *this; - } - - }; - - - class InArcIt : public Arc { - const Adaptor* _adaptor; - public: - - InArcIt() { } - - InArcIt(Invalid i) : Arc(i) { } - - InArcIt(const Adaptor& adaptor, const Node& node) - : _adaptor(&adaptor) { - _adaptor->firstIn(*this, node); - } - - InArcIt(const Adaptor& adaptor, const Arc& arc) : - Arc(arc), _adaptor(&adaptor) {} - - InArcIt& operator++() { - _adaptor->nextIn(*this); - return *this; - } - - }; - - class EdgeIt : public Parent::Edge { - const Adaptor* _adaptor; - public: - - EdgeIt() { } - - EdgeIt(Invalid i) : Edge(i) { } - - explicit EdgeIt(const Adaptor& adaptor) : _adaptor(&adaptor) { - _adaptor->first(static_cast(*this)); - } - - EdgeIt(const Adaptor& adaptor, const Edge& e) : - Edge(e), _adaptor(&adaptor) { } - - EdgeIt& operator++() { - _adaptor->next(*this); - return *this; - } - - }; - - class IncEdgeIt : public Edge { - friend class GraphAdaptorExtender; - const Adaptor* _adaptor; - bool direction; - public: - - IncEdgeIt() { } - - IncEdgeIt(Invalid i) : Edge(i), direction(false) { } - - IncEdgeIt(const Adaptor& adaptor, const Node &n) : _adaptor(&adaptor) { - _adaptor->firstInc(static_cast(*this), direction, n); - } - - IncEdgeIt(const Adaptor& adaptor, const Edge &e, const Node &n) - : _adaptor(&adaptor), Edge(e) { - direction = (_adaptor->u(e) == n); - } - - IncEdgeIt& operator++() { - _adaptor->nextInc(*this, direction); - return *this; - } - }; - - Node baseNode(const OutArcIt &a) const { - return Parent::source(a); - } - Node runningNode(const OutArcIt &a) const { - return Parent::target(a); - } - - Node baseNode(const InArcIt &a) const { - return Parent::target(a); - } - Node runningNode(const InArcIt &a) const { - return Parent::source(a); - } - - Node baseNode(const IncEdgeIt &e) const { - return e.direction ? Parent::u(e) : Parent::v(e); - } - Node runningNode(const IncEdgeIt &e) const { - return e.direction ? Parent::v(e) : Parent::u(e); - } - - }; - -} - - -#endif diff --git a/deps/lemon/lemon/bits/graph_extender.h b/deps/lemon/lemon/bits/graph_extender.h deleted file mode 100644 index 755a8907f..000000000 --- a/deps/lemon/lemon/bits/graph_extender.h +++ /dev/null @@ -1,1332 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_GRAPH_EXTENDER_H -#define LEMON_BITS_GRAPH_EXTENDER_H - -#include - -#include -#include - -#include -#include - -//\ingroup graphbits -//\file -//\brief Extenders for the graph types -namespace lemon { - - // \ingroup graphbits - // - // \brief Extender for the digraph implementations - template - class DigraphExtender : public Base { - typedef Base Parent; - - public: - - typedef DigraphExtender Digraph; - - // Base extensions - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - - int maxId(Node) const { - return Parent::maxNodeId(); - } - - int maxId(Arc) const { - return Parent::maxArcId(); - } - - static Node fromId(int id, Node) { - return Parent::nodeFromId(id); - } - - static Arc fromId(int id, Arc) { - return Parent::arcFromId(id); - } - - Node oppositeNode(const Node &node, const Arc &arc) const { - if (node == Parent::source(arc)) - return Parent::target(arc); - else if(node == Parent::target(arc)) - return Parent::source(arc); - else - return INVALID; - } - - // Alterable extension - - typedef AlterationNotifier NodeNotifier; - typedef AlterationNotifier ArcNotifier; - - - protected: - - mutable NodeNotifier node_notifier; - mutable ArcNotifier arc_notifier; - - public: - - NodeNotifier& notifier(Node) const { - return node_notifier; - } - - ArcNotifier& notifier(Arc) const { - return arc_notifier; - } - - class NodeIt : public Node { - const Digraph* _digraph; - public: - - NodeIt() {} - - NodeIt(Invalid i) : Node(i) { } - - explicit NodeIt(const Digraph& digraph) : _digraph(&digraph) { - _digraph->first(static_cast(*this)); - } - - NodeIt(const Digraph& digraph, const Node& node) - : Node(node), _digraph(&digraph) {} - - NodeIt& operator++() { - _digraph->next(*this); - return *this; - } - - }; - - - class ArcIt : public Arc { - const Digraph* _digraph; - public: - - ArcIt() { } - - ArcIt(Invalid i) : Arc(i) { } - - explicit ArcIt(const Digraph& digraph) : _digraph(&digraph) { - _digraph->first(static_cast(*this)); - } - - ArcIt(const Digraph& digraph, const Arc& arc) : - Arc(arc), _digraph(&digraph) { } - - ArcIt& operator++() { - _digraph->next(*this); - return *this; - } - - }; - - - class OutArcIt : public Arc { - const Digraph* _digraph; - public: - - OutArcIt() { } - - OutArcIt(Invalid i) : Arc(i) { } - - OutArcIt(const Digraph& digraph, const Node& node) - : _digraph(&digraph) { - _digraph->firstOut(*this, node); - } - - OutArcIt(const Digraph& digraph, const Arc& arc) - : Arc(arc), _digraph(&digraph) {} - - OutArcIt& operator++() { - _digraph->nextOut(*this); - return *this; - } - - }; - - - class InArcIt : public Arc { - const Digraph* _digraph; - public: - - InArcIt() { } - - InArcIt(Invalid i) : Arc(i) { } - - InArcIt(const Digraph& digraph, const Node& node) - : _digraph(&digraph) { - _digraph->firstIn(*this, node); - } - - InArcIt(const Digraph& digraph, const Arc& arc) : - Arc(arc), _digraph(&digraph) {} - - InArcIt& operator++() { - _digraph->nextIn(*this); - return *this; - } - - }; - - // \brief Base node of the iterator - // - // Returns the base node (i.e. the source in this case) of the iterator - Node baseNode(const OutArcIt &arc) const { - return Parent::source(arc); - } - // \brief Running node of the iterator - // - // Returns the running node (i.e. the target in this case) of the - // iterator - Node runningNode(const OutArcIt &arc) const { - return Parent::target(arc); - } - - // \brief Base node of the iterator - // - // Returns the base node (i.e. the target in this case) of the iterator - Node baseNode(const InArcIt &arc) const { - return Parent::target(arc); - } - // \brief Running node of the iterator - // - // Returns the running node (i.e. the source in this case) of the - // iterator - Node runningNode(const InArcIt &arc) const { - return Parent::source(arc); - } - - - template - class NodeMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit NodeMap(const Digraph& digraph) - : Parent(digraph) {} - NodeMap(const Digraph& digraph, const _Value& value) - : Parent(digraph, value) {} - - private: - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - template - class ArcMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit ArcMap(const Digraph& digraph) - : Parent(digraph) {} - ArcMap(const Digraph& digraph, const _Value& value) - : Parent(digraph, value) {} - - private: - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - - Node addNode() { - Node node = Parent::addNode(); - notifier(Node()).add(node); - return node; - } - - Arc addArc(const Node& from, const Node& to) { - Arc arc = Parent::addArc(from, to); - notifier(Arc()).add(arc); - return arc; - } - - void clear() { - notifier(Arc()).clear(); - notifier(Node()).clear(); - Parent::clear(); - } - - template - void build(const Digraph& digraph, NodeRefMap& nodeRef, ArcRefMap& arcRef) { - Parent::build(digraph, nodeRef, arcRef); - notifier(Node()).build(); - notifier(Arc()).build(); - } - - void erase(const Node& node) { - Arc arc; - Parent::firstOut(arc, node); - while (arc != INVALID ) { - erase(arc); - Parent::firstOut(arc, node); - } - - Parent::firstIn(arc, node); - while (arc != INVALID ) { - erase(arc); - Parent::firstIn(arc, node); - } - - notifier(Node()).erase(node); - Parent::erase(node); - } - - void erase(const Arc& arc) { - notifier(Arc()).erase(arc); - Parent::erase(arc); - } - - DigraphExtender() { - node_notifier.setContainer(*this); - arc_notifier.setContainer(*this); - } - - - ~DigraphExtender() { - arc_notifier.clear(); - node_notifier.clear(); - } - }; - - // \ingroup _graphbits - // - // \brief Extender for the Graphs - template - class GraphExtender : public Base { - typedef Base Parent; - - public: - - typedef GraphExtender Graph; - - typedef True UndirectedTag; - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - typedef typename Parent::Edge Edge; - - // Graph extension - - int maxId(Node) const { - return Parent::maxNodeId(); - } - - int maxId(Arc) const { - return Parent::maxArcId(); - } - - int maxId(Edge) const { - return Parent::maxEdgeId(); - } - - static Node fromId(int id, Node) { - return Parent::nodeFromId(id); - } - - static Arc fromId(int id, Arc) { - return Parent::arcFromId(id); - } - - static Edge fromId(int id, Edge) { - return Parent::edgeFromId(id); - } - - Node oppositeNode(const Node &n, const Edge &e) const { - if( n == Parent::u(e)) - return Parent::v(e); - else if( n == Parent::v(e)) - return Parent::u(e); - else - return INVALID; - } - - Arc oppositeArc(const Arc &arc) const { - return Parent::direct(arc, !Parent::direction(arc)); - } - - using Parent::direct; - Arc direct(const Edge &edge, const Node &node) const { - return Parent::direct(edge, Parent::u(edge) == node); - } - - // Alterable extension - - typedef AlterationNotifier NodeNotifier; - typedef AlterationNotifier ArcNotifier; - typedef AlterationNotifier EdgeNotifier; - - - protected: - - mutable NodeNotifier node_notifier; - mutable ArcNotifier arc_notifier; - mutable EdgeNotifier edge_notifier; - - public: - - NodeNotifier& notifier(Node) const { - return node_notifier; - } - - ArcNotifier& notifier(Arc) const { - return arc_notifier; - } - - EdgeNotifier& notifier(Edge) const { - return edge_notifier; - } - - - - class NodeIt : public Node { - const Graph* _graph; - public: - - NodeIt() {} - - NodeIt(Invalid i) : Node(i) { } - - explicit NodeIt(const Graph& graph) : _graph(&graph) { - _graph->first(static_cast(*this)); - } - - NodeIt(const Graph& graph, const Node& node) - : Node(node), _graph(&graph) {} - - NodeIt& operator++() { - _graph->next(*this); - return *this; - } - - }; - - - class ArcIt : public Arc { - const Graph* _graph; - public: - - ArcIt() { } - - ArcIt(Invalid i) : Arc(i) { } - - explicit ArcIt(const Graph& graph) : _graph(&graph) { - _graph->first(static_cast(*this)); - } - - ArcIt(const Graph& graph, const Arc& arc) : - Arc(arc), _graph(&graph) { } - - ArcIt& operator++() { - _graph->next(*this); - return *this; - } - - }; - - - class OutArcIt : public Arc { - const Graph* _graph; - public: - - OutArcIt() { } - - OutArcIt(Invalid i) : Arc(i) { } - - OutArcIt(const Graph& graph, const Node& node) - : _graph(&graph) { - _graph->firstOut(*this, node); - } - - OutArcIt(const Graph& graph, const Arc& arc) - : Arc(arc), _graph(&graph) {} - - OutArcIt& operator++() { - _graph->nextOut(*this); - return *this; - } - - }; - - - class InArcIt : public Arc { - const Graph* _graph; - public: - - InArcIt() { } - - InArcIt(Invalid i) : Arc(i) { } - - InArcIt(const Graph& graph, const Node& node) - : _graph(&graph) { - _graph->firstIn(*this, node); - } - - InArcIt(const Graph& graph, const Arc& arc) : - Arc(arc), _graph(&graph) {} - - InArcIt& operator++() { - _graph->nextIn(*this); - return *this; - } - - }; - - - class EdgeIt : public Parent::Edge { - const Graph* _graph; - public: - - EdgeIt() { } - - EdgeIt(Invalid i) : Edge(i) { } - - explicit EdgeIt(const Graph& graph) : _graph(&graph) { - _graph->first(static_cast(*this)); - } - - EdgeIt(const Graph& graph, const Edge& edge) : - Edge(edge), _graph(&graph) { } - - EdgeIt& operator++() { - _graph->next(*this); - return *this; - } - - }; - - class IncEdgeIt : public Parent::Edge { - friend class GraphExtender; - const Graph* _graph; - bool _direction; - public: - - IncEdgeIt() { } - - IncEdgeIt(Invalid i) : Edge(i), _direction(false) { } - - IncEdgeIt(const Graph& graph, const Node &node) : _graph(&graph) { - _graph->firstInc(*this, _direction, node); - } - - IncEdgeIt(const Graph& graph, const Edge &edge, const Node &node) - : _graph(&graph), Edge(edge) { - _direction = (_graph->source(edge) == node); - } - - IncEdgeIt& operator++() { - _graph->nextInc(*this, _direction); - return *this; - } - }; - - // \brief Base node of the iterator - // - // Returns the base node (ie. the source in this case) of the iterator - Node baseNode(const OutArcIt &arc) const { - return Parent::source(static_cast(arc)); - } - // \brief Running node of the iterator - // - // Returns the running node (ie. the target in this case) of the - // iterator - Node runningNode(const OutArcIt &arc) const { - return Parent::target(static_cast(arc)); - } - - // \brief Base node of the iterator - // - // Returns the base node (ie. the target in this case) of the iterator - Node baseNode(const InArcIt &arc) const { - return Parent::target(static_cast(arc)); - } - // \brief Running node of the iterator - // - // Returns the running node (ie. the source in this case) of the - // iterator - Node runningNode(const InArcIt &arc) const { - return Parent::source(static_cast(arc)); - } - - // Base node of the iterator - // - // Returns the base node of the iterator - Node baseNode(const IncEdgeIt &edge) const { - return edge._direction ? this->u(edge) : this->v(edge); - } - // Running node of the iterator - // - // Returns the running node of the iterator - Node runningNode(const IncEdgeIt &edge) const { - return edge._direction ? this->v(edge) : this->u(edge); - } - - // Mappable extension - - template - class NodeMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit NodeMap(const Graph& graph) - : Parent(graph) {} - NodeMap(const Graph& graph, const _Value& value) - : Parent(graph, value) {} - - private: - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - template - class ArcMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit ArcMap(const Graph& graph) - : Parent(graph) {} - ArcMap(const Graph& graph, const _Value& value) - : Parent(graph, value) {} - - private: - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - - template - class EdgeMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit EdgeMap(const Graph& graph) - : Parent(graph) {} - - EdgeMap(const Graph& graph, const _Value& value) - : Parent(graph, value) {} - - private: - EdgeMap& operator=(const EdgeMap& cmap) { - return operator=(cmap); - } - - template - EdgeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - // Alteration extension - - Node addNode() { - Node node = Parent::addNode(); - notifier(Node()).add(node); - return node; - } - - Edge addEdge(const Node& from, const Node& to) { - Edge edge = Parent::addEdge(from, to); - notifier(Edge()).add(edge); - std::vector ev; - ev.push_back(Parent::direct(edge, true)); - ev.push_back(Parent::direct(edge, false)); - notifier(Arc()).add(ev); - return edge; - } - - void clear() { - notifier(Arc()).clear(); - notifier(Edge()).clear(); - notifier(Node()).clear(); - Parent::clear(); - } - - template - void build(const Graph& graph, NodeRefMap& nodeRef, - EdgeRefMap& edgeRef) { - Parent::build(graph, nodeRef, edgeRef); - notifier(Node()).build(); - notifier(Edge()).build(); - notifier(Arc()).build(); - } - - void erase(const Node& node) { - Arc arc; - Parent::firstOut(arc, node); - while (arc != INVALID ) { - erase(arc); - Parent::firstOut(arc, node); - } - - Parent::firstIn(arc, node); - while (arc != INVALID ) { - erase(arc); - Parent::firstIn(arc, node); - } - - notifier(Node()).erase(node); - Parent::erase(node); - } - - void erase(const Edge& edge) { - std::vector av; - av.push_back(Parent::direct(edge, true)); - av.push_back(Parent::direct(edge, false)); - notifier(Arc()).erase(av); - notifier(Edge()).erase(edge); - Parent::erase(edge); - } - - GraphExtender() { - node_notifier.setContainer(*this); - arc_notifier.setContainer(*this); - edge_notifier.setContainer(*this); - } - - ~GraphExtender() { - edge_notifier.clear(); - arc_notifier.clear(); - node_notifier.clear(); - } - - }; - - // \ingroup _graphbits - // - // \brief Extender for the BpGraphs - template - class BpGraphExtender : public Base { - typedef Base Parent; - - public: - - typedef BpGraphExtender BpGraph; - - typedef True UndirectedTag; - - typedef typename Parent::Node Node; - typedef typename Parent::RedNode RedNode; - typedef typename Parent::BlueNode BlueNode; - typedef typename Parent::Arc Arc; - typedef typename Parent::Edge Edge; - - // BpGraph extension - - using Parent::first; - using Parent::next; - using Parent::id; - - int maxId(Node) const { - return Parent::maxNodeId(); - } - - int maxId(RedNode) const { - return Parent::maxRedId(); - } - - int maxId(BlueNode) const { - return Parent::maxBlueId(); - } - - int maxId(Arc) const { - return Parent::maxArcId(); - } - - int maxId(Edge) const { - return Parent::maxEdgeId(); - } - - static Node fromId(int id, Node) { - return Parent::nodeFromId(id); - } - - static Arc fromId(int id, Arc) { - return Parent::arcFromId(id); - } - - static Edge fromId(int id, Edge) { - return Parent::edgeFromId(id); - } - - Node u(Edge e) const { return this->redNode(e); } - Node v(Edge e) const { return this->blueNode(e); } - - Node oppositeNode(const Node &n, const Edge &e) const { - if( n == u(e)) - return v(e); - else if( n == v(e)) - return u(e); - else - return INVALID; - } - - Arc oppositeArc(const Arc &arc) const { - return Parent::direct(arc, !Parent::direction(arc)); - } - - using Parent::direct; - Arc direct(const Edge &edge, const Node &node) const { - return Parent::direct(edge, Parent::redNode(edge) == node); - } - - RedNode asRedNode(const Node& node) const { - if (node == INVALID || Parent::blue(node)) { - return INVALID; - } else { - return Parent::asRedNodeUnsafe(node); - } - } - - BlueNode asBlueNode(const Node& node) const { - if (node == INVALID || Parent::red(node)) { - return INVALID; - } else { - return Parent::asBlueNodeUnsafe(node); - } - } - - // Alterable extension - - typedef AlterationNotifier NodeNotifier; - typedef AlterationNotifier RedNodeNotifier; - typedef AlterationNotifier BlueNodeNotifier; - typedef AlterationNotifier ArcNotifier; - typedef AlterationNotifier EdgeNotifier; - - - protected: - - mutable NodeNotifier node_notifier; - mutable RedNodeNotifier red_node_notifier; - mutable BlueNodeNotifier blue_node_notifier; - mutable ArcNotifier arc_notifier; - mutable EdgeNotifier edge_notifier; - - public: - - NodeNotifier& notifier(Node) const { - return node_notifier; - } - - RedNodeNotifier& notifier(RedNode) const { - return red_node_notifier; - } - - BlueNodeNotifier& notifier(BlueNode) const { - return blue_node_notifier; - } - - ArcNotifier& notifier(Arc) const { - return arc_notifier; - } - - EdgeNotifier& notifier(Edge) const { - return edge_notifier; - } - - - - class NodeIt : public Node { - const BpGraph* _graph; - public: - - NodeIt() {} - - NodeIt(Invalid i) : Node(i) { } - - explicit NodeIt(const BpGraph& graph) : _graph(&graph) { - _graph->first(static_cast(*this)); - } - - NodeIt(const BpGraph& graph, const Node& node) - : Node(node), _graph(&graph) {} - - NodeIt& operator++() { - _graph->next(*this); - return *this; - } - - }; - - class RedNodeIt : public RedNode { - const BpGraph* _graph; - public: - - RedNodeIt() {} - - RedNodeIt(Invalid i) : RedNode(i) { } - - explicit RedNodeIt(const BpGraph& graph) : _graph(&graph) { - _graph->first(static_cast(*this)); - } - - RedNodeIt(const BpGraph& graph, const RedNode& node) - : RedNode(node), _graph(&graph) {} - - RedNodeIt& operator++() { - _graph->next(static_cast(*this)); - return *this; - } - - }; - - class BlueNodeIt : public BlueNode { - const BpGraph* _graph; - public: - - BlueNodeIt() {} - - BlueNodeIt(Invalid i) : BlueNode(i) { } - - explicit BlueNodeIt(const BpGraph& graph) : _graph(&graph) { - _graph->first(static_cast(*this)); - } - - BlueNodeIt(const BpGraph& graph, const BlueNode& node) - : BlueNode(node), _graph(&graph) {} - - BlueNodeIt& operator++() { - _graph->next(static_cast(*this)); - return *this; - } - - }; - - - class ArcIt : public Arc { - const BpGraph* _graph; - public: - - ArcIt() { } - - ArcIt(Invalid i) : Arc(i) { } - - explicit ArcIt(const BpGraph& graph) : _graph(&graph) { - _graph->first(static_cast(*this)); - } - - ArcIt(const BpGraph& graph, const Arc& arc) : - Arc(arc), _graph(&graph) { } - - ArcIt& operator++() { - _graph->next(*this); - return *this; - } - - }; - - - class OutArcIt : public Arc { - const BpGraph* _graph; - public: - - OutArcIt() { } - - OutArcIt(Invalid i) : Arc(i) { } - - OutArcIt(const BpGraph& graph, const Node& node) - : _graph(&graph) { - _graph->firstOut(*this, node); - } - - OutArcIt(const BpGraph& graph, const Arc& arc) - : Arc(arc), _graph(&graph) {} - - OutArcIt& operator++() { - _graph->nextOut(*this); - return *this; - } - - }; - - - class InArcIt : public Arc { - const BpGraph* _graph; - public: - - InArcIt() { } - - InArcIt(Invalid i) : Arc(i) { } - - InArcIt(const BpGraph& graph, const Node& node) - : _graph(&graph) { - _graph->firstIn(*this, node); - } - - InArcIt(const BpGraph& graph, const Arc& arc) : - Arc(arc), _graph(&graph) {} - - InArcIt& operator++() { - _graph->nextIn(*this); - return *this; - } - - }; - - - class EdgeIt : public Parent::Edge { - const BpGraph* _graph; - public: - - EdgeIt() { } - - EdgeIt(Invalid i) : Edge(i) { } - - explicit EdgeIt(const BpGraph& graph) : _graph(&graph) { - _graph->first(static_cast(*this)); - } - - EdgeIt(const BpGraph& graph, const Edge& edge) : - Edge(edge), _graph(&graph) { } - - EdgeIt& operator++() { - _graph->next(*this); - return *this; - } - - }; - - class IncEdgeIt : public Parent::Edge { - friend class BpGraphExtender; - const BpGraph* _graph; - bool _direction; - public: - - IncEdgeIt() { } - - IncEdgeIt(Invalid i) : Edge(i), _direction(false) { } - - IncEdgeIt(const BpGraph& graph, const Node &node) : _graph(&graph) { - _graph->firstInc(*this, _direction, node); - } - - IncEdgeIt(const BpGraph& graph, const Edge &edge, const Node &node) - : _graph(&graph), Edge(edge) { - _direction = (_graph->source(edge) == node); - } - - IncEdgeIt& operator++() { - _graph->nextInc(*this, _direction); - return *this; - } - }; - - // \brief Base node of the iterator - // - // Returns the base node (ie. the source in this case) of the iterator - Node baseNode(const OutArcIt &arc) const { - return Parent::source(static_cast(arc)); - } - // \brief Running node of the iterator - // - // Returns the running node (ie. the target in this case) of the - // iterator - Node runningNode(const OutArcIt &arc) const { - return Parent::target(static_cast(arc)); - } - - // \brief Base node of the iterator - // - // Returns the base node (ie. the target in this case) of the iterator - Node baseNode(const InArcIt &arc) const { - return Parent::target(static_cast(arc)); - } - // \brief Running node of the iterator - // - // Returns the running node (ie. the source in this case) of the - // iterator - Node runningNode(const InArcIt &arc) const { - return Parent::source(static_cast(arc)); - } - - // Base node of the iterator - // - // Returns the base node of the iterator - Node baseNode(const IncEdgeIt &edge) const { - return edge._direction ? this->u(edge) : this->v(edge); - } - // Running node of the iterator - // - // Returns the running node of the iterator - Node runningNode(const IncEdgeIt &edge) const { - return edge._direction ? this->v(edge) : this->u(edge); - } - - // Mappable extension - - template - class NodeMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit NodeMap(const BpGraph& bpgraph) - : Parent(bpgraph) {} - NodeMap(const BpGraph& bpgraph, const _Value& value) - : Parent(bpgraph, value) {} - - private: - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - template - class RedNodeMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit RedNodeMap(const BpGraph& bpgraph) - : Parent(bpgraph) {} - RedNodeMap(const BpGraph& bpgraph, const _Value& value) - : Parent(bpgraph, value) {} - - private: - RedNodeMap& operator=(const RedNodeMap& cmap) { - return operator=(cmap); - } - - template - RedNodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - template - class BlueNodeMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit BlueNodeMap(const BpGraph& bpgraph) - : Parent(bpgraph) {} - BlueNodeMap(const BpGraph& bpgraph, const _Value& value) - : Parent(bpgraph, value) {} - - private: - BlueNodeMap& operator=(const BlueNodeMap& cmap) { - return operator=(cmap); - } - - template - BlueNodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - template - class ArcMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit ArcMap(const BpGraph& graph) - : Parent(graph) {} - ArcMap(const BpGraph& graph, const _Value& value) - : Parent(graph, value) {} - - private: - ArcMap& operator=(const ArcMap& cmap) { - return operator=(cmap); - } - - template - ArcMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - - template - class EdgeMap - : public MapExtender > { - typedef MapExtender > Parent; - - public: - explicit EdgeMap(const BpGraph& graph) - : Parent(graph) {} - - EdgeMap(const BpGraph& graph, const _Value& value) - : Parent(graph, value) {} - - private: - EdgeMap& operator=(const EdgeMap& cmap) { - return operator=(cmap); - } - - template - EdgeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - }; - - // Alteration extension - - RedNode addRedNode() { - RedNode node = Parent::addRedNode(); - notifier(RedNode()).add(node); - notifier(Node()).add(node); - return node; - } - - BlueNode addBlueNode() { - BlueNode node = Parent::addBlueNode(); - notifier(BlueNode()).add(node); - notifier(Node()).add(node); - return node; - } - - Edge addEdge(const RedNode& from, const BlueNode& to) { - Edge edge = Parent::addEdge(from, to); - notifier(Edge()).add(edge); - std::vector av; - av.push_back(Parent::direct(edge, true)); - av.push_back(Parent::direct(edge, false)); - notifier(Arc()).add(av); - return edge; - } - - void clear() { - notifier(Arc()).clear(); - notifier(Edge()).clear(); - notifier(Node()).clear(); - notifier(BlueNode()).clear(); - notifier(RedNode()).clear(); - Parent::clear(); - } - - template - void build(const BpGraph& graph, NodeRefMap& nodeRef, - EdgeRefMap& edgeRef) { - Parent::build(graph, nodeRef, edgeRef); - notifier(RedNode()).build(); - notifier(BlueNode()).build(); - notifier(Node()).build(); - notifier(Edge()).build(); - notifier(Arc()).build(); - } - - void erase(const Node& node) { - Arc arc; - Parent::firstOut(arc, node); - while (arc != INVALID ) { - erase(arc); - Parent::firstOut(arc, node); - } - - Parent::firstIn(arc, node); - while (arc != INVALID ) { - erase(arc); - Parent::firstIn(arc, node); - } - - if (Parent::red(node)) { - notifier(RedNode()).erase(this->asRedNodeUnsafe(node)); - } else { - notifier(BlueNode()).erase(this->asBlueNodeUnsafe(node)); - } - - notifier(Node()).erase(node); - Parent::erase(node); - } - - void erase(const Edge& edge) { - std::vector av; - av.push_back(Parent::direct(edge, true)); - av.push_back(Parent::direct(edge, false)); - notifier(Arc()).erase(av); - notifier(Edge()).erase(edge); - Parent::erase(edge); - } - - BpGraphExtender() { - red_node_notifier.setContainer(*this); - blue_node_notifier.setContainer(*this); - node_notifier.setContainer(*this); - arc_notifier.setContainer(*this); - edge_notifier.setContainer(*this); - } - - ~BpGraphExtender() { - edge_notifier.clear(); - arc_notifier.clear(); - node_notifier.clear(); - blue_node_notifier.clear(); - red_node_notifier.clear(); - } - - }; - -} - -#endif diff --git a/deps/lemon/lemon/bits/lock.h b/deps/lemon/lemon/bits/lock.h deleted file mode 100644 index 09069998c..000000000 --- a/deps/lemon/lemon/bits/lock.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_LOCK_H -#define LEMON_BITS_LOCK_H - -#include -#if defined(LEMON_USE_PTHREAD) -#include -#elif defined(LEMON_USE_WIN32_THREADS) -#include -#endif - -namespace lemon { - namespace bits { - -#if defined(LEMON_USE_PTHREAD) - class Lock { - public: - Lock() { - pthread_mutex_init(&_lock, 0); - } - ~Lock() { - pthread_mutex_destroy(&_lock); - } - void lock() { - pthread_mutex_lock(&_lock); - } - void unlock() { - pthread_mutex_unlock(&_lock); - } - - private: - pthread_mutex_t _lock; - }; -#elif defined(LEMON_USE_WIN32_THREADS) - class Lock : public WinLock {}; -#else - class Lock { - public: - Lock() {} - ~Lock() {} - void lock() {} - void unlock() {} - }; -#endif - } -} - -#endif diff --git a/deps/lemon/lemon/bits/map_extender.h b/deps/lemon/lemon/bits/map_extender.h deleted file mode 100644 index f32403e65..000000000 --- a/deps/lemon/lemon/bits/map_extender.h +++ /dev/null @@ -1,332 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_MAP_EXTENDER_H -#define LEMON_BITS_MAP_EXTENDER_H - -#include - -#include - -#include -#include - -//\file -//\brief Extenders for iterable maps. - -namespace lemon { - - // \ingroup graphbits - // - // \brief Extender for maps - template - class MapExtender : public _Map { - typedef _Map Parent; - typedef typename Parent::GraphType GraphType; - - public: - - typedef MapExtender Map; - typedef typename Parent::Key Item; - - typedef typename Parent::Key Key; - typedef typename Parent::Value Value; - typedef typename Parent::Reference Reference; - typedef typename Parent::ConstReference ConstReference; - - typedef typename Parent::ReferenceMapTag ReferenceMapTag; - - class MapIt; - class ConstMapIt; - - friend class MapIt; - friend class ConstMapIt; - - public: - - MapExtender(const GraphType& graph) - : Parent(graph) {} - - MapExtender(const GraphType& graph, const Value& value) - : Parent(graph, value) {} - - private: - MapExtender& operator=(const MapExtender& cmap) { - return operator=(cmap); - } - - template - MapExtender& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - - public: - class MapIt : public Item { - typedef Item Parent; - - public: - - typedef typename Map::Value Value; - - MapIt() : map(NULL) {} - - MapIt(Invalid i) : Parent(i), map(NULL) {} - - explicit MapIt(Map& _map) : map(&_map) { - map->notifier()->first(*this); - } - - MapIt(const Map& _map, const Item& item) - : Parent(item), map(&_map) {} - - MapIt& operator++() { - map->notifier()->next(*this); - return *this; - } - - typename MapTraits::ConstReturnValue operator*() const { - return (*map)[*this]; - } - - typename MapTraits::ReturnValue operator*() { - return (*map)[*this]; - } - - void set(const Value& value) { - map->set(*this, value); - } - - protected: - Map* map; - - }; - - class ConstMapIt : public Item { - typedef Item Parent; - - public: - - typedef typename Map::Value Value; - - ConstMapIt() : map(NULL) {} - - ConstMapIt(Invalid i) : Parent(i), map(NULL) {} - - explicit ConstMapIt(Map& _map) : map(&_map) { - map->notifier()->first(*this); - } - - ConstMapIt(const Map& _map, const Item& item) - : Parent(item), map(_map) {} - - ConstMapIt& operator++() { - map->notifier()->next(*this); - return *this; - } - - typename MapTraits::ConstReturnValue operator*() const { - return map[*this]; - } - - protected: - const Map* map; - }; - - class ItemIt : public Item { - typedef Item Parent; - - public: - ItemIt() : map(NULL) {} - - - ItemIt(Invalid i) : Parent(i), map(NULL) {} - - explicit ItemIt(Map& _map) : map(&_map) { - map->notifier()->first(*this); - } - - ItemIt(const Map& _map, const Item& item) - : Parent(item), map(&_map) {} - - ItemIt& operator++() { - map->notifier()->next(*this); - return *this; - } - - protected: - const Map* map; - - }; - }; - - // \ingroup graphbits - // - // \brief Extender for maps which use a subset of the items. - template - class SubMapExtender : public _Map { - typedef _Map Parent; - typedef _Graph GraphType; - - public: - - typedef SubMapExtender Map; - typedef typename Parent::Key Item; - - typedef typename Parent::Key Key; - typedef typename Parent::Value Value; - typedef typename Parent::Reference Reference; - typedef typename Parent::ConstReference ConstReference; - - typedef typename Parent::ReferenceMapTag ReferenceMapTag; - - class MapIt; - class ConstMapIt; - - friend class MapIt; - friend class ConstMapIt; - - public: - - SubMapExtender(const GraphType& _graph) - : Parent(_graph), graph(_graph) {} - - SubMapExtender(const GraphType& _graph, const Value& _value) - : Parent(_graph, _value), graph(_graph) {} - - private: - SubMapExtender& operator=(const SubMapExtender& cmap) { - return operator=(cmap); - } - - template - SubMapExtender& operator=(const CMap& cmap) { - checkConcept, CMap>(); - Item it; - for (graph.first(it); it != INVALID; graph.next(it)) { - Parent::set(it, cmap[it]); - } - return *this; - } - - public: - class MapIt : public Item { - typedef Item Parent; - - public: - typedef typename Map::Value Value; - - MapIt() : map(NULL) {} - - MapIt(Invalid i) : Parent(i), map(NULL) { } - - explicit MapIt(Map& _map) : map(&_map) { - map->graph.first(*this); - } - - MapIt(const Map& _map, const Item& item) - : Parent(item), map(&_map) {} - - MapIt& operator++() { - map->graph.next(*this); - return *this; - } - - typename MapTraits::ConstReturnValue operator*() const { - return (*map)[*this]; - } - - typename MapTraits::ReturnValue operator*() { - return (*map)[*this]; - } - - void set(const Value& value) { - map->set(*this, value); - } - - protected: - Map* map; - - }; - - class ConstMapIt : public Item { - typedef Item Parent; - - public: - - typedef typename Map::Value Value; - - ConstMapIt() : map(NULL) {} - - ConstMapIt(Invalid i) : Parent(i), map(NULL) { } - - explicit ConstMapIt(Map& _map) : map(&_map) { - map->graph.first(*this); - } - - ConstMapIt(const Map& _map, const Item& item) - : Parent(item), map(&_map) {} - - ConstMapIt& operator++() { - map->graph.next(*this); - return *this; - } - - typename MapTraits::ConstReturnValue operator*() const { - return (*map)[*this]; - } - - protected: - const Map* map; - }; - - class ItemIt : public Item { - typedef Item Parent; - - public: - ItemIt() : map(NULL) {} - - - ItemIt(Invalid i) : Parent(i), map(NULL) { } - - explicit ItemIt(Map& _map) : map(&_map) { - map->graph.first(*this); - } - - ItemIt(const Map& _map, const Item& item) - : Parent(item), map(&_map) {} - - ItemIt& operator++() { - map->graph.next(*this); - return *this; - } - - protected: - const Map* map; - - }; - - private: - - const GraphType& graph; - - }; - -} - -#endif diff --git a/deps/lemon/lemon/bits/path_dump.h b/deps/lemon/lemon/bits/path_dump.h deleted file mode 100644 index 3e8cb8dd5..000000000 --- a/deps/lemon/lemon/bits/path_dump.h +++ /dev/null @@ -1,177 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_PATH_DUMP_H -#define LEMON_BITS_PATH_DUMP_H - -#include -#include - -namespace lemon { - - template - class PredMapPath { - public: - typedef True RevPathTag; - - typedef _Digraph Digraph; - typedef typename Digraph::Arc Arc; - typedef _PredMap PredMap; - - PredMapPath(const Digraph& _digraph, const PredMap& _predMap, - typename Digraph::Node _target) - : digraph(_digraph), predMap(_predMap), target(_target) {} - - int length() const { - int len = 0; - typename Digraph::Node node = target; - typename Digraph::Arc arc; - while ((arc = predMap[node]) != INVALID) { - node = digraph.source(arc); - ++len; - } - return len; - } - - bool empty() const { - return predMap[target] == INVALID; - } - - class RevArcIt { - public: - RevArcIt() {} - RevArcIt(Invalid) : path(0), current(INVALID) {} - RevArcIt(const PredMapPath& _path) - : path(&_path), current(_path.target) { - if (path->predMap[current] == INVALID) current = INVALID; - } - - operator const typename Digraph::Arc() const { - return path->predMap[current]; - } - - RevArcIt& operator++() { - current = path->digraph.source(path->predMap[current]); - if (path->predMap[current] == INVALID) current = INVALID; - return *this; - } - - bool operator==(const RevArcIt& e) const { - return current == e.current; - } - - bool operator!=(const RevArcIt& e) const { - return current != e.current; - } - - bool operator<(const RevArcIt& e) const { - return current < e.current; - } - - private: - const PredMapPath* path; - typename Digraph::Node current; - }; - - private: - const Digraph& digraph; - const PredMap& predMap; - typename Digraph::Node target; - }; - - - template - class PredMatrixMapPath { - public: - typedef True RevPathTag; - - typedef _Digraph Digraph; - typedef typename Digraph::Arc Arc; - typedef _PredMatrixMap PredMatrixMap; - - PredMatrixMapPath(const Digraph& _digraph, - const PredMatrixMap& _predMatrixMap, - typename Digraph::Node _source, - typename Digraph::Node _target) - : digraph(_digraph), predMatrixMap(_predMatrixMap), - source(_source), target(_target) {} - - int length() const { - int len = 0; - typename Digraph::Node node = target; - typename Digraph::Arc arc; - while ((arc = predMatrixMap(source, node)) != INVALID) { - node = digraph.source(arc); - ++len; - } - return len; - } - - bool empty() const { - return predMatrixMap(source, target) == INVALID; - } - - class RevArcIt { - public: - RevArcIt() {} - RevArcIt(Invalid) : path(0), current(INVALID) {} - RevArcIt(const PredMatrixMapPath& _path) - : path(&_path), current(_path.target) { - if (path->predMatrixMap(path->source, current) == INVALID) - current = INVALID; - } - - operator const typename Digraph::Arc() const { - return path->predMatrixMap(path->source, current); - } - - RevArcIt& operator++() { - current = - path->digraph.source(path->predMatrixMap(path->source, current)); - if (path->predMatrixMap(path->source, current) == INVALID) - current = INVALID; - return *this; - } - - bool operator==(const RevArcIt& e) const { - return current == e.current; - } - - bool operator!=(const RevArcIt& e) const { - return current != e.current; - } - - bool operator<(const RevArcIt& e) const { - return current < e.current; - } - - private: - const PredMatrixMapPath* path; - typename Digraph::Node current; - }; - - private: - const Digraph& digraph; - const PredMatrixMap& predMatrixMap; - typename Digraph::Node source; - typename Digraph::Node target; - }; - -} - -#endif diff --git a/deps/lemon/lemon/bits/solver_bits.h b/deps/lemon/lemon/bits/solver_bits.h deleted file mode 100644 index c34212be8..000000000 --- a/deps/lemon/lemon/bits/solver_bits.h +++ /dev/null @@ -1,194 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_SOLVER_BITS_H -#define LEMON_BITS_SOLVER_BITS_H - -#include - -namespace lemon { - - namespace _solver_bits { - - class VarIndex { - private: - struct ItemT { - int prev, next; - int index; - }; - std::vector items; - int first_item, last_item, first_free_item; - - std::vector cross; - - public: - - VarIndex() - : first_item(-1), last_item(-1), first_free_item(-1) { - } - - void clear() { - first_item = -1; - last_item = -1; - first_free_item = -1; - items.clear(); - cross.clear(); - } - - int addIndex(int idx) { - int n; - if (first_free_item == -1) { - n = items.size(); - items.push_back(ItemT()); - } else { - n = first_free_item; - first_free_item = items[n].next; - if (first_free_item != -1) { - items[first_free_item].prev = -1; - } - } - items[n].index = idx; - if (static_cast(cross.size()) <= idx) { - cross.resize(idx + 1, -1); - } - cross[idx] = n; - - items[n].prev = last_item; - items[n].next = -1; - if (last_item != -1) { - items[last_item].next = n; - } else { - first_item = n; - } - last_item = n; - - return n; - } - - int addIndex(int idx, int n) { - while (n >= static_cast(items.size())) { - items.push_back(ItemT()); - items.back().prev = -1; - items.back().next = first_free_item; - if (first_free_item != -1) { - items[first_free_item].prev = items.size() - 1; - } - first_free_item = items.size() - 1; - } - if (items[n].next != -1) { - items[items[n].next].prev = items[n].prev; - } - if (items[n].prev != -1) { - items[items[n].prev].next = items[n].next; - } else { - first_free_item = items[n].next; - } - - items[n].index = idx; - if (static_cast(cross.size()) <= idx) { - cross.resize(idx + 1, -1); - } - cross[idx] = n; - - items[n].prev = last_item; - items[n].next = -1; - if (last_item != -1) { - items[last_item].next = n; - } else { - first_item = n; - } - last_item = n; - - return n; - } - - void eraseIndex(int idx) { - int n = cross[idx]; - - if (items[n].prev != -1) { - items[items[n].prev].next = items[n].next; - } else { - first_item = items[n].next; - } - if (items[n].next != -1) { - items[items[n].next].prev = items[n].prev; - } else { - last_item = items[n].prev; - } - - if (first_free_item != -1) { - items[first_free_item].prev = n; - } - items[n].next = first_free_item; - items[n].prev = -1; - first_free_item = n; - - while (!cross.empty() && cross.back() == -1) { - cross.pop_back(); - } - } - - int maxIndex() const { - return cross.size() - 1; - } - - void shiftIndices(int idx) { - for (int i = idx + 1; i < static_cast(cross.size()); ++i) { - cross[i - 1] = cross[i]; - if (cross[i] != -1) { - --items[cross[i]].index; - } - } - cross.back() = -1; - cross.pop_back(); - while (!cross.empty() && cross.back() == -1) { - cross.pop_back(); - } - } - - void relocateIndex(int idx, int jdx) { - cross[idx] = cross[jdx]; - items[cross[jdx]].index = idx; - cross[jdx] = -1; - - while (!cross.empty() && cross.back() == -1) { - cross.pop_back(); - } - } - - int operator[](int idx) const { - return cross[idx]; - } - - int operator()(int fdx) const { - return items[fdx].index; - } - - void firstItem(int& fdx) const { - fdx = first_item; - } - - void nextItem(int& fdx) const { - fdx = items[fdx].next; - } - - }; - } -} - -#endif diff --git a/deps/lemon/lemon/bits/traits.h b/deps/lemon/lemon/bits/traits.h deleted file mode 100644 index 53fbd4564..000000000 --- a/deps/lemon/lemon/bits/traits.h +++ /dev/null @@ -1,388 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_TRAITS_H -#define LEMON_BITS_TRAITS_H - -//\file -//\brief Traits for graphs and maps -// - -#include - -namespace lemon { - - struct InvalidType {}; - - template - class ItemSetTraits {}; - - - template - struct NodeNotifierIndicator { - typedef InvalidType Type; - }; - template - struct NodeNotifierIndicator< - GR, - typename enable_if::type - > { - typedef typename GR::NodeNotifier Type; - }; - - template - class ItemSetTraits { - public: - - typedef GR Graph; - typedef GR Digraph; - - typedef typename GR::Node Item; - typedef typename GR::NodeIt ItemIt; - - typedef typename NodeNotifierIndicator::Type ItemNotifier; - - template - class Map : public GR::template NodeMap { - typedef typename GR::template NodeMap Parent; - - public: - typedef typename GR::template NodeMap Type; - typedef typename Parent::Value Value; - - Map(const GR& _digraph) : Parent(_digraph) {} - Map(const GR& _digraph, const Value& _value) - : Parent(_digraph, _value) {} - - }; - - }; - - template - struct ArcNotifierIndicator { - typedef InvalidType Type; - }; - template - struct ArcNotifierIndicator< - GR, - typename enable_if::type - > { - typedef typename GR::ArcNotifier Type; - }; - - template - class ItemSetTraits { - public: - - typedef GR Graph; - typedef GR Digraph; - - typedef typename GR::Arc Item; - typedef typename GR::ArcIt ItemIt; - - typedef typename ArcNotifierIndicator::Type ItemNotifier; - - template - class Map : public GR::template ArcMap { - typedef typename GR::template ArcMap Parent; - - public: - typedef typename GR::template ArcMap Type; - typedef typename Parent::Value Value; - - Map(const GR& _digraph) : Parent(_digraph) {} - Map(const GR& _digraph, const Value& _value) - : Parent(_digraph, _value) {} - }; - - }; - - template - struct EdgeNotifierIndicator { - typedef InvalidType Type; - }; - template - struct EdgeNotifierIndicator< - GR, - typename enable_if::type - > { - typedef typename GR::EdgeNotifier Type; - }; - - template - class ItemSetTraits { - public: - - typedef GR Graph; - typedef GR Digraph; - - typedef typename GR::Edge Item; - typedef typename GR::EdgeIt ItemIt; - - typedef typename EdgeNotifierIndicator::Type ItemNotifier; - - template - class Map : public GR::template EdgeMap { - typedef typename GR::template EdgeMap Parent; - - public: - typedef typename GR::template EdgeMap Type; - typedef typename Parent::Value Value; - - Map(const GR& _digraph) : Parent(_digraph) {} - Map(const GR& _digraph, const Value& _value) - : Parent(_digraph, _value) {} - }; - - }; - - template - struct RedNodeNotifierIndicator { - typedef InvalidType Type; - }; - template - struct RedNodeNotifierIndicator< - GR, - typename enable_if::type - > { - typedef typename GR::RedNodeNotifier Type; - }; - - template - class ItemSetTraits { - public: - - typedef GR BpGraph; - typedef GR Graph; - typedef GR Digraph; - - typedef typename GR::RedNode Item; - typedef typename GR::RedNodeIt ItemIt; - - typedef typename RedNodeNotifierIndicator::Type ItemNotifier; - - template - class Map : public GR::template RedNodeMap { - typedef typename GR::template RedNodeMap Parent; - - public: - typedef typename GR::template RedNodeMap Type; - typedef typename Parent::Value Value; - - Map(const GR& _bpgraph) : Parent(_bpgraph) {} - Map(const GR& _bpgraph, const Value& _value) - : Parent(_bpgraph, _value) {} - - }; - - }; - - template - struct BlueNodeNotifierIndicator { - typedef InvalidType Type; - }; - template - struct BlueNodeNotifierIndicator< - GR, - typename enable_if::type - > { - typedef typename GR::BlueNodeNotifier Type; - }; - - template - class ItemSetTraits { - public: - - typedef GR BpGraph; - typedef GR Graph; - typedef GR Digraph; - - typedef typename GR::BlueNode Item; - typedef typename GR::BlueNodeIt ItemIt; - - typedef typename BlueNodeNotifierIndicator::Type ItemNotifier; - - template - class Map : public GR::template BlueNodeMap { - typedef typename GR::template BlueNodeMap Parent; - - public: - typedef typename GR::template BlueNodeMap Type; - typedef typename Parent::Value Value; - - Map(const GR& _bpgraph) : Parent(_bpgraph) {} - Map(const GR& _bpgraph, const Value& _value) - : Parent(_bpgraph, _value) {} - - }; - - }; - - template - struct MapTraits { - typedef False ReferenceMapTag; - - typedef typename Map::Key Key; - typedef typename Map::Value Value; - - typedef Value ConstReturnValue; - typedef Value ReturnValue; - }; - - template - struct MapTraits< - Map, typename enable_if::type > - { - typedef True ReferenceMapTag; - - typedef typename Map::Key Key; - typedef typename Map::Value Value; - - typedef typename Map::ConstReference ConstReturnValue; - typedef typename Map::Reference ReturnValue; - - typedef typename Map::ConstReference ConstReference; - typedef typename Map::Reference Reference; - }; - - template - struct MatrixMapTraits { - typedef False ReferenceMapTag; - - typedef typename MatrixMap::FirstKey FirstKey; - typedef typename MatrixMap::SecondKey SecondKey; - typedef typename MatrixMap::Value Value; - - typedef Value ConstReturnValue; - typedef Value ReturnValue; - }; - - template - struct MatrixMapTraits< - MatrixMap, typename enable_if::type > - { - typedef True ReferenceMapTag; - - typedef typename MatrixMap::FirstKey FirstKey; - typedef typename MatrixMap::SecondKey SecondKey; - typedef typename MatrixMap::Value Value; - - typedef typename MatrixMap::ConstReference ConstReturnValue; - typedef typename MatrixMap::Reference ReturnValue; - - typedef typename MatrixMap::ConstReference ConstReference; - typedef typename MatrixMap::Reference Reference; - }; - - // Indicators for the tags - - template - struct NodeNumTagIndicator { - static const bool value = false; - }; - - template - struct NodeNumTagIndicator< - GR, - typename enable_if::type - > { - static const bool value = true; - }; - - template - struct ArcNumTagIndicator { - static const bool value = false; - }; - - template - struct ArcNumTagIndicator< - GR, - typename enable_if::type - > { - static const bool value = true; - }; - - template - struct EdgeNumTagIndicator { - static const bool value = false; - }; - - template - struct EdgeNumTagIndicator< - GR, - typename enable_if::type - > { - static const bool value = true; - }; - - template - struct FindArcTagIndicator { - static const bool value = false; - }; - - template - struct FindArcTagIndicator< - GR, - typename enable_if::type - > { - static const bool value = true; - }; - - template - struct FindEdgeTagIndicator { - static const bool value = false; - }; - - template - struct FindEdgeTagIndicator< - GR, - typename enable_if::type - > { - static const bool value = true; - }; - - template - struct UndirectedTagIndicator { - static const bool value = false; - }; - - template - struct UndirectedTagIndicator< - GR, - typename enable_if::type - > { - static const bool value = true; - }; - - template - struct BuildTagIndicator { - static const bool value = false; - }; - - template - struct BuildTagIndicator< - GR, - typename enable_if::type - > { - static const bool value = true; - }; - -} - -#endif diff --git a/deps/lemon/lemon/bits/variant.h b/deps/lemon/lemon/bits/variant.h deleted file mode 100644 index b8301892e..000000000 --- a/deps/lemon/lemon/bits/variant.h +++ /dev/null @@ -1,494 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_VARIANT_H -#define LEMON_BITS_VARIANT_H - -#include - -// \file -// \brief Variant types - -namespace lemon { - - namespace _variant_bits { - - template - struct CTMax { - static const int value = left < right ? right : left; - }; - - } - - - // \brief Simple Variant type for two types - // - // Simple Variant type for two types. The Variant type is a type-safe - // union. C++ has strong limitations for using unions, for - // example you cannot store a type with non-default constructor or - // destructor in a union. This class always knowns the current - // state of the variant and it cares for the proper construction - // and destruction. - template - class BiVariant { - public: - - // \brief The \c First type. - typedef _First First; - // \brief The \c Second type. - typedef _Second Second; - - // \brief Constructor - // - // This constructor initalizes to the default value of the \c First - // type. - BiVariant() { - flag = true; - new(reinterpret_cast(data)) First(); - } - - // \brief Constructor - // - // This constructor initalizes to the given value of the \c First - // type. - BiVariant(const First& f) { - flag = true; - new(reinterpret_cast(data)) First(f); - } - - // \brief Constructor - // - // This constructor initalizes to the given value of the \c - // Second type. - BiVariant(const Second& s) { - flag = false; - new(reinterpret_cast(data)) Second(s); - } - - // \brief Copy constructor - // - // Copy constructor - BiVariant(const BiVariant& bivariant) { - flag = bivariant.flag; - if (flag) { - new(reinterpret_cast(data)) First(bivariant.first()); - } else { - new(reinterpret_cast(data)) Second(bivariant.second()); - } - } - - // \brief Destrcutor - // - // Destructor - ~BiVariant() { - destroy(); - } - - // \brief Set to the default value of the \c First type. - // - // This function sets the variant to the default value of the \c - // First type. - BiVariant& setFirst() { - destroy(); - flag = true; - new(reinterpret_cast(data)) First(); - return *this; - } - - // \brief Set to the given value of the \c First type. - // - // This function sets the variant to the given value of the \c - // First type. - BiVariant& setFirst(const First& f) { - destroy(); - flag = true; - new(reinterpret_cast(data)) First(f); - return *this; - } - - // \brief Set to the default value of the \c Second type. - // - // This function sets the variant to the default value of the \c - // Second type. - BiVariant& setSecond() { - destroy(); - flag = false; - new(reinterpret_cast(data)) Second(); - return *this; - } - - // \brief Set to the given value of the \c Second type. - // - // This function sets the variant to the given value of the \c - // Second type. - BiVariant& setSecond(const Second& s) { - destroy(); - flag = false; - new(reinterpret_cast(data)) Second(s); - return *this; - } - - // \brief Operator form of the \c setFirst() - BiVariant& operator=(const First& f) { - return setFirst(f); - } - - // \brief Operator form of the \c setSecond() - BiVariant& operator=(const Second& s) { - return setSecond(s); - } - - // \brief Assign operator - BiVariant& operator=(const BiVariant& bivariant) { - if (this == &bivariant) return *this; - destroy(); - flag = bivariant.flag; - if (flag) { - new(reinterpret_cast(data)) First(bivariant.first()); - } else { - new(reinterpret_cast(data)) Second(bivariant.second()); - } - return *this; - } - - // \brief Reference to the value - // - // Reference to the value of the \c First type. - // \pre The BiVariant should store value of \c First type. - First& first() { - LEMON_DEBUG(flag, "Variant wrong state"); - return *reinterpret_cast(data); - } - - // \brief Const reference to the value - // - // Const reference to the value of the \c First type. - // \pre The BiVariant should store value of \c First type. - const First& first() const { - LEMON_DEBUG(flag, "Variant wrong state"); - return *reinterpret_cast(data); - } - - // \brief Operator form of the \c first() - operator First&() { return first(); } - // \brief Operator form of the const \c first() - operator const First&() const { return first(); } - - // \brief Reference to the value - // - // Reference to the value of the \c Second type. - // \pre The BiVariant should store value of \c Second type. - Second& second() { - LEMON_DEBUG(!flag, "Variant wrong state"); - return *reinterpret_cast(data); - } - - // \brief Const reference to the value - // - // Const reference to the value of the \c Second type. - // \pre The BiVariant should store value of \c Second type. - const Second& second() const { - LEMON_DEBUG(!flag, "Variant wrong state"); - return *reinterpret_cast(data); - } - - // \brief Operator form of the \c second() - operator Second&() { return second(); } - // \brief Operator form of the const \c second() - operator const Second&() const { return second(); } - - // \brief %True when the variant is in the first state - // - // %True when the variant stores value of the \c First type. - bool firstState() const { return flag; } - - // \brief %True when the variant is in the second state - // - // %True when the variant stores value of the \c Second type. - bool secondState() const { return !flag; } - - private: - - void destroy() { - if (flag) { - reinterpret_cast(data)->~First(); - } else { - reinterpret_cast(data)->~Second(); - } - } - - char data[_variant_bits::CTMax::value]; - bool flag; - }; - - namespace _variant_bits { - - template - struct Memory { - - typedef typename _TypeMap::template Map<_idx>::Type Current; - - static void destroy(int index, char* place) { - if (index == _idx) { - reinterpret_cast(place)->~Current(); - } else { - Memory<_idx - 1, _TypeMap>::destroy(index, place); - } - } - - static void copy(int index, char* to, const char* from) { - if (index == _idx) { - new (reinterpret_cast(to)) - Current(reinterpret_cast(from)); - } else { - Memory<_idx - 1, _TypeMap>::copy(index, to, from); - } - } - - }; - - template - struct Memory<-1, _TypeMap> { - - static void destroy(int, char*) { - LEMON_DEBUG(false, "Variant wrong index."); - } - - static void copy(int, char*, const char*) { - LEMON_DEBUG(false, "Variant wrong index."); - } - }; - - template - struct Size { - static const int value = - CTMax::Type), - Size<_idx - 1, _TypeMap>::value>::value; - }; - - template - struct Size<0, _TypeMap> { - static const int value = - sizeof(typename _TypeMap::template Map<0>::Type); - }; - - } - - // \brief Variant type - // - // Simple Variant type. The Variant type is a type-safe union. - // C++ has strong limitations for using unions, for example you - // cannot store type with non-default constructor or destructor in - // a union. This class always knowns the current state of the - // variant and it cares for the proper construction and - // destruction. - // - // \param _num The number of the types which can be stored in the - // variant type. - // \param _TypeMap This class describes the types of the Variant. The - // _TypeMap::Map::Type should be a valid type for each index - // in the range {0, 1, ..., _num - 1}. The \c VariantTypeMap is helper - // class to define such type mappings up to 10 types. - // - // And the usage of the class: - //\code - // typedef Variant<3, VariantTypeMap > MyVariant; - // MyVariant var; - // var.set<0>(12); - // std::cout << var.get<0>() << std::endl; - // var.set<1>("alpha"); - // std::cout << var.get<1>() << std::endl; - // var.set<2>(0.75); - // std::cout << var.get<2>() << std::endl; - //\endcode - // - // The result of course: - //\code - // 12 - // alpha - // 0.75 - //\endcode - template - class Variant { - public: - - static const int num = _num; - - typedef _TypeMap TypeMap; - - // \brief Constructor - // - // This constructor initalizes to the default value of the \c type - // with 0 index. - Variant() { - flag = 0; - new(reinterpret_cast::Type*>(data)) - typename TypeMap::template Map<0>::Type(); - } - - - // \brief Copy constructor - // - // Copy constructor - Variant(const Variant& variant) { - flag = variant.flag; - _variant_bits::Memory::copy(flag, data, variant.data); - } - - // \brief Assign operator - // - // Assign operator - Variant& operator=(const Variant& variant) { - if (this == &variant) return *this; - _variant_bits::Memory:: - destroy(flag, data); - flag = variant.flag; - _variant_bits::Memory:: - copy(flag, data, variant.data); - return *this; - } - - // \brief Destrcutor - // - // Destructor - ~Variant() { - _variant_bits::Memory::destroy(flag, data); - } - - // \brief Set to the default value of the type with \c _idx index. - // - // This function sets the variant to the default value of the - // type with \c _idx index. - template - Variant& set() { - _variant_bits::Memory::destroy(flag, data); - flag = _idx; - new(reinterpret_cast::Type*>(data)) - typename TypeMap::template Map<_idx>::Type(); - return *this; - } - - // \brief Set to the given value of the type with \c _idx index. - // - // This function sets the variant to the given value of the type - // with \c _idx index. - template - Variant& set(const typename _TypeMap::template Map<_idx>::Type& init) { - _variant_bits::Memory::destroy(flag, data); - flag = _idx; - new(reinterpret_cast::Type*>(data)) - typename TypeMap::template Map<_idx>::Type(init); - return *this; - } - - // \brief Gets the current value of the type with \c _idx index. - // - // Gets the current value of the type with \c _idx index. - template - const typename TypeMap::template Map<_idx>::Type& get() const { - LEMON_DEBUG(_idx == flag, "Variant wrong index"); - return *reinterpret_cast::Type*>(data); - } - - // \brief Gets the current value of the type with \c _idx index. - // - // Gets the current value of the type with \c _idx index. - template - typename _TypeMap::template Map<_idx>::Type& get() { - LEMON_DEBUG(_idx == flag, "Variant wrong index"); - return *reinterpret_cast::Type*> - (data); - } - - // \brief Returns the current state of the variant. - // - // Returns the current state of the variant. - int state() const { - return flag; - } - - private: - - char data[_variant_bits::Size::value]; - int flag; - }; - - namespace _variant_bits { - - template - struct Get { - typedef typename Get<_index - 1, typename _List::Next>::Type Type; - }; - - template - struct Get<0, _List> { - typedef typename _List::Type Type; - }; - - struct List {}; - - template - struct Insert { - typedef _List Next; - typedef _Type Type; - }; - - template - struct Mapper { - typedef List L10; - typedef Insert<_T9, L10> L9; - typedef Insert<_T8, L9> L8; - typedef Insert<_T7, L8> L7; - typedef Insert<_T6, L7> L6; - typedef Insert<_T5, L6> L5; - typedef Insert<_T4, L5> L4; - typedef Insert<_T3, L4> L3; - typedef Insert<_T2, L3> L2; - typedef Insert<_T1, L2> L1; - typedef Insert<_T0, L1> L0; - typedef typename Get<_idx, L0>::Type Type; - }; - - } - - // \brief Helper class for Variant - // - // Helper class to define type mappings for Variant. This class - // converts the template parameters to be mappable by integer. - // \see Variant - template < - typename _T0, - typename _T1 = void, typename _T2 = void, typename _T3 = void, - typename _T4 = void, typename _T5 = void, typename _T6 = void, - typename _T7 = void, typename _T8 = void, typename _T9 = void> - struct VariantTypeMap { - template - struct Map { - typedef typename _variant_bits:: - Mapper<_idx, _T0, _T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9>::Type - Type; - }; - }; - -} - - -#endif diff --git a/deps/lemon/lemon/bits/vector_map.h b/deps/lemon/lemon/bits/vector_map.h deleted file mode 100644 index d60841def..000000000 --- a/deps/lemon/lemon/bits/vector_map.h +++ /dev/null @@ -1,244 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_VECTOR_MAP_H -#define LEMON_BITS_VECTOR_MAP_H - -#include -#include - -#include -#include - -#include -#include - -//\ingroup graphbits -// -//\file -//\brief Vector based graph maps. -namespace lemon { - - // \ingroup graphbits - // - // \brief Graph map based on the std::vector storage. - // - // The VectorMap template class is graph map structure that automatically - // updates the map when a key is added to or erased from the graph. - // This map type uses std::vector to store the values. - // - // \tparam _Graph The graph this map is attached to. - // \tparam _Item The item type of the graph items. - // \tparam _Value The value type of the map. - template - class VectorMap - : public ItemSetTraits<_Graph, _Item>::ItemNotifier::ObserverBase { - private: - - // The container type of the map. - typedef std::vector<_Value> Container; - - public: - - // The graph type of the map. - typedef _Graph GraphType; - // The item type of the map. - typedef _Item Item; - // The reference map tag. - typedef True ReferenceMapTag; - - // The key type of the map. - typedef _Item Key; - // The value type of the map. - typedef _Value Value; - - // The notifier type. - typedef typename ItemSetTraits<_Graph, _Item>::ItemNotifier Notifier; - - // The map type. - typedef VectorMap Map; - - // The reference type of the map; - typedef typename Container::reference Reference; - // The const reference type of the map; - typedef typename Container::const_reference ConstReference; - - private: - - // The base class of the map. - typedef typename Notifier::ObserverBase Parent; - - public: - - // \brief Constructor to attach the new map into the notifier. - // - // It constructs a map and attachs it into the notifier. - // It adds all the items of the graph to the map. - VectorMap(const GraphType& graph) { - Parent::attach(graph.notifier(Item())); - container.resize(Parent::notifier()->maxId() + 1); - } - - // \brief Constructor uses given value to initialize the map. - // - // It constructs a map uses a given value to initialize the map. - // It adds all the items of the graph to the map. - VectorMap(const GraphType& graph, const Value& value) { - Parent::attach(graph.notifier(Item())); - container.resize(Parent::notifier()->maxId() + 1, value); - } - - private: - // \brief Copy constructor - // - // Copy constructor. - VectorMap(const VectorMap& _copy) : Parent() { - if (_copy.attached()) { - Parent::attach(*_copy.notifier()); - container = _copy.container; - } - } - - // \brief Assign operator. - // - // This operator assigns for each item in the map the - // value mapped to the same item in the copied map. - // The parameter map should be indiced with the same - // itemset because this assign operator does not change - // the container of the map. - VectorMap& operator=(const VectorMap& cmap) { - return operator=(cmap); - } - - - // \brief Template assign operator. - // - // The given parameter should conform to the ReadMap - // concecpt and could be indiced by the current item set of - // the NodeMap. In this case the value for each item - // is assigned by the value of the given ReadMap. - template - VectorMap& operator=(const CMap& cmap) { - checkConcept, CMap>(); - const typename Parent::Notifier* nf = Parent::notifier(); - Item it; - for (nf->first(it); it != INVALID; nf->next(it)) { - set(it, cmap[it]); - } - return *this; - } - - public: - - // \brief The subcript operator. - // - // The subscript operator. The map can be subscripted by the - // actual items of the graph. - Reference operator[](const Key& key) { - return container[Parent::notifier()->id(key)]; - } - - // \brief The const subcript operator. - // - // The const subscript operator. The map can be subscripted by the - // actual items of the graph. - ConstReference operator[](const Key& key) const { - return container[Parent::notifier()->id(key)]; - } - - - // \brief The setter function of the map. - // - // It the same as operator[](key) = value expression. - void set(const Key& key, const Value& value) { - (*this)[key] = value; - } - - protected: - - // \brief Adds a new key to the map. - // - // It adds a new key to the map. It is called by the observer notifier - // and it overrides the add() member function of the observer base. - virtual void add(const Key& key) { - int id = Parent::notifier()->id(key); - if (id >= int(container.size())) { - container.resize(id + 1); - } - } - - // \brief Adds more new keys to the map. - // - // It adds more new keys to the map. It is called by the observer notifier - // and it overrides the add() member function of the observer base. - virtual void add(const std::vector& keys) { - int max = container.size() - 1; - for (int i = 0; i < int(keys.size()); ++i) { - int id = Parent::notifier()->id(keys[i]); - if (id >= max) { - max = id; - } - } - container.resize(max + 1); - } - - // \brief Erase a key from the map. - // - // Erase a key from the map. It is called by the observer notifier - // and it overrides the erase() member function of the observer base. - virtual void erase(const Key& key) { - container[Parent::notifier()->id(key)] = Value(); - } - - // \brief Erase more keys from the map. - // - // It erases more keys from the map. It is called by the observer notifier - // and it overrides the erase() member function of the observer base. - virtual void erase(const std::vector& keys) { - for (int i = 0; i < int(keys.size()); ++i) { - container[Parent::notifier()->id(keys[i])] = Value(); - } - } - - // \brief Build the map. - // - // It builds the map. It is called by the observer notifier - // and it overrides the build() member function of the observer base. - virtual void build() { - int size = Parent::notifier()->maxId() + 1; - container.reserve(size); - container.resize(size); - } - - // \brief Clear the map. - // - // It erases all items from the map. It is called by the observer notifier - // and it overrides the clear() member function of the observer base. - virtual void clear() { - container.clear(); - } - - private: - - Container container; - - }; - -} - -#endif diff --git a/deps/lemon/lemon/bits/windows.cc b/deps/lemon/lemon/bits/windows.cc deleted file mode 100644 index 7ad901c61..000000000 --- a/deps/lemon/lemon/bits/windows.cc +++ /dev/null @@ -1,166 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\file -///\brief Some basic non-inline functions and static global data. - -#include - -#ifdef WIN32 -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif -#ifdef UNICODE -#undef UNICODE -#endif -#include -#ifdef LOCALE_INVARIANT -#define MY_LOCALE LOCALE_INVARIANT -#else -#define MY_LOCALE LOCALE_NEUTRAL -#endif -#else -#include -#include -#ifndef WIN32 -#include -#endif -#include -#endif - -#include -#include - -namespace lemon { - namespace bits { - void getWinProcTimes(double &rtime, - double &utime, double &stime, - double &cutime, double &cstime) - { -#ifdef WIN32 - static const double ch = 4294967296.0e-7; - static const double cl = 1.0e-7; - - FILETIME system; - GetSystemTimeAsFileTime(&system); - rtime = ch * system.dwHighDateTime + cl * system.dwLowDateTime; - - FILETIME create, exit, kernel, user; - if (GetProcessTimes(GetCurrentProcess(),&create, &exit, &kernel, &user)) { - utime = ch * user.dwHighDateTime + cl * user.dwLowDateTime; - stime = ch * kernel.dwHighDateTime + cl * kernel.dwLowDateTime; - cutime = 0; - cstime = 0; - } else { - rtime = 0; - utime = 0; - stime = 0; - cutime = 0; - cstime = 0; - } -#else - timeval tv; - gettimeofday(&tv, 0); - rtime=tv.tv_sec+double(tv.tv_usec)/1e6; - - tms ts; - double tck=sysconf(_SC_CLK_TCK); - times(&ts); - utime=ts.tms_utime/tck; - stime=ts.tms_stime/tck; - cutime=ts.tms_cutime/tck; - cstime=ts.tms_cstime/tck; -#endif - } - - std::string getWinFormattedDate() - { - std::ostringstream os; -#ifdef WIN32 - SYSTEMTIME time; - GetSystemTime(&time); - char buf1[11], buf2[9], buf3[5]; - if (GetDateFormat(MY_LOCALE, 0, &time, - ("ddd MMM dd"), buf1, 11) && - GetTimeFormat(MY_LOCALE, 0, &time, - ("HH':'mm':'ss"), buf2, 9) && - GetDateFormat(MY_LOCALE, 0, &time, - ("yyyy"), buf3, 5)) { - os << buf1 << ' ' << buf2 << ' ' << buf3; - } - else os << "unknown"; -#else - timeval tv; - gettimeofday(&tv, 0); - - char cbuf[26]; - ctime_r(&tv.tv_sec,cbuf); - os << cbuf; -#endif - return os.str(); - } - - int getWinRndSeed() - { -#ifdef WIN32 - FILETIME time; - GetSystemTimeAsFileTime(&time); - return GetCurrentProcessId() + time.dwHighDateTime + time.dwLowDateTime; -#else - timeval tv; - gettimeofday(&tv, 0); - return getpid() + tv.tv_sec + tv.tv_usec; -#endif - } - - WinLock::WinLock() { -#ifdef WIN32 - CRITICAL_SECTION *lock = new CRITICAL_SECTION; - InitializeCriticalSection(lock); - _repr = lock; -#else - _repr = 0; //Just to avoid 'unused variable' warning with clang -#endif - } - - WinLock::~WinLock() { -#ifdef WIN32 - CRITICAL_SECTION *lock = static_cast(_repr); - DeleteCriticalSection(lock); - delete lock; -#endif - } - - void WinLock::lock() { -#ifdef WIN32 - CRITICAL_SECTION *lock = static_cast(_repr); - EnterCriticalSection(lock); -#endif - } - - void WinLock::unlock() { -#ifdef WIN32 - CRITICAL_SECTION *lock = static_cast(_repr); - LeaveCriticalSection(lock); -#endif - } - } -} diff --git a/deps/lemon/lemon/bits/windows.h b/deps/lemon/lemon/bits/windows.h deleted file mode 100644 index c09bb1284..000000000 --- a/deps/lemon/lemon/bits/windows.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BITS_WINDOWS_H -#define LEMON_BITS_WINDOWS_H - -#include - -namespace lemon { - namespace bits { - void getWinProcTimes(double &rtime, - double &utime, double &stime, - double &cutime, double &cstime); - std::string getWinFormattedDate(); - int getWinRndSeed(); - - class WinLock { - public: - WinLock(); - ~WinLock(); - void lock(); - void unlock(); - private: - void *_repr; - }; - } -} - -#endif diff --git a/deps/lemon/lemon/bucket_heap.h b/deps/lemon/lemon/bucket_heap.h deleted file mode 100644 index 92dbc08f0..000000000 --- a/deps/lemon/lemon/bucket_heap.h +++ /dev/null @@ -1,594 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2010 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_BUCKET_HEAP_H -#define LEMON_BUCKET_HEAP_H - -///\ingroup heaps -///\file -///\brief Bucket heap implementation. - -#include -#include -#include - -namespace lemon { - - namespace _bucket_heap_bits { - - template - struct DirectionTraits { - static bool less(int left, int right) { - return left < right; - } - static void increase(int& value) { - ++value; - } - }; - - template <> - struct DirectionTraits { - static bool less(int left, int right) { - return left > right; - } - static void increase(int& value) { - --value; - } - }; - - } - - /// \ingroup heaps - /// - /// \brief Bucket heap data structure. - /// - /// This class implements the \e bucket \e heap data structure. - /// It practically conforms to the \ref concepts::Heap "heap concept", - /// but it has some limitations. - /// - /// The bucket heap is a very simple structure. It can store only - /// \c int priorities and it maintains a list of items for each priority - /// in the range [0..C). So it should only be used when the - /// priorities are small. It is not intended to use as a Dijkstra heap. - /// - /// \tparam IM A read-writable item map with \c int values, used - /// internally to handle the cross references. - /// \tparam MIN Indicate if the heap is a \e min-heap or a \e max-heap. - /// The default is \e min-heap. If this parameter is set to \c false, - /// then the comparison is reversed, so the top(), prio() and pop() - /// functions deal with the item having maximum priority instead of the - /// minimum. - /// - /// \sa SimpleBucketHeap - template - class BucketHeap { - - public: - - /// Type of the item-int map. - typedef IM ItemIntMap; - /// Type of the priorities. - typedef int Prio; - /// Type of the items stored in the heap. - typedef typename ItemIntMap::Key Item; - /// Type of the item-priority pairs. - typedef std::pair Pair; - - private: - - typedef _bucket_heap_bits::DirectionTraits Direction; - - public: - - /// \brief Type to represent the states of the items. - /// - /// Each item has a state associated to it. It can be "in heap", - /// "pre-heap" or "post-heap". The latter two are indifferent from the - /// heap's point of view, but may be useful to the user. - /// - /// The item-int map must be initialized in such way that it assigns - /// \c PRE_HEAP (-1) to any element to be put in the heap. - enum State { - IN_HEAP = 0, ///< = 0. - PRE_HEAP = -1, ///< = -1. - POST_HEAP = -2 ///< = -2. - }; - - public: - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - explicit BucketHeap(ItemIntMap &map) : _iim(map), _minimum(0) {} - - /// \brief The number of items stored in the heap. - /// - /// This function returns the number of items stored in the heap. - int size() const { return _data.size(); } - - /// \brief Check if the heap is empty. - /// - /// This function returns \c true if the heap is empty. - bool empty() const { return _data.empty(); } - - /// \brief Make the heap empty. - /// - /// This functon makes the heap empty. - /// It does not change the cross reference map. If you want to reuse - /// a heap that is not surely empty, you should first clear it and - /// then you should set the cross reference map to \c PRE_HEAP - /// for each item. - void clear() { - _data.clear(); _first.clear(); _minimum = 0; - } - - private: - - void relocateLast(int idx) { - if (idx + 1 < int(_data.size())) { - _data[idx] = _data.back(); - if (_data[idx].prev != -1) { - _data[_data[idx].prev].next = idx; - } else { - _first[_data[idx].value] = idx; - } - if (_data[idx].next != -1) { - _data[_data[idx].next].prev = idx; - } - _iim[_data[idx].item] = idx; - } - _data.pop_back(); - } - - void unlace(int idx) { - if (_data[idx].prev != -1) { - _data[_data[idx].prev].next = _data[idx].next; - } else { - _first[_data[idx].value] = _data[idx].next; - } - if (_data[idx].next != -1) { - _data[_data[idx].next].prev = _data[idx].prev; - } - } - - void lace(int idx) { - if (int(_first.size()) <= _data[idx].value) { - _first.resize(_data[idx].value + 1, -1); - } - _data[idx].next = _first[_data[idx].value]; - if (_data[idx].next != -1) { - _data[_data[idx].next].prev = idx; - } - _first[_data[idx].value] = idx; - _data[idx].prev = -1; - } - - public: - - /// \brief Insert a pair of item and priority into the heap. - /// - /// This function inserts \c p.first to the heap with priority - /// \c p.second. - /// \param p The pair to insert. - /// \pre \c p.first must not be stored in the heap. - void push(const Pair& p) { - push(p.first, p.second); - } - - /// \brief Insert an item into the heap with the given priority. - /// - /// This function inserts the given item into the heap with the - /// given priority. - /// \param i The item to insert. - /// \param p The priority of the item. - /// \pre \e i must not be stored in the heap. - void push(const Item &i, const Prio &p) { - int idx = _data.size(); - _iim[i] = idx; - _data.push_back(BucketItem(i, p)); - lace(idx); - if (Direction::less(p, _minimum)) { - _minimum = p; - } - } - - /// \brief Return the item having minimum priority. - /// - /// This function returns the item having minimum priority. - /// \pre The heap must be non-empty. - Item top() const { - while (_first[_minimum] == -1) { - Direction::increase(_minimum); - } - return _data[_first[_minimum]].item; - } - - /// \brief The minimum priority. - /// - /// This function returns the minimum priority. - /// \pre The heap must be non-empty. - Prio prio() const { - while (_first[_minimum] == -1) { - Direction::increase(_minimum); - } - return _minimum; - } - - /// \brief Remove the item having minimum priority. - /// - /// This function removes the item having minimum priority. - /// \pre The heap must be non-empty. - void pop() { - while (_first[_minimum] == -1) { - Direction::increase(_minimum); - } - int idx = _first[_minimum]; - _iim[_data[idx].item] = -2; - unlace(idx); - relocateLast(idx); - } - - /// \brief Remove the given item from the heap. - /// - /// This function removes the given item from the heap if it is - /// already stored. - /// \param i The item to delete. - /// \pre \e i must be in the heap. - void erase(const Item &i) { - int idx = _iim[i]; - _iim[_data[idx].item] = -2; - unlace(idx); - relocateLast(idx); - } - - /// \brief The priority of the given item. - /// - /// This function returns the priority of the given item. - /// \param i The item. - /// \pre \e i must be in the heap. - Prio operator[](const Item &i) const { - int idx = _iim[i]; - return _data[idx].value; - } - - /// \brief Set the priority of an item or insert it, if it is - /// not stored in the heap. - /// - /// This method sets the priority of the given item if it is - /// already stored in the heap. Otherwise it inserts the given - /// item into the heap with the given priority. - /// \param i The item. - /// \param p The priority. - void set(const Item &i, const Prio &p) { - int idx = _iim[i]; - if (idx < 0) { - push(i, p); - } else if (Direction::less(p, _data[idx].value)) { - decrease(i, p); - } else { - increase(i, p); - } - } - - /// \brief Decrease the priority of an item to the given value. - /// - /// This function decreases the priority of an item to the given value. - /// \param i The item. - /// \param p The priority. - /// \pre \e i must be stored in the heap with priority at least \e p. - void decrease(const Item &i, const Prio &p) { - int idx = _iim[i]; - unlace(idx); - _data[idx].value = p; - if (Direction::less(p, _minimum)) { - _minimum = p; - } - lace(idx); - } - - /// \brief Increase the priority of an item to the given value. - /// - /// This function increases the priority of an item to the given value. - /// \param i The item. - /// \param p The priority. - /// \pre \e i must be stored in the heap with priority at most \e p. - void increase(const Item &i, const Prio &p) { - int idx = _iim[i]; - unlace(idx); - _data[idx].value = p; - lace(idx); - } - - /// \brief Return the state of an item. - /// - /// This method returns \c PRE_HEAP if the given item has never - /// been in the heap, \c IN_HEAP if it is in the heap at the moment, - /// and \c POST_HEAP otherwise. - /// In the latter case it is possible that the item will get back - /// to the heap again. - /// \param i The item. - State state(const Item &i) const { - int idx = _iim[i]; - if (idx >= 0) idx = 0; - return State(idx); - } - - /// \brief Set the state of an item in the heap. - /// - /// This function sets the state of the given item in the heap. - /// It can be used to manually clear the heap when it is important - /// to achive better time complexity. - /// \param i The item. - /// \param st The state. It should not be \c IN_HEAP. - void state(const Item& i, State st) { - switch (st) { - case POST_HEAP: - case PRE_HEAP: - if (state(i) == IN_HEAP) { - erase(i); - } - _iim[i] = st; - break; - case IN_HEAP: - break; - } - } - - private: - - struct BucketItem { - BucketItem(const Item& _item, int _value) - : item(_item), value(_value) {} - - Item item; - int value; - - int prev, next; - }; - - ItemIntMap& _iim; - std::vector _first; - std::vector _data; - mutable int _minimum; - - }; // class BucketHeap - - /// \ingroup heaps - /// - /// \brief Simplified bucket heap data structure. - /// - /// This class implements a simplified \e bucket \e heap data - /// structure. It does not provide some functionality, but it is - /// faster and simpler than BucketHeap. The main difference is - /// that BucketHeap stores a doubly-linked list for each key while - /// this class stores only simply-linked lists. It supports erasing - /// only for the item having minimum priority and it does not support - /// key increasing and decreasing. - /// - /// Note that this implementation does not conform to the - /// \ref concepts::Heap "heap concept" due to the lack of some - /// functionality. - /// - /// \tparam IM A read-writable item map with \c int values, used - /// internally to handle the cross references. - /// \tparam MIN Indicate if the heap is a \e min-heap or a \e max-heap. - /// The default is \e min-heap. If this parameter is set to \c false, - /// then the comparison is reversed, so the top(), prio() and pop() - /// functions deal with the item having maximum priority instead of the - /// minimum. - /// - /// \sa BucketHeap - template - class SimpleBucketHeap { - - public: - - /// Type of the item-int map. - typedef IM ItemIntMap; - /// Type of the priorities. - typedef int Prio; - /// Type of the items stored in the heap. - typedef typename ItemIntMap::Key Item; - /// Type of the item-priority pairs. - typedef std::pair Pair; - - private: - - typedef _bucket_heap_bits::DirectionTraits Direction; - - public: - - /// \brief Type to represent the states of the items. - /// - /// Each item has a state associated to it. It can be "in heap", - /// "pre-heap" or "post-heap". The latter two are indifferent from the - /// heap's point of view, but may be useful to the user. - /// - /// The item-int map must be initialized in such way that it assigns - /// \c PRE_HEAP (-1) to any element to be put in the heap. - enum State { - IN_HEAP = 0, ///< = 0. - PRE_HEAP = -1, ///< = -1. - POST_HEAP = -2 ///< = -2. - }; - - public: - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - explicit SimpleBucketHeap(ItemIntMap &map) - : _iim(map), _free(-1), _num(0), _minimum(0) {} - - /// \brief The number of items stored in the heap. - /// - /// This function returns the number of items stored in the heap. - int size() const { return _num; } - - /// \brief Check if the heap is empty. - /// - /// This function returns \c true if the heap is empty. - bool empty() const { return _num == 0; } - - /// \brief Make the heap empty. - /// - /// This functon makes the heap empty. - /// It does not change the cross reference map. If you want to reuse - /// a heap that is not surely empty, you should first clear it and - /// then you should set the cross reference map to \c PRE_HEAP - /// for each item. - void clear() { - _data.clear(); _first.clear(); _free = -1; _num = 0; _minimum = 0; - } - - /// \brief Insert a pair of item and priority into the heap. - /// - /// This function inserts \c p.first to the heap with priority - /// \c p.second. - /// \param p The pair to insert. - /// \pre \c p.first must not be stored in the heap. - void push(const Pair& p) { - push(p.first, p.second); - } - - /// \brief Insert an item into the heap with the given priority. - /// - /// This function inserts the given item into the heap with the - /// given priority. - /// \param i The item to insert. - /// \param p The priority of the item. - /// \pre \e i must not be stored in the heap. - void push(const Item &i, const Prio &p) { - int idx; - if (_free == -1) { - idx = _data.size(); - _data.push_back(BucketItem(i)); - } else { - idx = _free; - _free = _data[idx].next; - _data[idx].item = i; - } - _iim[i] = idx; - if (p >= int(_first.size())) _first.resize(p + 1, -1); - _data[idx].next = _first[p]; - _first[p] = idx; - if (Direction::less(p, _minimum)) { - _minimum = p; - } - ++_num; - } - - /// \brief Return the item having minimum priority. - /// - /// This function returns the item having minimum priority. - /// \pre The heap must be non-empty. - Item top() const { - while (_first[_minimum] == -1) { - Direction::increase(_minimum); - } - return _data[_first[_minimum]].item; - } - - /// \brief The minimum priority. - /// - /// This function returns the minimum priority. - /// \pre The heap must be non-empty. - Prio prio() const { - while (_first[_minimum] == -1) { - Direction::increase(_minimum); - } - return _minimum; - } - - /// \brief Remove the item having minimum priority. - /// - /// This function removes the item having minimum priority. - /// \pre The heap must be non-empty. - void pop() { - while (_first[_minimum] == -1) { - Direction::increase(_minimum); - } - int idx = _first[_minimum]; - _iim[_data[idx].item] = -2; - _first[_minimum] = _data[idx].next; - _data[idx].next = _free; - _free = idx; - --_num; - } - - /// \brief The priority of the given item. - /// - /// This function returns the priority of the given item. - /// \param i The item. - /// \pre \e i must be in the heap. - /// \warning This operator is not a constant time function because - /// it scans the whole data structure to find the proper value. - Prio operator[](const Item &i) const { - for (int k = 0; k < int(_first.size()); ++k) { - int idx = _first[k]; - while (idx != -1) { - if (_data[idx].item == i) { - return k; - } - idx = _data[idx].next; - } - } - return -1; - } - - /// \brief Return the state of an item. - /// - /// This method returns \c PRE_HEAP if the given item has never - /// been in the heap, \c IN_HEAP if it is in the heap at the moment, - /// and \c POST_HEAP otherwise. - /// In the latter case it is possible that the item will get back - /// to the heap again. - /// \param i The item. - State state(const Item &i) const { - int idx = _iim[i]; - if (idx >= 0) idx = 0; - return State(idx); - } - - private: - - struct BucketItem { - BucketItem(const Item& _item) - : item(_item) {} - - Item item; - int next; - }; - - ItemIntMap& _iim; - std::vector _first; - std::vector _data; - int _free, _num; - mutable int _minimum; - - }; // class SimpleBucketHeap - -} - -#endif diff --git a/deps/lemon/lemon/capacity_scaling.h b/deps/lemon/lemon/capacity_scaling.h deleted file mode 100644 index ca64b56d3..000000000 --- a/deps/lemon/lemon/capacity_scaling.h +++ /dev/null @@ -1,1014 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_CAPACITY_SCALING_H -#define LEMON_CAPACITY_SCALING_H - -/// \ingroup min_cost_flow_algs -/// -/// \file -/// \brief Capacity Scaling algorithm for finding a minimum cost flow. - -#include -#include -#include -#include - -namespace lemon { - - /// \brief Default traits class of CapacityScaling algorithm. - /// - /// Default traits class of CapacityScaling algorithm. - /// \tparam GR Digraph type. - /// \tparam V The number type used for flow amounts, capacity bounds - /// and supply values. By default it is \c int. - /// \tparam C The number type used for costs and potentials. - /// By default it is the same as \c V. - template - struct CapacityScalingDefaultTraits - { - /// The type of the digraph - typedef GR Digraph; - /// The type of the flow amounts, capacity bounds and supply values - typedef V Value; - /// The type of the arc costs - typedef C Cost; - - /// \brief The type of the heap used for internal Dijkstra computations. - /// - /// The type of the heap used for internal Dijkstra computations. - /// It must conform to the \ref lemon::concepts::Heap "Heap" concept, - /// its priority type must be \c Cost and its cross reference type - /// must be \ref RangeMap "RangeMap". - typedef BinHeap > Heap; - }; - - /// \addtogroup min_cost_flow_algs - /// @{ - - /// \brief Implementation of the Capacity Scaling algorithm for - /// finding a \ref min_cost_flow "minimum cost flow". - /// - /// \ref CapacityScaling implements the capacity scaling version - /// of the successive shortest path algorithm for finding a - /// \ref min_cost_flow "minimum cost flow" \cite amo93networkflows, - /// \cite edmondskarp72theoretical. It is an efficient dual - /// solution method, which runs in polynomial time - /// \f$O(m\log U (n+m)\log n)\f$, where U denotes the maximum - /// of node supply and arc capacity values. - /// - /// This algorithm is typically slower than \ref CostScaling and - /// \ref NetworkSimplex, but in special cases, it can be more - /// efficient than them. - /// (For more information, see \ref min_cost_flow_algs "the module page".) - /// - /// Most of the parameters of the problem (except for the digraph) - /// can be given using separate functions, and the algorithm can be - /// executed using the \ref run() function. If some parameters are not - /// specified, then default values will be used. - /// - /// \tparam GR The digraph type the algorithm runs on. - /// \tparam V The number type used for flow amounts, capacity bounds - /// and supply values in the algorithm. By default, it is \c int. - /// \tparam C The number type used for costs and potentials in the - /// algorithm. By default, it is the same as \c V. - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref CapacityScalingDefaultTraits - /// "CapacityScalingDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. - /// - /// \warning Both \c V and \c C must be signed number types. - /// \warning Capacity bounds and supply values must be integer, but - /// arc costs can be arbitrary real numbers. - /// \warning This algorithm does not support negative costs for - /// arcs having infinite upper bound. -#ifdef DOXYGEN - template -#else - template < typename GR, typename V = int, typename C = V, - typename TR = CapacityScalingDefaultTraits > -#endif - class CapacityScaling - { - public: - - /// The type of the digraph - typedef typename TR::Digraph Digraph; - /// The type of the flow amounts, capacity bounds and supply values - typedef typename TR::Value Value; - /// The type of the arc costs - typedef typename TR::Cost Cost; - - /// The type of the heap used for internal Dijkstra computations - typedef typename TR::Heap Heap; - - /// \brief The \ref lemon::CapacityScalingDefaultTraits "traits class" - /// of the algorithm - typedef TR Traits; - - public: - - /// \brief Problem type constants for the \c run() function. - /// - /// Enum type containing the problem type constants that can be - /// returned by the \ref run() function of the algorithm. - enum ProblemType { - /// The problem has no feasible solution (flow). - INFEASIBLE, - /// The problem has optimal solution (i.e. it is feasible and - /// bounded), and the algorithm has found optimal flow and node - /// potentials (primal and dual solutions). - OPTIMAL, - /// The digraph contains an arc of negative cost and infinite - /// upper bound. It means that the objective function is unbounded - /// on that arc, however, note that it could actually be bounded - /// over the feasible flows, but this algroithm cannot handle - /// these cases. - UNBOUNDED - }; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(GR); - - typedef std::vector IntVector; - typedef std::vector ValueVector; - typedef std::vector CostVector; - typedef std::vector BoolVector; - // Note: vector is used instead of vector for efficiency reasons - - private: - - // Data related to the underlying digraph - const GR &_graph; - int _node_num; - int _arc_num; - int _res_arc_num; - int _root; - - // Parameters of the problem - bool _has_lower; - Value _sum_supply; - - // Data structures for storing the digraph - IntNodeMap _node_id; - IntArcMap _arc_idf; - IntArcMap _arc_idb; - IntVector _first_out; - BoolVector _forward; - IntVector _source; - IntVector _target; - IntVector _reverse; - - // Node and arc data - ValueVector _lower; - ValueVector _upper; - CostVector _cost; - ValueVector _supply; - - ValueVector _res_cap; - CostVector _pi; - ValueVector _excess; - IntVector _excess_nodes; - IntVector _deficit_nodes; - - Value _delta; - int _factor; - IntVector _pred; - - public: - - /// \brief Constant for infinite upper bounds (capacities). - /// - /// Constant for infinite upper bounds (capacities). - /// It is \c std::numeric_limits::infinity() if available, - /// \c std::numeric_limits::max() otherwise. - const Value INF; - - private: - - // Special implementation of the Dijkstra algorithm for finding - // shortest paths in the residual network of the digraph with - // respect to the reduced arc costs and modifying the node - // potentials according to the found distance labels. - class ResidualDijkstra - { - private: - - int _node_num; - bool _geq; - const IntVector &_first_out; - const IntVector &_target; - const CostVector &_cost; - const ValueVector &_res_cap; - const ValueVector &_excess; - CostVector &_pi; - IntVector &_pred; - - IntVector _proc_nodes; - CostVector _dist; - - public: - - ResidualDijkstra(CapacityScaling& cs) : - _node_num(cs._node_num), _geq(cs._sum_supply < 0), - _first_out(cs._first_out), _target(cs._target), _cost(cs._cost), - _res_cap(cs._res_cap), _excess(cs._excess), _pi(cs._pi), - _pred(cs._pred), _dist(cs._node_num) - {} - - int run(int s, Value delta = 1) { - RangeMap heap_cross_ref(_node_num, Heap::PRE_HEAP); - Heap heap(heap_cross_ref); - heap.push(s, 0); - _pred[s] = -1; - _proc_nodes.clear(); - - // Process nodes - while (!heap.empty() && _excess[heap.top()] > -delta) { - int u = heap.top(), v; - Cost d = heap.prio() + _pi[u], dn; - _dist[u] = heap.prio(); - _proc_nodes.push_back(u); - heap.pop(); - - // Traverse outgoing residual arcs - int last_out = _geq ? _first_out[u+1] : _first_out[u+1] - 1; - for (int a = _first_out[u]; a != last_out; ++a) { - if (_res_cap[a] < delta) continue; - v = _target[a]; - switch (heap.state(v)) { - case Heap::PRE_HEAP: - heap.push(v, d + _cost[a] - _pi[v]); - _pred[v] = a; - break; - case Heap::IN_HEAP: - dn = d + _cost[a] - _pi[v]; - if (dn < heap[v]) { - heap.decrease(v, dn); - _pred[v] = a; - } - break; - case Heap::POST_HEAP: - break; - } - } - } - if (heap.empty()) return -1; - - // Update potentials of processed nodes - int t = heap.top(); - Cost dt = heap.prio(); - for (int i = 0; i < int(_proc_nodes.size()); ++i) { - _pi[_proc_nodes[i]] += _dist[_proc_nodes[i]] - dt; - } - - return t; - } - - }; //class ResidualDijkstra - - public: - - /// \name Named Template Parameters - /// @{ - - template - struct SetHeapTraits : public Traits { - typedef T Heap; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c Heap type. - /// - /// \ref named-templ-param "Named parameter" for setting \c Heap - /// type, which is used for internal Dijkstra computations. - /// It must conform to the \ref lemon::concepts::Heap "Heap" concept, - /// its priority type must be \c Cost and its cross reference type - /// must be \ref RangeMap "RangeMap". - template - struct SetHeap - : public CapacityScaling > { - typedef CapacityScaling > Create; - }; - - /// @} - - protected: - - CapacityScaling() {} - - public: - - /// \brief Constructor. - /// - /// The constructor of the class. - /// - /// \param graph The digraph the algorithm runs on. - CapacityScaling(const GR& graph) : - _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph), - INF(std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max()) - { - // Check the number types - LEMON_ASSERT(std::numeric_limits::is_signed, - "The flow type of CapacityScaling must be signed"); - LEMON_ASSERT(std::numeric_limits::is_signed, - "The cost type of CapacityScaling must be signed"); - - // Reset data structures - reset(); - } - - /// \name Parameters - /// The parameters of the algorithm can be specified using these - /// functions. - - /// @{ - - /// \brief Set the lower bounds on the arcs. - /// - /// This function sets the lower bounds on the arcs. - /// If it is not used before calling \ref run(), the lower bounds - /// will be set to zero on all arcs. - /// - /// \param map An arc map storing the lower bounds. - /// Its \c Value type must be convertible to the \c Value type - /// of the algorithm. - /// - /// \return (*this) - template - CapacityScaling& lowerMap(const LowerMap& map) { - _has_lower = true; - for (ArcIt a(_graph); a != INVALID; ++a) { - _lower[_arc_idf[a]] = map[a]; - } - return *this; - } - - /// \brief Set the upper bounds (capacities) on the arcs. - /// - /// This function sets the upper bounds (capacities) on the arcs. - /// If it is not used before calling \ref run(), the upper bounds - /// will be set to \ref INF on all arcs (i.e. the flow value will be - /// unbounded from above). - /// - /// \param map An arc map storing the upper bounds. - /// Its \c Value type must be convertible to the \c Value type - /// of the algorithm. - /// - /// \return (*this) - template - CapacityScaling& upperMap(const UpperMap& map) { - for (ArcIt a(_graph); a != INVALID; ++a) { - _upper[_arc_idf[a]] = map[a]; - } - return *this; - } - - /// \brief Set the costs of the arcs. - /// - /// This function sets the costs of the arcs. - /// If it is not used before calling \ref run(), the costs - /// will be set to \c 1 on all arcs. - /// - /// \param map An arc map storing the costs. - /// Its \c Value type must be convertible to the \c Cost type - /// of the algorithm. - /// - /// \return (*this) - template - CapacityScaling& costMap(const CostMap& map) { - for (ArcIt a(_graph); a != INVALID; ++a) { - _cost[_arc_idf[a]] = map[a]; - _cost[_arc_idb[a]] = -map[a]; - } - return *this; - } - - /// \brief Set the supply values of the nodes. - /// - /// This function sets the supply values of the nodes. - /// If neither this function nor \ref stSupply() is used before - /// calling \ref run(), the supply of each node will be set to zero. - /// - /// \param map A node map storing the supply values. - /// Its \c Value type must be convertible to the \c Value type - /// of the algorithm. - /// - /// \return (*this) - template - CapacityScaling& supplyMap(const SupplyMap& map) { - for (NodeIt n(_graph); n != INVALID; ++n) { - _supply[_node_id[n]] = map[n]; - } - return *this; - } - - /// \brief Set single source and target nodes and a supply value. - /// - /// This function sets a single source node and a single target node - /// and the required flow value. - /// If neither this function nor \ref supplyMap() is used before - /// calling \ref run(), the supply of each node will be set to zero. - /// - /// Using this function has the same effect as using \ref supplyMap() - /// with a map in which \c k is assigned to \c s, \c -k is - /// assigned to \c t and all other nodes have zero supply value. - /// - /// \param s The source node. - /// \param t The target node. - /// \param k The required amount of flow from node \c s to node \c t - /// (i.e. the supply of \c s and the demand of \c t). - /// - /// \return (*this) - CapacityScaling& stSupply(const Node& s, const Node& t, Value k) { - for (int i = 0; i != _node_num; ++i) { - _supply[i] = 0; - } - _supply[_node_id[s]] = k; - _supply[_node_id[t]] = -k; - return *this; - } - - /// @} - - /// \name Execution control - /// The algorithm can be executed using \ref run(). - - /// @{ - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. - /// The paramters can be specified using functions \ref lowerMap(), - /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). - /// For example, - /// \code - /// CapacityScaling cs(graph); - /// cs.lowerMap(lower).upperMap(upper).costMap(cost) - /// .supplyMap(sup).run(); - /// \endcode - /// - /// This function can be called more than once. All the given parameters - /// are kept for the next call, unless \ref resetParams() or \ref reset() - /// is used, thus only the modified parameters have to be set again. - /// If the underlying digraph was also modified after the construction - /// of the class (or the last \ref reset() call), then the \ref reset() - /// function must be called. - /// - /// \param factor The capacity scaling factor. It must be larger than - /// one to use scaling. If it is less or equal to one, then scaling - /// will be disabled. - /// - /// \return \c INFEASIBLE if no feasible flow exists, - /// \n \c OPTIMAL if the problem has optimal solution - /// (i.e. it is feasible and bounded), and the algorithm has found - /// optimal flow and node potentials (primal and dual solutions), - /// \n \c UNBOUNDED if the digraph contains an arc of negative cost - /// and infinite upper bound. It means that the objective function - /// is unbounded on that arc, however, note that it could actually be - /// bounded over the feasible flows, but this algroithm cannot handle - /// these cases. - /// - /// \see ProblemType - /// \see resetParams(), reset() - ProblemType run(int factor = 4) { - _factor = factor; - ProblemType pt = init(); - if (pt != OPTIMAL) return pt; - return start(); - } - - /// \brief Reset all the parameters that have been given before. - /// - /// This function resets all the paramaters that have been given - /// before using functions \ref lowerMap(), \ref upperMap(), - /// \ref costMap(), \ref supplyMap(), \ref stSupply(). - /// - /// It is useful for multiple \ref run() calls. Basically, all the given - /// parameters are kept for the next \ref run() call, unless - /// \ref resetParams() or \ref reset() is used. - /// If the underlying digraph was also modified after the construction - /// of the class or the last \ref reset() call, then the \ref reset() - /// function must be used, otherwise \ref resetParams() is sufficient. - /// - /// For example, - /// \code - /// CapacityScaling cs(graph); - /// - /// // First run - /// cs.lowerMap(lower).upperMap(upper).costMap(cost) - /// .supplyMap(sup).run(); - /// - /// // Run again with modified cost map (resetParams() is not called, - /// // so only the cost map have to be set again) - /// cost[e] += 100; - /// cs.costMap(cost).run(); - /// - /// // Run again from scratch using resetParams() - /// // (the lower bounds will be set to zero on all arcs) - /// cs.resetParams(); - /// cs.upperMap(capacity).costMap(cost) - /// .supplyMap(sup).run(); - /// \endcode - /// - /// \return (*this) - /// - /// \see reset(), run() - CapacityScaling& resetParams() { - for (int i = 0; i != _node_num; ++i) { - _supply[i] = 0; - } - for (int j = 0; j != _res_arc_num; ++j) { - _lower[j] = 0; - _upper[j] = INF; - _cost[j] = _forward[j] ? 1 : -1; - } - _has_lower = false; - return *this; - } - - /// \brief Reset the internal data structures and all the parameters - /// that have been given before. - /// - /// This function resets the internal data structures and all the - /// paramaters that have been given before using functions \ref lowerMap(), - /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). - /// - /// It is useful for multiple \ref run() calls. Basically, all the given - /// parameters are kept for the next \ref run() call, unless - /// \ref resetParams() or \ref reset() is used. - /// If the underlying digraph was also modified after the construction - /// of the class or the last \ref reset() call, then the \ref reset() - /// function must be used, otherwise \ref resetParams() is sufficient. - /// - /// See \ref resetParams() for examples. - /// - /// \return (*this) - /// - /// \see resetParams(), run() - CapacityScaling& reset() { - // Resize vectors - _node_num = countNodes(_graph); - _arc_num = countArcs(_graph); - _res_arc_num = 2 * (_arc_num + _node_num); - _root = _node_num; - ++_node_num; - - _first_out.resize(_node_num + 1); - _forward.resize(_res_arc_num); - _source.resize(_res_arc_num); - _target.resize(_res_arc_num); - _reverse.resize(_res_arc_num); - - _lower.resize(_res_arc_num); - _upper.resize(_res_arc_num); - _cost.resize(_res_arc_num); - _supply.resize(_node_num); - - _res_cap.resize(_res_arc_num); - _pi.resize(_node_num); - _excess.resize(_node_num); - _pred.resize(_node_num); - - // Copy the graph - int i = 0, j = 0, k = 2 * _arc_num + _node_num - 1; - for (NodeIt n(_graph); n != INVALID; ++n, ++i) { - _node_id[n] = i; - } - i = 0; - for (NodeIt n(_graph); n != INVALID; ++n, ++i) { - _first_out[i] = j; - for (OutArcIt a(_graph, n); a != INVALID; ++a, ++j) { - _arc_idf[a] = j; - _forward[j] = true; - _source[j] = i; - _target[j] = _node_id[_graph.runningNode(a)]; - } - for (InArcIt a(_graph, n); a != INVALID; ++a, ++j) { - _arc_idb[a] = j; - _forward[j] = false; - _source[j] = i; - _target[j] = _node_id[_graph.runningNode(a)]; - } - _forward[j] = false; - _source[j] = i; - _target[j] = _root; - _reverse[j] = k; - _forward[k] = true; - _source[k] = _root; - _target[k] = i; - _reverse[k] = j; - ++j; ++k; - } - _first_out[i] = j; - _first_out[_node_num] = k; - for (ArcIt a(_graph); a != INVALID; ++a) { - int fi = _arc_idf[a]; - int bi = _arc_idb[a]; - _reverse[fi] = bi; - _reverse[bi] = fi; - } - - // Reset parameters - resetParams(); - return *this; - } - - /// @} - - /// \name Query Functions - /// The results of the algorithm can be obtained using these - /// functions.\n - /// The \ref run() function must be called before using them. - - /// @{ - - /// \brief Return the total cost of the found flow. - /// - /// This function returns the total cost of the found flow. - /// Its complexity is O(m). - /// - /// \note The return type of the function can be specified as a - /// template parameter. For example, - /// \code - /// cs.totalCost(); - /// \endcode - /// It is useful if the total cost cannot be stored in the \c Cost - /// type of the algorithm, which is the default return type of the - /// function. - /// - /// \pre \ref run() must be called before using this function. - template - Number totalCost() const { - Number c = 0; - for (ArcIt a(_graph); a != INVALID; ++a) { - int i = _arc_idb[a]; - c += static_cast(_res_cap[i]) * - (-static_cast(_cost[i])); - } - return c; - } - -#ifndef DOXYGEN - Cost totalCost() const { - return totalCost(); - } -#endif - - /// \brief Return the flow on the given arc. - /// - /// This function returns the flow on the given arc. - /// - /// \pre \ref run() must be called before using this function. - Value flow(const Arc& a) const { - return _res_cap[_arc_idb[a]]; - } - - /// \brief Copy the flow values (the primal solution) into the - /// given map. - /// - /// This function copies the flow value on each arc into the given - /// map. The \c Value type of the algorithm must be convertible to - /// the \c Value type of the map. - /// - /// \pre \ref run() must be called before using this function. - template - void flowMap(FlowMap &map) const { - for (ArcIt a(_graph); a != INVALID; ++a) { - map.set(a, _res_cap[_arc_idb[a]]); - } - } - - /// \brief Return the potential (dual value) of the given node. - /// - /// This function returns the potential (dual value) of the - /// given node. - /// - /// \pre \ref run() must be called before using this function. - Cost potential(const Node& n) const { - return _pi[_node_id[n]]; - } - - /// \brief Copy the potential values (the dual solution) into the - /// given map. - /// - /// This function copies the potential (dual value) of each node - /// into the given map. - /// The \c Cost type of the algorithm must be convertible to the - /// \c Value type of the map. - /// - /// \pre \ref run() must be called before using this function. - template - void potentialMap(PotentialMap &map) const { - for (NodeIt n(_graph); n != INVALID; ++n) { - map.set(n, _pi[_node_id[n]]); - } - } - - /// @} - - private: - - // Initialize the algorithm - ProblemType init() { - if (_node_num <= 1) return INFEASIBLE; - - // Check the sum of supply values - _sum_supply = 0; - for (int i = 0; i != _root; ++i) { - _sum_supply += _supply[i]; - } - if (_sum_supply > 0) return INFEASIBLE; - - // Check lower and upper bounds - LEMON_DEBUG(checkBoundMaps(), - "Upper bounds must be greater or equal to the lower bounds"); - - - // Initialize vectors - for (int i = 0; i != _root; ++i) { - _pi[i] = 0; - _excess[i] = _supply[i]; - } - - // Remove non-zero lower bounds - const Value MAX = std::numeric_limits::max(); - int last_out; - if (_has_lower) { - for (int i = 0; i != _root; ++i) { - last_out = _first_out[i+1]; - for (int j = _first_out[i]; j != last_out; ++j) { - if (_forward[j]) { - Value c = _lower[j]; - if (c >= 0) { - _res_cap[j] = _upper[j] < MAX ? _upper[j] - c : INF; - } else { - _res_cap[j] = _upper[j] < MAX + c ? _upper[j] - c : INF; - } - _excess[i] -= c; - _excess[_target[j]] += c; - } else { - _res_cap[j] = 0; - } - } - } - } else { - for (int j = 0; j != _res_arc_num; ++j) { - _res_cap[j] = _forward[j] ? _upper[j] : 0; - } - } - - // Handle negative costs - for (int i = 0; i != _root; ++i) { - last_out = _first_out[i+1] - 1; - for (int j = _first_out[i]; j != last_out; ++j) { - Value rc = _res_cap[j]; - if (_cost[j] < 0 && rc > 0) { - if (rc >= MAX) return UNBOUNDED; - _excess[i] -= rc; - _excess[_target[j]] += rc; - _res_cap[j] = 0; - _res_cap[_reverse[j]] += rc; - } - } - } - - // Handle GEQ supply type - if (_sum_supply < 0) { - _pi[_root] = 0; - _excess[_root] = -_sum_supply; - for (int a = _first_out[_root]; a != _res_arc_num; ++a) { - int ra = _reverse[a]; - _res_cap[a] = -_sum_supply + 1; - _res_cap[ra] = 0; - _cost[a] = 0; - _cost[ra] = 0; - } - } else { - _pi[_root] = 0; - _excess[_root] = 0; - for (int a = _first_out[_root]; a != _res_arc_num; ++a) { - int ra = _reverse[a]; - _res_cap[a] = 1; - _res_cap[ra] = 0; - _cost[a] = 0; - _cost[ra] = 0; - } - } - - // Initialize delta value - if (_factor > 1) { - // With scaling - Value max_sup = 0, max_dem = 0, max_cap = 0; - for (int i = 0; i != _root; ++i) { - Value ex = _excess[i]; - if ( ex > max_sup) max_sup = ex; - if (-ex > max_dem) max_dem = -ex; - int last_out = _first_out[i+1] - 1; - for (int j = _first_out[i]; j != last_out; ++j) { - if (_res_cap[j] > max_cap) max_cap = _res_cap[j]; - } - } - max_sup = std::min(std::min(max_sup, max_dem), max_cap); - for (_delta = 1; 2 * _delta <= max_sup; _delta *= 2) ; - } else { - // Without scaling - _delta = 1; - } - - return OPTIMAL; - } - - // Check if the upper bound is greater than or equal to the lower bound - // on each forward arc. - bool checkBoundMaps() { - for (int j = 0; j != _res_arc_num; ++j) { - if (_forward[j] && _upper[j] < _lower[j]) return false; - } - return true; - } - - ProblemType start() { - // Execute the algorithm - ProblemType pt; - if (_delta > 1) - pt = startWithScaling(); - else - pt = startWithoutScaling(); - - // Handle non-zero lower bounds - if (_has_lower) { - int limit = _first_out[_root]; - for (int j = 0; j != limit; ++j) { - if (_forward[j]) _res_cap[_reverse[j]] += _lower[j]; - } - } - - // Shift potentials if necessary - Cost pr = _pi[_root]; - if (_sum_supply < 0 || pr > 0) { - for (int i = 0; i != _node_num; ++i) { - _pi[i] -= pr; - } - } - - return pt; - } - - // Execute the capacity scaling algorithm - ProblemType startWithScaling() { - // Perform capacity scaling phases - int s, t; - ResidualDijkstra _dijkstra(*this); - while (true) { - // Saturate all arcs not satisfying the optimality condition - int last_out; - for (int u = 0; u != _node_num; ++u) { - last_out = _sum_supply < 0 ? - _first_out[u+1] : _first_out[u+1] - 1; - for (int a = _first_out[u]; a != last_out; ++a) { - int v = _target[a]; - Cost c = _cost[a] + _pi[u] - _pi[v]; - Value rc = _res_cap[a]; - if (c < 0 && rc >= _delta) { - _excess[u] -= rc; - _excess[v] += rc; - _res_cap[a] = 0; - _res_cap[_reverse[a]] += rc; - } - } - } - - // Find excess nodes and deficit nodes - _excess_nodes.clear(); - _deficit_nodes.clear(); - for (int u = 0; u != _node_num; ++u) { - Value ex = _excess[u]; - if (ex >= _delta) _excess_nodes.push_back(u); - if (ex <= -_delta) _deficit_nodes.push_back(u); - } - int next_node = 0, next_def_node = 0; - - // Find augmenting shortest paths - while (next_node < int(_excess_nodes.size())) { - // Check deficit nodes - if (_delta > 1) { - bool delta_deficit = false; - for ( ; next_def_node < int(_deficit_nodes.size()); - ++next_def_node ) { - if (_excess[_deficit_nodes[next_def_node]] <= -_delta) { - delta_deficit = true; - break; - } - } - if (!delta_deficit) break; - } - - // Run Dijkstra in the residual network - s = _excess_nodes[next_node]; - if ((t = _dijkstra.run(s, _delta)) == -1) { - if (_delta > 1) { - ++next_node; - continue; - } - return INFEASIBLE; - } - - // Augment along a shortest path from s to t - Value d = std::min(_excess[s], -_excess[t]); - int u = t; - int a; - if (d > _delta) { - while ((a = _pred[u]) != -1) { - if (_res_cap[a] < d) d = _res_cap[a]; - u = _source[a]; - } - } - u = t; - while ((a = _pred[u]) != -1) { - _res_cap[a] -= d; - _res_cap[_reverse[a]] += d; - u = _source[a]; - } - _excess[s] -= d; - _excess[t] += d; - - if (_excess[s] < _delta) ++next_node; - } - - if (_delta == 1) break; - _delta = _delta <= _factor ? 1 : _delta / _factor; - } - - return OPTIMAL; - } - - // Execute the successive shortest path algorithm - ProblemType startWithoutScaling() { - // Find excess nodes - _excess_nodes.clear(); - for (int i = 0; i != _node_num; ++i) { - if (_excess[i] > 0) _excess_nodes.push_back(i); - } - if (_excess_nodes.size() == 0) return OPTIMAL; - int next_node = 0; - - // Find shortest paths - int s, t; - ResidualDijkstra _dijkstra(*this); - while ( _excess[_excess_nodes[next_node]] > 0 || - ++next_node < int(_excess_nodes.size()) ) - { - // Run Dijkstra in the residual network - s = _excess_nodes[next_node]; - if ((t = _dijkstra.run(s)) == -1) return INFEASIBLE; - - // Augment along a shortest path from s to t - Value d = std::min(_excess[s], -_excess[t]); - int u = t; - int a; - if (d > 1) { - while ((a = _pred[u]) != -1) { - if (_res_cap[a] < d) d = _res_cap[a]; - u = _source[a]; - } - } - u = t; - while ((a = _pred[u]) != -1) { - _res_cap[a] -= d; - _res_cap[_reverse[a]] += d; - u = _source[a]; - } - _excess[s] -= d; - _excess[t] += d; - } - - return OPTIMAL; - } - - }; //class CapacityScaling - - ///@} - -} //namespace lemon - -#endif //LEMON_CAPACITY_SCALING_H diff --git a/deps/lemon/lemon/cbc.cc b/deps/lemon/lemon/cbc.cc deleted file mode 100644 index 62331b1e2..000000000 --- a/deps/lemon/lemon/cbc.cc +++ /dev/null @@ -1,460 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\file -///\brief Implementation of the CBC MIP solver interface. - -#include "cbc.h" - -#include -#include -#include - -#include "coin/OsiClpSolverInterface.hpp" - -#include "coin/CbcCutGenerator.hpp" -#include "coin/CbcHeuristicLocal.hpp" -#include "coin/CbcHeuristicGreedy.hpp" -#include "coin/CbcHeuristicFPump.hpp" -#include "coin/CbcHeuristicRINS.hpp" - -#include "coin/CglGomory.hpp" -#include "coin/CglProbing.hpp" -#include "coin/CglKnapsackCover.hpp" -#include "coin/CglOddHole.hpp" -#include "coin/CglClique.hpp" -#include "coin/CglFlowCover.hpp" -#include "coin/CglMixedIntegerRounding.hpp" - -#include "coin/CbcHeuristic.hpp" - -namespace lemon { - - CbcMip::CbcMip() { - _prob = new CoinModel(); - _prob->setProblemName("LEMON"); - _osi_solver = 0; - _cbc_model = 0; - messageLevel(MESSAGE_NOTHING); - } - - CbcMip::CbcMip(const CbcMip& other) { - _prob = new CoinModel(*other._prob); - _prob->setProblemName("LEMON"); - _osi_solver = 0; - _cbc_model = 0; - messageLevel(MESSAGE_NOTHING); - } - - CbcMip::~CbcMip() { - delete _prob; - if (_osi_solver) delete _osi_solver; - if (_cbc_model) delete _cbc_model; - } - - const char* CbcMip::_solverName() const { return "CbcMip"; } - - int CbcMip::_addCol() { - _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0, 0, false); - return _prob->numberColumns() - 1; - } - - CbcMip* CbcMip::newSolver() const { - CbcMip* newlp = new CbcMip; - return newlp; - } - - CbcMip* CbcMip::cloneSolver() const { - CbcMip* copylp = new CbcMip(*this); - return copylp; - } - - int CbcMip::_addRow() { - _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX); - return _prob->numberRows() - 1; - } - - int CbcMip::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) { - std::vector indexes; - std::vector values; - - for(ExprIterator it = b; it != e; ++it) { - indexes.push_back(it->first); - values.push_back(it->second); - } - - _prob->addRow(values.size(), &indexes.front(), &values.front(), l, u); - return _prob->numberRows() - 1; - } - - void CbcMip::_eraseCol(int i) { - _prob->deleteColumn(i); - } - - void CbcMip::_eraseRow(int i) { - _prob->deleteRow(i); - } - - void CbcMip::_eraseColId(int i) { - cols.eraseIndex(i); - } - - void CbcMip::_eraseRowId(int i) { - rows.eraseIndex(i); - } - - void CbcMip::_getColName(int c, std::string& name) const { - name = _prob->getColumnName(c); - } - - void CbcMip::_setColName(int c, const std::string& name) { - _prob->setColumnName(c, name.c_str()); - } - - int CbcMip::_colByName(const std::string& name) const { - return _prob->column(name.c_str()); - } - - void CbcMip::_getRowName(int r, std::string& name) const { - name = _prob->getRowName(r); - } - - void CbcMip::_setRowName(int r, const std::string& name) { - _prob->setRowName(r, name.c_str()); - } - - int CbcMip::_rowByName(const std::string& name) const { - return _prob->row(name.c_str()); - } - - void CbcMip::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) { - for (ExprIterator it = b; it != e; ++it) { - _prob->setElement(i, it->first, it->second); - } - } - - void CbcMip::_getRowCoeffs(int ix, InsertIterator b) const { - int length = _prob->numberRows(); - - std::vector indices(length); - std::vector values(length); - - length = _prob->getRow(ix, &indices[0], &values[0]); - - for (int i = 0; i < length; ++i) { - *b = std::make_pair(indices[i], values[i]); - ++b; - } - } - - void CbcMip::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) { - for (ExprIterator it = b; it != e; ++it) { - _prob->setElement(it->first, ix, it->second); - } - } - - void CbcMip::_getColCoeffs(int ix, InsertIterator b) const { - int length = _prob->numberColumns(); - - std::vector indices(length); - std::vector values(length); - - length = _prob->getColumn(ix, &indices[0], &values[0]); - - for (int i = 0; i < length; ++i) { - *b = std::make_pair(indices[i], values[i]); - ++b; - } - } - - void CbcMip::_setCoeff(int ix, int jx, Value value) { - _prob->setElement(ix, jx, value); - } - - CbcMip::Value CbcMip::_getCoeff(int ix, int jx) const { - return _prob->getElement(ix, jx); - } - - - void CbcMip::_setColLowerBound(int i, Value lo) { - LEMON_ASSERT(lo != INF, "Invalid bound"); - _prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo); - } - - CbcMip::Value CbcMip::_getColLowerBound(int i) const { - double val = _prob->getColumnLower(i); - return val == - COIN_DBL_MAX ? - INF : val; - } - - void CbcMip::_setColUpperBound(int i, Value up) { - LEMON_ASSERT(up != -INF, "Invalid bound"); - _prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up); - } - - CbcMip::Value CbcMip::_getColUpperBound(int i) const { - double val = _prob->getColumnUpper(i); - return val == COIN_DBL_MAX ? INF : val; - } - - void CbcMip::_setRowLowerBound(int i, Value lo) { - LEMON_ASSERT(lo != INF, "Invalid bound"); - _prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo); - } - - CbcMip::Value CbcMip::_getRowLowerBound(int i) const { - double val = _prob->getRowLower(i); - return val == - COIN_DBL_MAX ? - INF : val; - } - - void CbcMip::_setRowUpperBound(int i, Value up) { - LEMON_ASSERT(up != -INF, "Invalid bound"); - _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up); - } - - CbcMip::Value CbcMip::_getRowUpperBound(int i) const { - double val = _prob->getRowUpper(i); - return val == COIN_DBL_MAX ? INF : val; - } - - void CbcMip::_setObjCoeffs(ExprIterator b, ExprIterator e) { - int num = _prob->numberColumns(); - for (int i = 0; i < num; ++i) { - _prob->setColumnObjective(i, 0.0); - } - for (ExprIterator it = b; it != e; ++it) { - _prob->setColumnObjective(it->first, it->second); - } - } - - void CbcMip::_getObjCoeffs(InsertIterator b) const { - int num = _prob->numberColumns(); - for (int i = 0; i < num; ++i) { - Value coef = _prob->getColumnObjective(i); - if (coef != 0.0) { - *b = std::make_pair(i, coef); - ++b; - } - } - } - - void CbcMip::_setObjCoeff(int i, Value obj_coef) { - _prob->setColumnObjective(i, obj_coef); - } - - CbcMip::Value CbcMip::_getObjCoeff(int i) const { - return _prob->getColumnObjective(i); - } - - CbcMip::SolveExitStatus CbcMip::_solve() { - - if (_osi_solver) { - delete _osi_solver; - } - _osi_solver = new OsiClpSolverInterface(); - - _osi_solver->loadFromCoinModel(*_prob); - - if (_cbc_model) { - delete _cbc_model; - } - _cbc_model= new CbcModel(*_osi_solver); - - _osi_solver->messageHandler()->setLogLevel(_message_level); - _cbc_model->setLogLevel(_message_level); - - _cbc_model->initialSolve(); - _cbc_model->solver()->setHintParam(OsiDoReducePrint, true, OsiHintTry); - - if (!_cbc_model->isInitialSolveAbandoned() && - _cbc_model->isInitialSolveProvenOptimal() && - !_cbc_model->isInitialSolveProvenPrimalInfeasible() && - !_cbc_model->isInitialSolveProvenDualInfeasible()) { - - CglProbing generator1; - generator1.setUsingObjective(true); - generator1.setMaxPass(3); - generator1.setMaxProbe(100); - generator1.setMaxLook(50); - generator1.setRowCuts(3); - _cbc_model->addCutGenerator(&generator1, -1, "Probing"); - - CglGomory generator2; - generator2.setLimit(300); - _cbc_model->addCutGenerator(&generator2, -1, "Gomory"); - - CglKnapsackCover generator3; - _cbc_model->addCutGenerator(&generator3, -1, "Knapsack"); - - CglOddHole generator4; - generator4.setMinimumViolation(0.005); - generator4.setMinimumViolationPer(0.00002); - generator4.setMaximumEntries(200); - _cbc_model->addCutGenerator(&generator4, -1, "OddHole"); - - CglClique generator5; - generator5.setStarCliqueReport(false); - generator5.setRowCliqueReport(false); - _cbc_model->addCutGenerator(&generator5, -1, "Clique"); - - CglMixedIntegerRounding mixedGen; - _cbc_model->addCutGenerator(&mixedGen, -1, "MixedIntegerRounding"); - - CglFlowCover flowGen; - _cbc_model->addCutGenerator(&flowGen, -1, "FlowCover"); - - OsiClpSolverInterface* osiclp = - dynamic_cast(_cbc_model->solver()); - if (osiclp->getNumRows() < 300 && osiclp->getNumCols() < 500) { - osiclp->setupForRepeatedUse(2, 0); - } - - CbcRounding heuristic1(*_cbc_model); - heuristic1.setWhen(3); - _cbc_model->addHeuristic(&heuristic1); - - CbcHeuristicLocal heuristic2(*_cbc_model); - heuristic2.setWhen(3); - _cbc_model->addHeuristic(&heuristic2); - - CbcHeuristicGreedyCover heuristic3(*_cbc_model); - heuristic3.setAlgorithm(11); - heuristic3.setWhen(3); - _cbc_model->addHeuristic(&heuristic3); - - CbcHeuristicFPump heuristic4(*_cbc_model); - heuristic4.setWhen(3); - _cbc_model->addHeuristic(&heuristic4); - - CbcHeuristicRINS heuristic5(*_cbc_model); - heuristic5.setWhen(3); - _cbc_model->addHeuristic(&heuristic5); - - if (_cbc_model->getNumCols() < 500) { - _cbc_model->setMaximumCutPassesAtRoot(-100); - } else if (_cbc_model->getNumCols() < 5000) { - _cbc_model->setMaximumCutPassesAtRoot(100); - } else { - _cbc_model->setMaximumCutPassesAtRoot(20); - } - - if (_cbc_model->getNumCols() < 5000) { - _cbc_model->setNumberStrong(10); - } - - _cbc_model->solver()->setIntParam(OsiMaxNumIterationHotStart, 100); - _cbc_model->branchAndBound(); - } - - if (_cbc_model->isAbandoned()) { - return UNSOLVED; - } else { - return SOLVED; - } - } - - CbcMip::Value CbcMip::_getSol(int i) const { - return _cbc_model->getColSolution()[i]; - } - - CbcMip::Value CbcMip::_getSolValue() const { - return _cbc_model->getObjValue(); - } - - CbcMip::ProblemType CbcMip::_getType() const { - if (_cbc_model->isProvenOptimal()) { - return OPTIMAL; - } else if (_cbc_model->isContinuousUnbounded()) { - return UNBOUNDED; - } - return FEASIBLE; - } - - void CbcMip::_setSense(Sense sense) { - switch (sense) { - case MIN: - _prob->setOptimizationDirection(1.0); - break; - case MAX: - _prob->setOptimizationDirection(- 1.0); - break; - } - } - - CbcMip::Sense CbcMip::_getSense() const { - if (_prob->optimizationDirection() > 0.0) { - return MIN; - } else if (_prob->optimizationDirection() < 0.0) { - return MAX; - } else { - LEMON_ASSERT(false, "Wrong sense"); - return CbcMip::Sense(); - } - } - - void CbcMip::_setColType(int i, CbcMip::ColTypes col_type) { - switch (col_type){ - case INTEGER: - _prob->setInteger(i); - break; - case REAL: - _prob->setContinuous(i); - break; - default:; - LEMON_ASSERT(false, "Wrong sense"); - } - } - - CbcMip::ColTypes CbcMip::_getColType(int i) const { - return _prob->getColumnIsInteger(i) ? INTEGER : REAL; - } - - void CbcMip::_clear() { - delete _prob; - if (_osi_solver) { - delete _osi_solver; - _osi_solver = 0; - } - if (_cbc_model) { - delete _cbc_model; - _cbc_model = 0; - } - - _prob = new CoinModel(); - } - - void CbcMip::_messageLevel(MessageLevel level) { - switch (level) { - case MESSAGE_NOTHING: - _message_level = 0; - break; - case MESSAGE_ERROR: - _message_level = 1; - break; - case MESSAGE_WARNING: - _message_level = 1; - break; - case MESSAGE_NORMAL: - _message_level = 2; - break; - case MESSAGE_VERBOSE: - _message_level = 3; - break; - } - } - -} //END OF NAMESPACE LEMON diff --git a/deps/lemon/lemon/cbc.h b/deps/lemon/lemon/cbc.h deleted file mode 100644 index 968e504ac..000000000 --- a/deps/lemon/lemon/cbc.h +++ /dev/null @@ -1,129 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_CBC_H -#define LEMON_CBC_H - -///\file -///\brief Header of the LEMON-CBC mip solver interface. -///\ingroup lp_group - -#include - -class CoinModel; -class OsiSolverInterface; -class CbcModel; - -namespace lemon { - - /// \brief Interface for the CBC MIP solver - /// - /// This class implements an interface for the CBC MIP solver. - ///\ingroup lp_group - class CbcMip : public MipSolver { - protected: - - CoinModel *_prob; - OsiSolverInterface *_osi_solver; - CbcModel *_cbc_model; - - public: - - /// \e - CbcMip(); - /// \e - CbcMip(const CbcMip&); - /// \e - ~CbcMip(); - /// \e - virtual CbcMip* newSolver() const; - /// \e - virtual CbcMip* cloneSolver() const; - - protected: - - virtual const char* _solverName() const; - - virtual int _addCol(); - virtual int _addRow(); - virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); - - virtual void _eraseCol(int i); - virtual void _eraseRow(int i); - - virtual void _eraseColId(int i); - virtual void _eraseRowId(int i); - - virtual void _getColName(int col, std::string& name) const; - virtual void _setColName(int col, const std::string& name); - virtual int _colByName(const std::string& name) const; - - virtual void _getRowName(int row, std::string& name) const; - virtual void _setRowName(int row, const std::string& name); - virtual int _rowByName(const std::string& name) const; - - virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); - virtual void _getRowCoeffs(int i, InsertIterator b) const; - - virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); - virtual void _getColCoeffs(int i, InsertIterator b) const; - - virtual void _setCoeff(int row, int col, Value value); - virtual Value _getCoeff(int row, int col) const; - - virtual void _setColLowerBound(int i, Value value); - virtual Value _getColLowerBound(int i) const; - virtual void _setColUpperBound(int i, Value value); - virtual Value _getColUpperBound(int i) const; - - virtual void _setRowLowerBound(int i, Value value); - virtual Value _getRowLowerBound(int i) const; - virtual void _setRowUpperBound(int i, Value value); - virtual Value _getRowUpperBound(int i) const; - - virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); - virtual void _getObjCoeffs(InsertIterator b) const; - - virtual void _setObjCoeff(int i, Value obj_coef); - virtual Value _getObjCoeff(int i) const; - - virtual void _setSense(Sense sense); - virtual Sense _getSense() const; - - virtual ColTypes _getColType(int col) const; - virtual void _setColType(int col, ColTypes col_type); - - virtual SolveExitStatus _solve(); - virtual ProblemType _getType() const; - virtual Value _getSol(int i) const; - virtual Value _getSolValue() const; - - virtual void _clear(); - - virtual void _messageLevel(MessageLevel level); - void _applyMessageLevel(); - - int _message_level; - - - - }; - -} - -#endif diff --git a/deps/lemon/lemon/christofides_tsp.h b/deps/lemon/lemon/christofides_tsp.h deleted file mode 100644 index 2997567a6..000000000 --- a/deps/lemon/lemon/christofides_tsp.h +++ /dev/null @@ -1,254 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_CHRISTOFIDES_TSP_H -#define LEMON_CHRISTOFIDES_TSP_H - -/// \ingroup tsp -/// \file -/// \brief Christofides algorithm for symmetric TSP - -#include -#include -#include -#include -#include - -namespace lemon { - - /// \ingroup tsp - /// - /// \brief Christofides algorithm for symmetric TSP. - /// - /// ChristofidesTsp implements Christofides' heuristic for solving - /// symmetric \ref tsp "TSP". - /// - /// This a well-known approximation method for the TSP problem with - /// metric cost function. - /// It has a guaranteed approximation factor of 3/2 (i.e. it finds a tour - /// whose total cost is at most 3/2 of the optimum), but it usually - /// provides better solutions in practice. - /// This implementation runs in O(n3log(n)) time. - /// - /// The algorithm starts with a \ref spantree "minimum cost spanning tree" and - /// finds a \ref MaxWeightedPerfectMatching "minimum cost perfect matching" - /// in the subgraph induced by the nodes that have odd degree in the - /// spanning tree. - /// Finally, it constructs the tour from the \ref EulerIt "Euler traversal" - /// of the union of the spanning tree and the matching. - /// During this last step, the algorithm simply skips the visited nodes - /// (i.e. creates shortcuts) assuming that the triangle inequality holds - /// for the cost function. - /// - /// \tparam CM Type of the cost map. - /// - /// \warning CM::Value must be a signed number type. - template - class ChristofidesTsp - { - public: - - /// Type of the cost map - typedef CM CostMap; - /// Type of the edge costs - typedef typename CM::Value Cost; - - private: - - GRAPH_TYPEDEFS(FullGraph); - - const FullGraph &_gr; - const CostMap &_cost; - std::vector _path; - Cost _sum; - - public: - - /// \brief Constructor - /// - /// Constructor. - /// \param gr The \ref FullGraph "full graph" the algorithm runs on. - /// \param cost The cost map. - ChristofidesTsp(const FullGraph &gr, const CostMap &cost) - : _gr(gr), _cost(cost) {} - - /// \name Execution Control - /// @{ - - /// \brief Runs the algorithm. - /// - /// This function runs the algorithm. - /// - /// \return The total cost of the found tour. - Cost run() { - _path.clear(); - - if (_gr.nodeNum() == 0) return _sum = 0; - else if (_gr.nodeNum() == 1) { - _path.push_back(_gr(0)); - return _sum = 0; - } - else if (_gr.nodeNum() == 2) { - _path.push_back(_gr(0)); - _path.push_back(_gr(1)); - return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; - } - - // Compute min. cost spanning tree - std::vector tree; - kruskal(_gr, _cost, std::back_inserter(tree)); - - FullGraph::NodeMap deg(_gr, 0); - for (int i = 0; i != int(tree.size()); ++i) { - Edge e = tree[i]; - ++deg[_gr.u(e)]; - ++deg[_gr.v(e)]; - } - - // Copy the induced subgraph of odd nodes - std::vector odd_nodes; - for (NodeIt u(_gr); u != INVALID; ++u) { - if (deg[u] % 2 == 1) odd_nodes.push_back(u); - } - - SmartGraph sgr; - SmartGraph::EdgeMap scost(sgr); - for (int i = 0; i != int(odd_nodes.size()); ++i) { - sgr.addNode(); - } - for (int i = 0; i != int(odd_nodes.size()); ++i) { - for (int j = 0; j != int(odd_nodes.size()); ++j) { - if (j == i) continue; - SmartGraph::Edge e = - sgr.addEdge(sgr.nodeFromId(i), sgr.nodeFromId(j)); - scost[e] = -_cost[_gr.edge(odd_nodes[i], odd_nodes[j])]; - } - } - - // Compute min. cost perfect matching - MaxWeightedPerfectMatching > - mwpm(sgr, scost); - mwpm.run(); - - for (SmartGraph::EdgeIt e(sgr); e != INVALID; ++e) { - if (mwpm.matching(e)) { - tree.push_back( _gr.edge(odd_nodes[sgr.id(sgr.u(e))], - odd_nodes[sgr.id(sgr.v(e))]) ); - } - } - - // Join the spanning tree and the matching - sgr.clear(); - for (int i = 0; i != _gr.nodeNum(); ++i) { - sgr.addNode(); - } - for (int i = 0; i != int(tree.size()); ++i) { - int ui = _gr.id(_gr.u(tree[i])), - vi = _gr.id(_gr.v(tree[i])); - sgr.addEdge(sgr.nodeFromId(ui), sgr.nodeFromId(vi)); - } - - // Compute the tour from the Euler traversal - SmartGraph::NodeMap visited(sgr, false); - for (EulerIt e(sgr); e != INVALID; ++e) { - SmartGraph::Node n = sgr.target(e); - if (!visited[n]) { - _path.push_back(_gr(sgr.id(n))); - visited[n] = true; - } - } - - _sum = _cost[_gr.edge(_path.back(), _path.front())]; - for (int i = 0; i < int(_path.size())-1; ++i) { - _sum += _cost[_gr.edge(_path[i], _path[i+1])]; - } - - return _sum; - } - - /// @} - - /// \name Query Functions - /// @{ - - /// \brief The total cost of the found tour. - /// - /// This function returns the total cost of the found tour. - /// - /// \pre run() must be called before using this function. - Cost tourCost() const { - return _sum; - } - - /// \brief Returns a const reference to the node sequence of the - /// found tour. - /// - /// This function returns a const reference to a vector - /// that stores the node sequence of the found tour. - /// - /// \pre run() must be called before using this function. - const std::vector& tourNodes() const { - return _path; - } - - /// \brief Gives back the node sequence of the found tour. - /// - /// This function copies the node sequence of the found tour into - /// an STL container through the given output iterator. The - /// value_type of the container must be FullGraph::Node. - /// For example, - /// \code - /// std::vector nodes(countNodes(graph)); - /// tsp.tourNodes(nodes.begin()); - /// \endcode - /// or - /// \code - /// std::list nodes; - /// tsp.tourNodes(std::back_inserter(nodes)); - /// \endcode - /// - /// \pre run() must be called before using this function. - template - void tourNodes(Iterator out) const { - std::copy(_path.begin(), _path.end(), out); - } - - /// \brief Gives back the found tour as a path. - /// - /// This function copies the found tour as a list of arcs/edges into - /// the given \ref lemon::concepts::Path "path structure". - /// - /// \pre run() must be called before using this function. - template - void tour(Path &path) const { - path.clear(); - for (int i = 0; i < int(_path.size()) - 1; ++i) { - path.addBack(_gr.arc(_path[i], _path[i+1])); - } - if (int(_path.size()) >= 2) { - path.addBack(_gr.arc(_path.back(), _path.front())); - } - } - - /// @} - - }; - -}; // namespace lemon - -#endif diff --git a/deps/lemon/lemon/circulation.h b/deps/lemon/lemon/circulation.h deleted file mode 100644 index b0f717b26..000000000 --- a/deps/lemon/lemon/circulation.h +++ /dev/null @@ -1,807 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_CIRCULATION_H -#define LEMON_CIRCULATION_H - -#include -#include -#include - -///\ingroup max_flow -///\file -///\brief Push-relabel algorithm for finding a feasible circulation. -/// -namespace lemon { - - /// \brief Default traits class of Circulation class. - /// - /// Default traits class of Circulation class. - /// - /// \tparam GR Type of the digraph the algorithm runs on. - /// \tparam LM The type of the lower bound map. - /// \tparam UM The type of the upper bound (capacity) map. - /// \tparam SM The type of the supply map. - template - struct CirculationDefaultTraits { - - /// \brief The type of the digraph the algorithm runs on. - typedef GR Digraph; - - /// \brief The type of the lower bound map. - /// - /// The type of the map that stores the lower bounds on the arcs. - /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. - typedef LM LowerMap; - - /// \brief The type of the upper bound (capacity) map. - /// - /// The type of the map that stores the upper bounds (capacities) - /// on the arcs. - /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. - typedef UM UpperMap; - - /// \brief The type of supply map. - /// - /// The type of the map that stores the signed supply values of the - /// nodes. - /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. - typedef SM SupplyMap; - - /// \brief The type of the flow and supply values. - typedef typename SupplyMap::Value Value; - - /// \brief The type of the map that stores the flow values. - /// - /// The type of the map that stores the flow values. - /// It must conform to the \ref concepts::ReadWriteMap "ReadWriteMap" - /// concept. -#ifdef DOXYGEN - typedef GR::ArcMap FlowMap; -#else - typedef typename Digraph::template ArcMap FlowMap; -#endif - - /// \brief Instantiates a FlowMap. - /// - /// This function instantiates a \ref FlowMap. - /// \param digraph The digraph for which we would like to define - /// the flow map. - static FlowMap* createFlowMap(const Digraph& digraph) { - return new FlowMap(digraph); - } - - /// \brief The elevator type used by the algorithm. - /// - /// The elevator type used by the algorithm. - /// - /// \sa Elevator, LinkedElevator -#ifdef DOXYGEN - typedef lemon::Elevator Elevator; -#else - typedef lemon::Elevator Elevator; -#endif - - /// \brief Instantiates an Elevator. - /// - /// This function instantiates an \ref Elevator. - /// \param digraph The digraph for which we would like to define - /// the elevator. - /// \param max_level The maximum level of the elevator. - static Elevator* createElevator(const Digraph& digraph, int max_level) { - return new Elevator(digraph, max_level); - } - - /// \brief The tolerance used by the algorithm - /// - /// The tolerance used by the algorithm to handle inexact computation. - typedef lemon::Tolerance Tolerance; - - }; - - /** - \brief Push-relabel algorithm for the network circulation problem. - - \ingroup max_flow - This class implements a push-relabel algorithm for the \e network - \e circulation problem. - It is to find a feasible circulation when lower and upper bounds - are given for the flow values on the arcs and lower bounds are - given for the difference between the outgoing and incoming flow - at the nodes. - - The exact formulation of this problem is the following. - Let \f$G=(V,A)\f$ be a digraph, \f$lower: A\rightarrow\mathbf{R}\f$ - \f$upper: A\rightarrow\mathbf{R}\cup\{\infty\}\f$ denote the lower and - upper bounds on the arcs, for which \f$lower(uv) \leq upper(uv)\f$ - holds for all \f$uv\in A\f$, and \f$sup: V\rightarrow\mathbf{R}\f$ - denotes the signed supply values of the nodes. - If \f$sup(u)>0\f$, then \f$u\f$ is a supply node with \f$sup(u)\f$ - supply, if \f$sup(u)<0\f$, then \f$u\f$ is a demand node with - \f$-sup(u)\f$ demand. - A feasible circulation is an \f$f: A\rightarrow\mathbf{R}\f$ - solution of the following problem. - - \f[ \sum_{uv\in A} f(uv) - \sum_{vu\in A} f(vu) - \geq sup(u) \quad \forall u\in V, \f] - \f[ lower(uv) \leq f(uv) \leq upper(uv) \quad \forall uv\in A. \f] - - The sum of the supply values, i.e. \f$\sum_{u\in V} sup(u)\f$ must be - zero or negative in order to have a feasible solution (since the sum - of the expressions on the left-hand side of the inequalities is zero). - It means that the total demand must be greater or equal to the total - supply and all the supplies have to be carried out from the supply nodes, - but there could be demands that are not satisfied. - If \f$\sum_{u\in V} sup(u)\f$ is zero, then all the supply/demand - constraints have to be satisfied with equality, i.e. all demands - have to be satisfied and all supplies have to be used. - - If you need the opposite inequalities in the supply/demand constraints - (i.e. the total demand is less than the total supply and all the demands - have to be satisfied while there could be supplies that are not used), - then you could easily transform the problem to the above form by reversing - the direction of the arcs and taking the negative of the supply values - (e.g. using \ref ReverseDigraph and \ref NegMap adaptors). - - This algorithm either calculates a feasible circulation, or provides - a \ref barrier() "barrier", which prooves that a feasible soultion - cannot exist. - - Note that this algorithm also provides a feasible solution for the - \ref min_cost_flow "minimum cost flow problem". - - \tparam GR The type of the digraph the algorithm runs on. - \tparam LM The type of the lower bound map. The default - map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". - \tparam UM The type of the upper bound (capacity) map. - The default map type is \c LM. - \tparam SM The type of the supply map. The default map type is - \ref concepts::Digraph::NodeMap "GR::NodeMap". - \tparam TR The traits class that defines various types used by the - algorithm. By default, it is \ref CirculationDefaultTraits - "CirculationDefaultTraits". - In most cases, this parameter should not be set directly, - consider to use the named template parameters instead. - */ -#ifdef DOXYGEN -template< typename GR, - typename LM, - typename UM, - typename SM, - typename TR > -#else -template< typename GR, - typename LM = typename GR::template ArcMap, - typename UM = LM, - typename SM = typename GR::template NodeMap, - typename TR = CirculationDefaultTraits > -#endif - class Circulation { - public: - - /// \brief The \ref lemon::CirculationDefaultTraits "traits class" - /// of the algorithm. - typedef TR Traits; - ///The type of the digraph the algorithm runs on. - typedef typename Traits::Digraph Digraph; - ///The type of the flow and supply values. - typedef typename Traits::Value Value; - - ///The type of the lower bound map. - typedef typename Traits::LowerMap LowerMap; - ///The type of the upper bound (capacity) map. - typedef typename Traits::UpperMap UpperMap; - ///The type of the supply map. - typedef typename Traits::SupplyMap SupplyMap; - ///The type of the flow map. - typedef typename Traits::FlowMap FlowMap; - - ///The type of the elevator. - typedef typename Traits::Elevator Elevator; - ///The type of the tolerance. - typedef typename Traits::Tolerance Tolerance; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - const Digraph &_g; - int _node_num; - - const LowerMap *_lo; - const UpperMap *_up; - const SupplyMap *_supply; - - FlowMap *_flow; - bool _local_flow; - - Elevator* _level; - bool _local_level; - - typedef typename Digraph::template NodeMap ExcessMap; - ExcessMap* _excess; - - Tolerance _tol; - int _el; - - public: - - typedef Circulation Create; - - ///\name Named Template Parameters - - ///@{ - - template - struct SetFlowMapTraits : public Traits { - typedef T FlowMap; - static FlowMap *createFlowMap(const Digraph&) { - LEMON_ASSERT(false, "FlowMap is not initialized"); - return 0; // ignore warnings - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// FlowMap type - /// - /// \ref named-templ-param "Named parameter" for setting FlowMap - /// type. - template - struct SetFlowMap - : public Circulation > { - typedef Circulation > Create; - }; - - template - struct SetElevatorTraits : public Traits { - typedef T Elevator; - static Elevator *createElevator(const Digraph&, int) { - LEMON_ASSERT(false, "Elevator is not initialized"); - return 0; // ignore warnings - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// Elevator type - /// - /// \ref named-templ-param "Named parameter" for setting Elevator - /// type. If this named parameter is used, then an external - /// elevator object must be passed to the algorithm using the - /// \ref elevator(Elevator&) "elevator()" function before calling - /// \ref run() or \ref init(). - /// \sa SetStandardElevator - template - struct SetElevator - : public Circulation > { - typedef Circulation > Create; - }; - - template - struct SetStandardElevatorTraits : public Traits { - typedef T Elevator; - static Elevator *createElevator(const Digraph& digraph, int max_level) { - return new Elevator(digraph, max_level); - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// Elevator type with automatic allocation - /// - /// \ref named-templ-param "Named parameter" for setting Elevator - /// type with automatic allocation. - /// The Elevator should have standard constructor interface to be - /// able to automatically created by the algorithm (i.e. the - /// digraph and the maximum level should be passed to it). - /// However, an external elevator object could also be passed to the - /// algorithm with the \ref elevator(Elevator&) "elevator()" function - /// before calling \ref run() or \ref init(). - /// \sa SetElevator - template - struct SetStandardElevator - : public Circulation > { - typedef Circulation > Create; - }; - - /// @} - - protected: - - Circulation() {} - - public: - - /// Constructor. - - /// The constructor of the class. - /// - /// \param graph The digraph the algorithm runs on. - /// \param lower The lower bounds for the flow values on the arcs. - /// \param upper The upper bounds (capacities) for the flow values - /// on the arcs. - /// \param supply The signed supply values of the nodes. - Circulation(const Digraph &graph, const LowerMap &lower, - const UpperMap &upper, const SupplyMap &supply) - : _g(graph), _lo(&lower), _up(&upper), _supply(&supply), - _flow(NULL), _local_flow(false), _level(NULL), _local_level(false), - _excess(NULL) {} - - /// Destructor. - ~Circulation() { - destroyStructures(); - } - - - private: - - bool checkBoundMaps() { - for (ArcIt e(_g);e!=INVALID;++e) { - if (_tol.less((*_up)[e], (*_lo)[e])) return false; - } - return true; - } - - void createStructures() { - _node_num = _el = countNodes(_g); - - if (!_flow) { - _flow = Traits::createFlowMap(_g); - _local_flow = true; - } - if (!_level) { - _level = Traits::createElevator(_g, _node_num); - _local_level = true; - } - if (!_excess) { - _excess = new ExcessMap(_g); - } - } - - void destroyStructures() { - if (_local_flow) { - delete _flow; - } - if (_local_level) { - delete _level; - } - if (_excess) { - delete _excess; - } - } - - public: - - /// Sets the lower bound map. - - /// Sets the lower bound map. - /// \return (*this) - Circulation& lowerMap(const LowerMap& map) { - _lo = ↦ - return *this; - } - - /// Sets the upper bound (capacity) map. - - /// Sets the upper bound (capacity) map. - /// \return (*this) - Circulation& upperMap(const UpperMap& map) { - _up = ↦ - return *this; - } - - /// Sets the supply map. - - /// Sets the supply map. - /// \return (*this) - Circulation& supplyMap(const SupplyMap& map) { - _supply = ↦ - return *this; - } - - /// \brief Sets the flow map. - /// - /// Sets the flow map. - /// If you don't use this function before calling \ref run() or - /// \ref init(), an instance will be allocated automatically. - /// The destructor deallocates this automatically allocated map, - /// of course. - /// \return (*this) - Circulation& flowMap(FlowMap& map) { - if (_local_flow) { - delete _flow; - _local_flow = false; - } - _flow = ↦ - return *this; - } - - /// \brief Sets the elevator used by algorithm. - /// - /// Sets the elevator used by algorithm. - /// If you don't use this function before calling \ref run() or - /// \ref init(), an instance will be allocated automatically. - /// The destructor deallocates this automatically allocated elevator, - /// of course. - /// \return (*this) - Circulation& elevator(Elevator& elevator) { - if (_local_level) { - delete _level; - _local_level = false; - } - _level = &elevator; - return *this; - } - - /// \brief Returns a const reference to the elevator. - /// - /// Returns a const reference to the elevator. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - const Elevator& elevator() const { - return *_level; - } - - /// \brief Sets the tolerance used by the algorithm. - /// - /// Sets the tolerance object used by the algorithm. - /// \return (*this) - Circulation& tolerance(const Tolerance& tolerance) { - _tol = tolerance; - return *this; - } - - /// \brief Returns a const reference to the tolerance. - /// - /// Returns a const reference to the tolerance object used by - /// the algorithm. - const Tolerance& tolerance() const { - return _tol; - } - - /// \name Execution Control - /// The simplest way to execute the algorithm is to call \ref run().\n - /// If you need better control on the initial solution or the execution, - /// you have to call one of the \ref init() functions first, then - /// the \ref start() function. - - ///@{ - - /// Initializes the internal data structures. - - /// Initializes the internal data structures and sets all flow values - /// to the lower bound. - void init() - { - LEMON_DEBUG(checkBoundMaps(), - "Upper bounds must be greater or equal to the lower bounds"); - - createStructures(); - - for(NodeIt n(_g);n!=INVALID;++n) { - (*_excess)[n] = (*_supply)[n]; - } - - for (ArcIt e(_g);e!=INVALID;++e) { - _flow->set(e, (*_lo)[e]); - (*_excess)[_g.target(e)] += (*_flow)[e]; - (*_excess)[_g.source(e)] -= (*_flow)[e]; - } - - // global relabeling tested, but in general case it provides - // worse performance for random digraphs - _level->initStart(); - for(NodeIt n(_g);n!=INVALID;++n) - _level->initAddItem(n); - _level->initFinish(); - for(NodeIt n(_g);n!=INVALID;++n) - if(_tol.positive((*_excess)[n])) - _level->activate(n); - } - - /// Initializes the internal data structures using a greedy approach. - - /// Initializes the internal data structures using a greedy approach - /// to construct the initial solution. - void greedyInit() - { - LEMON_DEBUG(checkBoundMaps(), - "Upper bounds must be greater or equal to the lower bounds"); - - createStructures(); - - for(NodeIt n(_g);n!=INVALID;++n) { - (*_excess)[n] = (*_supply)[n]; - } - - for (ArcIt e(_g);e!=INVALID;++e) { - if (!_tol.less(-(*_excess)[_g.target(e)], (*_up)[e])) { - _flow->set(e, (*_up)[e]); - (*_excess)[_g.target(e)] += (*_up)[e]; - (*_excess)[_g.source(e)] -= (*_up)[e]; - } else if (_tol.less(-(*_excess)[_g.target(e)], (*_lo)[e])) { - _flow->set(e, (*_lo)[e]); - (*_excess)[_g.target(e)] += (*_lo)[e]; - (*_excess)[_g.source(e)] -= (*_lo)[e]; - } else { - Value fc = -(*_excess)[_g.target(e)]; - _flow->set(e, fc); - (*_excess)[_g.target(e)] = 0; - (*_excess)[_g.source(e)] -= fc; - } - } - - _level->initStart(); - for(NodeIt n(_g);n!=INVALID;++n) - _level->initAddItem(n); - _level->initFinish(); - for(NodeIt n(_g);n!=INVALID;++n) - if(_tol.positive((*_excess)[n])) - _level->activate(n); - } - - ///Executes the algorithm - - ///This function executes the algorithm. - /// - ///\return \c true if a feasible circulation is found. - /// - ///\sa barrier() - ///\sa barrierMap() - bool start() - { - - Node act; - while((act=_level->highestActive())!=INVALID) { - int actlevel=(*_level)[act]; - int mlevel=_node_num; - Value exc=(*_excess)[act]; - - for(OutArcIt e(_g,act);e!=INVALID; ++e) { - Node v = _g.target(e); - Value fc=(*_up)[e]-(*_flow)[e]; - if(!_tol.positive(fc)) continue; - if((*_level)[v]set(e, (*_flow)[e] + exc); - (*_excess)[v] += exc; - if(!_level->active(v) && _tol.positive((*_excess)[v])) - _level->activate(v); - (*_excess)[act] = 0; - _level->deactivate(act); - goto next_l; - } - else { - _flow->set(e, (*_up)[e]); - (*_excess)[v] += fc; - if(!_level->active(v) && _tol.positive((*_excess)[v])) - _level->activate(v); - exc-=fc; - } - } - else if((*_level)[v]set(e, (*_flow)[e] - exc); - (*_excess)[v] += exc; - if(!_level->active(v) && _tol.positive((*_excess)[v])) - _level->activate(v); - (*_excess)[act] = 0; - _level->deactivate(act); - goto next_l; - } - else { - _flow->set(e, (*_lo)[e]); - (*_excess)[v] += fc; - if(!_level->active(v) && _tol.positive((*_excess)[v])) - _level->activate(v); - exc-=fc; - } - } - else if((*_level)[v]deactivate(act); - else if(mlevel==_node_num) { - _level->liftHighestActiveToTop(); - _el = _node_num; - return false; - } - else { - _level->liftHighestActive(mlevel+1); - if(_level->onLevel(actlevel)==0) { - _el = actlevel; - return false; - } - } - next_l: - ; - } - return true; - } - - /// Runs the algorithm. - - /// This function runs the algorithm. - /// - /// \return \c true if a feasible circulation is found. - /// - /// \note Apart from the return value, c.run() is just a shortcut of - /// the following code. - /// \code - /// c.greedyInit(); - /// c.start(); - /// \endcode - bool run() { - greedyInit(); - return start(); - } - - /// @} - - /// \name Query Functions - /// The results of the circulation algorithm can be obtained using - /// these functions.\n - /// Either \ref run() or \ref start() should be called before - /// using them. - - ///@{ - - /// \brief Returns the flow value on the given arc. - /// - /// Returns the flow value on the given arc. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - Value flow(const Arc& arc) const { - return (*_flow)[arc]; - } - - /// \brief Returns a const reference to the flow map. - /// - /// Returns a const reference to the arc map storing the found flow. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - const FlowMap& flowMap() const { - return *_flow; - } - - /** - \brief Returns \c true if the given node is in a barrier. - - Barrier is a set \e B of nodes for which - - \f[ \sum_{uv\in A: u\in B} upper(uv) - - \sum_{uv\in A: v\in B} lower(uv) < \sum_{v\in B} sup(v) \f] - - holds. The existence of a set with this property prooves that a - feasible circualtion cannot exist. - - This function returns \c true if the given node is in the found - barrier. If a feasible circulation is found, the function - gives back \c false for every node. - - \pre Either \ref run() or \ref init() must be called before - using this function. - - \sa barrierMap() - \sa checkBarrier() - */ - bool barrier(const Node& node) const - { - return (*_level)[node] >= _el; - } - - /// \brief Gives back a barrier. - /// - /// This function sets \c bar to the characteristic vector of the - /// found barrier. \c bar should be a \ref concepts::WriteMap "writable" - /// node map with \c bool (or convertible) value type. - /// - /// If a feasible circulation is found, the function gives back an - /// empty set, so \c bar[v] will be \c false for all nodes \c v. - /// - /// \note This function calls \ref barrier() for each node, - /// so it runs in O(n) time. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - /// - /// \sa barrier() - /// \sa checkBarrier() - template - void barrierMap(BarrierMap &bar) const - { - for(NodeIt n(_g);n!=INVALID;++n) - bar.set(n, (*_level)[n] >= _el); - } - - /// @} - - /// \name Checker Functions - /// The feasibility of the results can be checked using - /// these functions.\n - /// Either \ref run() or \ref start() should be called before - /// using them. - - ///@{ - - ///Check if the found flow is a feasible circulation - - ///Check if the found flow is a feasible circulation, - /// - bool checkFlow() const { - for(ArcIt e(_g);e!=INVALID;++e) - if((*_flow)[e]<(*_lo)[e]||(*_flow)[e]>(*_up)[e]) return false; - for(NodeIt n(_g);n!=INVALID;++n) - { - Value dif=-(*_supply)[n]; - for(InArcIt e(_g,n);e!=INVALID;++e) dif-=(*_flow)[e]; - for(OutArcIt e(_g,n);e!=INVALID;++e) dif+=(*_flow)[e]; - if(_tol.negative(dif)) return false; - } - return true; - } - - ///Check whether or not the last execution provides a barrier - - ///Check whether or not the last execution provides a barrier. - ///\sa barrier() - ///\sa barrierMap() - bool checkBarrier() const - { - Value delta=0; - Value inf_cap = std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max(); - for(NodeIt n(_g);n!=INVALID;++n) - if(barrier(n)) - delta-=(*_supply)[n]; - for(ArcIt e(_g);e!=INVALID;++e) - { - Node s=_g.source(e); - Node t=_g.target(e); - if(barrier(s)&&!barrier(t)) { - if (_tol.less(inf_cap - (*_up)[e], delta)) return false; - delta+=(*_up)[e]; - } - else if(barrier(t)&&!barrier(s)) delta-=(*_lo)[e]; - } - return _tol.negative(delta); - } - - /// @} - - }; - -} - -#endif diff --git a/deps/lemon/lemon/clp.cc b/deps/lemon/lemon/clp.cc deleted file mode 100644 index 7c0ea74f2..000000000 --- a/deps/lemon/lemon/clp.cc +++ /dev/null @@ -1,464 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include - -namespace lemon { - - ClpLp::ClpLp() { - _prob = new ClpSimplex(); - _init_temporals(); - messageLevel(MESSAGE_NOTHING); - } - - ClpLp::ClpLp(const ClpLp& other) { - _prob = new ClpSimplex(*other._prob); - rows = other.rows; - cols = other.cols; - _init_temporals(); - messageLevel(MESSAGE_NOTHING); - } - - ClpLp::~ClpLp() { - delete _prob; - _clear_temporals(); - } - - void ClpLp::_init_temporals() { - _primal_ray = 0; - _dual_ray = 0; - } - - void ClpLp::_clear_temporals() { - if (_primal_ray) { - delete[] _primal_ray; - _primal_ray = 0; - } - if (_dual_ray) { - delete[] _dual_ray; - _dual_ray = 0; - } - } - - ClpLp* ClpLp::newSolver() const { - ClpLp* newlp = new ClpLp; - return newlp; - } - - ClpLp* ClpLp::cloneSolver() const { - ClpLp* copylp = new ClpLp(*this); - return copylp; - } - - const char* ClpLp::_solverName() const { return "ClpLp"; } - - int ClpLp::_addCol() { - _prob->addColumn(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX, 0.0); - return _prob->numberColumns() - 1; - } - - int ClpLp::_addRow() { - _prob->addRow(0, 0, 0, -COIN_DBL_MAX, COIN_DBL_MAX); - return _prob->numberRows() - 1; - } - - int ClpLp::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) { - std::vector indexes; - std::vector values; - - for(ExprIterator it = b; it != e; ++it) { - indexes.push_back(it->first); - values.push_back(it->second); - } - - _prob->addRow(values.size(), &indexes.front(), &values.front(), l, u); - return _prob->numberRows() - 1; - } - - - void ClpLp::_eraseCol(int c) { - _col_names_ref.erase(_prob->getColumnName(c)); - _prob->deleteColumns(1, &c); - } - - void ClpLp::_eraseRow(int r) { - _row_names_ref.erase(_prob->getRowName(r)); - _prob->deleteRows(1, &r); - } - - void ClpLp::_eraseColId(int i) { - cols.eraseIndex(i); - cols.shiftIndices(i); - } - - void ClpLp::_eraseRowId(int i) { - rows.eraseIndex(i); - rows.shiftIndices(i); - } - - void ClpLp::_getColName(int c, std::string& name) const { - name = _prob->getColumnName(c); - } - - void ClpLp::_setColName(int c, const std::string& name) { - _prob->setColumnName(c, const_cast(name)); - _col_names_ref[name] = c; - } - - int ClpLp::_colByName(const std::string& name) const { - std::map::const_iterator it = _col_names_ref.find(name); - return it != _col_names_ref.end() ? it->second : -1; - } - - void ClpLp::_getRowName(int r, std::string& name) const { - name = _prob->getRowName(r); - } - - void ClpLp::_setRowName(int r, const std::string& name) { - _prob->setRowName(r, const_cast(name)); - _row_names_ref[name] = r; - } - - int ClpLp::_rowByName(const std::string& name) const { - std::map::const_iterator it = _row_names_ref.find(name); - return it != _row_names_ref.end() ? it->second : -1; - } - - - void ClpLp::_setRowCoeffs(int ix, ExprIterator b, ExprIterator e) { - std::map coeffs; - - int n = _prob->clpMatrix()->getNumCols(); - - const int* indices = _prob->clpMatrix()->getIndices(); - const double* elements = _prob->clpMatrix()->getElements(); - - for (int i = 0; i < n; ++i) { - CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i]; - CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i]; - - const int* it = std::lower_bound(indices + begin, indices + end, ix); - if (it != indices + end && *it == ix && elements[it - indices] != 0.0) { - coeffs[i] = 0.0; - } - } - - for (ExprIterator it = b; it != e; ++it) { - coeffs[it->first] = it->second; - } - - for (std::map::iterator it = coeffs.begin(); - it != coeffs.end(); ++it) { - _prob->modifyCoefficient(ix, it->first, it->second); - } - } - - void ClpLp::_getRowCoeffs(int ix, InsertIterator b) const { - int n = _prob->clpMatrix()->getNumCols(); - - const int* indices = _prob->clpMatrix()->getIndices(); - const double* elements = _prob->clpMatrix()->getElements(); - - for (int i = 0; i < n; ++i) { - CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[i]; - CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[i]; - - const int* it = std::lower_bound(indices + begin, indices + end, ix); - if (it != indices + end && *it == ix) { - *b = std::make_pair(i, elements[it - indices]); - } - } - } - - void ClpLp::_setColCoeffs(int ix, ExprIterator b, ExprIterator e) { - std::map coeffs; - - CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix]; - CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix]; - - const int* indices = _prob->clpMatrix()->getIndices(); - const double* elements = _prob->clpMatrix()->getElements(); - - for (CoinBigIndex i = begin; i != end; ++i) { - if (elements[i] != 0.0) { - coeffs[indices[i]] = 0.0; - } - } - for (ExprIterator it = b; it != e; ++it) { - coeffs[it->first] = it->second; - } - for (std::map::iterator it = coeffs.begin(); - it != coeffs.end(); ++it) { - _prob->modifyCoefficient(it->first, ix, it->second); - } - } - - void ClpLp::_getColCoeffs(int ix, InsertIterator b) const { - CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix]; - CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix]; - - const int* indices = _prob->clpMatrix()->getIndices(); - const double* elements = _prob->clpMatrix()->getElements(); - - for (CoinBigIndex i = begin; i != end; ++i) { - *b = std::make_pair(indices[i], elements[i]); - ++b; - } - } - - void ClpLp::_setCoeff(int ix, int jx, Value value) { - _prob->modifyCoefficient(ix, jx, value); - } - - ClpLp::Value ClpLp::_getCoeff(int ix, int jx) const { - CoinBigIndex begin = _prob->clpMatrix()->getVectorStarts()[ix]; - CoinBigIndex end = begin + _prob->clpMatrix()->getVectorLengths()[ix]; - - const int* indices = _prob->clpMatrix()->getIndices(); - const double* elements = _prob->clpMatrix()->getElements(); - - const int* it = std::lower_bound(indices + begin, indices + end, jx); - if (it != indices + end && *it == jx) { - return elements[it - indices]; - } else { - return 0.0; - } - } - - void ClpLp::_setColLowerBound(int i, Value lo) { - _prob->setColumnLower(i, lo == - INF ? - COIN_DBL_MAX : lo); - } - - ClpLp::Value ClpLp::_getColLowerBound(int i) const { - double val = _prob->getColLower()[i]; - return val == - COIN_DBL_MAX ? - INF : val; - } - - void ClpLp::_setColUpperBound(int i, Value up) { - _prob->setColumnUpper(i, up == INF ? COIN_DBL_MAX : up); - } - - ClpLp::Value ClpLp::_getColUpperBound(int i) const { - double val = _prob->getColUpper()[i]; - return val == COIN_DBL_MAX ? INF : val; - } - - void ClpLp::_setRowLowerBound(int i, Value lo) { - _prob->setRowLower(i, lo == - INF ? - COIN_DBL_MAX : lo); - } - - ClpLp::Value ClpLp::_getRowLowerBound(int i) const { - double val = _prob->getRowLower()[i]; - return val == - COIN_DBL_MAX ? - INF : val; - } - - void ClpLp::_setRowUpperBound(int i, Value up) { - _prob->setRowUpper(i, up == INF ? COIN_DBL_MAX : up); - } - - ClpLp::Value ClpLp::_getRowUpperBound(int i) const { - double val = _prob->getRowUpper()[i]; - return val == COIN_DBL_MAX ? INF : val; - } - - void ClpLp::_setObjCoeffs(ExprIterator b, ExprIterator e) { - int num = _prob->clpMatrix()->getNumCols(); - for (int i = 0; i < num; ++i) { - _prob->setObjectiveCoefficient(i, 0.0); - } - for (ExprIterator it = b; it != e; ++it) { - _prob->setObjectiveCoefficient(it->first, it->second); - } - } - - void ClpLp::_getObjCoeffs(InsertIterator b) const { - int num = _prob->clpMatrix()->getNumCols(); - for (int i = 0; i < num; ++i) { - Value coef = _prob->getObjCoefficients()[i]; - if (coef != 0.0) { - *b = std::make_pair(i, coef); - ++b; - } - } - } - - void ClpLp::_setObjCoeff(int i, Value obj_coef) { - _prob->setObjectiveCoefficient(i, obj_coef); - } - - ClpLp::Value ClpLp::_getObjCoeff(int i) const { - return _prob->getObjCoefficients()[i]; - } - - ClpLp::SolveExitStatus ClpLp::_solve() { - return _prob->primal() >= 0 ? SOLVED : UNSOLVED; - } - - ClpLp::SolveExitStatus ClpLp::solvePrimal() { - return _prob->primal() >= 0 ? SOLVED : UNSOLVED; - } - - ClpLp::SolveExitStatus ClpLp::solveDual() { - return _prob->dual() >= 0 ? SOLVED : UNSOLVED; - } - - ClpLp::SolveExitStatus ClpLp::solveBarrier() { - return _prob->barrier() >= 0 ? SOLVED : UNSOLVED; - } - - ClpLp::Value ClpLp::_getPrimal(int i) const { - return _prob->primalColumnSolution()[i]; - } - ClpLp::Value ClpLp::_getPrimalValue() const { - return _prob->objectiveValue(); - } - - ClpLp::Value ClpLp::_getDual(int i) const { - return _prob->dualRowSolution()[i]; - } - - ClpLp::Value ClpLp::_getPrimalRay(int i) const { - if (!_primal_ray) { - _primal_ray = _prob->unboundedRay(); - LEMON_ASSERT(_primal_ray != 0, "Primal ray is not provided"); - } - return _primal_ray[i]; - } - - ClpLp::Value ClpLp::_getDualRay(int i) const { - if (!_dual_ray) { - _dual_ray = _prob->infeasibilityRay(); - LEMON_ASSERT(_dual_ray != 0, "Dual ray is not provided"); - } - return _dual_ray[i]; - } - - ClpLp::VarStatus ClpLp::_getColStatus(int i) const { - switch (_prob->getColumnStatus(i)) { - case ClpSimplex::basic: - return BASIC; - case ClpSimplex::isFree: - return FREE; - case ClpSimplex::atUpperBound: - return UPPER; - case ClpSimplex::atLowerBound: - return LOWER; - case ClpSimplex::isFixed: - return FIXED; - case ClpSimplex::superBasic: - return FREE; - default: - LEMON_ASSERT(false, "Wrong column status"); - return VarStatus(); - } - } - - ClpLp::VarStatus ClpLp::_getRowStatus(int i) const { - switch (_prob->getColumnStatus(i)) { - case ClpSimplex::basic: - return BASIC; - case ClpSimplex::isFree: - return FREE; - case ClpSimplex::atUpperBound: - return UPPER; - case ClpSimplex::atLowerBound: - return LOWER; - case ClpSimplex::isFixed: - return FIXED; - case ClpSimplex::superBasic: - return FREE; - default: - LEMON_ASSERT(false, "Wrong row status"); - return VarStatus(); - } - } - - - ClpLp::ProblemType ClpLp::_getPrimalType() const { - if (_prob->isProvenOptimal()) { - return OPTIMAL; - } else if (_prob->isProvenPrimalInfeasible()) { - return INFEASIBLE; - } else if (_prob->isProvenDualInfeasible()) { - return UNBOUNDED; - } else { - return UNDEFINED; - } - } - - ClpLp::ProblemType ClpLp::_getDualType() const { - if (_prob->isProvenOptimal()) { - return OPTIMAL; - } else if (_prob->isProvenDualInfeasible()) { - return INFEASIBLE; - } else if (_prob->isProvenPrimalInfeasible()) { - return INFEASIBLE; - } else { - return UNDEFINED; - } - } - - void ClpLp::_setSense(ClpLp::Sense sense) { - switch (sense) { - case MIN: - _prob->setOptimizationDirection(1); - break; - case MAX: - _prob->setOptimizationDirection(-1); - break; - } - } - - ClpLp::Sense ClpLp::_getSense() const { - double dir = _prob->optimizationDirection(); - if (dir > 0.0) { - return MIN; - } else { - return MAX; - } - } - - void ClpLp::_clear() { - delete _prob; - _prob = new ClpSimplex(); - _col_names_ref.clear(); - _clear_temporals(); - } - - void ClpLp::_messageLevel(MessageLevel level) { - switch (level) { - case MESSAGE_NOTHING: - _prob->setLogLevel(0); - break; - case MESSAGE_ERROR: - _prob->setLogLevel(1); - break; - case MESSAGE_WARNING: - _prob->setLogLevel(2); - break; - case MESSAGE_NORMAL: - _prob->setLogLevel(3); - break; - case MESSAGE_VERBOSE: - _prob->setLogLevel(4); - break; - } - } - -} //END OF NAMESPACE LEMON diff --git a/deps/lemon/lemon/clp.h b/deps/lemon/lemon/clp.h deleted file mode 100644 index fd331ac13..000000000 --- a/deps/lemon/lemon/clp.h +++ /dev/null @@ -1,164 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_CLP_H -#define LEMON_CLP_H - -///\file -///\brief Header of the LEMON-CLP lp solver interface. - -#include -#include - -#include - -class ClpSimplex; - -namespace lemon { - - /// \ingroup lp_group - /// - /// \brief Interface for the CLP solver - /// - /// This class implements an interface for the Clp LP solver. The - /// Clp library is an object oriented lp solver library developed at - /// the IBM. The CLP is part of the COIN-OR package and it can be - /// used with Common Public License. - class ClpLp : public LpSolver { - protected: - - ClpSimplex* _prob; - - std::map _col_names_ref; - std::map _row_names_ref; - - public: - - /// \e - ClpLp(); - /// \e - ClpLp(const ClpLp&); - /// \e - ~ClpLp(); - - /// \e - virtual ClpLp* newSolver() const; - /// \e - virtual ClpLp* cloneSolver() const; - - protected: - - mutable double* _primal_ray; - mutable double* _dual_ray; - - void _init_temporals(); - void _clear_temporals(); - - protected: - - virtual const char* _solverName() const; - - virtual int _addCol(); - virtual int _addRow(); - virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); - - virtual void _eraseCol(int i); - virtual void _eraseRow(int i); - - virtual void _eraseColId(int i); - virtual void _eraseRowId(int i); - - virtual void _getColName(int col, std::string& name) const; - virtual void _setColName(int col, const std::string& name); - virtual int _colByName(const std::string& name) const; - - virtual void _getRowName(int row, std::string& name) const; - virtual void _setRowName(int row, const std::string& name); - virtual int _rowByName(const std::string& name) const; - - virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); - virtual void _getRowCoeffs(int i, InsertIterator b) const; - - virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); - virtual void _getColCoeffs(int i, InsertIterator b) const; - - virtual void _setCoeff(int row, int col, Value value); - virtual Value _getCoeff(int row, int col) const; - - virtual void _setColLowerBound(int i, Value value); - virtual Value _getColLowerBound(int i) const; - virtual void _setColUpperBound(int i, Value value); - virtual Value _getColUpperBound(int i) const; - - virtual void _setRowLowerBound(int i, Value value); - virtual Value _getRowLowerBound(int i) const; - virtual void _setRowUpperBound(int i, Value value); - virtual Value _getRowUpperBound(int i) const; - - virtual void _setObjCoeffs(ExprIterator, ExprIterator); - virtual void _getObjCoeffs(InsertIterator) const; - - virtual void _setObjCoeff(int i, Value obj_coef); - virtual Value _getObjCoeff(int i) const; - - virtual void _setSense(Sense sense); - virtual Sense _getSense() const; - - virtual SolveExitStatus _solve(); - - virtual Value _getPrimal(int i) const; - virtual Value _getDual(int i) const; - - virtual Value _getPrimalValue() const; - - virtual Value _getPrimalRay(int i) const; - virtual Value _getDualRay(int i) const; - - virtual VarStatus _getColStatus(int i) const; - virtual VarStatus _getRowStatus(int i) const; - - virtual ProblemType _getPrimalType() const; - virtual ProblemType _getDualType() const; - - virtual void _clear(); - - virtual void _messageLevel(MessageLevel); - - public: - - ///Solves LP with primal simplex method. - SolveExitStatus solvePrimal(); - - ///Solves LP with dual simplex method. - SolveExitStatus solveDual(); - - ///Solves LP with barrier method. - SolveExitStatus solveBarrier(); - - ///Returns the constraint identifier understood by CLP. - int clpRow(Row r) const { return rows(id(r)); } - - ///Returns the variable identifier understood by CLP. - int clpCol(Col c) const { return cols(id(c)); } - - }; - -} //END OF NAMESPACE LEMON - -#endif //LEMON_CLP_H - diff --git a/deps/lemon/lemon/color.cc b/deps/lemon/lemon/color.cc deleted file mode 100644 index a49167b5c..000000000 --- a/deps/lemon/lemon/color.cc +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\file -///\brief Color constants - -#include - -namespace lemon { - - const Color WHITE(1,1,1); - - const Color BLACK(0,0,0); - const Color RED(1,0,0); - const Color GREEN(0,1,0); - const Color BLUE(0,0,1); - const Color YELLOW(1,1,0); - const Color MAGENTA(1,0,1); - const Color CYAN(0,1,1); - - const Color GREY(0,0,0); - const Color DARK_RED(.5,0,0); - const Color DARK_GREEN(0,.5,0); - const Color DARK_BLUE(0,0,.5); - const Color DARK_YELLOW(.5,.5,0); - const Color DARK_MAGENTA(.5,0,.5); - const Color DARK_CYAN(0,.5,.5); - -} //namespace lemon diff --git a/deps/lemon/lemon/color.h b/deps/lemon/lemon/color.h deleted file mode 100644 index 02357910f..000000000 --- a/deps/lemon/lemon/color.h +++ /dev/null @@ -1,204 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_COLOR_H -#define LEMON_COLOR_H - -#include -#include -#include - - -///\ingroup misc -///\file -///\brief Tools to manage RGB colors. - -namespace lemon { - - - /// \addtogroup misc - /// @{ - - ///Data structure representing RGB colors. - - ///Data structure representing RGB colors. - class Color - { - double _r,_g,_b; - public: - ///Default constructor - Color() {} - ///Constructor - Color(double r,double g,double b) :_r(r),_g(g),_b(b) {}; - ///Set the red component - double & red() {return _r;} - ///Return the red component - const double & red() const {return _r;} - ///Set the green component - double & green() {return _g;} - ///Return the green component - const double & green() const {return _g;} - ///Set the blue component - double & blue() {return _b;} - ///Return the blue component - const double & blue() const {return _b;} - ///Set the color components - void set(double r,double g,double b) { _r=r;_g=g;_b=b; }; - }; - - /// White color constant - extern const Color WHITE; - /// Black color constant - extern const Color BLACK; - /// Red color constant - extern const Color RED; - /// Green color constant - extern const Color GREEN; - /// Blue color constant - extern const Color BLUE; - /// Yellow color constant - extern const Color YELLOW; - /// Magenta color constant - extern const Color MAGENTA; - /// Cyan color constant - extern const Color CYAN; - /// Grey color constant - extern const Color GREY; - /// Dark red color constant - extern const Color DARK_RED; - /// Dark green color constant - extern const Color DARK_GREEN; - /// Drak blue color constant - extern const Color DARK_BLUE; - /// Dark yellow color constant - extern const Color DARK_YELLOW; - /// Dark magenta color constant - extern const Color DARK_MAGENTA; - /// Dark cyan color constant - extern const Color DARK_CYAN; - - ///Map ints to different Colors - - ///This map assigns one of the predefined \ref Color "Color"s to - ///each int. It is possible to change the colors as well as - ///their number. The integer range is cyclically mapped to the - ///provided set of colors. - /// - ///This is a true \ref concepts::ReferenceMap "reference map", so - ///you can also change the actual colors. - - class Palette : public MapBase - { - std::vector colors; - public: - ///Constructor - - ///Constructor. - ///\param have_white Indicates whether white is among the - ///provided initial colors (\c true) or not (\c false). If it is true, - ///white will be assigned to \c 0. - ///\param num The number of the allocated colors. If it is \c -1, - ///the default color configuration is set up (26 color plus optionaly the - ///white). If \c num is less then 26/27 then the default color - ///list is cut. Otherwise the color list is filled repeatedly with - ///the default color list. (The colors can be changed later on.) - Palette(bool have_white=false,int num=-1) - { - if (num==0) return; - do { - if(have_white) colors.push_back(Color(1,1,1)); - - colors.push_back(Color(0,0,0)); - colors.push_back(Color(1,0,0)); - colors.push_back(Color(0,1,0)); - colors.push_back(Color(0,0,1)); - colors.push_back(Color(1,1,0)); - colors.push_back(Color(1,0,1)); - colors.push_back(Color(0,1,1)); - - colors.push_back(Color(.5,0,0)); - colors.push_back(Color(0,.5,0)); - colors.push_back(Color(0,0,.5)); - colors.push_back(Color(.5,.5,0)); - colors.push_back(Color(.5,0,.5)); - colors.push_back(Color(0,.5,.5)); - - colors.push_back(Color(.5,.5,.5)); - colors.push_back(Color(1,.5,.5)); - colors.push_back(Color(.5,1,.5)); - colors.push_back(Color(.5,.5,1)); - colors.push_back(Color(1,1,.5)); - colors.push_back(Color(1,.5,1)); - colors.push_back(Color(.5,1,1)); - - colors.push_back(Color(1,.5,0)); - colors.push_back(Color(.5,1,0)); - colors.push_back(Color(1,0,.5)); - colors.push_back(Color(0,1,.5)); - colors.push_back(Color(0,.5,1)); - colors.push_back(Color(.5,0,1)); - } while(int(colors.size())=0) colors.resize(num); - } - ///\e - Color &operator[](int i) - { - return colors[i%colors.size()]; - } - ///\e - const Color &operator[](int i) const - { - return colors[i%colors.size()]; - } - ///\e - void set(int i,const Color &c) - { - colors[i%colors.size()]=c; - } - ///Adds a new color to the end of the color list. - void add(const Color &c) - { - colors.push_back(c); - } - - ///Sets the number of the existing colors. - void resize(int s) { colors.resize(s);} - ///Returns the number of the existing colors. - int size() const { return int(colors.size());} - }; - - ///Returns a visibly distinct \ref Color - - ///Returns a \ref Color which is as different from the given parameter - ///as it is possible. - inline Color distantColor(const Color &c) - { - return Color(c.red()<.5?1:0,c.green()<.5?1:0,c.blue()<.5?1:0); - } - ///Returns black for light colors and white for the dark ones. - - ///Returns black for light colors and white for the dark ones. - inline Color distantBW(const Color &c){ - return (.2125*c.red()+.7154*c.green()+.0721*c.blue())<.5 ? WHITE : BLACK; - } - - /// @} - -} //END OF NAMESPACE LEMON - -#endif // LEMON_COLOR_H diff --git a/deps/lemon/lemon/concept_check.h b/deps/lemon/lemon/concept_check.h deleted file mode 100644 index 38355b0f2..000000000 --- a/deps/lemon/lemon/concept_check.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -// The contents of this file was inspired by the concept checking -// utility of the BOOST library (http://www.boost.org). - -///\file -///\brief Basic utilities for concept checking. -/// - -#ifndef LEMON_CONCEPT_CHECK_H -#define LEMON_CONCEPT_CHECK_H - -namespace lemon { - - /* - "inline" is used for ignore_unused_variable_warning() - and function_requires() to make sure there is no - overtarget with g++. - */ - - template inline void ignore_unused_variable_warning(const T&) { } - template - inline void ignore_unused_variable_warning(const T1&, const T2&) { } - template - inline void ignore_unused_variable_warning(const T1&, const T2&, - const T3&) { } - template - inline void ignore_unused_variable_warning(const T1&, const T2&, - const T3&, const T4&) { } - template - inline void ignore_unused_variable_warning(const T1&, const T2&, - const T3&, const T4&, - const T5&) { } - template - inline void ignore_unused_variable_warning(const T1&, const T2&, - const T3&, const T4&, - const T5&, const T6&) { } - - ///\e - template - inline void function_requires() - { -#if !defined(NDEBUG) - void (Concept::*x)() = & Concept::constraints; - ::lemon::ignore_unused_variable_warning(x); -#endif - } - - ///\e - template - inline void checkConcept() { -#if !defined(NDEBUG) - typedef typename Concept::template Constraints ConceptCheck; - void (ConceptCheck::*x)() = & ConceptCheck::constraints; - ::lemon::ignore_unused_variable_warning(x); -#endif - } - -} // namespace lemon - -#endif // LEMON_CONCEPT_CHECK_H diff --git a/deps/lemon/lemon/concepts/bpgraph.h b/deps/lemon/lemon/concepts/bpgraph.h deleted file mode 100644 index 2ebdeaf8b..000000000 --- a/deps/lemon/lemon/concepts/bpgraph.h +++ /dev/null @@ -1,1029 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\ingroup graph_concepts -///\file -///\brief The concept of undirected graphs. - -#ifndef LEMON_CONCEPTS_BPGRAPH_H -#define LEMON_CONCEPTS_BPGRAPH_H - -#include -#include -#include -#include - -namespace lemon { - namespace concepts { - - /// \ingroup graph_concepts - /// - /// \brief Class describing the concept of undirected bipartite graphs. - /// - /// This class describes the common interface of all undirected - /// bipartite graphs. - /// - /// Like all concept classes, it only provides an interface - /// without any sensible implementation. So any general algorithm for - /// undirected bipartite graphs should compile with this class, - /// but it will not run properly, of course. - /// An actual graph implementation like \ref ListBpGraph or - /// \ref SmartBpGraph may have additional functionality. - /// - /// The bipartite graphs also fulfill the concept of \ref Graph - /// "undirected graphs". Bipartite graphs provide a bipartition of - /// the node set, namely a red and blue set of the nodes. The - /// nodes can be iterated with the RedNodeIt and BlueNodeIt in the - /// two node sets. With RedNodeMap and BlueNodeMap values can be - /// assigned to the nodes in the two sets. - /// - /// The edges of the graph cannot connect two nodes of the same - /// set. The edges inherent orientation is from the red nodes to - /// the blue nodes. - /// - /// \sa Graph - class BpGraph { - private: - /// BpGraphs are \e not copy constructible. Use bpGraphCopy instead. - BpGraph(const BpGraph&) {} - /// \brief Assignment of a graph to another one is \e not allowed. - /// Use bpGraphCopy instead. - void operator=(const BpGraph&) {} - - public: - /// Default constructor. - BpGraph() {} - - /// \brief Undirected graphs should be tagged with \c UndirectedTag. - /// - /// Undirected graphs should be tagged with \c UndirectedTag. - /// - /// This tag helps the \c enable_if technics to make compile time - /// specializations for undirected graphs. - typedef True UndirectedTag; - - /// The node type of the graph - - /// This class identifies a node of the graph. It also serves - /// as a base class of the node iterators, - /// thus they convert to this type. - class Node { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the object to an undefined value. - Node() { } - /// Copy constructor. - - /// Copy constructor. - /// - Node(const Node&) { } - - /// %Invalid constructor \& conversion. - - /// Initializes the object to be invalid. - /// \sa Invalid for more details. - Node(Invalid) { } - /// Equality operator - - /// Equality operator. - /// - /// Two iterators are equal if and only if they point to the - /// same object or both are \c INVALID. - bool operator==(Node) const { return true; } - - /// Inequality operator - - /// Inequality operator. - bool operator!=(Node) const { return true; } - - /// Artificial ordering operator. - - /// Artificial ordering operator. - /// - /// \note This operator only has to define some strict ordering of - /// the items; this order has nothing to do with the iteration - /// ordering of the items. - bool operator<(Node) const { return false; } - - }; - - /// Class to represent red nodes. - - /// This class represents the red nodes of the graph. It does - /// not supposed to be used directly, because the nodes can be - /// represented as Node instances. This class can be used as - /// template parameter for special map classes. - class RedNode : public Node { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the object to an undefined value. - RedNode() { } - /// Copy constructor. - - /// Copy constructor. - /// - RedNode(const RedNode&) : Node() { } - - /// %Invalid constructor \& conversion. - - /// Initializes the object to be invalid. - /// \sa Invalid for more details. - RedNode(Invalid) { } - - }; - - /// Class to represent blue nodes. - - /// This class represents the blue nodes of the graph. It does - /// not supposed to be used directly, because the nodes can be - /// represented as Node instances. This class can be used as - /// template parameter for special map classes. - class BlueNode : public Node { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the object to an undefined value. - BlueNode() { } - /// Copy constructor. - - /// Copy constructor. - /// - BlueNode(const BlueNode&) : Node() { } - - /// %Invalid constructor \& conversion. - - /// Initializes the object to be invalid. - /// \sa Invalid for more details. - BlueNode(Invalid) { } - - }; - - /// Iterator class for the red nodes. - - /// This iterator goes through each red node of the graph. - /// Its usage is quite simple, for example, you can count the number - /// of red nodes in a graph \c g of type \c %BpGraph like this: - ///\code - /// int count=0; - /// for (BpGraph::RedNodeIt n(g); n!=INVALID; ++n) ++count; - ///\endcode - class RedNodeIt : public RedNode { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - RedNodeIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - RedNodeIt(const RedNodeIt& n) : RedNode(n) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - RedNodeIt(Invalid) { } - /// Sets the iterator to the first red node. - - /// Sets the iterator to the first red node of the given - /// digraph. - explicit RedNodeIt(const BpGraph&) { } - /// Sets the iterator to the given red node. - - /// Sets the iterator to the given red node of the given - /// digraph. - RedNodeIt(const BpGraph&, const RedNode&) { } - /// Next node. - - /// Assign the iterator to the next red node. - /// - RedNodeIt& operator++() { return *this; } - }; - - /// Iterator class for the blue nodes. - - /// This iterator goes through each blue node of the graph. - /// Its usage is quite simple, for example, you can count the number - /// of blue nodes in a graph \c g of type \c %BpGraph like this: - ///\code - /// int count=0; - /// for (BpGraph::BlueNodeIt n(g); n!=INVALID; ++n) ++count; - ///\endcode - class BlueNodeIt : public BlueNode { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - BlueNodeIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - BlueNodeIt(const BlueNodeIt& n) : BlueNode(n) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - BlueNodeIt(Invalid) { } - /// Sets the iterator to the first blue node. - - /// Sets the iterator to the first blue node of the given - /// digraph. - explicit BlueNodeIt(const BpGraph&) { } - /// Sets the iterator to the given blue node. - - /// Sets the iterator to the given blue node of the given - /// digraph. - BlueNodeIt(const BpGraph&, const BlueNode&) { } - /// Next node. - - /// Assign the iterator to the next blue node. - /// - BlueNodeIt& operator++() { return *this; } - }; - - /// Iterator class for the nodes. - - /// This iterator goes through each node of the graph. - /// Its usage is quite simple, for example, you can count the number - /// of nodes in a graph \c g of type \c %BpGraph like this: - ///\code - /// int count=0; - /// for (BpGraph::NodeIt n(g); n!=INVALID; ++n) ++count; - ///\endcode - class NodeIt : public Node { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - NodeIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - NodeIt(const NodeIt& n) : Node(n) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - NodeIt(Invalid) { } - /// Sets the iterator to the first node. - - /// Sets the iterator to the first node of the given digraph. - /// - explicit NodeIt(const BpGraph&) { } - /// Sets the iterator to the given node. - - /// Sets the iterator to the given node of the given digraph. - /// - NodeIt(const BpGraph&, const Node&) { } - /// Next node. - - /// Assign the iterator to the next node. - /// - NodeIt& operator++() { return *this; } - }; - - - /// The edge type of the graph - - /// This class identifies an edge of the graph. It also serves - /// as a base class of the edge iterators, - /// thus they will convert to this type. - class Edge { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the object to an undefined value. - Edge() { } - /// Copy constructor. - - /// Copy constructor. - /// - Edge(const Edge&) { } - /// %Invalid constructor \& conversion. - - /// Initializes the object to be invalid. - /// \sa Invalid for more details. - Edge(Invalid) { } - /// Equality operator - - /// Equality operator. - /// - /// Two iterators are equal if and only if they point to the - /// same object or both are \c INVALID. - bool operator==(Edge) const { return true; } - /// Inequality operator - - /// Inequality operator. - bool operator!=(Edge) const { return true; } - - /// Artificial ordering operator. - - /// Artificial ordering operator. - /// - /// \note This operator only has to define some strict ordering of - /// the edges; this order has nothing to do with the iteration - /// ordering of the edges. - bool operator<(Edge) const { return false; } - }; - - /// Iterator class for the edges. - - /// This iterator goes through each edge of the graph. - /// Its usage is quite simple, for example, you can count the number - /// of edges in a graph \c g of type \c %BpGraph as follows: - ///\code - /// int count=0; - /// for(BpGraph::EdgeIt e(g); e!=INVALID; ++e) ++count; - ///\endcode - class EdgeIt : public Edge { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - EdgeIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - EdgeIt(const EdgeIt& e) : Edge(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - EdgeIt(Invalid) { } - /// Sets the iterator to the first edge. - - /// Sets the iterator to the first edge of the given graph. - /// - explicit EdgeIt(const BpGraph&) { } - /// Sets the iterator to the given edge. - - /// Sets the iterator to the given edge of the given graph. - /// - EdgeIt(const BpGraph&, const Edge&) { } - /// Next edge - - /// Assign the iterator to the next edge. - /// - EdgeIt& operator++() { return *this; } - }; - - /// Iterator class for the incident edges of a node. - - /// This iterator goes trough the incident undirected edges - /// of a certain node of a graph. - /// Its usage is quite simple, for example, you can compute the - /// degree (i.e. the number of incident edges) of a node \c n - /// in a graph \c g of type \c %BpGraph as follows. - /// - ///\code - /// int count=0; - /// for(BpGraph::IncEdgeIt e(g, n); e!=INVALID; ++e) ++count; - ///\endcode - /// - /// \warning Loop edges will be iterated twice. - class IncEdgeIt : public Edge { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - IncEdgeIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - IncEdgeIt(const IncEdgeIt& e) : Edge(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - IncEdgeIt(Invalid) { } - /// Sets the iterator to the first incident edge. - - /// Sets the iterator to the first incident edge of the given node. - /// - IncEdgeIt(const BpGraph&, const Node&) { } - /// Sets the iterator to the given edge. - - /// Sets the iterator to the given edge of the given graph. - /// - IncEdgeIt(const BpGraph&, const Edge&) { } - /// Next incident edge - - /// Assign the iterator to the next incident edge - /// of the corresponding node. - IncEdgeIt& operator++() { return *this; } - }; - - /// The arc type of the graph - - /// This class identifies a directed arc of the graph. It also serves - /// as a base class of the arc iterators, - /// thus they will convert to this type. - class Arc { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the object to an undefined value. - Arc() { } - /// Copy constructor. - - /// Copy constructor. - /// - Arc(const Arc&) { } - /// %Invalid constructor \& conversion. - - /// Initializes the object to be invalid. - /// \sa Invalid for more details. - Arc(Invalid) { } - /// Equality operator - - /// Equality operator. - /// - /// Two iterators are equal if and only if they point to the - /// same object or both are \c INVALID. - bool operator==(Arc) const { return true; } - /// Inequality operator - - /// Inequality operator. - bool operator!=(Arc) const { return true; } - - /// Artificial ordering operator. - - /// Artificial ordering operator. - /// - /// \note This operator only has to define some strict ordering of - /// the arcs; this order has nothing to do with the iteration - /// ordering of the arcs. - bool operator<(Arc) const { return false; } - - /// Converison to \c Edge - - /// Converison to \c Edge. - /// - operator Edge() const { return Edge(); } - }; - - /// Iterator class for the arcs. - - /// This iterator goes through each directed arc of the graph. - /// Its usage is quite simple, for example, you can count the number - /// of arcs in a graph \c g of type \c %BpGraph as follows: - ///\code - /// int count=0; - /// for(BpGraph::ArcIt a(g); a!=INVALID; ++a) ++count; - ///\endcode - class ArcIt : public Arc { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - ArcIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - ArcIt(const ArcIt& e) : Arc(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - ArcIt(Invalid) { } - /// Sets the iterator to the first arc. - - /// Sets the iterator to the first arc of the given graph. - /// - explicit ArcIt(const BpGraph &g) - { - ::lemon::ignore_unused_variable_warning(g); - } - /// Sets the iterator to the given arc. - - /// Sets the iterator to the given arc of the given graph. - /// - ArcIt(const BpGraph&, const Arc&) { } - /// Next arc - - /// Assign the iterator to the next arc. - /// - ArcIt& operator++() { return *this; } - }; - - /// Iterator class for the outgoing arcs of a node. - - /// This iterator goes trough the \e outgoing directed arcs of a - /// certain node of a graph. - /// Its usage is quite simple, for example, you can count the number - /// of outgoing arcs of a node \c n - /// in a graph \c g of type \c %BpGraph as follows. - ///\code - /// int count=0; - /// for (Digraph::OutArcIt a(g, n); a!=INVALID; ++a) ++count; - ///\endcode - class OutArcIt : public Arc { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - OutArcIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - OutArcIt(const OutArcIt& e) : Arc(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - OutArcIt(Invalid) { } - /// Sets the iterator to the first outgoing arc. - - /// Sets the iterator to the first outgoing arc of the given node. - /// - OutArcIt(const BpGraph& n, const Node& g) { - ::lemon::ignore_unused_variable_warning(n); - ::lemon::ignore_unused_variable_warning(g); - } - /// Sets the iterator to the given arc. - - /// Sets the iterator to the given arc of the given graph. - /// - OutArcIt(const BpGraph&, const Arc&) { } - /// Next outgoing arc - - /// Assign the iterator to the next - /// outgoing arc of the corresponding node. - OutArcIt& operator++() { return *this; } - }; - - /// Iterator class for the incoming arcs of a node. - - /// This iterator goes trough the \e incoming directed arcs of a - /// certain node of a graph. - /// Its usage is quite simple, for example, you can count the number - /// of incoming arcs of a node \c n - /// in a graph \c g of type \c %BpGraph as follows. - ///\code - /// int count=0; - /// for (Digraph::InArcIt a(g, n); a!=INVALID; ++a) ++count; - ///\endcode - class InArcIt : public Arc { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - InArcIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - InArcIt(const InArcIt& e) : Arc(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - InArcIt(Invalid) { } - /// Sets the iterator to the first incoming arc. - - /// Sets the iterator to the first incoming arc of the given node. - /// - InArcIt(const BpGraph& g, const Node& n) { - ::lemon::ignore_unused_variable_warning(n); - ::lemon::ignore_unused_variable_warning(g); - } - /// Sets the iterator to the given arc. - - /// Sets the iterator to the given arc of the given graph. - /// - InArcIt(const BpGraph&, const Arc&) { } - /// Next incoming arc - - /// Assign the iterator to the next - /// incoming arc of the corresponding node. - InArcIt& operator++() { return *this; } - }; - - /// \brief Standard graph map type for the nodes. - /// - /// Standard graph map type for the nodes. - /// It conforms to the ReferenceMap concept. - template - class NodeMap : public ReferenceMap - { - public: - - /// Constructor - explicit NodeMap(const BpGraph&) { } - /// Constructor with given initial value - NodeMap(const BpGraph&, T) { } - - private: - ///Copy constructor - NodeMap(const NodeMap& nm) : - ReferenceMap(nm) { } - ///Assignment operator - template - NodeMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - }; - - /// \brief Standard graph map type for the red nodes. - /// - /// Standard graph map type for the red nodes. - /// It conforms to the ReferenceMap concept. - template - class RedNodeMap : public ReferenceMap - { - public: - - /// Constructor - explicit RedNodeMap(const BpGraph&) { } - /// Constructor with given initial value - RedNodeMap(const BpGraph&, T) { } - - private: - ///Copy constructor - RedNodeMap(const RedNodeMap& nm) : - ReferenceMap(nm) { } - ///Assignment operator - template - RedNodeMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - }; - - /// \brief Standard graph map type for the blue nodes. - /// - /// Standard graph map type for the blue nodes. - /// It conforms to the ReferenceMap concept. - template - class BlueNodeMap : public ReferenceMap - { - public: - - /// Constructor - explicit BlueNodeMap(const BpGraph&) { } - /// Constructor with given initial value - BlueNodeMap(const BpGraph&, T) { } - - private: - ///Copy constructor - BlueNodeMap(const BlueNodeMap& nm) : - ReferenceMap(nm) { } - ///Assignment operator - template - BlueNodeMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - }; - - /// \brief Standard graph map type for the arcs. - /// - /// Standard graph map type for the arcs. - /// It conforms to the ReferenceMap concept. - template - class ArcMap : public ReferenceMap - { - public: - - /// Constructor - explicit ArcMap(const BpGraph&) { } - /// Constructor with given initial value - ArcMap(const BpGraph&, T) { } - - private: - ///Copy constructor - ArcMap(const ArcMap& em) : - ReferenceMap(em) { } - ///Assignment operator - template - ArcMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - }; - - /// \brief Standard graph map type for the edges. - /// - /// Standard graph map type for the edges. - /// It conforms to the ReferenceMap concept. - template - class EdgeMap : public ReferenceMap - { - public: - - /// Constructor - explicit EdgeMap(const BpGraph&) { } - /// Constructor with given initial value - EdgeMap(const BpGraph&, T) { } - - private: - ///Copy constructor - EdgeMap(const EdgeMap& em) : - ReferenceMap(em) {} - ///Assignment operator - template - EdgeMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - }; - - /// \brief Gives back %true for red nodes. - /// - /// Gives back %true for red nodes. - bool red(const Node&) const { return true; } - - /// \brief Gives back %true for blue nodes. - /// - /// Gives back %true for blue nodes. - bool blue(const Node&) const { return true; } - - /// \brief Converts the node to red node object. - /// - /// This function converts unsafely the node to red node - /// object. It should be called only if the node is from the red - /// partition or INVALID. - RedNode asRedNodeUnsafe(const Node&) const { return RedNode(); } - - /// \brief Converts the node to blue node object. - /// - /// This function converts unsafely the node to blue node - /// object. It should be called only if the node is from the red - /// partition or INVALID. - BlueNode asBlueNodeUnsafe(const Node&) const { return BlueNode(); } - - /// \brief Converts the node to red node object. - /// - /// This function converts safely the node to red node - /// object. If the node is not from the red partition, then it - /// returns INVALID. - RedNode asRedNode(const Node&) const { return RedNode(); } - - /// \brief Converts the node to blue node object. - /// - /// This function converts unsafely the node to blue node - /// object. If the node is not from the blue partition, then it - /// returns INVALID. - BlueNode asBlueNode(const Node&) const { return BlueNode(); } - - /// \brief Gives back the red end node of the edge. - /// - /// Gives back the red end node of the edge. - RedNode redNode(const Edge&) const { return RedNode(); } - - /// \brief Gives back the blue end node of the edge. - /// - /// Gives back the blue end node of the edge. - BlueNode blueNode(const Edge&) const { return BlueNode(); } - - /// \brief The first node of the edge. - /// - /// It is a synonim for the \c redNode(). - Node u(Edge) const { return INVALID; } - - /// \brief The second node of the edge. - /// - /// It is a synonim for the \c blueNode(). - Node v(Edge) const { return INVALID; } - - /// \brief The source node of the arc. - /// - /// Returns the source node of the given arc. - Node source(Arc) const { return INVALID; } - - /// \brief The target node of the arc. - /// - /// Returns the target node of the given arc. - Node target(Arc) const { return INVALID; } - - /// \brief The ID of the node. - /// - /// Returns the ID of the given node. - int id(Node) const { return -1; } - - /// \brief The red ID of the node. - /// - /// Returns the red ID of the given node. - int id(RedNode) const { return -1; } - - /// \brief The blue ID of the node. - /// - /// Returns the blue ID of the given node. - int id(BlueNode) const { return -1; } - - /// \brief The ID of the edge. - /// - /// Returns the ID of the given edge. - int id(Edge) const { return -1; } - - /// \brief The ID of the arc. - /// - /// Returns the ID of the given arc. - int id(Arc) const { return -1; } - - /// \brief The node with the given ID. - /// - /// Returns the node with the given ID. - /// \pre The argument should be a valid node ID in the graph. - Node nodeFromId(int) const { return INVALID; } - - /// \brief The edge with the given ID. - /// - /// Returns the edge with the given ID. - /// \pre The argument should be a valid edge ID in the graph. - Edge edgeFromId(int) const { return INVALID; } - - /// \brief The arc with the given ID. - /// - /// Returns the arc with the given ID. - /// \pre The argument should be a valid arc ID in the graph. - Arc arcFromId(int) const { return INVALID; } - - /// \brief An upper bound on the node IDs. - /// - /// Returns an upper bound on the node IDs. - int maxNodeId() const { return -1; } - - /// \brief An upper bound on the red IDs. - /// - /// Returns an upper bound on the red IDs. - int maxRedId() const { return -1; } - - /// \brief An upper bound on the blue IDs. - /// - /// Returns an upper bound on the blue IDs. - int maxBlueId() const { return -1; } - - /// \brief An upper bound on the edge IDs. - /// - /// Returns an upper bound on the edge IDs. - int maxEdgeId() const { return -1; } - - /// \brief An upper bound on the arc IDs. - /// - /// Returns an upper bound on the arc IDs. - int maxArcId() const { return -1; } - - /// \brief The direction of the arc. - /// - /// Returns \c true if the given arc goes from a red node to a blue node. - bool direction(Arc) const { return true; } - - /// \brief Direct the edge. - /// - /// Direct the given edge. The returned arc - /// represents the given edge and its direction comes - /// from the bool parameter. If it is \c true, then the source of the node - /// will be a red node. - Arc direct(Edge, bool) const { - return INVALID; - } - - /// \brief Direct the edge. - /// - /// Direct the given edge. The returned arc represents the given - /// edge and its source node is the given node. - Arc direct(Edge, Node) const { - return INVALID; - } - - /// \brief The oppositely directed arc. - /// - /// Returns the oppositely directed arc representing the same edge. - Arc oppositeArc(Arc) const { return INVALID; } - - /// \brief The opposite node on the edge. - /// - /// Returns the opposite node on the given edge. - Node oppositeNode(Node, Edge) const { return INVALID; } - - void first(Node&) const {} - void next(Node&) const {} - - void firstRed(RedNode&) const {} - void nextRed(RedNode&) const {} - - void firstBlue(BlueNode&) const {} - void nextBlue(BlueNode&) const {} - - void first(Edge&) const {} - void next(Edge&) const {} - - void first(Arc&) const {} - void next(Arc&) const {} - - void firstOut(Arc&, Node) const {} - void nextOut(Arc&) const {} - - void firstIn(Arc&, Node) const {} - void nextIn(Arc&) const {} - - void firstInc(Edge &, bool &, const Node &) const {} - void nextInc(Edge &, bool &) const {} - - // The second parameter is dummy. - Node fromId(int, Node) const { return INVALID; } - // The second parameter is dummy. - Edge fromId(int, Edge) const { return INVALID; } - // The second parameter is dummy. - Arc fromId(int, Arc) const { return INVALID; } - - // Dummy parameter. - int maxId(Node) const { return -1; } - // Dummy parameter. - int maxId(RedNode) const { return -1; } - // Dummy parameter. - int maxId(BlueNode) const { return -1; } - // Dummy parameter. - int maxId(Edge) const { return -1; } - // Dummy parameter. - int maxId(Arc) const { return -1; } - - /// \brief The base node of the iterator. - /// - /// Returns the base node of the given incident edge iterator. - Node baseNode(IncEdgeIt) const { return INVALID; } - - /// \brief The running node of the iterator. - /// - /// Returns the running node of the given incident edge iterator. - Node runningNode(IncEdgeIt) const { return INVALID; } - - /// \brief The base node of the iterator. - /// - /// Returns the base node of the given outgoing arc iterator - /// (i.e. the source node of the corresponding arc). - Node baseNode(OutArcIt) const { return INVALID; } - - /// \brief The running node of the iterator. - /// - /// Returns the running node of the given outgoing arc iterator - /// (i.e. the target node of the corresponding arc). - Node runningNode(OutArcIt) const { return INVALID; } - - /// \brief The base node of the iterator. - /// - /// Returns the base node of the given incoming arc iterator - /// (i.e. the target node of the corresponding arc). - Node baseNode(InArcIt) const { return INVALID; } - - /// \brief The running node of the iterator. - /// - /// Returns the running node of the given incoming arc iterator - /// (i.e. the source node of the corresponding arc). - Node runningNode(InArcIt) const { return INVALID; } - - template - struct Constraints { - void constraints() { - checkConcept(); - checkConcept, _BpGraph>(); - checkConcept, _BpGraph>(); - checkConcept, _BpGraph>(); - } - }; - - }; - - } - -} - -#endif diff --git a/deps/lemon/lemon/concepts/digraph.h b/deps/lemon/lemon/concepts/digraph.h deleted file mode 100644 index dc3c36bbb..000000000 --- a/deps/lemon/lemon/concepts/digraph.h +++ /dev/null @@ -1,491 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_CONCEPTS_DIGRAPH_H -#define LEMON_CONCEPTS_DIGRAPH_H - -///\ingroup graph_concepts -///\file -///\brief The concept of directed graphs. - -#include -#include -#include -#include - -namespace lemon { - namespace concepts { - - /// \ingroup graph_concepts - /// - /// \brief Class describing the concept of directed graphs. - /// - /// This class describes the common interface of all directed - /// graphs (digraphs). - /// - /// Like all concept classes, it only provides an interface - /// without any sensible implementation. So any general algorithm for - /// directed graphs should compile with this class, but it will not - /// run properly, of course. - /// An actual digraph implementation like \ref ListDigraph or - /// \ref SmartDigraph may have additional functionality. - /// - /// \sa Graph - class Digraph { - private: - /// Diraphs are \e not copy constructible. Use DigraphCopy instead. - Digraph(const Digraph &) {} - /// \brief Assignment of a digraph to another one is \e not allowed. - /// Use DigraphCopy instead. - void operator=(const Digraph &) {} - - public: - /// Default constructor. - Digraph() { } - - /// The node type of the digraph - - /// This class identifies a node of the digraph. It also serves - /// as a base class of the node iterators, - /// thus they convert to this type. - class Node { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the object to an undefined value. - Node() { } - /// Copy constructor. - - /// Copy constructor. - /// - Node(const Node&) { } - - /// %Invalid constructor \& conversion. - - /// Initializes the object to be invalid. - /// \sa Invalid for more details. - Node(Invalid) { } - /// Equality operator - - /// Equality operator. - /// - /// Two iterators are equal if and only if they point to the - /// same object or both are \c INVALID. - bool operator==(Node) const { return true; } - - /// Inequality operator - - /// Inequality operator. - bool operator!=(Node) const { return true; } - - /// Artificial ordering operator. - - /// Artificial ordering operator. - /// - /// \note This operator only has to define some strict ordering of - /// the nodes; this order has nothing to do with the iteration - /// ordering of the nodes. - bool operator<(Node) const { return false; } - }; - - /// Iterator class for the nodes. - - /// This iterator goes through each node of the digraph. - /// Its usage is quite simple, for example, you can count the number - /// of nodes in a digraph \c g of type \c %Digraph like this: - ///\code - /// int count=0; - /// for (Digraph::NodeIt n(g); n!=INVALID; ++n) ++count; - ///\endcode - class NodeIt : public Node { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - NodeIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - NodeIt(const NodeIt& n) : Node(n) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - NodeIt(Invalid) { } - /// Sets the iterator to the first node. - - /// Sets the iterator to the first node of the given digraph. - /// - explicit NodeIt(const Digraph&) { } - /// Sets the iterator to the given node. - - /// Sets the iterator to the given node of the given digraph. - /// - NodeIt(const Digraph&, const Node&) { } - /// Next node. - - /// Assign the iterator to the next node. - /// - NodeIt& operator++() { return *this; } - }; - - - /// The arc type of the digraph - - /// This class identifies an arc of the digraph. It also serves - /// as a base class of the arc iterators, - /// thus they will convert to this type. - class Arc { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the object to an undefined value. - Arc() { } - /// Copy constructor. - - /// Copy constructor. - /// - Arc(const Arc&) { } - /// %Invalid constructor \& conversion. - - /// Initializes the object to be invalid. - /// \sa Invalid for more details. - Arc(Invalid) { } - /// Equality operator - - /// Equality operator. - /// - /// Two iterators are equal if and only if they point to the - /// same object or both are \c INVALID. - bool operator==(Arc) const { return true; } - /// Inequality operator - - /// Inequality operator. - bool operator!=(Arc) const { return true; } - - /// Artificial ordering operator. - - /// Artificial ordering operator. - /// - /// \note This operator only has to define some strict ordering of - /// the arcs; this order has nothing to do with the iteration - /// ordering of the arcs. - bool operator<(Arc) const { return false; } - }; - - /// Iterator class for the outgoing arcs of a node. - - /// This iterator goes trough the \e outgoing arcs of a certain node - /// of a digraph. - /// Its usage is quite simple, for example, you can count the number - /// of outgoing arcs of a node \c n - /// in a digraph \c g of type \c %Digraph as follows. - ///\code - /// int count=0; - /// for (Digraph::OutArcIt a(g, n); a!=INVALID; ++a) ++count; - ///\endcode - class OutArcIt : public Arc { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - OutArcIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - OutArcIt(const OutArcIt& e) : Arc(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - OutArcIt(Invalid) { } - /// Sets the iterator to the first outgoing arc. - - /// Sets the iterator to the first outgoing arc of the given node. - /// - OutArcIt(const Digraph&, const Node&) { } - /// Sets the iterator to the given arc. - - /// Sets the iterator to the given arc of the given digraph. - /// - OutArcIt(const Digraph&, const Arc&) { } - /// Next outgoing arc - - /// Assign the iterator to the next - /// outgoing arc of the corresponding node. - OutArcIt& operator++() { return *this; } - }; - - /// Iterator class for the incoming arcs of a node. - - /// This iterator goes trough the \e incoming arcs of a certain node - /// of a digraph. - /// Its usage is quite simple, for example, you can count the number - /// of incoming arcs of a node \c n - /// in a digraph \c g of type \c %Digraph as follows. - ///\code - /// int count=0; - /// for(Digraph::InArcIt a(g, n); a!=INVALID; ++a) ++count; - ///\endcode - class InArcIt : public Arc { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - InArcIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - InArcIt(const InArcIt& e) : Arc(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - InArcIt(Invalid) { } - /// Sets the iterator to the first incoming arc. - - /// Sets the iterator to the first incoming arc of the given node. - /// - InArcIt(const Digraph&, const Node&) { } - /// Sets the iterator to the given arc. - - /// Sets the iterator to the given arc of the given digraph. - /// - InArcIt(const Digraph&, const Arc&) { } - /// Next incoming arc - - /// Assign the iterator to the next - /// incoming arc of the corresponding node. - InArcIt& operator++() { return *this; } - }; - - /// Iterator class for the arcs. - - /// This iterator goes through each arc of the digraph. - /// Its usage is quite simple, for example, you can count the number - /// of arcs in a digraph \c g of type \c %Digraph as follows: - ///\code - /// int count=0; - /// for(Digraph::ArcIt a(g); a!=INVALID; ++a) ++count; - ///\endcode - class ArcIt : public Arc { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - ArcIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - ArcIt(const ArcIt& e) : Arc(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - ArcIt(Invalid) { } - /// Sets the iterator to the first arc. - - /// Sets the iterator to the first arc of the given digraph. - /// - explicit ArcIt(const Digraph& g) { - ::lemon::ignore_unused_variable_warning(g); - } - /// Sets the iterator to the given arc. - - /// Sets the iterator to the given arc of the given digraph. - /// - ArcIt(const Digraph&, const Arc&) { } - /// Next arc - - /// Assign the iterator to the next arc. - /// - ArcIt& operator++() { return *this; } - }; - - /// \brief The source node of the arc. - /// - /// Returns the source node of the given arc. - Node source(Arc) const { return INVALID; } - - /// \brief The target node of the arc. - /// - /// Returns the target node of the given arc. - Node target(Arc) const { return INVALID; } - - /// \brief The ID of the node. - /// - /// Returns the ID of the given node. - int id(Node) const { return -1; } - - /// \brief The ID of the arc. - /// - /// Returns the ID of the given arc. - int id(Arc) const { return -1; } - - /// \brief The node with the given ID. - /// - /// Returns the node with the given ID. - /// \pre The argument should be a valid node ID in the digraph. - Node nodeFromId(int) const { return INVALID; } - - /// \brief The arc with the given ID. - /// - /// Returns the arc with the given ID. - /// \pre The argument should be a valid arc ID in the digraph. - Arc arcFromId(int) const { return INVALID; } - - /// \brief An upper bound on the node IDs. - /// - /// Returns an upper bound on the node IDs. - int maxNodeId() const { return -1; } - - /// \brief An upper bound on the arc IDs. - /// - /// Returns an upper bound on the arc IDs. - int maxArcId() const { return -1; } - - void first(Node&) const {} - void next(Node&) const {} - - void first(Arc&) const {} - void next(Arc&) const {} - - - void firstIn(Arc&, const Node&) const {} - void nextIn(Arc&) const {} - - void firstOut(Arc&, const Node&) const {} - void nextOut(Arc&) const {} - - // The second parameter is dummy. - Node fromId(int, Node) const { return INVALID; } - // The second parameter is dummy. - Arc fromId(int, Arc) const { return INVALID; } - - // Dummy parameter. - int maxId(Node) const { return -1; } - // Dummy parameter. - int maxId(Arc) const { return -1; } - - /// \brief The opposite node on the arc. - /// - /// Returns the opposite node on the given arc. - Node oppositeNode(Node, Arc) const { return INVALID; } - - /// \brief The base node of the iterator. - /// - /// Returns the base node of the given outgoing arc iterator - /// (i.e. the source node of the corresponding arc). - Node baseNode(OutArcIt) const { return INVALID; } - - /// \brief The running node of the iterator. - /// - /// Returns the running node of the given outgoing arc iterator - /// (i.e. the target node of the corresponding arc). - Node runningNode(OutArcIt) const { return INVALID; } - - /// \brief The base node of the iterator. - /// - /// Returns the base node of the given incoming arc iterator - /// (i.e. the target node of the corresponding arc). - Node baseNode(InArcIt) const { return INVALID; } - - /// \brief The running node of the iterator. - /// - /// Returns the running node of the given incoming arc iterator - /// (i.e. the source node of the corresponding arc). - Node runningNode(InArcIt) const { return INVALID; } - - /// \brief Standard graph map type for the nodes. - /// - /// Standard graph map type for the nodes. - /// It conforms to the ReferenceMap concept. - template - class NodeMap : public ReferenceMap { - public: - - /// Constructor - explicit NodeMap(const Digraph&) { } - /// Constructor with given initial value - NodeMap(const Digraph&, T) { } - - private: - ///Copy constructor - NodeMap(const NodeMap& nm) : - ReferenceMap(nm) { } - ///Assignment operator - template - NodeMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - }; - - /// \brief Standard graph map type for the arcs. - /// - /// Standard graph map type for the arcs. - /// It conforms to the ReferenceMap concept. - template - class ArcMap : public ReferenceMap { - public: - - /// Constructor - explicit ArcMap(const Digraph&) { } - /// Constructor with given initial value - ArcMap(const Digraph&, T) { } - - private: - ///Copy constructor - ArcMap(const ArcMap& em) : - ReferenceMap(em) { } - ///Assignment operator - template - ArcMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - }; - - template - struct Constraints { - void constraints() { - checkConcept(); - checkConcept, _Digraph>(); - checkConcept, _Digraph>(); - checkConcept, _Digraph>(); - } - }; - - }; - - } //namespace concepts -} //namespace lemon - - - -#endif diff --git a/deps/lemon/lemon/concepts/graph.h b/deps/lemon/lemon/concepts/graph.h deleted file mode 100644 index 76e43da06..000000000 --- a/deps/lemon/lemon/concepts/graph.h +++ /dev/null @@ -1,788 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\ingroup graph_concepts -///\file -///\brief The concept of undirected graphs. - -#ifndef LEMON_CONCEPTS_GRAPH_H -#define LEMON_CONCEPTS_GRAPH_H - -#include -#include -#include -#include - -namespace lemon { - namespace concepts { - - /// \ingroup graph_concepts - /// - /// \brief Class describing the concept of undirected graphs. - /// - /// This class describes the common interface of all undirected - /// graphs. - /// - /// Like all concept classes, it only provides an interface - /// without any sensible implementation. So any general algorithm for - /// undirected graphs should compile with this class, but it will not - /// run properly, of course. - /// An actual graph implementation like \ref ListGraph or - /// \ref SmartGraph may have additional functionality. - /// - /// The undirected graphs also fulfill the concept of \ref Digraph - /// "directed graphs", since each edge can also be regarded as two - /// oppositely directed arcs. - /// Undirected graphs provide an Edge type for the undirected edges and - /// an Arc type for the directed arcs. The Arc type is convertible to - /// Edge or inherited from it, i.e. the corresponding edge can be - /// obtained from an arc. - /// EdgeIt and EdgeMap classes can be used for the edges, while ArcIt - /// and ArcMap classes can be used for the arcs (just like in digraphs). - /// Both InArcIt and OutArcIt iterates on the same edges but with - /// opposite direction. IncEdgeIt also iterates on the same edges - /// as OutArcIt and InArcIt, but it is not convertible to Arc, - /// only to Edge. - /// - /// In LEMON, each undirected edge has an inherent orientation. - /// Thus it can defined if an arc is forward or backward oriented in - /// an undirected graph with respect to this default oriantation of - /// the represented edge. - /// With the direction() and direct() functions the direction - /// of an arc can be obtained and set, respectively. - /// - /// Only nodes and edges can be added to or removed from an undirected - /// graph and the corresponding arcs are added or removed automatically. - /// - /// \sa Digraph - class Graph { - private: - /// Graphs are \e not copy constructible. Use GraphCopy instead. - Graph(const Graph&) {} - /// \brief Assignment of a graph to another one is \e not allowed. - /// Use GraphCopy instead. - void operator=(const Graph&) {} - - public: - /// Default constructor. - Graph() {} - - /// \brief Undirected graphs should be tagged with \c UndirectedTag. - /// - /// Undirected graphs should be tagged with \c UndirectedTag. - /// - /// This tag helps the \c enable_if technics to make compile time - /// specializations for undirected graphs. - typedef True UndirectedTag; - - /// The node type of the graph - - /// This class identifies a node of the graph. It also serves - /// as a base class of the node iterators, - /// thus they convert to this type. - class Node { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the object to an undefined value. - Node() { } - /// Copy constructor. - - /// Copy constructor. - /// - Node(const Node&) { } - - /// %Invalid constructor \& conversion. - - /// Initializes the object to be invalid. - /// \sa Invalid for more details. - Node(Invalid) { } - /// Equality operator - - /// Equality operator. - /// - /// Two iterators are equal if and only if they point to the - /// same object or both are \c INVALID. - bool operator==(Node) const { return true; } - - /// Inequality operator - - /// Inequality operator. - bool operator!=(Node) const { return true; } - - /// Artificial ordering operator. - - /// Artificial ordering operator. - /// - /// \note This operator only has to define some strict ordering of - /// the items; this order has nothing to do with the iteration - /// ordering of the items. - bool operator<(Node) const { return false; } - - }; - - /// Iterator class for the nodes. - - /// This iterator goes through each node of the graph. - /// Its usage is quite simple, for example, you can count the number - /// of nodes in a graph \c g of type \c %Graph like this: - ///\code - /// int count=0; - /// for (Graph::NodeIt n(g); n!=INVALID; ++n) ++count; - ///\endcode - class NodeIt : public Node { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - NodeIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - NodeIt(const NodeIt& n) : Node(n) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - NodeIt(Invalid) { } - /// Sets the iterator to the first node. - - /// Sets the iterator to the first node of the given digraph. - /// - explicit NodeIt(const Graph&) { } - /// Sets the iterator to the given node. - - /// Sets the iterator to the given node of the given digraph. - /// - NodeIt(const Graph&, const Node&) { } - /// Next node. - - /// Assign the iterator to the next node. - /// - NodeIt& operator++() { return *this; } - }; - - - /// The edge type of the graph - - /// This class identifies an edge of the graph. It also serves - /// as a base class of the edge iterators, - /// thus they will convert to this type. - class Edge { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the object to an undefined value. - Edge() { } - /// Copy constructor. - - /// Copy constructor. - /// - Edge(const Edge&) { } - /// %Invalid constructor \& conversion. - - /// Initializes the object to be invalid. - /// \sa Invalid for more details. - Edge(Invalid) { } - /// Equality operator - - /// Equality operator. - /// - /// Two iterators are equal if and only if they point to the - /// same object or both are \c INVALID. - bool operator==(Edge) const { return true; } - /// Inequality operator - - /// Inequality operator. - bool operator!=(Edge) const { return true; } - - /// Artificial ordering operator. - - /// Artificial ordering operator. - /// - /// \note This operator only has to define some strict ordering of - /// the edges; this order has nothing to do with the iteration - /// ordering of the edges. - bool operator<(Edge) const { return false; } - }; - - /// Iterator class for the edges. - - /// This iterator goes through each edge of the graph. - /// Its usage is quite simple, for example, you can count the number - /// of edges in a graph \c g of type \c %Graph as follows: - ///\code - /// int count=0; - /// for(Graph::EdgeIt e(g); e!=INVALID; ++e) ++count; - ///\endcode - class EdgeIt : public Edge { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - EdgeIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - EdgeIt(const EdgeIt& e) : Edge(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - EdgeIt(Invalid) { } - /// Sets the iterator to the first edge. - - /// Sets the iterator to the first edge of the given graph. - /// - explicit EdgeIt(const Graph&) { } - /// Sets the iterator to the given edge. - - /// Sets the iterator to the given edge of the given graph. - /// - EdgeIt(const Graph&, const Edge&) { } - /// Next edge - - /// Assign the iterator to the next edge. - /// - EdgeIt& operator++() { return *this; } - }; - - /// Iterator class for the incident edges of a node. - - /// This iterator goes trough the incident undirected edges - /// of a certain node of a graph. - /// Its usage is quite simple, for example, you can compute the - /// degree (i.e. the number of incident edges) of a node \c n - /// in a graph \c g of type \c %Graph as follows. - /// - ///\code - /// int count=0; - /// for(Graph::IncEdgeIt e(g, n); e!=INVALID; ++e) ++count; - ///\endcode - /// - /// \warning Loop edges will be iterated twice. - class IncEdgeIt : public Edge { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - IncEdgeIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - IncEdgeIt(const IncEdgeIt& e) : Edge(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - IncEdgeIt(Invalid) { } - /// Sets the iterator to the first incident edge. - - /// Sets the iterator to the first incident edge of the given node. - /// - IncEdgeIt(const Graph&, const Node&) { } - /// Sets the iterator to the given edge. - - /// Sets the iterator to the given edge of the given graph. - /// - IncEdgeIt(const Graph&, const Edge&) { } - /// Next incident edge - - /// Assign the iterator to the next incident edge - /// of the corresponding node. - IncEdgeIt& operator++() { return *this; } - }; - - /// The arc type of the graph - - /// This class identifies a directed arc of the graph. It also serves - /// as a base class of the arc iterators, - /// thus they will convert to this type. - class Arc { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the object to an undefined value. - Arc() { } - /// Copy constructor. - - /// Copy constructor. - /// - Arc(const Arc&) { } - /// %Invalid constructor \& conversion. - - /// Initializes the object to be invalid. - /// \sa Invalid for more details. - Arc(Invalid) { } - /// Equality operator - - /// Equality operator. - /// - /// Two iterators are equal if and only if they point to the - /// same object or both are \c INVALID. - bool operator==(Arc) const { return true; } - /// Inequality operator - - /// Inequality operator. - bool operator!=(Arc) const { return true; } - - /// Artificial ordering operator. - - /// Artificial ordering operator. - /// - /// \note This operator only has to define some strict ordering of - /// the arcs; this order has nothing to do with the iteration - /// ordering of the arcs. - bool operator<(Arc) const { return false; } - - /// Converison to \c Edge - - /// Converison to \c Edge. - /// - operator Edge() const { return Edge(); } - }; - - /// Iterator class for the arcs. - - /// This iterator goes through each directed arc of the graph. - /// Its usage is quite simple, for example, you can count the number - /// of arcs in a graph \c g of type \c %Graph as follows: - ///\code - /// int count=0; - /// for(Graph::ArcIt a(g); a!=INVALID; ++a) ++count; - ///\endcode - class ArcIt : public Arc { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - ArcIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - ArcIt(const ArcIt& e) : Arc(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - ArcIt(Invalid) { } - /// Sets the iterator to the first arc. - - /// Sets the iterator to the first arc of the given graph. - /// - explicit ArcIt(const Graph &g) { - ::lemon::ignore_unused_variable_warning(g); - } - /// Sets the iterator to the given arc. - - /// Sets the iterator to the given arc of the given graph. - /// - ArcIt(const Graph&, const Arc&) { } - /// Next arc - - /// Assign the iterator to the next arc. - /// - ArcIt& operator++() { return *this; } - }; - - /// Iterator class for the outgoing arcs of a node. - - /// This iterator goes trough the \e outgoing directed arcs of a - /// certain node of a graph. - /// Its usage is quite simple, for example, you can count the number - /// of outgoing arcs of a node \c n - /// in a graph \c g of type \c %Graph as follows. - ///\code - /// int count=0; - /// for (Digraph::OutArcIt a(g, n); a!=INVALID; ++a) ++count; - ///\endcode - class OutArcIt : public Arc { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - OutArcIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - OutArcIt(const OutArcIt& e) : Arc(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - OutArcIt(Invalid) { } - /// Sets the iterator to the first outgoing arc. - - /// Sets the iterator to the first outgoing arc of the given node. - /// - OutArcIt(const Graph& n, const Node& g) { - ::lemon::ignore_unused_variable_warning(n); - ::lemon::ignore_unused_variable_warning(g); - } - /// Sets the iterator to the given arc. - - /// Sets the iterator to the given arc of the given graph. - /// - OutArcIt(const Graph&, const Arc&) { } - /// Next outgoing arc - - /// Assign the iterator to the next - /// outgoing arc of the corresponding node. - OutArcIt& operator++() { return *this; } - }; - - /// Iterator class for the incoming arcs of a node. - - /// This iterator goes trough the \e incoming directed arcs of a - /// certain node of a graph. - /// Its usage is quite simple, for example, you can count the number - /// of incoming arcs of a node \c n - /// in a graph \c g of type \c %Graph as follows. - ///\code - /// int count=0; - /// for (Digraph::InArcIt a(g, n); a!=INVALID; ++a) ++count; - ///\endcode - class InArcIt : public Arc { - public: - /// Default constructor - - /// Default constructor. - /// \warning It sets the iterator to an undefined value. - InArcIt() { } - /// Copy constructor. - - /// Copy constructor. - /// - InArcIt(const InArcIt& e) : Arc(e) { } - /// %Invalid constructor \& conversion. - - /// Initializes the iterator to be invalid. - /// \sa Invalid for more details. - InArcIt(Invalid) { } - /// Sets the iterator to the first incoming arc. - - /// Sets the iterator to the first incoming arc of the given node. - /// - InArcIt(const Graph& g, const Node& n) { - ::lemon::ignore_unused_variable_warning(n); - ::lemon::ignore_unused_variable_warning(g); - } - /// Sets the iterator to the given arc. - - /// Sets the iterator to the given arc of the given graph. - /// - InArcIt(const Graph&, const Arc&) { } - /// Next incoming arc - - /// Assign the iterator to the next - /// incoming arc of the corresponding node. - InArcIt& operator++() { return *this; } - }; - - /// \brief Standard graph map type for the nodes. - /// - /// Standard graph map type for the nodes. - /// It conforms to the ReferenceMap concept. - template - class NodeMap : public ReferenceMap - { - public: - - /// Constructor - explicit NodeMap(const Graph&) { } - /// Constructor with given initial value - NodeMap(const Graph&, T) { } - - private: - ///Copy constructor - NodeMap(const NodeMap& nm) : - ReferenceMap(nm) { } - ///Assignment operator - template - NodeMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - }; - - /// \brief Standard graph map type for the arcs. - /// - /// Standard graph map type for the arcs. - /// It conforms to the ReferenceMap concept. - template - class ArcMap : public ReferenceMap - { - public: - - /// Constructor - explicit ArcMap(const Graph&) { } - /// Constructor with given initial value - ArcMap(const Graph&, T) { } - - private: - ///Copy constructor - ArcMap(const ArcMap& em) : - ReferenceMap(em) { } - ///Assignment operator - template - ArcMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - }; - - /// \brief Standard graph map type for the edges. - /// - /// Standard graph map type for the edges. - /// It conforms to the ReferenceMap concept. - template - class EdgeMap : public ReferenceMap - { - public: - - /// Constructor - explicit EdgeMap(const Graph&) { } - /// Constructor with given initial value - EdgeMap(const Graph&, T) { } - - private: - ///Copy constructor - EdgeMap(const EdgeMap& em) : - ReferenceMap(em) {} - ///Assignment operator - template - EdgeMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - }; - - /// \brief The first node of the edge. - /// - /// Returns the first node of the given edge. - /// - /// Edges don't have source and target nodes, however, methods - /// u() and v() are used to query the two end-nodes of an edge. - /// The orientation of an edge that arises this way is called - /// the inherent direction, it is used to define the default - /// direction for the corresponding arcs. - /// \sa v() - /// \sa direction() - Node u(Edge) const { return INVALID; } - - /// \brief The second node of the edge. - /// - /// Returns the second node of the given edge. - /// - /// Edges don't have source and target nodes, however, methods - /// u() and v() are used to query the two end-nodes of an edge. - /// The orientation of an edge that arises this way is called - /// the inherent direction, it is used to define the default - /// direction for the corresponding arcs. - /// \sa u() - /// \sa direction() - Node v(Edge) const { return INVALID; } - - /// \brief The source node of the arc. - /// - /// Returns the source node of the given arc. - Node source(Arc) const { return INVALID; } - - /// \brief The target node of the arc. - /// - /// Returns the target node of the given arc. - Node target(Arc) const { return INVALID; } - - /// \brief The ID of the node. - /// - /// Returns the ID of the given node. - int id(Node) const { return -1; } - - /// \brief The ID of the edge. - /// - /// Returns the ID of the given edge. - int id(Edge) const { return -1; } - - /// \brief The ID of the arc. - /// - /// Returns the ID of the given arc. - int id(Arc) const { return -1; } - - /// \brief The node with the given ID. - /// - /// Returns the node with the given ID. - /// \pre The argument should be a valid node ID in the graph. - Node nodeFromId(int) const { return INVALID; } - - /// \brief The edge with the given ID. - /// - /// Returns the edge with the given ID. - /// \pre The argument should be a valid edge ID in the graph. - Edge edgeFromId(int) const { return INVALID; } - - /// \brief The arc with the given ID. - /// - /// Returns the arc with the given ID. - /// \pre The argument should be a valid arc ID in the graph. - Arc arcFromId(int) const { return INVALID; } - - /// \brief An upper bound on the node IDs. - /// - /// Returns an upper bound on the node IDs. - int maxNodeId() const { return -1; } - - /// \brief An upper bound on the edge IDs. - /// - /// Returns an upper bound on the edge IDs. - int maxEdgeId() const { return -1; } - - /// \brief An upper bound on the arc IDs. - /// - /// Returns an upper bound on the arc IDs. - int maxArcId() const { return -1; } - - /// \brief The direction of the arc. - /// - /// Returns \c true if the direction of the given arc is the same as - /// the inherent orientation of the represented edge. - bool direction(Arc) const { return true; } - - /// \brief Direct the edge. - /// - /// Direct the given edge. The returned arc - /// represents the given edge and its direction comes - /// from the bool parameter. If it is \c true, then the direction - /// of the arc is the same as the inherent orientation of the edge. - Arc direct(Edge, bool) const { - return INVALID; - } - - /// \brief Direct the edge. - /// - /// Direct the given edge. The returned arc represents the given - /// edge and its source node is the given node. - Arc direct(Edge, Node) const { - return INVALID; - } - - /// \brief The oppositely directed arc. - /// - /// Returns the oppositely directed arc representing the same edge. - Arc oppositeArc(Arc) const { return INVALID; } - - /// \brief The opposite node on the edge. - /// - /// Returns the opposite node on the given edge. - Node oppositeNode(Node, Edge) const { return INVALID; } - - void first(Node&) const {} - void next(Node&) const {} - - void first(Edge&) const {} - void next(Edge&) const {} - - void first(Arc&) const {} - void next(Arc&) const {} - - void firstOut(Arc&, Node) const {} - void nextOut(Arc&) const {} - - void firstIn(Arc&, Node) const {} - void nextIn(Arc&) const {} - - void firstInc(Edge &, bool &, const Node &) const {} - void nextInc(Edge &, bool &) const {} - - // The second parameter is dummy. - Node fromId(int, Node) const { return INVALID; } - // The second parameter is dummy. - Edge fromId(int, Edge) const { return INVALID; } - // The second parameter is dummy. - Arc fromId(int, Arc) const { return INVALID; } - - // Dummy parameter. - int maxId(Node) const { return -1; } - // Dummy parameter. - int maxId(Edge) const { return -1; } - // Dummy parameter. - int maxId(Arc) const { return -1; } - - /// \brief The base node of the iterator. - /// - /// Returns the base node of the given incident edge iterator. - Node baseNode(IncEdgeIt) const { return INVALID; } - - /// \brief The running node of the iterator. - /// - /// Returns the running node of the given incident edge iterator. - Node runningNode(IncEdgeIt) const { return INVALID; } - - /// \brief The base node of the iterator. - /// - /// Returns the base node of the given outgoing arc iterator - /// (i.e. the source node of the corresponding arc). - Node baseNode(OutArcIt) const { return INVALID; } - - /// \brief The running node of the iterator. - /// - /// Returns the running node of the given outgoing arc iterator - /// (i.e. the target node of the corresponding arc). - Node runningNode(OutArcIt) const { return INVALID; } - - /// \brief The base node of the iterator. - /// - /// Returns the base node of the given incoming arc iterator - /// (i.e. the target node of the corresponding arc). - Node baseNode(InArcIt) const { return INVALID; } - - /// \brief The running node of the iterator. - /// - /// Returns the running node of the given incoming arc iterator - /// (i.e. the source node of the corresponding arc). - Node runningNode(InArcIt) const { return INVALID; } - - template - struct Constraints { - void constraints() { - checkConcept(); - checkConcept, _Graph>(); - checkConcept, _Graph>(); - checkConcept, _Graph>(); - } - }; - - }; - - } - -} - -#endif diff --git a/deps/lemon/lemon/concepts/graph_components.h b/deps/lemon/lemon/concepts/graph_components.h deleted file mode 100644 index 9df28f37e..000000000 --- a/deps/lemon/lemon/concepts/graph_components.h +++ /dev/null @@ -1,2134 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\ingroup graph_concepts -///\file -///\brief The concepts of graph components. - -#ifndef LEMON_CONCEPTS_GRAPH_COMPONENTS_H -#define LEMON_CONCEPTS_GRAPH_COMPONENTS_H - -#include -#include - -#include - -namespace lemon { - namespace concepts { - - /// \brief Concept class for \c Node, \c Arc and \c Edge types. - /// - /// This class describes the concept of \c Node, \c Arc and \c Edge - /// subtypes of digraph and graph types. - /// - /// \note This class is a template class so that we can use it to - /// create graph skeleton classes. The reason for this is that \c Node - /// and \c Arc (or \c Edge) types should \e not derive from the same - /// base class. For \c Node you should instantiate it with character - /// \c 'n', for \c Arc with \c 'a' and for \c Edge with \c 'e'. -#ifndef DOXYGEN - template -#endif - class GraphItem { - public: - /// \brief Default constructor. - /// - /// Default constructor. - /// \warning The default constructor is not required to set - /// the item to some well-defined value. So you should consider it - /// as uninitialized. - GraphItem() {} - - /// \brief Copy constructor. - /// - /// Copy constructor. - GraphItem(const GraphItem &) {} - - /// \brief Constructor for conversion from \c INVALID. - /// - /// Constructor for conversion from \c INVALID. - /// It initializes the item to be invalid. - /// \sa Invalid for more details. - GraphItem(Invalid) {} - - /// \brief Assignment operator. - /// - /// Assignment operator for the item. - GraphItem& operator=(const GraphItem&) { return *this; } - - /// \brief Assignment operator for INVALID. - /// - /// This operator makes the item invalid. - GraphItem& operator=(Invalid) { return *this; } - - /// \brief Equality operator. - /// - /// Equality operator. - bool operator==(const GraphItem&) const { return false; } - - /// \brief Inequality operator. - /// - /// Inequality operator. - bool operator!=(const GraphItem&) const { return false; } - - /// \brief Ordering operator. - /// - /// This operator defines an ordering of the items. - /// It makes possible to use graph item types as key types in - /// associative containers (e.g. \c std::map). - /// - /// \note This operator only has to define some strict ordering of - /// the items; this order has nothing to do with the iteration - /// ordering of the items. - bool operator<(const GraphItem&) const { return false; } - - template - struct Constraints { - void constraints() { - _GraphItem i1; - i1=INVALID; - _GraphItem i2 = i1; - _GraphItem i3 = INVALID; - - i1 = i2 = i3; - - bool b; - ::lemon::ignore_unused_variable_warning(b); - - b = (ia == ib) && (ia != ib); - b = (ia == INVALID) && (ib != INVALID); - b = (ia < ib); - } - - const _GraphItem &ia; - const _GraphItem &ib; - Constraints() {} - }; - }; - - /// \brief Base skeleton class for directed graphs. - /// - /// This class describes the base interface of directed graph types. - /// All digraph %concepts have to conform to this class. - /// It just provides types for nodes and arcs and functions - /// to get the source and the target nodes of arcs. - class BaseDigraphComponent { - public: - - typedef BaseDigraphComponent Digraph; - - /// \brief Node class of the digraph. - /// - /// This class represents the nodes of the digraph. - typedef GraphItem<'n'> Node; - - /// \brief Arc class of the digraph. - /// - /// This class represents the arcs of the digraph. - typedef GraphItem<'a'> Arc; - - /// \brief Return the source node of an arc. - /// - /// This function returns the source node of an arc. - Node source(const Arc&) const { return INVALID; } - - /// \brief Return the target node of an arc. - /// - /// This function returns the target node of an arc. - Node target(const Arc&) const { return INVALID; } - - /// \brief Return the opposite node on the given arc. - /// - /// This function returns the opposite node on the given arc. - Node oppositeNode(const Node&, const Arc&) const { - return INVALID; - } - - template - struct Constraints { - typedef typename _Digraph::Node Node; - typedef typename _Digraph::Arc Arc; - - void constraints() { - checkConcept, Node>(); - checkConcept, Arc>(); - { - Node n; - Arc e(INVALID); - n = digraph.source(e); - n = digraph.target(e); - n = digraph.oppositeNode(n, e); - } - } - - const _Digraph& digraph; - Constraints() {} - }; - }; - - /// \brief Base skeleton class for undirected graphs. - /// - /// This class describes the base interface of undirected graph types. - /// All graph %concepts have to conform to this class. - /// It extends the interface of \ref BaseDigraphComponent with an - /// \c Edge type and functions to get the end nodes of edges, - /// to convert from arcs to edges and to get both direction of edges. - class BaseGraphComponent : public BaseDigraphComponent { - public: - - typedef BaseGraphComponent Graph; - - typedef BaseDigraphComponent::Node Node; - typedef BaseDigraphComponent::Arc Arc; - - /// \brief Undirected edge class of the graph. - /// - /// This class represents the undirected edges of the graph. - /// Undirected graphs can be used as directed graphs, each edge is - /// represented by two opposite directed arcs. - class Edge : public GraphItem<'e'> { - typedef GraphItem<'e'> Parent; - - public: - /// \brief Default constructor. - /// - /// Default constructor. - /// \warning The default constructor is not required to set - /// the item to some well-defined value. So you should consider it - /// as uninitialized. - Edge() {} - - /// \brief Copy constructor. - /// - /// Copy constructor. - Edge(const Edge &) : Parent() {} - - /// \brief Constructor for conversion from \c INVALID. - /// - /// Constructor for conversion from \c INVALID. - /// It initializes the item to be invalid. - /// \sa Invalid for more details. - Edge(Invalid) {} - - /// \brief Constructor for conversion from an arc. - /// - /// Constructor for conversion from an arc. - /// Besides the core graph item functionality each arc should - /// be convertible to the represented edge. - Edge(const Arc&) {} - }; - - /// \brief Return one end node of an edge. - /// - /// This function returns one end node of an edge. - Node u(const Edge&) const { return INVALID; } - - /// \brief Return the other end node of an edge. - /// - /// This function returns the other end node of an edge. - Node v(const Edge&) const { return INVALID; } - - /// \brief Return a directed arc related to an edge. - /// - /// This function returns a directed arc from its direction and the - /// represented edge. - Arc direct(const Edge&, bool) const { return INVALID; } - - /// \brief Return a directed arc related to an edge. - /// - /// This function returns a directed arc from its source node and the - /// represented edge. - Arc direct(const Edge&, const Node&) const { return INVALID; } - - /// \brief Return the direction of the arc. - /// - /// Returns the direction of the arc. Each arc represents an - /// edge with a direction. It gives back the - /// direction. - bool direction(const Arc&) const { return true; } - - /// \brief Return the opposite arc. - /// - /// This function returns the opposite arc, i.e. the arc representing - /// the same edge and has opposite direction. - Arc oppositeArc(const Arc&) const { return INVALID; } - - template - struct Constraints { - typedef typename _Graph::Node Node; - typedef typename _Graph::Arc Arc; - typedef typename _Graph::Edge Edge; - - void constraints() { - checkConcept(); - checkConcept, Edge>(); - { - Node n; - Edge ue(INVALID); - Arc e; - n = graph.u(ue); - n = graph.v(ue); - e = graph.direct(ue, true); - e = graph.direct(ue, false); - e = graph.direct(ue, n); - e = graph.oppositeArc(e); - ue = e; - bool d = graph.direction(e); - ::lemon::ignore_unused_variable_warning(d); - } - } - - const _Graph& graph; - Constraints() {} - }; - - }; - - /// \brief Base skeleton class for undirected bipartite graphs. - /// - /// This class describes the base interface of undirected - /// bipartite graph types. All bipartite graph %concepts have to - /// conform to this class. It extends the interface of \ref - /// BaseGraphComponent with an \c Edge type and functions to get - /// the end nodes of edges, to convert from arcs to edges and to - /// get both direction of edges. - class BaseBpGraphComponent : public BaseGraphComponent { - public: - - typedef BaseBpGraphComponent BpGraph; - - typedef BaseDigraphComponent::Node Node; - typedef BaseDigraphComponent::Arc Arc; - - /// \brief Class to represent red nodes. - /// - /// This class represents the red nodes of the graph. The red - /// nodes can also be used as normal nodes. - class RedNode : public Node { - typedef Node Parent; - - public: - /// \brief Default constructor. - /// - /// Default constructor. - /// \warning The default constructor is not required to set - /// the item to some well-defined value. So you should consider it - /// as uninitialized. - RedNode() {} - - /// \brief Copy constructor. - /// - /// Copy constructor. - RedNode(const RedNode &) : Parent() {} - - /// \brief Constructor for conversion from \c INVALID. - /// - /// Constructor for conversion from \c INVALID. - /// It initializes the item to be invalid. - /// \sa Invalid for more details. - RedNode(Invalid) {} - }; - - /// \brief Class to represent blue nodes. - /// - /// This class represents the blue nodes of the graph. The blue - /// nodes can also be used as normal nodes. - class BlueNode : public Node { - typedef Node Parent; - - public: - /// \brief Default constructor. - /// - /// Default constructor. - /// \warning The default constructor is not required to set - /// the item to some well-defined value. So you should consider it - /// as uninitialized. - BlueNode() {} - - /// \brief Copy constructor. - /// - /// Copy constructor. - BlueNode(const BlueNode &) : Parent() {} - - /// \brief Constructor for conversion from \c INVALID. - /// - /// Constructor for conversion from \c INVALID. - /// It initializes the item to be invalid. - /// \sa Invalid for more details. - BlueNode(Invalid) {} - - /// \brief Constructor for conversion from a node. - /// - /// Constructor for conversion from a node. The conversion can - /// be invalid, since the Node can be member of the red - /// set. - BlueNode(const Node&) {} - }; - - /// \brief Gives back %true for red nodes. - /// - /// Gives back %true for red nodes. - bool red(const Node&) const { return true; } - - /// \brief Gives back %true for blue nodes. - /// - /// Gives back %true for blue nodes. - bool blue(const Node&) const { return true; } - - /// \brief Gives back the red end node of the edge. - /// - /// Gives back the red end node of the edge. - RedNode redNode(const Edge&) const { return RedNode(); } - - /// \brief Gives back the blue end node of the edge. - /// - /// Gives back the blue end node of the edge. - BlueNode blueNode(const Edge&) const { return BlueNode(); } - - /// \brief Converts the node to red node object. - /// - /// This function converts unsafely the node to red node - /// object. It should be called only if the node is from the red - /// partition or INVALID. - RedNode asRedNodeUnsafe(const Node&) const { return RedNode(); } - - /// \brief Converts the node to blue node object. - /// - /// This function converts unsafely the node to blue node - /// object. It should be called only if the node is from the red - /// partition or INVALID. - BlueNode asBlueNodeUnsafe(const Node&) const { return BlueNode(); } - - /// \brief Converts the node to red node object. - /// - /// This function converts safely the node to red node - /// object. If the node is not from the red partition, then it - /// returns INVALID. - RedNode asRedNode(const Node&) const { return RedNode(); } - - /// \brief Converts the node to blue node object. - /// - /// This function converts unsafely the node to blue node - /// object. If the node is not from the blue partition, then it - /// returns INVALID. - BlueNode asBlueNode(const Node&) const { return BlueNode(); } - - template - struct Constraints { - typedef typename _BpGraph::Node Node; - typedef typename _BpGraph::RedNode RedNode; - typedef typename _BpGraph::BlueNode BlueNode; - typedef typename _BpGraph::Arc Arc; - typedef typename _BpGraph::Edge Edge; - - void constraints() { - checkConcept(); - checkConcept, RedNode>(); - checkConcept, BlueNode>(); - { - Node n; - RedNode rn; - BlueNode bn; - Node rnan = rn; - Node bnan = bn; - Edge e; - bool b; - b = bpgraph.red(rnan); - b = bpgraph.blue(bnan); - rn = bpgraph.redNode(e); - bn = bpgraph.blueNode(e); - rn = bpgraph.asRedNodeUnsafe(rnan); - bn = bpgraph.asBlueNodeUnsafe(bnan); - rn = bpgraph.asRedNode(rnan); - bn = bpgraph.asBlueNode(bnan); - ::lemon::ignore_unused_variable_warning(b); - } - } - - const _BpGraph& bpgraph; - }; - - }; - - /// \brief Skeleton class for \e idable directed graphs. - /// - /// This class describes the interface of \e idable directed graphs. - /// It extends \ref BaseDigraphComponent with the core ID functions. - /// The ids of the items must be unique and immutable. - /// This concept is part of the Digraph concept. - template - class IDableDigraphComponent : public BAS { - public: - - typedef BAS Base; - typedef typename Base::Node Node; - typedef typename Base::Arc Arc; - - /// \brief Return a unique integer id for the given node. - /// - /// This function returns a unique integer id for the given node. - int id(const Node&) const { return -1; } - - /// \brief Return the node by its unique id. - /// - /// This function returns the node by its unique id. - /// If the digraph does not contain a node with the given id, - /// then the result of the function is undefined. - Node nodeFromId(int) const { return INVALID; } - - /// \brief Return a unique integer id for the given arc. - /// - /// This function returns a unique integer id for the given arc. - int id(const Arc&) const { return -1; } - - /// \brief Return the arc by its unique id. - /// - /// This function returns the arc by its unique id. - /// If the digraph does not contain an arc with the given id, - /// then the result of the function is undefined. - Arc arcFromId(int) const { return INVALID; } - - /// \brief Return an integer greater or equal to the maximum - /// node id. - /// - /// This function returns an integer greater or equal to the - /// maximum node id. - int maxNodeId() const { return -1; } - - /// \brief Return an integer greater or equal to the maximum - /// arc id. - /// - /// This function returns an integer greater or equal to the - /// maximum arc id. - int maxArcId() const { return -1; } - - template - struct Constraints { - - void constraints() { - checkConcept(); - typename _Digraph::Node node; - node=INVALID; - int nid = digraph.id(node); - nid = digraph.id(node); - node = digraph.nodeFromId(nid); - typename _Digraph::Arc arc; - arc=INVALID; - int eid = digraph.id(arc); - eid = digraph.id(arc); - arc = digraph.arcFromId(eid); - - nid = digraph.maxNodeId(); - ::lemon::ignore_unused_variable_warning(nid); - eid = digraph.maxArcId(); - ::lemon::ignore_unused_variable_warning(eid); - } - - const _Digraph& digraph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for \e idable undirected graphs. - /// - /// This class describes the interface of \e idable undirected - /// graphs. It extends \ref IDableDigraphComponent with the core ID - /// functions of undirected graphs. - /// The ids of the items must be unique and immutable. - /// This concept is part of the Graph concept. - template - class IDableGraphComponent : public IDableDigraphComponent { - public: - - typedef BAS Base; - typedef typename Base::Edge Edge; - - using IDableDigraphComponent::id; - - /// \brief Return a unique integer id for the given edge. - /// - /// This function returns a unique integer id for the given edge. - int id(const Edge&) const { return -1; } - - /// \brief Return the edge by its unique id. - /// - /// This function returns the edge by its unique id. - /// If the graph does not contain an edge with the given id, - /// then the result of the function is undefined. - Edge edgeFromId(int) const { return INVALID; } - - /// \brief Return an integer greater or equal to the maximum - /// edge id. - /// - /// This function returns an integer greater or equal to the - /// maximum edge id. - int maxEdgeId() const { return -1; } - - template - struct Constraints { - - void constraints() { - checkConcept, _Graph >(); - typename _Graph::Edge edge; - int ueid = graph.id(edge); - ueid = graph.id(edge); - edge = graph.edgeFromId(ueid); - ueid = graph.maxEdgeId(); - ::lemon::ignore_unused_variable_warning(ueid); - } - - const _Graph& graph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for \e idable undirected bipartite graphs. - /// - /// This class describes the interface of \e idable undirected - /// bipartite graphs. It extends \ref IDableGraphComponent with - /// the core ID functions of undirected bipartite graphs. Beside - /// the regular node ids, this class also provides ids within the - /// the red and blue sets of the nodes. This concept is part of - /// the BpGraph concept. - template - class IDableBpGraphComponent : public IDableGraphComponent { - public: - - typedef BAS Base; - typedef IDableGraphComponent Parent; - typedef typename Base::Node Node; - typedef typename Base::RedNode RedNode; - typedef typename Base::BlueNode BlueNode; - - using Parent::id; - - /// \brief Return a unique integer id for the given node in the red set. - /// - /// Return a unique integer id for the given node in the red set. - int id(const RedNode&) const { return -1; } - - /// \brief Return a unique integer id for the given node in the blue set. - /// - /// Return a unique integer id for the given node in the blue set. - int id(const BlueNode&) const { return -1; } - - /// \brief Return an integer greater or equal to the maximum - /// node id in the red set. - /// - /// Return an integer greater or equal to the maximum - /// node id in the red set. - int maxRedId() const { return -1; } - - /// \brief Return an integer greater or equal to the maximum - /// node id in the blue set. - /// - /// Return an integer greater or equal to the maximum - /// node id in the blue set. - int maxBlueId() const { return -1; } - - template - struct Constraints { - - void constraints() { - checkConcept, _BpGraph>(); - typename _BpGraph::Node node; - typename _BpGraph::RedNode red; - typename _BpGraph::BlueNode blue; - int rid = bpgraph.id(red); - int bid = bpgraph.id(blue); - rid = bpgraph.maxRedId(); - bid = bpgraph.maxBlueId(); - ::lemon::ignore_unused_variable_warning(rid); - ::lemon::ignore_unused_variable_warning(bid); - } - - const _BpGraph& bpgraph; - }; - }; - - /// \brief Concept class for \c NodeIt, \c ArcIt and \c EdgeIt types. - /// - /// This class describes the concept of \c NodeIt, \c ArcIt and - /// \c EdgeIt subtypes of digraph and graph types. - template - class GraphItemIt : public Item { - public: - /// \brief Default constructor. - /// - /// Default constructor. - /// \warning The default constructor is not required to set - /// the iterator to some well-defined value. So you should consider it - /// as uninitialized. - GraphItemIt() {} - - /// \brief Copy constructor. - /// - /// Copy constructor. - GraphItemIt(const GraphItemIt& it) : Item(it) {} - - /// \brief Constructor that sets the iterator to the first item. - /// - /// Constructor that sets the iterator to the first item. - explicit GraphItemIt(const GR&) {} - - /// \brief Constructor for conversion from \c INVALID. - /// - /// Constructor for conversion from \c INVALID. - /// It initializes the iterator to be invalid. - /// \sa Invalid for more details. - GraphItemIt(Invalid) {} - - /// \brief Assignment operator. - /// - /// Assignment operator for the iterator. - GraphItemIt& operator=(const GraphItemIt&) { return *this; } - - /// \brief Increment the iterator. - /// - /// This operator increments the iterator, i.e. assigns it to the - /// next item. - GraphItemIt& operator++() { return *this; } - - /// \brief Equality operator - /// - /// Equality operator. - /// Two iterators are equal if and only if they point to the - /// same object or both are invalid. - bool operator==(const GraphItemIt&) const { return true;} - - /// \brief Inequality operator - /// - /// Inequality operator. - /// Two iterators are equal if and only if they point to the - /// same object or both are invalid. - bool operator!=(const GraphItemIt&) const { return true;} - - template - struct Constraints { - void constraints() { - checkConcept, _GraphItemIt>(); - _GraphItemIt it1(g); - _GraphItemIt it2; - _GraphItemIt it3 = it1; - _GraphItemIt it4 = INVALID; - ::lemon::ignore_unused_variable_warning(it3); - ::lemon::ignore_unused_variable_warning(it4); - - it2 = ++it1; - ++it2 = it1; - ++(++it1); - - Item bi = it1; - bi = it2; - } - const GR& g; - Constraints() {} - }; - }; - - /// \brief Concept class for \c InArcIt, \c OutArcIt and - /// \c IncEdgeIt types. - /// - /// This class describes the concept of \c InArcIt, \c OutArcIt - /// and \c IncEdgeIt subtypes of digraph and graph types. - /// - /// \note Since these iterator classes do not inherit from the same - /// base class, there is an additional template parameter (selector) - /// \c sel. For \c InArcIt you should instantiate it with character - /// \c 'i', for \c OutArcIt with \c 'o' and for \c IncEdgeIt with \c 'e'. - template - class GraphIncIt : public Item { - public: - /// \brief Default constructor. - /// - /// Default constructor. - /// \warning The default constructor is not required to set - /// the iterator to some well-defined value. So you should consider it - /// as uninitialized. - GraphIncIt() {} - - /// \brief Copy constructor. - /// - /// Copy constructor. - GraphIncIt(const GraphIncIt& it) : Item(it) {} - - /// \brief Constructor that sets the iterator to the first - /// incoming or outgoing arc. - /// - /// Constructor that sets the iterator to the first arc - /// incoming to or outgoing from the given node. - explicit GraphIncIt(const GR&, const Base&) {} - - /// \brief Constructor for conversion from \c INVALID. - /// - /// Constructor for conversion from \c INVALID. - /// It initializes the iterator to be invalid. - /// \sa Invalid for more details. - GraphIncIt(Invalid) {} - - /// \brief Assignment operator. - /// - /// Assignment operator for the iterator. - GraphIncIt& operator=(const GraphIncIt&) { return *this; } - - /// \brief Increment the iterator. - /// - /// This operator increments the iterator, i.e. assigns it to the - /// next arc incoming to or outgoing from the given node. - GraphIncIt& operator++() { return *this; } - - /// \brief Equality operator - /// - /// Equality operator. - /// Two iterators are equal if and only if they point to the - /// same object or both are invalid. - bool operator==(const GraphIncIt&) const { return true;} - - /// \brief Inequality operator - /// - /// Inequality operator. - /// Two iterators are equal if and only if they point to the - /// same object or both are invalid. - bool operator!=(const GraphIncIt&) const { return true;} - - template - struct Constraints { - void constraints() { - checkConcept, _GraphIncIt>(); - _GraphIncIt it1(graph, node); - _GraphIncIt it2; - _GraphIncIt it3 = it1; - _GraphIncIt it4 = INVALID; - ::lemon::ignore_unused_variable_warning(it3); - ::lemon::ignore_unused_variable_warning(it4); - - it2 = ++it1; - ++it2 = it1; - ++(++it1); - Item e = it1; - e = it2; - } - const Base& node; - const GR& graph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for iterable directed graphs. - /// - /// This class describes the interface of iterable directed - /// graphs. It extends \ref BaseDigraphComponent with the core - /// iterable interface. - /// This concept is part of the Digraph concept. - template - class IterableDigraphComponent : public BAS { - - public: - - typedef BAS Base; - typedef typename Base::Node Node; - typedef typename Base::Arc Arc; - - typedef IterableDigraphComponent Digraph; - - /// \name Base Iteration - /// - /// This interface provides functions for iteration on digraph items. - /// - /// @{ - - /// \brief Return the first node. - /// - /// This function gives back the first node in the iteration order. - void first(Node&) const {} - - /// \brief Return the next node. - /// - /// This function gives back the next node in the iteration order. - void next(Node&) const {} - - /// \brief Return the first arc. - /// - /// This function gives back the first arc in the iteration order. - void first(Arc&) const {} - - /// \brief Return the next arc. - /// - /// This function gives back the next arc in the iteration order. - void next(Arc&) const {} - - /// \brief Return the first arc incoming to the given node. - /// - /// This function gives back the first arc incoming to the - /// given node. - void firstIn(Arc&, const Node&) const {} - - /// \brief Return the next arc incoming to the given node. - /// - /// This function gives back the next arc incoming to the - /// given node. - void nextIn(Arc&) const {} - - /// \brief Return the first arc outgoing form the given node. - /// - /// This function gives back the first arc outgoing form the - /// given node. - void firstOut(Arc&, const Node&) const {} - - /// \brief Return the next arc outgoing form the given node. - /// - /// This function gives back the next arc outgoing form the - /// given node. - void nextOut(Arc&) const {} - - /// @} - - /// \name Class Based Iteration - /// - /// This interface provides iterator classes for digraph items. - /// - /// @{ - - /// \brief This iterator goes through each node. - /// - /// This iterator goes through each node. - /// - typedef GraphItemIt NodeIt; - - /// \brief This iterator goes through each arc. - /// - /// This iterator goes through each arc. - /// - typedef GraphItemIt ArcIt; - - /// \brief This iterator goes trough the incoming arcs of a node. - /// - /// This iterator goes trough the \e incoming arcs of a certain node - /// of a digraph. - typedef GraphIncIt InArcIt; - - /// \brief This iterator goes trough the outgoing arcs of a node. - /// - /// This iterator goes trough the \e outgoing arcs of a certain node - /// of a digraph. - typedef GraphIncIt OutArcIt; - - /// \brief The base node of the iterator. - /// - /// This function gives back the base node of the iterator. - /// It is always the target node of the pointed arc. - Node baseNode(const InArcIt&) const { return INVALID; } - - /// \brief The running node of the iterator. - /// - /// This function gives back the running node of the iterator. - /// It is always the source node of the pointed arc. - Node runningNode(const InArcIt&) const { return INVALID; } - - /// \brief The base node of the iterator. - /// - /// This function gives back the base node of the iterator. - /// It is always the source node of the pointed arc. - Node baseNode(const OutArcIt&) const { return INVALID; } - - /// \brief The running node of the iterator. - /// - /// This function gives back the running node of the iterator. - /// It is always the target node of the pointed arc. - Node runningNode(const OutArcIt&) const { return INVALID; } - - /// @} - - template - struct Constraints { - void constraints() { - checkConcept(); - - { - typename _Digraph::Node node(INVALID); - typename _Digraph::Arc arc(INVALID); - { - digraph.first(node); - digraph.next(node); - } - { - digraph.first(arc); - digraph.next(arc); - } - { - digraph.firstIn(arc, node); - digraph.nextIn(arc); - } - { - digraph.firstOut(arc, node); - digraph.nextOut(arc); - } - } - - { - checkConcept, - typename _Digraph::ArcIt >(); - checkConcept, - typename _Digraph::NodeIt >(); - checkConcept, typename _Digraph::InArcIt>(); - checkConcept, typename _Digraph::OutArcIt>(); - - typename _Digraph::Node n; - const typename _Digraph::InArcIt iait(INVALID); - const typename _Digraph::OutArcIt oait(INVALID); - n = digraph.baseNode(iait); - n = digraph.runningNode(iait); - n = digraph.baseNode(oait); - n = digraph.runningNode(oait); - ::lemon::ignore_unused_variable_warning(n); - } - } - - const _Digraph& digraph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for iterable undirected graphs. - /// - /// This class describes the interface of iterable undirected - /// graphs. It extends \ref IterableDigraphComponent with the core - /// iterable interface of undirected graphs. - /// This concept is part of the Graph concept. - template - class IterableGraphComponent : public IterableDigraphComponent { - public: - - typedef BAS Base; - typedef typename Base::Node Node; - typedef typename Base::Arc Arc; - typedef typename Base::Edge Edge; - - - typedef IterableGraphComponent Graph; - - /// \name Base Iteration - /// - /// This interface provides functions for iteration on edges. - /// - /// @{ - - using IterableDigraphComponent::first; - using IterableDigraphComponent::next; - - /// \brief Return the first edge. - /// - /// This function gives back the first edge in the iteration order. - void first(Edge&) const {} - - /// \brief Return the next edge. - /// - /// This function gives back the next edge in the iteration order. - void next(Edge&) const {} - - /// \brief Return the first edge incident to the given node. - /// - /// This function gives back the first edge incident to the given - /// node. The bool parameter gives back the direction for which the - /// source node of the directed arc representing the edge is the - /// given node. - void firstInc(Edge&, bool&, const Node&) const {} - - /// \brief Gives back the next of the edges from the - /// given node. - /// - /// This function gives back the next edge incident to the given - /// node. The bool parameter should be used as \c firstInc() use it. - void nextInc(Edge&, bool&) const {} - - using IterableDigraphComponent::baseNode; - using IterableDigraphComponent::runningNode; - - /// @} - - /// \name Class Based Iteration - /// - /// This interface provides iterator classes for edges. - /// - /// @{ - - /// \brief This iterator goes through each edge. - /// - /// This iterator goes through each edge. - typedef GraphItemIt EdgeIt; - - /// \brief This iterator goes trough the incident edges of a - /// node. - /// - /// This iterator goes trough the incident edges of a certain - /// node of a graph. - typedef GraphIncIt IncEdgeIt; - - /// \brief The base node of the iterator. - /// - /// This function gives back the base node of the iterator. - Node baseNode(const IncEdgeIt&) const { return INVALID; } - - /// \brief The running node of the iterator. - /// - /// This function gives back the running node of the iterator. - Node runningNode(const IncEdgeIt&) const { return INVALID; } - - /// @} - - template - struct Constraints { - void constraints() { - checkConcept, _Graph>(); - - { - typename _Graph::Node node(INVALID); - typename _Graph::Edge edge(INVALID); - bool dir; - { - graph.first(edge); - graph.next(edge); - } - { - graph.firstInc(edge, dir, node); - graph.nextInc(edge, dir); - } - - } - - { - checkConcept, - typename _Graph::EdgeIt >(); - checkConcept, typename _Graph::IncEdgeIt>(); - - typename _Graph::Node n; - const typename _Graph::IncEdgeIt ieit(INVALID); - n = graph.baseNode(ieit); - n = graph.runningNode(ieit); - } - } - - const _Graph& graph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for iterable undirected bipartite graphs. - /// - /// This class describes the interface of iterable undirected - /// bipartite graphs. It extends \ref IterableGraphComponent with - /// the core iterable interface of undirected bipartite graphs. - /// This concept is part of the BpGraph concept. - template - class IterableBpGraphComponent : public IterableGraphComponent { - public: - - typedef BAS Base; - typedef typename Base::Node Node; - typedef typename Base::RedNode RedNode; - typedef typename Base::BlueNode BlueNode; - typedef typename Base::Arc Arc; - typedef typename Base::Edge Edge; - - typedef IterableBpGraphComponent BpGraph; - - using IterableGraphComponent::first; - using IterableGraphComponent::next; - - /// \name Base Iteration - /// - /// This interface provides functions for iteration on red and blue nodes. - /// - /// @{ - - /// \brief Return the first red node. - /// - /// This function gives back the first red node in the iteration order. - void first(RedNode&) const {} - - /// \brief Return the next red node. - /// - /// This function gives back the next red node in the iteration order. - void next(RedNode&) const {} - - /// \brief Return the first blue node. - /// - /// This function gives back the first blue node in the iteration order. - void first(BlueNode&) const {} - - /// \brief Return the next blue node. - /// - /// This function gives back the next blue node in the iteration order. - void next(BlueNode&) const {} - - - /// @} - - /// \name Class Based Iteration - /// - /// This interface provides iterator classes for red and blue nodes. - /// - /// @{ - - /// \brief This iterator goes through each red node. - /// - /// This iterator goes through each red node. - typedef GraphItemIt RedNodeIt; - - /// \brief This iterator goes through each blue node. - /// - /// This iterator goes through each blue node. - typedef GraphItemIt BlueNodeIt; - - /// @} - - template - struct Constraints { - void constraints() { - checkConcept, _BpGraph>(); - - typename _BpGraph::RedNode rn(INVALID); - bpgraph.first(rn); - bpgraph.next(rn); - typename _BpGraph::BlueNode bn(INVALID); - bpgraph.first(bn); - bpgraph.next(bn); - - checkConcept, - typename _BpGraph::RedNodeIt>(); - checkConcept, - typename _BpGraph::BlueNodeIt>(); - } - - const _BpGraph& bpgraph; - }; - }; - - /// \brief Skeleton class for alterable directed graphs. - /// - /// This class describes the interface of alterable directed - /// graphs. It extends \ref BaseDigraphComponent with the alteration - /// notifier interface. It implements - /// an observer-notifier pattern for each digraph item. More - /// obsevers can be registered into the notifier and whenever an - /// alteration occured in the digraph all the observers will be - /// notified about it. - template - class AlterableDigraphComponent : public BAS { - public: - - typedef BAS Base; - typedef typename Base::Node Node; - typedef typename Base::Arc Arc; - - - /// Node alteration notifier class. - typedef AlterationNotifier - NodeNotifier; - /// Arc alteration notifier class. - typedef AlterationNotifier - ArcNotifier; - - mutable NodeNotifier node_notifier; - mutable ArcNotifier arc_notifier; - - /// \brief Return the node alteration notifier. - /// - /// This function gives back the node alteration notifier. - NodeNotifier& notifier(Node) const { - return node_notifier; - } - - /// \brief Return the arc alteration notifier. - /// - /// This function gives back the arc alteration notifier. - ArcNotifier& notifier(Arc) const { - return arc_notifier; - } - - template - struct Constraints { - void constraints() { - checkConcept(); - typename _Digraph::NodeNotifier& nn - = digraph.notifier(typename _Digraph::Node()); - - typename _Digraph::ArcNotifier& en - = digraph.notifier(typename _Digraph::Arc()); - - ::lemon::ignore_unused_variable_warning(nn); - ::lemon::ignore_unused_variable_warning(en); - } - - const _Digraph& digraph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for alterable undirected graphs. - /// - /// This class describes the interface of alterable undirected - /// graphs. It extends \ref AlterableDigraphComponent with the alteration - /// notifier interface of undirected graphs. It implements - /// an observer-notifier pattern for the edges. More - /// obsevers can be registered into the notifier and whenever an - /// alteration occured in the graph all the observers will be - /// notified about it. - template - class AlterableGraphComponent : public AlterableDigraphComponent { - public: - - typedef BAS Base; - typedef AlterableDigraphComponent Parent; - typedef typename Base::Edge Edge; - - - /// Edge alteration notifier class. - typedef AlterationNotifier - EdgeNotifier; - - mutable EdgeNotifier edge_notifier; - - using Parent::notifier; - - /// \brief Return the edge alteration notifier. - /// - /// This function gives back the edge alteration notifier. - EdgeNotifier& notifier(Edge) const { - return edge_notifier; - } - - template - struct Constraints { - void constraints() { - checkConcept, _Graph>(); - typename _Graph::EdgeNotifier& uen - = graph.notifier(typename _Graph::Edge()); - ::lemon::ignore_unused_variable_warning(uen); - } - - const _Graph& graph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for alterable undirected bipartite graphs. - /// - /// This class describes the interface of alterable undirected - /// bipartite graphs. It extends \ref AlterableGraphComponent with - /// the alteration notifier interface of bipartite graphs. It - /// implements an observer-notifier pattern for the red and blue - /// nodes. More obsevers can be registered into the notifier and - /// whenever an alteration occured in the graph all the observers - /// will be notified about it. - template - class AlterableBpGraphComponent : public AlterableGraphComponent { - public: - - typedef BAS Base; - typedef AlterableGraphComponent Parent; - typedef typename Base::RedNode RedNode; - typedef typename Base::BlueNode BlueNode; - - - /// Red node alteration notifier class. - typedef AlterationNotifier - RedNodeNotifier; - - /// Blue node alteration notifier class. - typedef AlterationNotifier - BlueNodeNotifier; - - mutable RedNodeNotifier red_node_notifier; - mutable BlueNodeNotifier blue_node_notifier; - - using Parent::notifier; - - /// \brief Return the red node alteration notifier. - /// - /// This function gives back the red node alteration notifier. - RedNodeNotifier& notifier(RedNode) const { - return red_node_notifier; - } - - /// \brief Return the blue node alteration notifier. - /// - /// This function gives back the blue node alteration notifier. - BlueNodeNotifier& notifier(BlueNode) const { - return blue_node_notifier; - } - - template - struct Constraints { - void constraints() { - checkConcept, _BpGraph>(); - typename _BpGraph::RedNodeNotifier& rnn - = bpgraph.notifier(typename _BpGraph::RedNode()); - typename _BpGraph::BlueNodeNotifier& bnn - = bpgraph.notifier(typename _BpGraph::BlueNode()); - ::lemon::ignore_unused_variable_warning(rnn); - ::lemon::ignore_unused_variable_warning(bnn); - } - - const _BpGraph& bpgraph; - }; - }; - - /// \brief Concept class for standard graph maps. - /// - /// This class describes the concept of standard graph maps, i.e. - /// the \c NodeMap, \c ArcMap and \c EdgeMap subtypes of digraph and - /// graph types, which can be used for associating data to graph items. - /// The standard graph maps must conform to the ReferenceMap concept. - template - class GraphMap : public ReferenceMap { - typedef ReferenceMap Parent; - - public: - - /// The key type of the map. - typedef K Key; - /// The value type of the map. - typedef V Value; - /// The reference type of the map. - typedef Value& Reference; - /// The const reference type of the map. - typedef const Value& ConstReference; - - // The reference map tag. - typedef True ReferenceMapTag; - - /// \brief Construct a new map. - /// - /// Construct a new map for the graph. - explicit GraphMap(const GR&) {} - /// \brief Construct a new map with default value. - /// - /// Construct a new map for the graph and initalize the values. - GraphMap(const GR&, const Value&) {} - - private: - /// \brief Copy constructor. - /// - /// Copy Constructor. - GraphMap(const GraphMap&) : Parent() {} - - /// \brief Assignment operator. - /// - /// Assignment operator. It does not mofify the underlying graph, - /// it just iterates on the current item set and set the map - /// with the value returned by the assigned map. - template - GraphMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - - public: - template - struct Constraints { - void constraints() { - checkConcept - , _Map>(); - _Map m1(g); - _Map m2(g,t); - - // Copy constructor - // _Map m3(m); - - // Assignment operator - // ReadMap cmap; - // m3 = cmap; - - ::lemon::ignore_unused_variable_warning(m1); - ::lemon::ignore_unused_variable_warning(m2); - // ::lemon::ignore_unused_variable_warning(m3); - } - - const _Map &m; - const GR &g; - const typename GraphMap::Value &t; - Constraints() {} - }; - - }; - - /// \brief Skeleton class for mappable directed graphs. - /// - /// This class describes the interface of mappable directed graphs. - /// It extends \ref BaseDigraphComponent with the standard digraph - /// map classes, namely \c NodeMap and \c ArcMap. - /// This concept is part of the Digraph concept. - template - class MappableDigraphComponent : public BAS { - public: - - typedef BAS Base; - typedef typename Base::Node Node; - typedef typename Base::Arc Arc; - - typedef MappableDigraphComponent Digraph; - - /// \brief Standard graph map for the nodes. - /// - /// Standard graph map for the nodes. - /// It conforms to the ReferenceMap concept. - template - class NodeMap : public GraphMap { - typedef GraphMap Parent; - - public: - /// \brief Construct a new map. - /// - /// Construct a new map for the digraph. - explicit NodeMap(const MappableDigraphComponent& digraph) - : Parent(digraph) {} - - /// \brief Construct a new map with default value. - /// - /// Construct a new map for the digraph and initalize the values. - NodeMap(const MappableDigraphComponent& digraph, const V& value) - : Parent(digraph, value) {} - - private: - /// \brief Copy constructor. - /// - /// Copy Constructor. - NodeMap(const NodeMap& nm) : Parent(nm) {} - - /// \brief Assignment operator. - /// - /// Assignment operator. - template - NodeMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - - }; - - /// \brief Standard graph map for the arcs. - /// - /// Standard graph map for the arcs. - /// It conforms to the ReferenceMap concept. - template - class ArcMap : public GraphMap { - typedef GraphMap Parent; - - public: - /// \brief Construct a new map. - /// - /// Construct a new map for the digraph. - explicit ArcMap(const MappableDigraphComponent& digraph) - : Parent(digraph) {} - - /// \brief Construct a new map with default value. - /// - /// Construct a new map for the digraph and initalize the values. - ArcMap(const MappableDigraphComponent& digraph, const V& value) - : Parent(digraph, value) {} - - private: - /// \brief Copy constructor. - /// - /// Copy Constructor. - ArcMap(const ArcMap& nm) : Parent(nm) {} - - /// \brief Assignment operator. - /// - /// Assignment operator. - template - ArcMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - - }; - - - template - struct Constraints { - - struct Dummy { - int value; - Dummy() : value(0) {} - Dummy(int _v) : value(_v) {} - }; - - void constraints() { - checkConcept(); - { // int map test - typedef typename _Digraph::template NodeMap IntNodeMap; - checkConcept, - IntNodeMap >(); - } { // bool map test - typedef typename _Digraph::template NodeMap BoolNodeMap; - checkConcept, - BoolNodeMap >(); - } { // Dummy map test - typedef typename _Digraph::template NodeMap DummyNodeMap; - checkConcept, - DummyNodeMap >(); - } - - { // int map test - typedef typename _Digraph::template ArcMap IntArcMap; - checkConcept, - IntArcMap >(); - } { // bool map test - typedef typename _Digraph::template ArcMap BoolArcMap; - checkConcept, - BoolArcMap >(); - } { // Dummy map test - typedef typename _Digraph::template ArcMap DummyArcMap; - checkConcept, - DummyArcMap >(); - } - } - - const _Digraph& digraph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for mappable undirected graphs. - /// - /// This class describes the interface of mappable undirected graphs. - /// It extends \ref MappableDigraphComponent with the standard graph - /// map class for edges (\c EdgeMap). - /// This concept is part of the Graph concept. - template - class MappableGraphComponent : public MappableDigraphComponent { - public: - - typedef BAS Base; - typedef typename Base::Edge Edge; - - typedef MappableGraphComponent Graph; - - /// \brief Standard graph map for the edges. - /// - /// Standard graph map for the edges. - /// It conforms to the ReferenceMap concept. - template - class EdgeMap : public GraphMap { - typedef GraphMap Parent; - - public: - /// \brief Construct a new map. - /// - /// Construct a new map for the graph. - explicit EdgeMap(const MappableGraphComponent& graph) - : Parent(graph) {} - - /// \brief Construct a new map with default value. - /// - /// Construct a new map for the graph and initalize the values. - EdgeMap(const MappableGraphComponent& graph, const V& value) - : Parent(graph, value) {} - - private: - /// \brief Copy constructor. - /// - /// Copy Constructor. - EdgeMap(const EdgeMap& nm) : Parent(nm) {} - - /// \brief Assignment operator. - /// - /// Assignment operator. - template - EdgeMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - - }; - - - template - struct Constraints { - - struct Dummy { - int value; - Dummy() : value(0) {} - Dummy(int _v) : value(_v) {} - }; - - void constraints() { - checkConcept, _Graph>(); - - { // int map test - typedef typename _Graph::template EdgeMap IntEdgeMap; - checkConcept, - IntEdgeMap >(); - } { // bool map test - typedef typename _Graph::template EdgeMap BoolEdgeMap; - checkConcept, - BoolEdgeMap >(); - } { // Dummy map test - typedef typename _Graph::template EdgeMap DummyEdgeMap; - checkConcept, - DummyEdgeMap >(); - } - } - - const _Graph& graph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for mappable undirected bipartite graphs. - /// - /// This class describes the interface of mappable undirected - /// bipartite graphs. It extends \ref MappableGraphComponent with - /// the standard graph map class for red and blue nodes (\c - /// RedNodeMap and BlueNodeMap). This concept is part of the - /// BpGraph concept. - template - class MappableBpGraphComponent : public MappableGraphComponent { - public: - - typedef BAS Base; - typedef typename Base::Node Node; - - typedef MappableBpGraphComponent BpGraph; - - /// \brief Standard graph map for the red nodes. - /// - /// Standard graph map for the red nodes. - /// It conforms to the ReferenceMap concept. - template - class RedNodeMap : public GraphMap { - typedef GraphMap Parent; - - public: - /// \brief Construct a new map. - /// - /// Construct a new map for the graph. - explicit RedNodeMap(const MappableBpGraphComponent& graph) - : Parent(graph) {} - - /// \brief Construct a new map with default value. - /// - /// Construct a new map for the graph and initalize the values. - RedNodeMap(const MappableBpGraphComponent& graph, const V& value) - : Parent(graph, value) {} - - private: - /// \brief Copy constructor. - /// - /// Copy Constructor. - RedNodeMap(const RedNodeMap& nm) : Parent(nm) {} - - /// \brief Assignment operator. - /// - /// Assignment operator. - template - RedNodeMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - - }; - - /// \brief Standard graph map for the blue nodes. - /// - /// Standard graph map for the blue nodes. - /// It conforms to the ReferenceMap concept. - template - class BlueNodeMap : public GraphMap { - typedef GraphMap Parent; - - public: - /// \brief Construct a new map. - /// - /// Construct a new map for the graph. - explicit BlueNodeMap(const MappableBpGraphComponent& graph) - : Parent(graph) {} - - /// \brief Construct a new map with default value. - /// - /// Construct a new map for the graph and initalize the values. - BlueNodeMap(const MappableBpGraphComponent& graph, const V& value) - : Parent(graph, value) {} - - private: - /// \brief Copy constructor. - /// - /// Copy Constructor. - BlueNodeMap(const BlueNodeMap& nm) : Parent(nm) {} - - /// \brief Assignment operator. - /// - /// Assignment operator. - template - BlueNodeMap& operator=(const CMap&) { - checkConcept, CMap>(); - return *this; - } - - }; - - - template - struct Constraints { - - struct Dummy { - int value; - Dummy() : value(0) {} - Dummy(int _v) : value(_v) {} - }; - - void constraints() { - checkConcept, _BpGraph>(); - - { // int map test - typedef typename _BpGraph::template RedNodeMap - IntRedNodeMap; - checkConcept, - IntRedNodeMap >(); - } { // bool map test - typedef typename _BpGraph::template RedNodeMap - BoolRedNodeMap; - checkConcept, - BoolRedNodeMap >(); - } { // Dummy map test - typedef typename _BpGraph::template RedNodeMap - DummyRedNodeMap; - checkConcept, - DummyRedNodeMap >(); - } - - { // int map test - typedef typename _BpGraph::template BlueNodeMap - IntBlueNodeMap; - checkConcept, - IntBlueNodeMap >(); - } { // bool map test - typedef typename _BpGraph::template BlueNodeMap - BoolBlueNodeMap; - checkConcept, - BoolBlueNodeMap >(); - } { // Dummy map test - typedef typename _BpGraph::template BlueNodeMap - DummyBlueNodeMap; - checkConcept, - DummyBlueNodeMap >(); - } - } - - const _BpGraph& bpgraph; - }; - }; - - /// \brief Skeleton class for extendable directed graphs. - /// - /// This class describes the interface of extendable directed graphs. - /// It extends \ref BaseDigraphComponent with functions for adding - /// nodes and arcs to the digraph. - /// This concept requires \ref AlterableDigraphComponent. - template - class ExtendableDigraphComponent : public BAS { - public: - typedef BAS Base; - - typedef typename Base::Node Node; - typedef typename Base::Arc Arc; - - /// \brief Add a new node to the digraph. - /// - /// This function adds a new node to the digraph. - Node addNode() { - return INVALID; - } - - /// \brief Add a new arc connecting the given two nodes. - /// - /// This function adds a new arc connecting the given two nodes - /// of the digraph. - Arc addArc(const Node&, const Node&) { - return INVALID; - } - - template - struct Constraints { - void constraints() { - checkConcept(); - typename _Digraph::Node node_a, node_b; - node_a = digraph.addNode(); - node_b = digraph.addNode(); - typename _Digraph::Arc arc; - arc = digraph.addArc(node_a, node_b); - } - - _Digraph& digraph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for extendable undirected graphs. - /// - /// This class describes the interface of extendable undirected graphs. - /// It extends \ref BaseGraphComponent with functions for adding - /// nodes and edges to the graph. - /// This concept requires \ref AlterableGraphComponent. - template - class ExtendableGraphComponent : public BAS { - public: - - typedef BAS Base; - typedef typename Base::Node Node; - typedef typename Base::Edge Edge; - - /// \brief Add a new node to the digraph. - /// - /// This function adds a new node to the digraph. - Node addNode() { - return INVALID; - } - - /// \brief Add a new edge connecting the given two nodes. - /// - /// This function adds a new edge connecting the given two nodes - /// of the graph. - Edge addEdge(const Node&, const Node&) { - return INVALID; - } - - template - struct Constraints { - void constraints() { - checkConcept(); - typename _Graph::Node node_a, node_b; - node_a = graph.addNode(); - node_b = graph.addNode(); - typename _Graph::Edge edge; - edge = graph.addEdge(node_a, node_b); - } - - _Graph& graph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for extendable undirected bipartite graphs. - /// - /// This class describes the interface of extendable undirected - /// bipartite graphs. It extends \ref BaseGraphComponent with - /// functions for adding nodes and edges to the graph. This - /// concept requires \ref AlterableBpGraphComponent. - template - class ExtendableBpGraphComponent : public BAS { - public: - - typedef BAS Base; - typedef typename Base::Node Node; - typedef typename Base::RedNode RedNode; - typedef typename Base::BlueNode BlueNode; - typedef typename Base::Edge Edge; - - /// \brief Add a new red node to the digraph. - /// - /// This function adds a red new node to the digraph. - RedNode addRedNode() { - return INVALID; - } - - /// \brief Add a new blue node to the digraph. - /// - /// This function adds a blue new node to the digraph. - BlueNode addBlueNode() { - return INVALID; - } - - /// \brief Add a new edge connecting the given two nodes. - /// - /// This function adds a new edge connecting the given two nodes - /// of the graph. The first node has to be a red node, and the - /// second one a blue node. - Edge addEdge(const RedNode&, const BlueNode&) { - return INVALID; - } - Edge addEdge(const BlueNode&, const RedNode&) { - return INVALID; - } - - template - struct Constraints { - void constraints() { - checkConcept(); - typename _BpGraph::RedNode red_node; - typename _BpGraph::BlueNode blue_node; - red_node = bpgraph.addRedNode(); - blue_node = bpgraph.addBlueNode(); - typename _BpGraph::Edge edge; - edge = bpgraph.addEdge(red_node, blue_node); - edge = bpgraph.addEdge(blue_node, red_node); - } - - _BpGraph& bpgraph; - }; - }; - - /// \brief Skeleton class for erasable directed graphs. - /// - /// This class describes the interface of erasable directed graphs. - /// It extends \ref BaseDigraphComponent with functions for removing - /// nodes and arcs from the digraph. - /// This concept requires \ref AlterableDigraphComponent. - template - class ErasableDigraphComponent : public BAS { - public: - - typedef BAS Base; - typedef typename Base::Node Node; - typedef typename Base::Arc Arc; - - /// \brief Erase a node from the digraph. - /// - /// This function erases the given node from the digraph and all arcs - /// connected to the node. - void erase(const Node&) {} - - /// \brief Erase an arc from the digraph. - /// - /// This function erases the given arc from the digraph. - void erase(const Arc&) {} - - template - struct Constraints { - void constraints() { - checkConcept(); - const typename _Digraph::Node node(INVALID); - digraph.erase(node); - const typename _Digraph::Arc arc(INVALID); - digraph.erase(arc); - } - - _Digraph& digraph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for erasable undirected graphs. - /// - /// This class describes the interface of erasable undirected graphs. - /// It extends \ref BaseGraphComponent with functions for removing - /// nodes and edges from the graph. - /// This concept requires \ref AlterableGraphComponent. - template - class ErasableGraphComponent : public BAS { - public: - - typedef BAS Base; - typedef typename Base::Node Node; - typedef typename Base::Edge Edge; - - /// \brief Erase a node from the graph. - /// - /// This function erases the given node from the graph and all edges - /// connected to the node. - void erase(const Node&) {} - - /// \brief Erase an edge from the digraph. - /// - /// This function erases the given edge from the digraph. - void erase(const Edge&) {} - - template - struct Constraints { - void constraints() { - checkConcept(); - const typename _Graph::Node node(INVALID); - graph.erase(node); - const typename _Graph::Edge edge(INVALID); - graph.erase(edge); - } - - _Graph& graph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for erasable undirected graphs. - /// - /// This class describes the interface of erasable undirected - /// bipartite graphs. It extends \ref BaseBpGraphComponent with - /// functions for removing nodes and edges from the graph. This - /// concept requires \ref AlterableBpGraphComponent. - template - class ErasableBpGraphComponent : public ErasableGraphComponent {}; - - /// \brief Skeleton class for clearable directed graphs. - /// - /// This class describes the interface of clearable directed graphs. - /// It extends \ref BaseDigraphComponent with a function for clearing - /// the digraph. - /// This concept requires \ref AlterableDigraphComponent. - template - class ClearableDigraphComponent : public BAS { - public: - - typedef BAS Base; - - /// \brief Erase all nodes and arcs from the digraph. - /// - /// This function erases all nodes and arcs from the digraph. - void clear() {} - - template - struct Constraints { - void constraints() { - checkConcept(); - digraph.clear(); - } - - _Digraph& digraph; - Constraints() {} - }; - }; - - /// \brief Skeleton class for clearable undirected graphs. - /// - /// This class describes the interface of clearable undirected graphs. - /// It extends \ref BaseGraphComponent with a function for clearing - /// the graph. - /// This concept requires \ref AlterableGraphComponent. - template - class ClearableGraphComponent : public ClearableDigraphComponent {}; - - /// \brief Skeleton class for clearable undirected biparite graphs. - /// - /// This class describes the interface of clearable undirected - /// bipartite graphs. It extends \ref BaseBpGraphComponent with a - /// function for clearing the graph. This concept requires \ref - /// AlterableBpGraphComponent. - template - class ClearableBpGraphComponent : public ClearableGraphComponent {}; - - } - -} - -#endif diff --git a/deps/lemon/lemon/concepts/heap.h b/deps/lemon/lemon/concepts/heap.h deleted file mode 100644 index 8c7a25121..000000000 --- a/deps/lemon/lemon/concepts/heap.h +++ /dev/null @@ -1,324 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_CONCEPTS_HEAP_H -#define LEMON_CONCEPTS_HEAP_H - -///\ingroup concept -///\file -///\brief The concept of heaps. - -#include -#include - -namespace lemon { - - namespace concepts { - - /// \addtogroup concept - /// @{ - - /// \brief The heap concept. - /// - /// This concept class describes the main interface of heaps. - /// The various \ref heaps "heap structures" are efficient - /// implementations of the abstract data type \e priority \e queue. - /// They store items with specified values called \e priorities - /// in such a way that finding and removing the item with minimum - /// priority are efficient. The basic operations are adding and - /// erasing items, changing the priority of an item, etc. - /// - /// Heaps are crucial in several algorithms, such as Dijkstra and Prim. - /// Any class that conforms to this concept can be used easily in such - /// algorithms. - /// - /// \tparam PR Type of the priorities of the items. - /// \tparam IM A read-writable item map with \c int values, used - /// internally to handle the cross references. - /// \tparam CMP A functor class for comparing the priorities. - /// The default is \c std::less. -#ifdef DOXYGEN - template -#else - template > -#endif - class Heap { - public: - - /// Type of the item-int map. - typedef IM ItemIntMap; - /// Type of the priorities. - typedef PR Prio; - /// Type of the items stored in the heap. - typedef typename ItemIntMap::Key Item; - - /// \brief Type to represent the states of the items. - /// - /// Each item has a state associated to it. It can be "in heap", - /// "pre-heap" or "post-heap". The latter two are indifferent from the - /// heap's point of view, but may be useful to the user. - /// - /// The item-int map must be initialized in such way that it assigns - /// \c PRE_HEAP (-1) to any element to be put in the heap. - enum State { - IN_HEAP = 0, ///< = 0. The "in heap" state constant. - PRE_HEAP = -1, ///< = -1. The "pre-heap" state constant. - POST_HEAP = -2 ///< = -2. The "post-heap" state constant. - }; - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to keys of type - /// \c Item. It is used internally by the heap implementations to - /// handle the cross references. The assigned value must be - /// \c PRE_HEAP (-1) for each item. -#ifdef DOXYGEN - explicit Heap(ItemIntMap &map) {} -#else - explicit Heap(ItemIntMap&) {} -#endif - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to keys of type - /// \c Item. It is used internally by the heap implementations to - /// handle the cross references. The assigned value must be - /// \c PRE_HEAP (-1) for each item. - /// \param comp The function object used for comparing the priorities. -#ifdef DOXYGEN - explicit Heap(ItemIntMap &map, const CMP &comp) {} -#else - explicit Heap(ItemIntMap&, const CMP&) {} -#endif - - /// \brief The number of items stored in the heap. - /// - /// This function returns the number of items stored in the heap. - int size() const { return 0; } - - /// \brief Check if the heap is empty. - /// - /// This function returns \c true if the heap is empty. - bool empty() const { return false; } - - /// \brief Make the heap empty. - /// - /// This functon makes the heap empty. - /// It does not change the cross reference map. If you want to reuse - /// a heap that is not surely empty, you should first clear it and - /// then you should set the cross reference map to \c PRE_HEAP - /// for each item. - void clear() {} - - /// \brief Insert an item into the heap with the given priority. - /// - /// This function inserts the given item into the heap with the - /// given priority. - /// \param i The item to insert. - /// \param p The priority of the item. - /// \pre \e i must not be stored in the heap. -#ifdef DOXYGEN - void push(const Item &i, const Prio &p) {} -#else - void push(const Item&, const Prio&) {} -#endif - - /// \brief Return the item having minimum priority. - /// - /// This function returns the item having minimum priority. - /// \pre The heap must be non-empty. - Item top() const { return Item(); } - - /// \brief The minimum priority. - /// - /// This function returns the minimum priority. - /// \pre The heap must be non-empty. - Prio prio() const { return Prio(); } - - /// \brief Remove the item having minimum priority. - /// - /// This function removes the item having minimum priority. - /// \pre The heap must be non-empty. - void pop() {} - - /// \brief Remove the given item from the heap. - /// - /// This function removes the given item from the heap if it is - /// already stored. - /// \param i The item to delete. - /// \pre \e i must be in the heap. -#ifdef DOXYGEN - void erase(const Item &i) {} -#else - void erase(const Item&) {} -#endif - - /// \brief The priority of the given item. - /// - /// This function returns the priority of the given item. - /// \param i The item. - /// \pre \e i must be in the heap. -#ifdef DOXYGEN - Prio operator[](const Item &i) const {} -#else - Prio operator[](const Item&) const { return Prio(); } -#endif - - /// \brief Set the priority of an item or insert it, if it is - /// not stored in the heap. - /// - /// This method sets the priority of the given item if it is - /// already stored in the heap. Otherwise it inserts the given - /// item into the heap with the given priority. - /// - /// \param i The item. - /// \param p The priority. -#ifdef DOXYGEN - void set(const Item &i, const Prio &p) {} -#else - void set(const Item&, const Prio&) {} -#endif - - /// \brief Decrease the priority of an item to the given value. - /// - /// This function decreases the priority of an item to the given value. - /// \param i The item. - /// \param p The priority. - /// \pre \e i must be stored in the heap with priority at least \e p. -#ifdef DOXYGEN - void decrease(const Item &i, const Prio &p) {} -#else - void decrease(const Item&, const Prio&) {} -#endif - - /// \brief Increase the priority of an item to the given value. - /// - /// This function increases the priority of an item to the given value. - /// \param i The item. - /// \param p The priority. - /// \pre \e i must be stored in the heap with priority at most \e p. -#ifdef DOXYGEN - void increase(const Item &i, const Prio &p) {} -#else - void increase(const Item&, const Prio&) {} -#endif - - /// \brief Return the state of an item. - /// - /// This method returns \c PRE_HEAP if the given item has never - /// been in the heap, \c IN_HEAP if it is in the heap at the moment, - /// and \c POST_HEAP otherwise. - /// In the latter case it is possible that the item will get back - /// to the heap again. - /// \param i The item. -#ifdef DOXYGEN - State state(const Item &i) const {} -#else - State state(const Item&) const { return PRE_HEAP; } -#endif - - /// \brief Set the state of an item in the heap. - /// - /// This function sets the state of the given item in the heap. - /// It can be used to manually clear the heap when it is important - /// to achive better time complexity. - /// \param i The item. - /// \param st The state. It should not be \c IN_HEAP. -#ifdef DOXYGEN - void state(const Item& i, State st) {} -#else - void state(const Item&, State) {} -#endif - - - template - struct Constraints { - public: - void constraints() { - typedef typename _Heap::Item OwnItem; - typedef typename _Heap::Prio OwnPrio; - typedef typename _Heap::State OwnState; - - Item item; - Prio prio; - item=Item(); - prio=Prio(); - ::lemon::ignore_unused_variable_warning(item); - ::lemon::ignore_unused_variable_warning(prio); - - OwnItem own_item; - OwnPrio own_prio; - OwnState own_state; - own_item=Item(); - own_prio=Prio(); - ::lemon::ignore_unused_variable_warning(own_item); - ::lemon::ignore_unused_variable_warning(own_prio); - ::lemon::ignore_unused_variable_warning(own_state); - - _Heap heap1(map); - _Heap heap2 = heap1; - ::lemon::ignore_unused_variable_warning(heap1); - ::lemon::ignore_unused_variable_warning(heap2); - - int s = heap.size(); - ::lemon::ignore_unused_variable_warning(s); - bool e = heap.empty(); - ::lemon::ignore_unused_variable_warning(e); - - prio = heap.prio(); - item = heap.top(); - prio = heap[item]; - own_prio = heap.prio(); - own_item = heap.top(); - own_prio = heap[own_item]; - - heap.push(item, prio); - heap.push(own_item, own_prio); - heap.pop(); - - heap.set(item, prio); - heap.decrease(item, prio); - heap.increase(item, prio); - heap.set(own_item, own_prio); - heap.decrease(own_item, own_prio); - heap.increase(own_item, own_prio); - - heap.erase(item); - heap.erase(own_item); - heap.clear(); - - own_state = heap.state(own_item); - heap.state(own_item, own_state); - - own_state = _Heap::PRE_HEAP; - own_state = _Heap::IN_HEAP; - own_state = _Heap::POST_HEAP; - } - - _Heap& heap; - ItemIntMap& map; - Constraints() {} - }; - }; - - /// @} - } // namespace lemon -} -#endif diff --git a/deps/lemon/lemon/concepts/maps.h b/deps/lemon/lemon/concepts/maps.h deleted file mode 100644 index 88b66b511..000000000 --- a/deps/lemon/lemon/concepts/maps.h +++ /dev/null @@ -1,223 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_CONCEPTS_MAPS_H -#define LEMON_CONCEPTS_MAPS_H - -#include -#include - -///\ingroup map_concepts -///\file -///\brief The concept of maps. - -namespace lemon { - - namespace concepts { - - /// \addtogroup map_concepts - /// @{ - - /// Readable map concept - - /// Readable map concept. - /// - template - class ReadMap - { - public: - /// The key type of the map. - typedef K Key; - /// \brief The value type of the map. - /// (The type of objects associated with the keys). - typedef T Value; - - /// Returns the value associated with the given key. - Value operator[](const Key &) const { - return *(static_cast(0)+1); - } - - template - struct Constraints { - void constraints() { - Value val = m[key]; - val = m[key]; - typename _ReadMap::Value own_val = m[own_key]; - own_val = m[own_key]; - - ::lemon::ignore_unused_variable_warning(key); - ::lemon::ignore_unused_variable_warning(val); - ::lemon::ignore_unused_variable_warning(own_key); - ::lemon::ignore_unused_variable_warning(own_val); - } - const Key& key; - const typename _ReadMap::Key& own_key; - const _ReadMap& m; - Constraints() {} - }; - - }; - - - /// Writable map concept - - /// Writable map concept. - /// - template - class WriteMap - { - public: - /// The key type of the map. - typedef K Key; - /// \brief The value type of the map. - /// (The type of objects associated with the keys). - typedef T Value; - - /// Sets the value associated with the given key. - void set(const Key &, const Value &) {} - - /// Default constructor. - WriteMap() {} - - template - struct Constraints { - void constraints() { - m.set(key, val); - m.set(own_key, own_val); - - ::lemon::ignore_unused_variable_warning(key); - ::lemon::ignore_unused_variable_warning(val); - ::lemon::ignore_unused_variable_warning(own_key); - ::lemon::ignore_unused_variable_warning(own_val); - } - const Key& key; - const Value& val; - const typename _WriteMap::Key& own_key; - const typename _WriteMap::Value& own_val; - _WriteMap& m; - Constraints() {} - }; - }; - - /// Read/writable map concept - - /// Read/writable map concept. - /// - template - class ReadWriteMap : public ReadMap, - public WriteMap - { - public: - /// The key type of the map. - typedef K Key; - /// \brief The value type of the map. - /// (The type of objects associated with the keys). - typedef T Value; - - /// Returns the value associated with the given key. - Value operator[](const Key &) const { - Value *r = 0; - return *r; - } - - /// Sets the value associated with the given key. - void set(const Key &, const Value &) {} - - template - struct Constraints { - void constraints() { - checkConcept, _ReadWriteMap >(); - checkConcept, _ReadWriteMap >(); - } - }; - }; - - - /// Dereferable map concept - - /// Dereferable map concept. - /// - template - class ReferenceMap : public ReadWriteMap - { - public: - /// Tag for reference maps. - typedef True ReferenceMapTag; - /// The key type of the map. - typedef K Key; - /// \brief The value type of the map. - /// (The type of objects associated with the keys). - typedef T Value; - /// The reference type of the map. - typedef R Reference; - /// The const reference type of the map. - typedef CR ConstReference; - - public: - - /// Returns a reference to the value associated with the given key. - Reference operator[](const Key &) { - Value *r = 0; - return *r; - } - - /// Returns a const reference to the value associated with the given key. - ConstReference operator[](const Key &) const { - Value *r = 0; - return *r; - } - - /// Sets the value associated with the given key. - void set(const Key &k,const Value &t) { operator[](k)=t; } - - template - struct Constraints { - typename enable_if::type - constraints() { - checkConcept, _ReferenceMap >(); - ref = m[key]; - m[key] = val; - m[key] = ref; - m[key] = cref; - own_ref = m[own_key]; - m[own_key] = own_val; - m[own_key] = own_ref; - m[own_key] = own_cref; - m[key] = m[own_key]; - m[own_key] = m[key]; - } - const Key& key; - Value& val; - Reference ref; - ConstReference cref; - const typename _ReferenceMap::Key& own_key; - typename _ReferenceMap::Value& own_val; - typename _ReferenceMap::Reference own_ref; - typename _ReferenceMap::ConstReference own_cref; - _ReferenceMap& m; - Constraints() {} - }; - }; - - // @} - - } //namespace concepts - -} //namespace lemon - -#endif diff --git a/deps/lemon/lemon/concepts/path.h b/deps/lemon/lemon/concepts/path.h deleted file mode 100644 index 18e4b0180..000000000 --- a/deps/lemon/lemon/concepts/path.h +++ /dev/null @@ -1,312 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\ingroup concept -///\file -///\brief The concept of paths -/// - -#ifndef LEMON_CONCEPTS_PATH_H -#define LEMON_CONCEPTS_PATH_H - -#include -#include - -namespace lemon { - namespace concepts { - - /// \addtogroup concept - /// @{ - - /// \brief A skeleton structure for representing directed paths in - /// a digraph. - /// - /// A skeleton structure for representing directed paths in a - /// digraph. - /// In a sense, a path can be treated as a list of arcs. - /// LEMON path types just store this list. As a consequence, they cannot - /// enumerate the nodes on the path directly and a zero length path - /// cannot store its source node. - /// - /// The arcs of a path should be stored in the order of their directions, - /// i.e. the target node of each arc should be the same as the source - /// node of the next arc. This consistency could be checked using - /// \ref checkPath(). - /// The source and target nodes of a (consistent) path can be obtained - /// using \ref pathSource() and \ref pathTarget(). - /// - /// A path can be constructed from another path of any type using the - /// copy constructor or the assignment operator. - /// - /// \tparam GR The digraph type in which the path is. - template - class Path { - public: - - /// Type of the underlying digraph. - typedef GR Digraph; - /// Arc type of the underlying digraph. - typedef typename Digraph::Arc Arc; - - class ArcIt; - - /// \brief Default constructor - Path() {} - - /// \brief Template copy constructor - template - Path(const CPath& cpath) {} - - /// \brief Template assigment operator - template - Path& operator=(const CPath& cpath) { - ::lemon::ignore_unused_variable_warning(cpath); - return *this; - } - - /// Length of the path, i.e. the number of arcs on the path. - int length() const { return 0;} - - /// Returns whether the path is empty. - bool empty() const { return true;} - - /// Resets the path to an empty path. - void clear() {} - - /// \brief LEMON style iterator for enumerating the arcs of a path. - /// - /// LEMON style iterator class for enumerating the arcs of a path. - class ArcIt { - public: - /// Default constructor - ArcIt() {} - /// Invalid constructor - ArcIt(Invalid) {} - /// Sets the iterator to the first arc of the given path - ArcIt(const Path &) {} - - /// Conversion to \c Arc - operator Arc() const { return INVALID; } - - /// Next arc - ArcIt& operator++() {return *this;} - - /// Comparison operator - bool operator==(const ArcIt&) const {return true;} - /// Comparison operator - bool operator!=(const ArcIt&) const {return true;} - /// Comparison operator - bool operator<(const ArcIt&) const {return false;} - - }; - - template - struct Constraints { - void constraints() { - Path pc; - _Path p, pp(pc); - int l = p.length(); - int e = p.empty(); - p.clear(); - - p = pc; - - typename _Path::ArcIt id, ii(INVALID), i(p); - - ++i; - typename Digraph::Arc ed = i; - - e = (i == ii); - e = (i != ii); - e = (i < ii); - - ::lemon::ignore_unused_variable_warning(l); - ::lemon::ignore_unused_variable_warning(pp); - ::lemon::ignore_unused_variable_warning(e); - ::lemon::ignore_unused_variable_warning(id); - ::lemon::ignore_unused_variable_warning(ii); - ::lemon::ignore_unused_variable_warning(ed); - } - }; - - }; - - namespace _path_bits { - - template - struct PathDumperConstraints { - void constraints() { - int l = p.length(); - int e = p.empty(); - - typename _Path::ArcIt id, i(p); - - ++i; - typename _Digraph::Arc ed = i; - - e = (i == INVALID); - e = (i != INVALID); - - ::lemon::ignore_unused_variable_warning(l); - ::lemon::ignore_unused_variable_warning(e); - ::lemon::ignore_unused_variable_warning(id); - ::lemon::ignore_unused_variable_warning(ed); - } - _Path& p; - PathDumperConstraints() {} - }; - - template - struct PathDumperConstraints< - _Digraph, _Path, - typename enable_if::type - > { - void constraints() { - int l = p.length(); - int e = p.empty(); - - typename _Path::RevArcIt id, i(p); - - ++i; - typename _Digraph::Arc ed = i; - - e = (i == INVALID); - e = (i != INVALID); - - ::lemon::ignore_unused_variable_warning(l); - ::lemon::ignore_unused_variable_warning(e); - ::lemon::ignore_unused_variable_warning(id); - ::lemon::ignore_unused_variable_warning(ed); - } - _Path& p; - PathDumperConstraints() {} - }; - - } - - - /// \brief A skeleton structure for path dumpers. - /// - /// A skeleton structure for path dumpers. The path dumpers are - /// the generalization of the paths, they can enumerate the arcs - /// of the path either in forward or in backward order. - /// These classes are typically not used directly, they are rather - /// used to be assigned to a real path type. - /// - /// The main purpose of this concept is that the shortest path - /// algorithms can enumerate the arcs easily in reverse order. - /// In LEMON, such algorithms give back a (reverse) path dumper that - /// can be assigned to a real path. The dumpers can be implemented as - /// an adaptor class to the predecessor map. - /// - /// \tparam GR The digraph type in which the path is. - template - class PathDumper { - public: - - /// Type of the underlying digraph. - typedef GR Digraph; - /// Arc type of the underlying digraph. - typedef typename Digraph::Arc Arc; - - /// Length of the path, i.e. the number of arcs on the path. - int length() const { return 0;} - - /// Returns whether the path is empty. - bool empty() const { return true;} - - /// \brief Forward or reverse dumping - /// - /// If this tag is defined to be \c True, then reverse dumping - /// is provided in the path dumper. In this case, \c RevArcIt - /// iterator should be implemented instead of \c ArcIt iterator. - typedef False RevPathTag; - - /// \brief LEMON style iterator for enumerating the arcs of a path. - /// - /// LEMON style iterator class for enumerating the arcs of a path. - class ArcIt { - public: - /// Default constructor - ArcIt() {} - /// Invalid constructor - ArcIt(Invalid) {} - /// Sets the iterator to the first arc of the given path - ArcIt(const PathDumper&) {} - - /// Conversion to \c Arc - operator Arc() const { return INVALID; } - - /// Next arc - ArcIt& operator++() {return *this;} - - /// Comparison operator - bool operator==(const ArcIt&) const {return true;} - /// Comparison operator - bool operator!=(const ArcIt&) const {return true;} - /// Comparison operator - bool operator<(const ArcIt&) const {return false;} - - }; - - /// \brief LEMON style iterator for enumerating the arcs of a path - /// in reverse direction. - /// - /// LEMON style iterator class for enumerating the arcs of a path - /// in reverse direction. - class RevArcIt { - public: - /// Default constructor - RevArcIt() {} - /// Invalid constructor - RevArcIt(Invalid) {} - /// Sets the iterator to the last arc of the given path - RevArcIt(const PathDumper &) {} - - /// Conversion to \c Arc - operator Arc() const { return INVALID; } - - /// Next arc - RevArcIt& operator++() {return *this;} - - /// Comparison operator - bool operator==(const RevArcIt&) const {return true;} - /// Comparison operator - bool operator!=(const RevArcIt&) const {return true;} - /// Comparison operator - bool operator<(const RevArcIt&) const {return false;} - - }; - - template - struct Constraints { - void constraints() { - function_requires<_path_bits:: - PathDumperConstraints >(); - } - }; - - }; - - - ///@} - } - -} // namespace lemon - -#endif diff --git a/deps/lemon/lemon/config.h.in b/deps/lemon/lemon/config.h.in deleted file mode 100644 index 37d8c04d7..000000000 --- a/deps/lemon/lemon/config.h.in +++ /dev/null @@ -1,22 +0,0 @@ -#define LEMON_VERSION "@PROJECT_VERSION@" -#cmakedefine LEMON_HAVE_LONG_LONG 1 - -#cmakedefine LEMON_HAVE_LP 1 -#cmakedefine LEMON_HAVE_MIP 1 -#cmakedefine LEMON_HAVE_GLPK 1 -#cmakedefine LEMON_HAVE_CPLEX 1 -#cmakedefine LEMON_HAVE_SOPLEX 1 -#cmakedefine LEMON_HAVE_CLP 1 -#cmakedefine LEMON_HAVE_CBC 1 - -#define _LEMON_CPLEX 1 -#define _LEMON_CLP 2 -#define _LEMON_GLPK 3 -#define _LEMON_SOPLEX 4 -#define _LEMON_CBC 5 - -#cmakedefine LEMON_DEFAULT_LP _LEMON_@LEMON_DEFAULT_LP@ -#cmakedefine LEMON_DEFAULT_MIP _LEMON_@LEMON_DEFAULT_MIP@ - -#cmakedefine LEMON_USE_PTHREAD 1 -#cmakedefine LEMON_USE_WIN32_THREADS 1 diff --git a/deps/lemon/lemon/connectivity.h b/deps/lemon/lemon/connectivity.h deleted file mode 100644 index 6bd85a188..000000000 --- a/deps/lemon/lemon/connectivity.h +++ /dev/null @@ -1,1688 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_CONNECTIVITY_H -#define LEMON_CONNECTIVITY_H - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -/// \ingroup graph_properties -/// \file -/// \brief Connectivity algorithms -/// -/// Connectivity algorithms - -namespace lemon { - - /// \ingroup graph_properties - /// - /// \brief Check whether an undirected graph is connected. - /// - /// This function checks whether the given undirected graph is connected, - /// i.e. there is a path between any two nodes in the graph. - /// - /// \return \c true if the graph is connected. - /// \note By definition, the empty graph is connected. - /// - /// \see countConnectedComponents(), connectedComponents() - /// \see stronglyConnected() - template - bool connected(const Graph& graph) { - checkConcept(); - typedef typename Graph::NodeIt NodeIt; - if (NodeIt(graph) == INVALID) return true; - Dfs dfs(graph); - dfs.run(NodeIt(graph)); - for (NodeIt it(graph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - return false; - } - } - return true; - } - - /// \ingroup graph_properties - /// - /// \brief Count the number of connected components of an undirected graph - /// - /// This function counts the number of connected components of the given - /// undirected graph. - /// - /// The connected components are the classes of an equivalence relation - /// on the nodes of an undirected graph. Two nodes are in the same class - /// if they are connected with a path. - /// - /// \return The number of connected components. - /// \note By definition, the empty graph consists - /// of zero connected components. - /// - /// \see connected(), connectedComponents() - template - int countConnectedComponents(const Graph &graph) { - checkConcept(); - typedef typename Graph::Node Node; - typedef typename Graph::Arc Arc; - - typedef NullMap PredMap; - typedef NullMap DistMap; - - int compNum = 0; - typename Bfs:: - template SetPredMap:: - template SetDistMap:: - Create bfs(graph); - - PredMap predMap; - bfs.predMap(predMap); - - DistMap distMap; - bfs.distMap(distMap); - - bfs.init(); - for(typename Graph::NodeIt n(graph); n != INVALID; ++n) { - if (!bfs.reached(n)) { - bfs.addSource(n); - bfs.start(); - ++compNum; - } - } - return compNum; - } - - /// \ingroup graph_properties - /// - /// \brief Find the connected components of an undirected graph - /// - /// This function finds the connected components of the given undirected - /// graph. - /// - /// The connected components are the classes of an equivalence relation - /// on the nodes of an undirected graph. Two nodes are in the same class - /// if they are connected with a path. - /// - /// \image html connected_components.png - /// \image latex connected_components.eps "Connected components" width=\textwidth - /// - /// \param graph The undirected graph. - /// \retval compMap A writable node map. The values will be set from 0 to - /// the number of the connected components minus one. Each value of the map - /// will be set exactly once, and the values of a certain component will be - /// set continuously. - /// \return The number of connected components. - /// \note By definition, the empty graph consists - /// of zero connected components. - /// - /// \see connected(), countConnectedComponents() - template - int connectedComponents(const Graph &graph, NodeMap &compMap) { - checkConcept(); - typedef typename Graph::Node Node; - typedef typename Graph::Arc Arc; - checkConcept, NodeMap>(); - - typedef NullMap PredMap; - typedef NullMap DistMap; - - int compNum = 0; - typename Bfs:: - template SetPredMap:: - template SetDistMap:: - Create bfs(graph); - - PredMap predMap; - bfs.predMap(predMap); - - DistMap distMap; - bfs.distMap(distMap); - - bfs.init(); - for(typename Graph::NodeIt n(graph); n != INVALID; ++n) { - if(!bfs.reached(n)) { - bfs.addSource(n); - while (!bfs.emptyQueue()) { - compMap.set(bfs.nextNode(), compNum); - bfs.processNextNode(); - } - ++compNum; - } - } - return compNum; - } - - namespace _connectivity_bits { - - template - struct LeaveOrderVisitor : public DfsVisitor { - public: - typedef typename Digraph::Node Node; - LeaveOrderVisitor(Iterator it) : _it(it) {} - - void leave(const Node& node) { - *(_it++) = node; - } - - private: - Iterator _it; - }; - - template - struct FillMapVisitor : public DfsVisitor { - public: - typedef typename Digraph::Node Node; - typedef typename Map::Value Value; - - FillMapVisitor(Map& map, Value& value) - : _map(map), _value(value) {} - - void reach(const Node& node) { - _map.set(node, _value); - } - private: - Map& _map; - Value& _value; - }; - - template - struct StronglyConnectedCutArcsVisitor : public DfsVisitor { - public: - typedef typename Digraph::Node Node; - typedef typename Digraph::Arc Arc; - - StronglyConnectedCutArcsVisitor(const Digraph& digraph, - ArcMap& cutMap, - int& cutNum) - : _digraph(digraph), _cutMap(cutMap), _cutNum(cutNum), - _compMap(digraph, -1), _num(-1) { - } - - void start(const Node&) { - ++_num; - } - - void reach(const Node& node) { - _compMap.set(node, _num); - } - - void examine(const Arc& arc) { - if (_compMap[_digraph.source(arc)] != - _compMap[_digraph.target(arc)]) { - _cutMap.set(arc, true); - ++_cutNum; - } - } - private: - const Digraph& _digraph; - ArcMap& _cutMap; - int& _cutNum; - - typename Digraph::template NodeMap _compMap; - int _num; - }; - - } - - - /// \ingroup graph_properties - /// - /// \brief Check whether a directed graph is strongly connected. - /// - /// This function checks whether the given directed graph is strongly - /// connected, i.e. any two nodes of the digraph are - /// connected with directed paths in both direction. - /// - /// \return \c true if the digraph is strongly connected. - /// \note By definition, the empty digraph is strongly connected. - /// - /// \see countStronglyConnectedComponents(), stronglyConnectedComponents() - /// \see connected() - template - bool stronglyConnected(const Digraph& digraph) { - checkConcept(); - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - - typename Digraph::Node source = NodeIt(digraph); - if (source == INVALID) return true; - - using namespace _connectivity_bits; - - typedef DfsVisitor Visitor; - Visitor visitor; - - DfsVisit dfs(digraph, visitor); - dfs.init(); - dfs.addSource(source); - dfs.start(); - - for (NodeIt it(digraph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - return false; - } - } - - typedef ReverseDigraph RDigraph; - typedef typename RDigraph::NodeIt RNodeIt; - RDigraph rdigraph(digraph); - - typedef DfsVisitor RVisitor; - RVisitor rvisitor; - - DfsVisit rdfs(rdigraph, rvisitor); - rdfs.init(); - rdfs.addSource(source); - rdfs.start(); - - for (RNodeIt it(rdigraph); it != INVALID; ++it) { - if (!rdfs.reached(it)) { - return false; - } - } - - return true; - } - - /// \ingroup graph_properties - /// - /// \brief Count the number of strongly connected components of a - /// directed graph - /// - /// This function counts the number of strongly connected components of - /// the given directed graph. - /// - /// The strongly connected components are the classes of an - /// equivalence relation on the nodes of a digraph. Two nodes are in - /// the same class if they are connected with directed paths in both - /// direction. - /// - /// \return The number of strongly connected components. - /// \note By definition, the empty digraph has zero - /// strongly connected components. - /// - /// \see stronglyConnected(), stronglyConnectedComponents() - template - int countStronglyConnectedComponents(const Digraph& digraph) { - checkConcept(); - - using namespace _connectivity_bits; - - typedef typename Digraph::Node Node; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::ArcIt ArcIt; - - typedef std::vector Container; - typedef typename Container::iterator Iterator; - - Container nodes(countNodes(digraph)); - typedef LeaveOrderVisitor Visitor; - Visitor visitor(nodes.begin()); - - DfsVisit dfs(digraph, visitor); - dfs.init(); - for (NodeIt it(digraph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - dfs.start(); - } - } - - typedef typename Container::reverse_iterator RIterator; - typedef ReverseDigraph RDigraph; - - RDigraph rdigraph(digraph); - - typedef DfsVisitor RVisitor; - RVisitor rvisitor; - - DfsVisit rdfs(rdigraph, rvisitor); - - int compNum = 0; - - rdfs.init(); - for (RIterator it = nodes.rbegin(); it != nodes.rend(); ++it) { - if (!rdfs.reached(*it)) { - rdfs.addSource(*it); - rdfs.start(); - ++compNum; - } - } - return compNum; - } - - /// \ingroup graph_properties - /// - /// \brief Find the strongly connected components of a directed graph - /// - /// This function finds the strongly connected components of the given - /// directed graph. In addition, the numbering of the components will - /// satisfy that there is no arc going from a higher numbered component - /// to a lower one (i.e. it provides a topological order of the components). - /// - /// The strongly connected components are the classes of an - /// equivalence relation on the nodes of a digraph. Two nodes are in - /// the same class if they are connected with directed paths in both - /// direction. - /// - /// \image html strongly_connected_components.png - /// \image latex strongly_connected_components.eps "Strongly connected components" width=\textwidth - /// - /// \param digraph The digraph. - /// \retval compMap A writable node map. The values will be set from 0 to - /// the number of the strongly connected components minus one. Each value - /// of the map will be set exactly once, and the values of a certain - /// component will be set continuously. - /// \return The number of strongly connected components. - /// \note By definition, the empty digraph has zero - /// strongly connected components. - /// - /// \see stronglyConnected(), countStronglyConnectedComponents() - template - int stronglyConnectedComponents(const Digraph& digraph, NodeMap& compMap) { - checkConcept(); - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - checkConcept, NodeMap>(); - - using namespace _connectivity_bits; - - typedef std::vector Container; - typedef typename Container::iterator Iterator; - - Container nodes(countNodes(digraph)); - typedef LeaveOrderVisitor Visitor; - Visitor visitor(nodes.begin()); - - DfsVisit dfs(digraph, visitor); - dfs.init(); - for (NodeIt it(digraph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - dfs.start(); - } - } - - typedef typename Container::reverse_iterator RIterator; - typedef ReverseDigraph RDigraph; - - RDigraph rdigraph(digraph); - - int compNum = 0; - - typedef FillMapVisitor RVisitor; - RVisitor rvisitor(compMap, compNum); - - DfsVisit rdfs(rdigraph, rvisitor); - - rdfs.init(); - for (RIterator it = nodes.rbegin(); it != nodes.rend(); ++it) { - if (!rdfs.reached(*it)) { - rdfs.addSource(*it); - rdfs.start(); - ++compNum; - } - } - return compNum; - } - - /// \ingroup graph_properties - /// - /// \brief Find the cut arcs of the strongly connected components. - /// - /// This function finds the cut arcs of the strongly connected components - /// of the given digraph. - /// - /// The strongly connected components are the classes of an - /// equivalence relation on the nodes of a digraph. Two nodes are in - /// the same class if they are connected with directed paths in both - /// direction. - /// The strongly connected components are separated by the cut arcs. - /// - /// \param digraph The digraph. - /// \retval cutMap A writable arc map. The values will be set to \c true - /// for the cut arcs (exactly once for each cut arc), and will not be - /// changed for other arcs. - /// \return The number of cut arcs. - /// - /// \see stronglyConnected(), stronglyConnectedComponents() - template - int stronglyConnectedCutArcs(const Digraph& digraph, ArcMap& cutMap) { - checkConcept(); - typedef typename Digraph::Node Node; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::NodeIt NodeIt; - checkConcept, ArcMap>(); - - using namespace _connectivity_bits; - - typedef std::vector Container; - typedef typename Container::iterator Iterator; - - Container nodes(countNodes(digraph)); - typedef LeaveOrderVisitor Visitor; - Visitor visitor(nodes.begin()); - - DfsVisit dfs(digraph, visitor); - dfs.init(); - for (NodeIt it(digraph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - dfs.start(); - } - } - - typedef typename Container::reverse_iterator RIterator; - typedef ReverseDigraph RDigraph; - - RDigraph rdigraph(digraph); - - int cutNum = 0; - - typedef StronglyConnectedCutArcsVisitor RVisitor; - RVisitor rvisitor(rdigraph, cutMap, cutNum); - - DfsVisit rdfs(rdigraph, rvisitor); - - rdfs.init(); - for (RIterator it = nodes.rbegin(); it != nodes.rend(); ++it) { - if (!rdfs.reached(*it)) { - rdfs.addSource(*it); - rdfs.start(); - } - } - return cutNum; - } - - namespace _connectivity_bits { - - template - class CountBiNodeConnectedComponentsVisitor : public DfsVisitor { - public: - typedef typename Digraph::Node Node; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::Edge Edge; - - CountBiNodeConnectedComponentsVisitor(const Digraph& graph, int &compNum) - : _graph(graph), _compNum(compNum), - _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {} - - void start(const Node& node) { - _predMap.set(node, INVALID); - } - - void reach(const Node& node) { - _numMap.set(node, _num); - _retMap.set(node, _num); - ++_num; - } - - void discover(const Arc& edge) { - _predMap.set(_graph.target(edge), _graph.source(edge)); - } - - void examine(const Arc& edge) { - if (_graph.source(edge) == _graph.target(edge) && - _graph.direction(edge)) { - ++_compNum; - return; - } - if (_predMap[_graph.source(edge)] == _graph.target(edge)) { - return; - } - if (_retMap[_graph.source(edge)] > _numMap[_graph.target(edge)]) { - _retMap.set(_graph.source(edge), _numMap[_graph.target(edge)]); - } - } - - void backtrack(const Arc& edge) { - if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { - _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); - } - if (_numMap[_graph.source(edge)] <= _retMap[_graph.target(edge)]) { - ++_compNum; - } - } - - private: - const Digraph& _graph; - int& _compNum; - - typename Digraph::template NodeMap _numMap; - typename Digraph::template NodeMap _retMap; - typename Digraph::template NodeMap _predMap; - int _num; - }; - - template - class BiNodeConnectedComponentsVisitor : public DfsVisitor { - public: - typedef typename Digraph::Node Node; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::Edge Edge; - - BiNodeConnectedComponentsVisitor(const Digraph& graph, - ArcMap& compMap, int &compNum) - : _graph(graph), _compMap(compMap), _compNum(compNum), - _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {} - - void start(const Node& node) { - _predMap.set(node, INVALID); - } - - void reach(const Node& node) { - _numMap.set(node, _num); - _retMap.set(node, _num); - ++_num; - } - - void discover(const Arc& edge) { - Node target = _graph.target(edge); - _predMap.set(target, edge); - _edgeStack.push(edge); - } - - void examine(const Arc& edge) { - Node source = _graph.source(edge); - Node target = _graph.target(edge); - if (source == target && _graph.direction(edge)) { - _compMap.set(edge, _compNum); - ++_compNum; - return; - } - if (_numMap[target] < _numMap[source]) { - if (_predMap[source] != _graph.oppositeArc(edge)) { - _edgeStack.push(edge); - } - } - if (_predMap[source] != INVALID && - target == _graph.source(_predMap[source])) { - return; - } - if (_retMap[source] > _numMap[target]) { - _retMap.set(source, _numMap[target]); - } - } - - void backtrack(const Arc& edge) { - Node source = _graph.source(edge); - Node target = _graph.target(edge); - if (_retMap[source] > _retMap[target]) { - _retMap.set(source, _retMap[target]); - } - if (_numMap[source] <= _retMap[target]) { - while (_edgeStack.top() != edge) { - _compMap.set(_edgeStack.top(), _compNum); - _edgeStack.pop(); - } - _compMap.set(edge, _compNum); - _edgeStack.pop(); - ++_compNum; - } - } - - private: - const Digraph& _graph; - ArcMap& _compMap; - int& _compNum; - - typename Digraph::template NodeMap _numMap; - typename Digraph::template NodeMap _retMap; - typename Digraph::template NodeMap _predMap; - std::stack _edgeStack; - int _num; - }; - - - template - class BiNodeConnectedCutNodesVisitor : public DfsVisitor { - public: - typedef typename Digraph::Node Node; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::Edge Edge; - - BiNodeConnectedCutNodesVisitor(const Digraph& graph, NodeMap& cutMap, - int& cutNum) - : _graph(graph), _cutMap(cutMap), _cutNum(cutNum), - _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {} - - void start(const Node& node) { - _predMap.set(node, INVALID); - rootCut = false; - } - - void reach(const Node& node) { - _numMap.set(node, _num); - _retMap.set(node, _num); - ++_num; - } - - void discover(const Arc& edge) { - _predMap.set(_graph.target(edge), _graph.source(edge)); - } - - void examine(const Arc& edge) { - if (_graph.source(edge) == _graph.target(edge) && - _graph.direction(edge)) { - if (!_cutMap[_graph.source(edge)]) { - _cutMap.set(_graph.source(edge), true); - ++_cutNum; - } - return; - } - if (_predMap[_graph.source(edge)] == _graph.target(edge)) return; - if (_retMap[_graph.source(edge)] > _numMap[_graph.target(edge)]) { - _retMap.set(_graph.source(edge), _numMap[_graph.target(edge)]); - } - } - - void backtrack(const Arc& edge) { - if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { - _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); - } - if (_numMap[_graph.source(edge)] <= _retMap[_graph.target(edge)]) { - if (_predMap[_graph.source(edge)] != INVALID) { - if (!_cutMap[_graph.source(edge)]) { - _cutMap.set(_graph.source(edge), true); - ++_cutNum; - } - } else if (rootCut) { - if (!_cutMap[_graph.source(edge)]) { - _cutMap.set(_graph.source(edge), true); - ++_cutNum; - } - } else { - rootCut = true; - } - } - } - - private: - const Digraph& _graph; - NodeMap& _cutMap; - int& _cutNum; - - typename Digraph::template NodeMap _numMap; - typename Digraph::template NodeMap _retMap; - typename Digraph::template NodeMap _predMap; - std::stack _edgeStack; - int _num; - bool rootCut; - }; - - } - - template - int countBiNodeConnectedComponents(const Graph& graph); - - /// \ingroup graph_properties - /// - /// \brief Check whether an undirected graph is bi-node-connected. - /// - /// This function checks whether the given undirected graph is - /// bi-node-connected, i.e. a connected graph without articulation - /// node. - /// - /// \return \c true if the graph bi-node-connected. - /// - /// \note By definition, - /// \li a graph consisting of zero or one node is bi-node-connected, - /// \li a graph consisting of two isolated nodes - /// is \e not bi-node-connected and - /// \li a graph consisting of two nodes connected by an edge - /// is bi-node-connected. - /// - /// \see countBiNodeConnectedComponents(), biNodeConnectedComponents() - template - bool biNodeConnected(const Graph& graph) { - bool hasNonIsolated = false, hasIsolated = false; - for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { - if (typename Graph::OutArcIt(graph, n) == INVALID) { - if (hasIsolated || hasNonIsolated) { - return false; - } else { - hasIsolated = true; - } - } else { - if (hasIsolated) { - return false; - } else { - hasNonIsolated = true; - } - } - } - return countBiNodeConnectedComponents(graph) <= 1; - } - - /// \ingroup graph_properties - /// - /// \brief Count the number of bi-node-connected components of an - /// undirected graph. - /// - /// This function counts the number of bi-node-connected components of - /// the given undirected graph. - /// - /// The bi-node-connected components are the classes of an equivalence - /// relation on the edges of a undirected graph. Two edges are in the - /// same class if they are on same circle. - /// - /// \return The number of bi-node-connected components. - /// - /// \see biNodeConnected(), biNodeConnectedComponents() - template - int countBiNodeConnectedComponents(const Graph& graph) { - checkConcept(); - typedef typename Graph::NodeIt NodeIt; - - using namespace _connectivity_bits; - - typedef CountBiNodeConnectedComponentsVisitor Visitor; - - int compNum = 0; - Visitor visitor(graph, compNum); - - DfsVisit dfs(graph, visitor); - dfs.init(); - - for (NodeIt it(graph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - dfs.start(); - } - } - return compNum; - } - - /// \ingroup graph_properties - /// - /// \brief Find the bi-node-connected components of an undirected graph. - /// - /// This function finds the bi-node-connected components of the given - /// undirected graph. - /// - /// The bi-node-connected components are the classes of an equivalence - /// relation on the edges of a undirected graph. Two edges are in the - /// same class if they are on same circle. - /// - /// \image html node_biconnected_components.png - /// \image latex node_biconnected_components.eps "bi-node-connected components" width=\textwidth - /// - /// \param graph The undirected graph. - /// \retval compMap A writable edge map. The values will be set from 0 - /// to the number of the bi-node-connected components minus one. Each - /// value of the map will be set exactly once, and the values of a - /// certain component will be set continuously. - /// \return The number of bi-node-connected components. - /// - /// \see biNodeConnected(), countBiNodeConnectedComponents() - template - int biNodeConnectedComponents(const Graph& graph, - EdgeMap& compMap) { - checkConcept(); - typedef typename Graph::NodeIt NodeIt; - typedef typename Graph::Edge Edge; - checkConcept, EdgeMap>(); - - using namespace _connectivity_bits; - - typedef BiNodeConnectedComponentsVisitor Visitor; - - int compNum = 0; - Visitor visitor(graph, compMap, compNum); - - DfsVisit dfs(graph, visitor); - dfs.init(); - - for (NodeIt it(graph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - dfs.start(); - } - } - return compNum; - } - - /// \ingroup graph_properties - /// - /// \brief Find the bi-node-connected cut nodes in an undirected graph. - /// - /// This function finds the bi-node-connected cut nodes in the given - /// undirected graph. - /// - /// The bi-node-connected components are the classes of an equivalence - /// relation on the edges of a undirected graph. Two edges are in the - /// same class if they are on same circle. - /// The bi-node-connected components are separted by the cut nodes of - /// the components. - /// - /// \param graph The undirected graph. - /// \retval cutMap A writable node map. The values will be set to - /// \c true for the nodes that separate two or more components - /// (exactly once for each cut node), and will not be changed for - /// other nodes. - /// \return The number of the cut nodes. - /// - /// \see biNodeConnected(), biNodeConnectedComponents() - template - int biNodeConnectedCutNodes(const Graph& graph, NodeMap& cutMap) { - checkConcept(); - typedef typename Graph::Node Node; - typedef typename Graph::NodeIt NodeIt; - checkConcept, NodeMap>(); - - using namespace _connectivity_bits; - - typedef BiNodeConnectedCutNodesVisitor Visitor; - - int cutNum = 0; - Visitor visitor(graph, cutMap, cutNum); - - DfsVisit dfs(graph, visitor); - dfs.init(); - - for (NodeIt it(graph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - dfs.start(); - } - } - return cutNum; - } - - namespace _connectivity_bits { - - template - class CountBiEdgeConnectedComponentsVisitor : public DfsVisitor { - public: - typedef typename Digraph::Node Node; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::Edge Edge; - - CountBiEdgeConnectedComponentsVisitor(const Digraph& graph, int &compNum) - : _graph(graph), _compNum(compNum), - _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {} - - void start(const Node& node) { - _predMap.set(node, INVALID); - } - - void reach(const Node& node) { - _numMap.set(node, _num); - _retMap.set(node, _num); - ++_num; - } - - void leave(const Node& node) { - if (_numMap[node] <= _retMap[node]) { - ++_compNum; - } - } - - void discover(const Arc& edge) { - _predMap.set(_graph.target(edge), edge); - } - - void examine(const Arc& edge) { - if (_predMap[_graph.source(edge)] == _graph.oppositeArc(edge)) { - return; - } - if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { - _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); - } - } - - void backtrack(const Arc& edge) { - if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { - _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); - } - } - - private: - const Digraph& _graph; - int& _compNum; - - typename Digraph::template NodeMap _numMap; - typename Digraph::template NodeMap _retMap; - typename Digraph::template NodeMap _predMap; - int _num; - }; - - template - class BiEdgeConnectedComponentsVisitor : public DfsVisitor { - public: - typedef typename Digraph::Node Node; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::Edge Edge; - - BiEdgeConnectedComponentsVisitor(const Digraph& graph, - NodeMap& compMap, int &compNum) - : _graph(graph), _compMap(compMap), _compNum(compNum), - _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {} - - void start(const Node& node) { - _predMap.set(node, INVALID); - } - - void reach(const Node& node) { - _numMap.set(node, _num); - _retMap.set(node, _num); - _nodeStack.push(node); - ++_num; - } - - void leave(const Node& node) { - if (_numMap[node] <= _retMap[node]) { - while (_nodeStack.top() != node) { - _compMap.set(_nodeStack.top(), _compNum); - _nodeStack.pop(); - } - _compMap.set(node, _compNum); - _nodeStack.pop(); - ++_compNum; - } - } - - void discover(const Arc& edge) { - _predMap.set(_graph.target(edge), edge); - } - - void examine(const Arc& edge) { - if (_predMap[_graph.source(edge)] == _graph.oppositeArc(edge)) { - return; - } - if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { - _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); - } - } - - void backtrack(const Arc& edge) { - if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { - _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); - } - } - - private: - const Digraph& _graph; - NodeMap& _compMap; - int& _compNum; - - typename Digraph::template NodeMap _numMap; - typename Digraph::template NodeMap _retMap; - typename Digraph::template NodeMap _predMap; - std::stack _nodeStack; - int _num; - }; - - - template - class BiEdgeConnectedCutEdgesVisitor : public DfsVisitor { - public: - typedef typename Digraph::Node Node; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::Edge Edge; - - BiEdgeConnectedCutEdgesVisitor(const Digraph& graph, - ArcMap& cutMap, int &cutNum) - : _graph(graph), _cutMap(cutMap), _cutNum(cutNum), - _numMap(graph), _retMap(graph), _predMap(graph), _num(0) {} - - void start(const Node& node) { - _predMap[node] = INVALID; - } - - void reach(const Node& node) { - _numMap.set(node, _num); - _retMap.set(node, _num); - ++_num; - } - - void leave(const Node& node) { - if (_numMap[node] <= _retMap[node]) { - if (_predMap[node] != INVALID) { - _cutMap.set(_predMap[node], true); - ++_cutNum; - } - } - } - - void discover(const Arc& edge) { - _predMap.set(_graph.target(edge), edge); - } - - void examine(const Arc& edge) { - if (_predMap[_graph.source(edge)] == _graph.oppositeArc(edge)) { - return; - } - if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { - _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); - } - } - - void backtrack(const Arc& edge) { - if (_retMap[_graph.source(edge)] > _retMap[_graph.target(edge)]) { - _retMap.set(_graph.source(edge), _retMap[_graph.target(edge)]); - } - } - - private: - const Digraph& _graph; - ArcMap& _cutMap; - int& _cutNum; - - typename Digraph::template NodeMap _numMap; - typename Digraph::template NodeMap _retMap; - typename Digraph::template NodeMap _predMap; - int _num; - }; - } - - template - int countBiEdgeConnectedComponents(const Graph& graph); - - /// \ingroup graph_properties - /// - /// \brief Check whether an undirected graph is bi-edge-connected. - /// - /// This function checks whether the given undirected graph is - /// bi-edge-connected, i.e. any two nodes are connected with at least - /// two edge-disjoint paths. - /// - /// \return \c true if the graph is bi-edge-connected. - /// \note By definition, the empty graph is bi-edge-connected. - /// - /// \see countBiEdgeConnectedComponents(), biEdgeConnectedComponents() - template - bool biEdgeConnected(const Graph& graph) { - return countBiEdgeConnectedComponents(graph) <= 1; - } - - /// \ingroup graph_properties - /// - /// \brief Count the number of bi-edge-connected components of an - /// undirected graph. - /// - /// This function counts the number of bi-edge-connected components of - /// the given undirected graph. - /// - /// The bi-edge-connected components are the classes of an equivalence - /// relation on the nodes of an undirected graph. Two nodes are in the - /// same class if they are connected with at least two edge-disjoint - /// paths. - /// - /// \return The number of bi-edge-connected components. - /// - /// \see biEdgeConnected(), biEdgeConnectedComponents() - template - int countBiEdgeConnectedComponents(const Graph& graph) { - checkConcept(); - typedef typename Graph::NodeIt NodeIt; - - using namespace _connectivity_bits; - - typedef CountBiEdgeConnectedComponentsVisitor Visitor; - - int compNum = 0; - Visitor visitor(graph, compNum); - - DfsVisit dfs(graph, visitor); - dfs.init(); - - for (NodeIt it(graph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - dfs.start(); - } - } - return compNum; - } - - /// \ingroup graph_properties - /// - /// \brief Find the bi-edge-connected components of an undirected graph. - /// - /// This function finds the bi-edge-connected components of the given - /// undirected graph. - /// - /// The bi-edge-connected components are the classes of an equivalence - /// relation on the nodes of an undirected graph. Two nodes are in the - /// same class if they are connected with at least two edge-disjoint - /// paths. - /// - /// \image html edge_biconnected_components.png - /// \image latex edge_biconnected_components.eps "bi-edge-connected components" width=\textwidth - /// - /// \param graph The undirected graph. - /// \retval compMap A writable node map. The values will be set from 0 to - /// the number of the bi-edge-connected components minus one. Each value - /// of the map will be set exactly once, and the values of a certain - /// component will be set continuously. - /// \return The number of bi-edge-connected components. - /// - /// \see biEdgeConnected(), countBiEdgeConnectedComponents() - template - int biEdgeConnectedComponents(const Graph& graph, NodeMap& compMap) { - checkConcept(); - typedef typename Graph::NodeIt NodeIt; - typedef typename Graph::Node Node; - checkConcept, NodeMap>(); - - using namespace _connectivity_bits; - - typedef BiEdgeConnectedComponentsVisitor Visitor; - - int compNum = 0; - Visitor visitor(graph, compMap, compNum); - - DfsVisit dfs(graph, visitor); - dfs.init(); - - for (NodeIt it(graph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - dfs.start(); - } - } - return compNum; - } - - /// \ingroup graph_properties - /// - /// \brief Find the bi-edge-connected cut edges in an undirected graph. - /// - /// This function finds the bi-edge-connected cut edges in the given - /// undirected graph. - /// - /// The bi-edge-connected components are the classes of an equivalence - /// relation on the nodes of an undirected graph. Two nodes are in the - /// same class if they are connected with at least two edge-disjoint - /// paths. - /// The bi-edge-connected components are separted by the cut edges of - /// the components. - /// - /// \param graph The undirected graph. - /// \retval cutMap A writable edge map. The values will be set to \c true - /// for the cut edges (exactly once for each cut edge), and will not be - /// changed for other edges. - /// \return The number of cut edges. - /// - /// \see biEdgeConnected(), biEdgeConnectedComponents() - template - int biEdgeConnectedCutEdges(const Graph& graph, EdgeMap& cutMap) { - checkConcept(); - typedef typename Graph::NodeIt NodeIt; - typedef typename Graph::Edge Edge; - checkConcept, EdgeMap>(); - - using namespace _connectivity_bits; - - typedef BiEdgeConnectedCutEdgesVisitor Visitor; - - int cutNum = 0; - Visitor visitor(graph, cutMap, cutNum); - - DfsVisit dfs(graph, visitor); - dfs.init(); - - for (NodeIt it(graph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - dfs.start(); - } - } - return cutNum; - } - - - namespace _connectivity_bits { - - template - class TopologicalSortVisitor : public DfsVisitor { - public: - typedef typename Digraph::Node Node; - typedef typename Digraph::Arc edge; - - TopologicalSortVisitor(IntNodeMap& order, int num) - : _order(order), _num(num) {} - - void leave(const Node& node) { - _order.set(node, --_num); - } - - private: - IntNodeMap& _order; - int _num; - }; - - } - - /// \ingroup graph_properties - /// - /// \brief Check whether a digraph is DAG. - /// - /// This function checks whether the given digraph is DAG, i.e. - /// \e Directed \e Acyclic \e Graph. - /// \return \c true if there is no directed cycle in the digraph. - /// \see acyclic() - template - bool dag(const Digraph& digraph) { - - checkConcept(); - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - - typedef typename Digraph::template NodeMap ProcessedMap; - - typename Dfs::template SetProcessedMap:: - Create dfs(digraph); - - ProcessedMap processed(digraph); - dfs.processedMap(processed); - - dfs.init(); - for (NodeIt it(digraph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - while (!dfs.emptyQueue()) { - Arc arc = dfs.nextArc(); - Node target = digraph.target(arc); - if (dfs.reached(target) && !processed[target]) { - return false; - } - dfs.processNextArc(); - } - } - } - return true; - } - - /// \ingroup graph_properties - /// - /// \brief Sort the nodes of a DAG into topolgical order. - /// - /// This function sorts the nodes of the given acyclic digraph (DAG) - /// into topolgical order. - /// - /// \param digraph The digraph, which must be DAG. - /// \retval order A writable node map. The values will be set from 0 to - /// the number of the nodes in the digraph minus one. Each value of the - /// map will be set exactly once, and the values will be set descending - /// order. - /// - /// \see dag(), checkedTopologicalSort() - template - void topologicalSort(const Digraph& digraph, NodeMap& order) { - using namespace _connectivity_bits; - - checkConcept(); - checkConcept, NodeMap>(); - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - - TopologicalSortVisitor - visitor(order, countNodes(digraph)); - - DfsVisit > - dfs(digraph, visitor); - - dfs.init(); - for (NodeIt it(digraph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - dfs.start(); - } - } - } - - /// \ingroup graph_properties - /// - /// \brief Sort the nodes of a DAG into topolgical order. - /// - /// This function sorts the nodes of the given acyclic digraph (DAG) - /// into topolgical order and also checks whether the given digraph - /// is DAG. - /// - /// \param digraph The digraph. - /// \retval order A readable and writable node map. The values will be - /// set from 0 to the number of the nodes in the digraph minus one. - /// Each value of the map will be set exactly once, and the values will - /// be set descending order. - /// \return \c false if the digraph is not DAG. - /// - /// \see dag(), topologicalSort() - template - bool checkedTopologicalSort(const Digraph& digraph, NodeMap& order) { - using namespace _connectivity_bits; - - checkConcept(); - checkConcept, - NodeMap>(); - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - - for (NodeIt it(digraph); it != INVALID; ++it) { - order.set(it, -1); - } - - TopologicalSortVisitor - visitor(order, countNodes(digraph)); - - DfsVisit > - dfs(digraph, visitor); - - dfs.init(); - for (NodeIt it(digraph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - while (!dfs.emptyQueue()) { - Arc arc = dfs.nextArc(); - Node target = digraph.target(arc); - if (dfs.reached(target) && order[target] == -1) { - return false; - } - dfs.processNextArc(); - } - } - } - return true; - } - - /// \ingroup graph_properties - /// - /// \brief Check whether an undirected graph is acyclic. - /// - /// This function checks whether the given undirected graph is acyclic. - /// \return \c true if there is no cycle in the graph. - /// \see dag() - template - bool acyclic(const Graph& graph) { - checkConcept(); - typedef typename Graph::Node Node; - typedef typename Graph::NodeIt NodeIt; - typedef typename Graph::Arc Arc; - Dfs dfs(graph); - dfs.init(); - for (NodeIt it(graph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - dfs.addSource(it); - while (!dfs.emptyQueue()) { - Arc arc = dfs.nextArc(); - Node source = graph.source(arc); - Node target = graph.target(arc); - if (dfs.reached(target) && - dfs.predArc(source) != graph.oppositeArc(arc)) { - return false; - } - dfs.processNextArc(); - } - } - } - return true; - } - - /// \ingroup graph_properties - /// - /// \brief Check whether an undirected graph is tree. - /// - /// This function checks whether the given undirected graph is tree. - /// \return \c true if the graph is acyclic and connected. - /// \see acyclic(), connected() - template - bool tree(const Graph& graph) { - checkConcept(); - typedef typename Graph::Node Node; - typedef typename Graph::NodeIt NodeIt; - typedef typename Graph::Arc Arc; - if (NodeIt(graph) == INVALID) return true; - Dfs dfs(graph); - dfs.init(); - dfs.addSource(NodeIt(graph)); - while (!dfs.emptyQueue()) { - Arc arc = dfs.nextArc(); - Node source = graph.source(arc); - Node target = graph.target(arc); - if (dfs.reached(target) && - dfs.predArc(source) != graph.oppositeArc(arc)) { - return false; - } - dfs.processNextArc(); - } - for (NodeIt it(graph); it != INVALID; ++it) { - if (!dfs.reached(it)) { - return false; - } - } - return true; - } - - namespace _connectivity_bits { - - template - class BipartiteVisitor : public BfsVisitor { - public: - typedef typename Digraph::Arc Arc; - typedef typename Digraph::Node Node; - - BipartiteVisitor(const Digraph& graph, bool& bipartite) - : _graph(graph), _part(graph), _bipartite(bipartite) {} - - void start(const Node& node) { - _part[node] = true; - } - void discover(const Arc& edge) { - _part.set(_graph.target(edge), !_part[_graph.source(edge)]); - } - void examine(const Arc& edge) { - _bipartite = _bipartite && - _part[_graph.target(edge)] != _part[_graph.source(edge)]; - } - - private: - - const Digraph& _graph; - typename Digraph::template NodeMap _part; - bool& _bipartite; - }; - - template - class BipartitePartitionsVisitor : public BfsVisitor { - public: - typedef typename Digraph::Arc Arc; - typedef typename Digraph::Node Node; - - BipartitePartitionsVisitor(const Digraph& graph, - PartMap& part, bool& bipartite) - : _graph(graph), _part(part), _bipartite(bipartite) {} - - void start(const Node& node) { - _part.set(node, true); - } - void discover(const Arc& edge) { - _part.set(_graph.target(edge), !_part[_graph.source(edge)]); - } - void examine(const Arc& edge) { - _bipartite = _bipartite && - _part[_graph.target(edge)] != _part[_graph.source(edge)]; - } - - private: - - const Digraph& _graph; - PartMap& _part; - bool& _bipartite; - }; - } - - /// \ingroup graph_properties - /// - /// \brief Check whether an undirected graph is bipartite. - /// - /// The function checks whether the given undirected graph is bipartite. - /// \return \c true if the graph is bipartite. - /// - /// \see bipartitePartitions() - template - bool bipartite(const Graph &graph){ - using namespace _connectivity_bits; - - checkConcept(); - - typedef typename Graph::NodeIt NodeIt; - typedef typename Graph::ArcIt ArcIt; - - bool bipartite = true; - - BipartiteVisitor - visitor(graph, bipartite); - BfsVisit > - bfs(graph, visitor); - bfs.init(); - for(NodeIt it(graph); it != INVALID; ++it) { - if(!bfs.reached(it)){ - bfs.addSource(it); - while (!bfs.emptyQueue()) { - bfs.processNextNode(); - if (!bipartite) return false; - } - } - } - return true; - } - - /// \ingroup graph_properties - /// - /// \brief Find the bipartite partitions of an undirected graph. - /// - /// This function checks whether the given undirected graph is bipartite - /// and gives back the bipartite partitions. - /// - /// \image html bipartite_partitions.png - /// \image latex bipartite_partitions.eps "Bipartite partititions" width=\textwidth - /// - /// \param graph The undirected graph. - /// \retval partMap A writable node map of \c bool (or convertible) value - /// type. The values will be set to \c true for one component and - /// \c false for the other one. - /// \return \c true if the graph is bipartite, \c false otherwise. - /// - /// \see bipartite() - template - bool bipartitePartitions(const Graph &graph, NodeMap &partMap){ - using namespace _connectivity_bits; - - checkConcept(); - checkConcept, NodeMap>(); - - typedef typename Graph::Node Node; - typedef typename Graph::NodeIt NodeIt; - typedef typename Graph::ArcIt ArcIt; - - bool bipartite = true; - - BipartitePartitionsVisitor - visitor(graph, partMap, bipartite); - BfsVisit > - bfs(graph, visitor); - bfs.init(); - for(NodeIt it(graph); it != INVALID; ++it) { - if(!bfs.reached(it)){ - bfs.addSource(it); - while (!bfs.emptyQueue()) { - bfs.processNextNode(); - if (!bipartite) return false; - } - } - } - return true; - } - - /// \ingroup graph_properties - /// - /// \brief Check whether the given graph contains no loop arcs/edges. - /// - /// This function returns \c true if there are no loop arcs/edges in - /// the given graph. It works for both directed and undirected graphs. - template - bool loopFree(const Graph& graph) { - for (typename Graph::ArcIt it(graph); it != INVALID; ++it) { - if (graph.source(it) == graph.target(it)) return false; - } - return true; - } - - /// \ingroup graph_properties - /// - /// \brief Check whether the given graph contains no parallel arcs/edges. - /// - /// This function returns \c true if there are no parallel arcs/edges in - /// the given graph. It works for both directed and undirected graphs. - template - bool parallelFree(const Graph& graph) { - typename Graph::template NodeMap reached(graph, 0); - int cnt = 1; - for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { - for (typename Graph::OutArcIt a(graph, n); a != INVALID; ++a) { - if (reached[graph.target(a)] == cnt) return false; - reached[graph.target(a)] = cnt; - } - ++cnt; - } - return true; - } - - /// \ingroup graph_properties - /// - /// \brief Check whether the given graph is simple. - /// - /// This function returns \c true if the given graph is simple, i.e. - /// it contains no loop arcs/edges and no parallel arcs/edges. - /// The function works for both directed and undirected graphs. - /// \see loopFree(), parallelFree() - template - bool simpleGraph(const Graph& graph) { - typename Graph::template NodeMap reached(graph, 0); - int cnt = 1; - for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { - reached[n] = cnt; - for (typename Graph::OutArcIt a(graph, n); a != INVALID; ++a) { - if (reached[graph.target(a)] == cnt) return false; - reached[graph.target(a)] = cnt; - } - ++cnt; - } - return true; - } - -} //namespace lemon - -#endif //LEMON_CONNECTIVITY_H diff --git a/deps/lemon/lemon/core.h b/deps/lemon/lemon/core.h deleted file mode 100644 index 3b8dc3000..000000000 --- a/deps/lemon/lemon/core.h +++ /dev/null @@ -1,2512 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_CORE_H -#define LEMON_CORE_H - -#include -#include - -#include -#include -#include -#include - -// Disable the following warnings when compiling with MSVC: -// C4250: 'class1' : inherits 'class2::member' via dominance -// C4355: 'this' : used in base member initializer list -// C4503: 'function' : decorated name length exceeded, name was truncated -// C4800: 'type' : forcing value to bool 'true' or 'false' (performance warning) -// C4996: 'function': was declared deprecated -#ifdef _MSC_VER -#pragma warning( disable : 4250 4355 4503 4800 4996 ) - -#ifdef _MSC_VER -#ifdef BUILDING_LEMON -#define LEMON_DECLSPEC __declspec(dllexport) -#else -#define LEMON_DECLSPEC __declspec(dllimport) -#endif -#endif -#else -#define LEMON_DECLSPEC -#endif - -#ifdef __GNUC__ -#define GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) -#endif - -#if GCC_VERSION >= 40800 -// Needed by the [DI]GRAPH_TYPEDEFS marcos for gcc 4.8 -#pragma GCC diagnostic ignored "-Wunused-local-typedefs" -#endif - -///\file -///\brief LEMON core utilities. -/// -///This header file contains core utilities for LEMON. -///It is automatically included by all graph types, therefore it usually -///do not have to be included directly. - -namespace lemon { - - /// \brief Dummy type to make it easier to create invalid iterators. - /// - /// Dummy type to make it easier to create invalid iterators. - /// See \ref INVALID for the usage. - struct Invalid { - public: - bool operator==(Invalid) { return true; } - bool operator!=(Invalid) { return false; } - bool operator< (Invalid) { return false; } - }; - - /// \brief Invalid iterators. - /// - /// \ref Invalid is a global type that converts to each iterator - /// in such a way that the value of the target iterator will be invalid. - static const Invalid INVALID = Invalid(); - - /// \addtogroup gutils - /// @{ - - ///Create convenience typedefs for the digraph types and iterators - - ///This \c \#define creates convenient type definitions for the following - ///types of \c Digraph: \c Node, \c NodeIt, \c Arc, \c ArcIt, \c InArcIt, - ///\c OutArcIt, \c BoolNodeMap, \c IntNodeMap, \c DoubleNodeMap, - ///\c BoolArcMap, \c IntArcMap, \c DoubleArcMap. - /// - ///\note If the graph type is a dependent type, ie. the graph type depend - ///on a template parameter, then use \c TEMPLATE_DIGRAPH_TYPEDEFS() - ///macro. -#define DIGRAPH_TYPEDEFS(Digraph) \ - typedef Digraph::Node Node; \ - typedef Digraph::NodeIt NodeIt; \ - typedef Digraph::Arc Arc; \ - typedef Digraph::ArcIt ArcIt; \ - typedef Digraph::InArcIt InArcIt; \ - typedef Digraph::OutArcIt OutArcIt; \ - typedef Digraph::NodeMap BoolNodeMap; \ - typedef Digraph::NodeMap IntNodeMap; \ - typedef Digraph::NodeMap DoubleNodeMap; \ - typedef Digraph::ArcMap BoolArcMap; \ - typedef Digraph::ArcMap IntArcMap; \ - typedef Digraph::ArcMap DoubleArcMap - - ///Create convenience typedefs for the digraph types and iterators - - ///\see DIGRAPH_TYPEDEFS - /// - ///\note Use this macro, if the graph type is a dependent type, - ///ie. the graph type depend on a template parameter. -#define TEMPLATE_DIGRAPH_TYPEDEFS(Digraph) \ - typedef typename Digraph::Node Node; \ - typedef typename Digraph::NodeIt NodeIt; \ - typedef typename Digraph::Arc Arc; \ - typedef typename Digraph::ArcIt ArcIt; \ - typedef typename Digraph::InArcIt InArcIt; \ - typedef typename Digraph::OutArcIt OutArcIt; \ - typedef typename Digraph::template NodeMap BoolNodeMap; \ - typedef typename Digraph::template NodeMap IntNodeMap; \ - typedef typename Digraph::template NodeMap DoubleNodeMap; \ - typedef typename Digraph::template ArcMap BoolArcMap; \ - typedef typename Digraph::template ArcMap IntArcMap; \ - typedef typename Digraph::template ArcMap DoubleArcMap - - ///Create convenience typedefs for the graph types and iterators - - ///This \c \#define creates the same convenient type definitions as defined - ///by \ref DIGRAPH_TYPEDEFS(Graph) and six more, namely it creates - ///\c Edge, \c EdgeIt, \c IncEdgeIt, \c BoolEdgeMap, \c IntEdgeMap, - ///\c DoubleEdgeMap. - /// - ///\note If the graph type is a dependent type, ie. the graph type depend - ///on a template parameter, then use \c TEMPLATE_GRAPH_TYPEDEFS() - ///macro. -#define GRAPH_TYPEDEFS(Graph) \ - DIGRAPH_TYPEDEFS(Graph); \ - typedef Graph::Edge Edge; \ - typedef Graph::EdgeIt EdgeIt; \ - typedef Graph::IncEdgeIt IncEdgeIt; \ - typedef Graph::EdgeMap BoolEdgeMap; \ - typedef Graph::EdgeMap IntEdgeMap; \ - typedef Graph::EdgeMap DoubleEdgeMap - - ///Create convenience typedefs for the graph types and iterators - - ///\see GRAPH_TYPEDEFS - /// - ///\note Use this macro, if the graph type is a dependent type, - ///ie. the graph type depend on a template parameter. -#define TEMPLATE_GRAPH_TYPEDEFS(Graph) \ - TEMPLATE_DIGRAPH_TYPEDEFS(Graph); \ - typedef typename Graph::Edge Edge; \ - typedef typename Graph::EdgeIt EdgeIt; \ - typedef typename Graph::IncEdgeIt IncEdgeIt; \ - typedef typename Graph::template EdgeMap BoolEdgeMap; \ - typedef typename Graph::template EdgeMap IntEdgeMap; \ - typedef typename Graph::template EdgeMap DoubleEdgeMap - - ///Create convenience typedefs for the bipartite graph types and iterators - - ///This \c \#define creates the same convenient type definitions as - ///defined by \ref GRAPH_TYPEDEFS(BpGraph) and ten more, namely it - ///creates \c RedNode, \c RedNodeIt, \c BoolRedNodeMap, - ///\c IntRedNodeMap, \c DoubleRedNodeMap, \c BlueNode, \c BlueNodeIt, - ///\c BoolBlueNodeMap, \c IntBlueNodeMap, \c DoubleBlueNodeMap. - /// - ///\note If the graph type is a dependent type, ie. the graph type depend - ///on a template parameter, then use \c TEMPLATE_BPGRAPH_TYPEDEFS() - ///macro. -#define BPGRAPH_TYPEDEFS(BpGraph) \ - GRAPH_TYPEDEFS(BpGraph); \ - typedef BpGraph::RedNode RedNode; \ - typedef BpGraph::RedNodeIt RedNodeIt; \ - typedef BpGraph::RedNodeMap BoolRedNodeMap; \ - typedef BpGraph::RedNodeMap IntRedNodeMap; \ - typedef BpGraph::RedNodeMap DoubleRedNodeMap; \ - typedef BpGraph::BlueNode BlueNode; \ - typedef BpGraph::BlueNodeIt BlueNodeIt; \ - typedef BpGraph::BlueNodeMap BoolBlueNodeMap; \ - typedef BpGraph::BlueNodeMap IntBlueNodeMap; \ - typedef BpGraph::BlueNodeMap DoubleBlueNodeMap - - ///Create convenience typedefs for the bipartite graph types and iterators - - ///\see BPGRAPH_TYPEDEFS - /// - ///\note Use this macro, if the graph type is a dependent type, - ///ie. the graph type depend on a template parameter. -#define TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph) \ - TEMPLATE_GRAPH_TYPEDEFS(BpGraph); \ - typedef typename BpGraph::RedNode RedNode; \ - typedef typename BpGraph::RedNodeIt RedNodeIt; \ - typedef typename BpGraph::template RedNodeMap BoolRedNodeMap; \ - typedef typename BpGraph::template RedNodeMap IntRedNodeMap; \ - typedef typename BpGraph::template RedNodeMap DoubleRedNodeMap; \ - typedef typename BpGraph::BlueNode BlueNode; \ - typedef typename BpGraph::BlueNodeIt BlueNodeIt; \ - typedef typename BpGraph::template BlueNodeMap BoolBlueNodeMap; \ - typedef typename BpGraph::template BlueNodeMap IntBlueNodeMap; \ - typedef typename BpGraph::template BlueNodeMap DoubleBlueNodeMap - - /// \brief Function to count the items in a graph. - /// - /// This function counts the items (nodes, arcs etc.) in a graph. - /// The complexity of the function is linear because - /// it iterates on all of the items. - template - inline int countItems(const Graph& g) { - typedef typename ItemSetTraits::ItemIt ItemIt; - int num = 0; - for (ItemIt it(g); it != INVALID; ++it) { - ++num; - } - return num; - } - - // Node counting: - - namespace _core_bits { - - template - struct CountNodesSelector { - static int count(const Graph &g) { - return countItems(g); - } - }; - - template - struct CountNodesSelector< - Graph, typename - enable_if::type> - { - static int count(const Graph &g) { - return g.nodeNum(); - } - }; - } - - /// \brief Function to count the nodes in the graph. - /// - /// This function counts the nodes in the graph. - /// The complexity of the function is O(n), but for some - /// graph structures it is specialized to run in O(1). - /// - /// \note If the graph contains a \c nodeNum() member function and a - /// \c NodeNumTag tag then this function calls directly the member - /// function to query the cardinality of the node set. - template - inline int countNodes(const Graph& g) { - return _core_bits::CountNodesSelector::count(g); - } - - namespace _graph_utils_bits { - - template - struct CountRedNodesSelector { - static int count(const Graph &g) { - return countItems(g); - } - }; - - template - struct CountRedNodesSelector< - Graph, typename - enable_if::type> - { - static int count(const Graph &g) { - return g.redNum(); - } - }; - } - - /// \brief Function to count the red nodes in the graph. - /// - /// This function counts the red nodes in the graph. - /// The complexity of the function is O(n) but for some - /// graph structures it is specialized to run in O(1). - /// - /// If the graph contains a \e redNum() member function and a - /// \e NodeNumTag tag then this function calls directly the member - /// function to query the cardinality of the node set. - template - inline int countRedNodes(const Graph& g) { - return _graph_utils_bits::CountRedNodesSelector::count(g); - } - - namespace _graph_utils_bits { - - template - struct CountBlueNodesSelector { - static int count(const Graph &g) { - return countItems(g); - } - }; - - template - struct CountBlueNodesSelector< - Graph, typename - enable_if::type> - { - static int count(const Graph &g) { - return g.blueNum(); - } - }; - } - - /// \brief Function to count the blue nodes in the graph. - /// - /// This function counts the blue nodes in the graph. - /// The complexity of the function is O(n) but for some - /// graph structures it is specialized to run in O(1). - /// - /// If the graph contains a \e blueNum() member function and a - /// \e NodeNumTag tag then this function calls directly the member - /// function to query the cardinality of the node set. - template - inline int countBlueNodes(const Graph& g) { - return _graph_utils_bits::CountBlueNodesSelector::count(g); - } - - // Arc counting: - - namespace _core_bits { - - template - struct CountArcsSelector { - static int count(const Graph &g) { - return countItems(g); - } - }; - - template - struct CountArcsSelector< - Graph, - typename enable_if::type> - { - static int count(const Graph &g) { - return g.arcNum(); - } - }; - } - - /// \brief Function to count the arcs in the graph. - /// - /// This function counts the arcs in the graph. - /// The complexity of the function is O(m), but for some - /// graph structures it is specialized to run in O(1). - /// - /// \note If the graph contains a \c arcNum() member function and a - /// \c ArcNumTag tag then this function calls directly the member - /// function to query the cardinality of the arc set. - template - inline int countArcs(const Graph& g) { - return _core_bits::CountArcsSelector::count(g); - } - - // Edge counting: - - namespace _core_bits { - - template - struct CountEdgesSelector { - static int count(const Graph &g) { - return countItems(g); - } - }; - - template - struct CountEdgesSelector< - Graph, - typename enable_if::type> - { - static int count(const Graph &g) { - return g.edgeNum(); - } - }; - } - - /// \brief Function to count the edges in the graph. - /// - /// This function counts the edges in the graph. - /// The complexity of the function is O(m), but for some - /// graph structures it is specialized to run in O(1). - /// - /// \note If the graph contains a \c edgeNum() member function and a - /// \c EdgeNumTag tag then this function calls directly the member - /// function to query the cardinality of the edge set. - template - inline int countEdges(const Graph& g) { - return _core_bits::CountEdgesSelector::count(g); - - } - - - template - inline int countNodeDegree(const Graph& _g, const typename Graph::Node& _n) { - int num = 0; - for (DegIt it(_g, _n); it != INVALID; ++it) { - ++num; - } - return num; - } - - /// \brief Function to count the number of the out-arcs from node \c n. - /// - /// This function counts the number of the out-arcs from node \c n - /// in the graph \c g. - template - inline int countOutArcs(const Graph& g, const typename Graph::Node& n) { - return countNodeDegree(g, n); - } - - /// \brief Function to count the number of the in-arcs to node \c n. - /// - /// This function counts the number of the in-arcs to node \c n - /// in the graph \c g. - template - inline int countInArcs(const Graph& g, const typename Graph::Node& n) { - return countNodeDegree(g, n); - } - - /// \brief Function to count the number of the inc-edges to node \c n. - /// - /// This function counts the number of the inc-edges to node \c n - /// in the undirected graph \c g. - template - inline int countIncEdges(const Graph& g, const typename Graph::Node& n) { - return countNodeDegree(g, n); - } - - namespace _core_bits { - - template - class MapCopyBase { - public: - virtual void copy(const Digraph& from, const RefMap& refMap) = 0; - - virtual ~MapCopyBase() {} - }; - - template - class MapCopy : public MapCopyBase { - public: - - MapCopy(const FromMap& map, ToMap& tmap) - : _map(map), _tmap(tmap) {} - - virtual void copy(const Digraph& digraph, const RefMap& refMap) { - typedef typename ItemSetTraits::ItemIt ItemIt; - for (ItemIt it(digraph); it != INVALID; ++it) { - _tmap.set(refMap[it], _map[it]); - } - } - - private: - const FromMap& _map; - ToMap& _tmap; - }; - - template - class ItemCopy : public MapCopyBase { - public: - - ItemCopy(const Item& item, It& it) : _item(item), _it(it) {} - - virtual void copy(const Digraph&, const RefMap& refMap) { - _it = refMap[_item]; - } - - private: - Item _item; - It& _it; - }; - - template - class RefCopy : public MapCopyBase { - public: - - RefCopy(Ref& map) : _map(map) {} - - virtual void copy(const Digraph& digraph, const RefMap& refMap) { - typedef typename ItemSetTraits::ItemIt ItemIt; - for (ItemIt it(digraph); it != INVALID; ++it) { - _map.set(it, refMap[it]); - } - } - - private: - Ref& _map; - }; - - template - class CrossRefCopy : public MapCopyBase { - public: - - CrossRefCopy(CrossRef& cmap) : _cmap(cmap) {} - - virtual void copy(const Digraph& digraph, const RefMap& refMap) { - typedef typename ItemSetTraits::ItemIt ItemIt; - for (ItemIt it(digraph); it != INVALID; ++it) { - _cmap.set(refMap[it], it); - } - } - - private: - CrossRef& _cmap; - }; - - template - struct DigraphCopySelector { - template - static void copy(const From& from, Digraph &to, - NodeRefMap& nodeRefMap, ArcRefMap& arcRefMap) { - to.clear(); - for (typename From::NodeIt it(from); it != INVALID; ++it) { - nodeRefMap[it] = to.addNode(); - } - for (typename From::ArcIt it(from); it != INVALID; ++it) { - arcRefMap[it] = to.addArc(nodeRefMap[from.source(it)], - nodeRefMap[from.target(it)]); - } - } - }; - - template - struct DigraphCopySelector< - Digraph, - typename enable_if::type> - { - template - static void copy(const From& from, Digraph &to, - NodeRefMap& nodeRefMap, ArcRefMap& arcRefMap) { - to.build(from, nodeRefMap, arcRefMap); - } - }; - - template - struct GraphCopySelector { - template - static void copy(const From& from, Graph &to, - NodeRefMap& nodeRefMap, EdgeRefMap& edgeRefMap) { - to.clear(); - for (typename From::NodeIt it(from); it != INVALID; ++it) { - nodeRefMap[it] = to.addNode(); - } - for (typename From::EdgeIt it(from); it != INVALID; ++it) { - edgeRefMap[it] = to.addEdge(nodeRefMap[from.u(it)], - nodeRefMap[from.v(it)]); - } - } - }; - - template - struct GraphCopySelector< - Graph, - typename enable_if::type> - { - template - static void copy(const From& from, Graph &to, - NodeRefMap& nodeRefMap, - EdgeRefMap& edgeRefMap) { - to.build(from, nodeRefMap, edgeRefMap); - } - }; - - template - struct BpGraphCopySelector { - template - static void copy(const From& from, BpGraph &to, - RedNodeRefMap& redNodeRefMap, - BlueNodeRefMap& blueNodeRefMap, - EdgeRefMap& edgeRefMap) { - to.clear(); - for (typename From::RedNodeIt it(from); it != INVALID; ++it) { - redNodeRefMap[it] = to.addRedNode(); - } - for (typename From::BlueNodeIt it(from); it != INVALID; ++it) { - blueNodeRefMap[it] = to.addBlueNode(); - } - for (typename From::EdgeIt it(from); it != INVALID; ++it) { - edgeRefMap[it] = to.addEdge(redNodeRefMap[from.redNode(it)], - blueNodeRefMap[from.blueNode(it)]); - } - } - }; - - template - struct BpGraphCopySelector< - BpGraph, - typename enable_if::type> - { - template - static void copy(const From& from, BpGraph &to, - RedNodeRefMap& redNodeRefMap, - BlueNodeRefMap& blueNodeRefMap, - EdgeRefMap& edgeRefMap) { - to.build(from, redNodeRefMap, blueNodeRefMap, edgeRefMap); - } - }; - - } - - /// \brief Check whether a graph is undirected. - /// - /// This function returns \c true if the given graph is undirected. -#ifdef DOXYGEN - template - bool undirected(const GR& g) { return false; } -#else - template - typename enable_if, bool>::type - undirected(const GR&) { - return true; - } - template - typename disable_if, bool>::type - undirected(const GR&) { - return false; - } -#endif - - /// \brief Class to copy a digraph. - /// - /// Class to copy a digraph to another digraph (duplicate a digraph). The - /// simplest way of using it is through the \c digraphCopy() function. - /// - /// This class not only make a copy of a digraph, but it can create - /// references and cross references between the nodes and arcs of - /// the two digraphs, and it can copy maps to use with the newly created - /// digraph. - /// - /// To make a copy from a digraph, first an instance of DigraphCopy - /// should be created, then the data belongs to the digraph should - /// assigned to copy. In the end, the \c run() member should be - /// called. - /// - /// The next code copies a digraph with several data: - ///\code - /// DigraphCopy cg(orig_graph, new_graph); - /// // Create references for the nodes - /// OrigGraph::NodeMap nr(orig_graph); - /// cg.nodeRef(nr); - /// // Create cross references (inverse) for the arcs - /// NewGraph::ArcMap acr(new_graph); - /// cg.arcCrossRef(acr); - /// // Copy an arc map - /// OrigGraph::ArcMap oamap(orig_graph); - /// NewGraph::ArcMap namap(new_graph); - /// cg.arcMap(oamap, namap); - /// // Copy a node - /// OrigGraph::Node on; - /// NewGraph::Node nn; - /// cg.node(on, nn); - /// // Execute copying - /// cg.run(); - ///\endcode - template - class DigraphCopy { - private: - - typedef typename From::Node Node; - typedef typename From::NodeIt NodeIt; - typedef typename From::Arc Arc; - typedef typename From::ArcIt ArcIt; - - typedef typename To::Node TNode; - typedef typename To::Arc TArc; - - typedef typename From::template NodeMap NodeRefMap; - typedef typename From::template ArcMap ArcRefMap; - - public: - - /// \brief Constructor of DigraphCopy. - /// - /// Constructor of DigraphCopy for copying the content of the - /// \c from digraph into the \c to digraph. - DigraphCopy(const From& from, To& to) - : _from(from), _to(to) {} - - /// \brief Destructor of DigraphCopy - /// - /// Destructor of DigraphCopy. - ~DigraphCopy() { - for (int i = 0; i < int(_node_maps.size()); ++i) { - delete _node_maps[i]; - } - for (int i = 0; i < int(_arc_maps.size()); ++i) { - delete _arc_maps[i]; - } - - } - - /// \brief Copy the node references into the given map. - /// - /// This function copies the node references into the given map. - /// The parameter should be a map, whose key type is the Node type of - /// the source digraph, while the value type is the Node type of the - /// destination digraph. - template - DigraphCopy& nodeRef(NodeRef& map) { - _node_maps.push_back(new _core_bits::RefCopy(map)); - return *this; - } - - /// \brief Copy the node cross references into the given map. - /// - /// This function copies the node cross references (reverse references) - /// into the given map. The parameter should be a map, whose key type - /// is the Node type of the destination digraph, while the value type is - /// the Node type of the source digraph. - template - DigraphCopy& nodeCrossRef(NodeCrossRef& map) { - _node_maps.push_back(new _core_bits::CrossRefCopy(map)); - return *this; - } - - /// \brief Make a copy of the given node map. - /// - /// This function makes a copy of the given node map for the newly - /// created digraph. - /// The key type of the new map \c tmap should be the Node type of the - /// destination digraph, and the key type of the original map \c map - /// should be the Node type of the source digraph. - template - DigraphCopy& nodeMap(const FromMap& map, ToMap& tmap) { - _node_maps.push_back(new _core_bits::MapCopy(map, tmap)); - return *this; - } - - /// \brief Make a copy of the given node. - /// - /// This function makes a copy of the given node. - DigraphCopy& node(const Node& node, TNode& tnode) { - _node_maps.push_back(new _core_bits::ItemCopy(node, tnode)); - return *this; - } - - /// \brief Copy the arc references into the given map. - /// - /// This function copies the arc references into the given map. - /// The parameter should be a map, whose key type is the Arc type of - /// the source digraph, while the value type is the Arc type of the - /// destination digraph. - template - DigraphCopy& arcRef(ArcRef& map) { - _arc_maps.push_back(new _core_bits::RefCopy(map)); - return *this; - } - - /// \brief Copy the arc cross references into the given map. - /// - /// This function copies the arc cross references (reverse references) - /// into the given map. The parameter should be a map, whose key type - /// is the Arc type of the destination digraph, while the value type is - /// the Arc type of the source digraph. - template - DigraphCopy& arcCrossRef(ArcCrossRef& map) { - _arc_maps.push_back(new _core_bits::CrossRefCopy(map)); - return *this; - } - - /// \brief Make a copy of the given arc map. - /// - /// This function makes a copy of the given arc map for the newly - /// created digraph. - /// The key type of the new map \c tmap should be the Arc type of the - /// destination digraph, and the key type of the original map \c map - /// should be the Arc type of the source digraph. - template - DigraphCopy& arcMap(const FromMap& map, ToMap& tmap) { - _arc_maps.push_back(new _core_bits::MapCopy(map, tmap)); - return *this; - } - - /// \brief Make a copy of the given arc. - /// - /// This function makes a copy of the given arc. - DigraphCopy& arc(const Arc& arc, TArc& tarc) { - _arc_maps.push_back(new _core_bits::ItemCopy(arc, tarc)); - return *this; - } - - /// \brief Execute copying. - /// - /// This function executes the copying of the digraph along with the - /// copying of the assigned data. - void run() { - NodeRefMap nodeRefMap(_from); - ArcRefMap arcRefMap(_from); - _core_bits::DigraphCopySelector:: - copy(_from, _to, nodeRefMap, arcRefMap); - for (int i = 0; i < int(_node_maps.size()); ++i) { - _node_maps[i]->copy(_from, nodeRefMap); - } - for (int i = 0; i < int(_arc_maps.size()); ++i) { - _arc_maps[i]->copy(_from, arcRefMap); - } - } - - protected: - - const From& _from; - To& _to; - - std::vector<_core_bits::MapCopyBase* > - _node_maps; - - std::vector<_core_bits::MapCopyBase* > - _arc_maps; - - }; - - /// \brief Copy a digraph to another digraph. - /// - /// This function copies a digraph to another digraph. - /// The complete usage of it is detailed in the DigraphCopy class, but - /// a short example shows a basic work: - ///\code - /// digraphCopy(src, trg).nodeRef(nr).arcCrossRef(acr).run(); - ///\endcode - /// - /// After the copy the \c nr map will contain the mapping from the - /// nodes of the \c from digraph to the nodes of the \c to digraph and - /// \c acr will contain the mapping from the arcs of the \c to digraph - /// to the arcs of the \c from digraph. - /// - /// \see DigraphCopy - template - DigraphCopy digraphCopy(const From& from, To& to) { - return DigraphCopy(from, to); - } - - /// \brief Class to copy a graph. - /// - /// Class to copy a graph to another graph (duplicate a graph). The - /// simplest way of using it is through the \c graphCopy() function. - /// - /// This class not only make a copy of a graph, but it can create - /// references and cross references between the nodes, edges and arcs of - /// the two graphs, and it can copy maps for using with the newly created - /// graph. - /// - /// To make a copy from a graph, first an instance of GraphCopy - /// should be created, then the data belongs to the graph should - /// assigned to copy. In the end, the \c run() member should be - /// called. - /// - /// The next code copies a graph with several data: - ///\code - /// GraphCopy cg(orig_graph, new_graph); - /// // Create references for the nodes - /// OrigGraph::NodeMap nr(orig_graph); - /// cg.nodeRef(nr); - /// // Create cross references (inverse) for the edges - /// NewGraph::EdgeMap ecr(new_graph); - /// cg.edgeCrossRef(ecr); - /// // Copy an edge map - /// OrigGraph::EdgeMap oemap(orig_graph); - /// NewGraph::EdgeMap nemap(new_graph); - /// cg.edgeMap(oemap, nemap); - /// // Copy a node - /// OrigGraph::Node on; - /// NewGraph::Node nn; - /// cg.node(on, nn); - /// // Execute copying - /// cg.run(); - ///\endcode - template - class GraphCopy { - private: - - typedef typename From::Node Node; - typedef typename From::NodeIt NodeIt; - typedef typename From::Arc Arc; - typedef typename From::ArcIt ArcIt; - typedef typename From::Edge Edge; - typedef typename From::EdgeIt EdgeIt; - - typedef typename To::Node TNode; - typedef typename To::Arc TArc; - typedef typename To::Edge TEdge; - - typedef typename From::template NodeMap NodeRefMap; - typedef typename From::template EdgeMap EdgeRefMap; - - struct ArcRefMap { - ArcRefMap(const From& from, const To& to, - const EdgeRefMap& edge_ref, const NodeRefMap& node_ref) - : _from(from), _to(to), - _edge_ref(edge_ref), _node_ref(node_ref) {} - - typedef typename From::Arc Key; - typedef typename To::Arc Value; - - Value operator[](const Key& key) const { - bool forward = _from.u(key) != _from.v(key) ? - _node_ref[_from.source(key)] == - _to.source(_to.direct(_edge_ref[key], true)) : - _from.direction(key); - return _to.direct(_edge_ref[key], forward); - } - - const From& _from; - const To& _to; - const EdgeRefMap& _edge_ref; - const NodeRefMap& _node_ref; - }; - - public: - - /// \brief Constructor of GraphCopy. - /// - /// Constructor of GraphCopy for copying the content of the - /// \c from graph into the \c to graph. - GraphCopy(const From& from, To& to) - : _from(from), _to(to) {} - - /// \brief Destructor of GraphCopy - /// - /// Destructor of GraphCopy. - ~GraphCopy() { - for (int i = 0; i < int(_node_maps.size()); ++i) { - delete _node_maps[i]; - } - for (int i = 0; i < int(_arc_maps.size()); ++i) { - delete _arc_maps[i]; - } - for (int i = 0; i < int(_edge_maps.size()); ++i) { - delete _edge_maps[i]; - } - } - - /// \brief Copy the node references into the given map. - /// - /// This function copies the node references into the given map. - /// The parameter should be a map, whose key type is the Node type of - /// the source graph, while the value type is the Node type of the - /// destination graph. - template - GraphCopy& nodeRef(NodeRef& map) { - _node_maps.push_back(new _core_bits::RefCopy(map)); - return *this; - } - - /// \brief Copy the node cross references into the given map. - /// - /// This function copies the node cross references (reverse references) - /// into the given map. The parameter should be a map, whose key type - /// is the Node type of the destination graph, while the value type is - /// the Node type of the source graph. - template - GraphCopy& nodeCrossRef(NodeCrossRef& map) { - _node_maps.push_back(new _core_bits::CrossRefCopy(map)); - return *this; - } - - /// \brief Make a copy of the given node map. - /// - /// This function makes a copy of the given node map for the newly - /// created graph. - /// The key type of the new map \c tmap should be the Node type of the - /// destination graph, and the key type of the original map \c map - /// should be the Node type of the source graph. - template - GraphCopy& nodeMap(const FromMap& map, ToMap& tmap) { - _node_maps.push_back(new _core_bits::MapCopy(map, tmap)); - return *this; - } - - /// \brief Make a copy of the given node. - /// - /// This function makes a copy of the given node. - GraphCopy& node(const Node& node, TNode& tnode) { - _node_maps.push_back(new _core_bits::ItemCopy(node, tnode)); - return *this; - } - - /// \brief Copy the arc references into the given map. - /// - /// This function copies the arc references into the given map. - /// The parameter should be a map, whose key type is the Arc type of - /// the source graph, while the value type is the Arc type of the - /// destination graph. - template - GraphCopy& arcRef(ArcRef& map) { - _arc_maps.push_back(new _core_bits::RefCopy(map)); - return *this; - } - - /// \brief Copy the arc cross references into the given map. - /// - /// This function copies the arc cross references (reverse references) - /// into the given map. The parameter should be a map, whose key type - /// is the Arc type of the destination graph, while the value type is - /// the Arc type of the source graph. - template - GraphCopy& arcCrossRef(ArcCrossRef& map) { - _arc_maps.push_back(new _core_bits::CrossRefCopy(map)); - return *this; - } - - /// \brief Make a copy of the given arc map. - /// - /// This function makes a copy of the given arc map for the newly - /// created graph. - /// The key type of the new map \c tmap should be the Arc type of the - /// destination graph, and the key type of the original map \c map - /// should be the Arc type of the source graph. - template - GraphCopy& arcMap(const FromMap& map, ToMap& tmap) { - _arc_maps.push_back(new _core_bits::MapCopy(map, tmap)); - return *this; - } - - /// \brief Make a copy of the given arc. - /// - /// This function makes a copy of the given arc. - GraphCopy& arc(const Arc& arc, TArc& tarc) { - _arc_maps.push_back(new _core_bits::ItemCopy(arc, tarc)); - return *this; - } - - /// \brief Copy the edge references into the given map. - /// - /// This function copies the edge references into the given map. - /// The parameter should be a map, whose key type is the Edge type of - /// the source graph, while the value type is the Edge type of the - /// destination graph. - template - GraphCopy& edgeRef(EdgeRef& map) { - _edge_maps.push_back(new _core_bits::RefCopy(map)); - return *this; - } - - /// \brief Copy the edge cross references into the given map. - /// - /// This function copies the edge cross references (reverse references) - /// into the given map. The parameter should be a map, whose key type - /// is the Edge type of the destination graph, while the value type is - /// the Edge type of the source graph. - template - GraphCopy& edgeCrossRef(EdgeCrossRef& map) { - _edge_maps.push_back(new _core_bits::CrossRefCopy(map)); - return *this; - } - - /// \brief Make a copy of the given edge map. - /// - /// This function makes a copy of the given edge map for the newly - /// created graph. - /// The key type of the new map \c tmap should be the Edge type of the - /// destination graph, and the key type of the original map \c map - /// should be the Edge type of the source graph. - template - GraphCopy& edgeMap(const FromMap& map, ToMap& tmap) { - _edge_maps.push_back(new _core_bits::MapCopy(map, tmap)); - return *this; - } - - /// \brief Make a copy of the given edge. - /// - /// This function makes a copy of the given edge. - GraphCopy& edge(const Edge& edge, TEdge& tedge) { - _edge_maps.push_back(new _core_bits::ItemCopy(edge, tedge)); - return *this; - } - - /// \brief Execute copying. - /// - /// This function executes the copying of the graph along with the - /// copying of the assigned data. - void run() { - NodeRefMap nodeRefMap(_from); - EdgeRefMap edgeRefMap(_from); - ArcRefMap arcRefMap(_from, _to, edgeRefMap, nodeRefMap); - _core_bits::GraphCopySelector:: - copy(_from, _to, nodeRefMap, edgeRefMap); - for (int i = 0; i < int(_node_maps.size()); ++i) { - _node_maps[i]->copy(_from, nodeRefMap); - } - for (int i = 0; i < int(_edge_maps.size()); ++i) { - _edge_maps[i]->copy(_from, edgeRefMap); - } - for (int i = 0; i < int(_arc_maps.size()); ++i) { - _arc_maps[i]->copy(_from, arcRefMap); - } - } - - private: - - const From& _from; - To& _to; - - std::vector<_core_bits::MapCopyBase* > - _node_maps; - - std::vector<_core_bits::MapCopyBase* > - _arc_maps; - - std::vector<_core_bits::MapCopyBase* > - _edge_maps; - - }; - - /// \brief Copy a graph to another graph. - /// - /// This function copies a graph to another graph. - /// The complete usage of it is detailed in the GraphCopy class, - /// but a short example shows a basic work: - ///\code - /// graphCopy(src, trg).nodeRef(nr).edgeCrossRef(ecr).run(); - ///\endcode - /// - /// After the copy the \c nr map will contain the mapping from the - /// nodes of the \c from graph to the nodes of the \c to graph and - /// \c ecr will contain the mapping from the edges of the \c to graph - /// to the edges of the \c from graph. - /// - /// \see GraphCopy - template - GraphCopy - graphCopy(const From& from, To& to) { - return GraphCopy(from, to); - } - - /// \brief Class to copy a bipartite graph. - /// - /// Class to copy a bipartite graph to another graph (duplicate a - /// graph). The simplest way of using it is through the - /// \c bpGraphCopy() function. - /// - /// This class not only make a copy of a bipartite graph, but it can - /// create references and cross references between the nodes, edges - /// and arcs of the two graphs, and it can copy maps for using with - /// the newly created graph. - /// - /// To make a copy from a graph, first an instance of BpGraphCopy - /// should be created, then the data belongs to the graph should - /// assigned to copy. In the end, the \c run() member should be - /// called. - /// - /// The next code copies a graph with several data: - ///\code - /// BpGraphCopy cg(orig_graph, new_graph); - /// // Create references for the nodes - /// OrigBpGraph::NodeMap nr(orig_graph); - /// cg.nodeRef(nr); - /// // Create cross references (inverse) for the edges - /// NewBpGraph::EdgeMap ecr(new_graph); - /// cg.edgeCrossRef(ecr); - /// // Copy a red node map - /// OrigBpGraph::RedNodeMap ormap(orig_graph); - /// NewBpGraph::RedNodeMap nrmap(new_graph); - /// cg.redNodeMap(ormap, nrmap); - /// // Copy a node - /// OrigBpGraph::Node on; - /// NewBpGraph::Node nn; - /// cg.node(on, nn); - /// // Execute copying - /// cg.run(); - ///\endcode - template - class BpGraphCopy { - private: - - typedef typename From::Node Node; - typedef typename From::RedNode RedNode; - typedef typename From::BlueNode BlueNode; - typedef typename From::NodeIt NodeIt; - typedef typename From::Arc Arc; - typedef typename From::ArcIt ArcIt; - typedef typename From::Edge Edge; - typedef typename From::EdgeIt EdgeIt; - - typedef typename To::Node TNode; - typedef typename To::RedNode TRedNode; - typedef typename To::BlueNode TBlueNode; - typedef typename To::Arc TArc; - typedef typename To::Edge TEdge; - - typedef typename From::template RedNodeMap RedNodeRefMap; - typedef typename From::template BlueNodeMap BlueNodeRefMap; - typedef typename From::template EdgeMap EdgeRefMap; - - struct NodeRefMap { - NodeRefMap(const From& from, const RedNodeRefMap& red_node_ref, - const BlueNodeRefMap& blue_node_ref) - : _from(from), _red_node_ref(red_node_ref), - _blue_node_ref(blue_node_ref) {} - - typedef typename From::Node Key; - typedef typename To::Node Value; - - Value operator[](const Key& key) const { - if (_from.red(key)) { - return _red_node_ref[_from.asRedNodeUnsafe(key)]; - } else { - return _blue_node_ref[_from.asBlueNodeUnsafe(key)]; - } - } - - const From& _from; - const RedNodeRefMap& _red_node_ref; - const BlueNodeRefMap& _blue_node_ref; - }; - - struct ArcRefMap { - ArcRefMap(const From& from, const To& to, const EdgeRefMap& edge_ref) - : _from(from), _to(to), _edge_ref(edge_ref) {} - - typedef typename From::Arc Key; - typedef typename To::Arc Value; - - Value operator[](const Key& key) const { - return _to.direct(_edge_ref[key], _from.direction(key)); - } - - const From& _from; - const To& _to; - const EdgeRefMap& _edge_ref; - }; - - public: - - /// \brief Constructor of BpGraphCopy. - /// - /// Constructor of BpGraphCopy for copying the content of the - /// \c from graph into the \c to graph. - BpGraphCopy(const From& from, To& to) - : _from(from), _to(to) {} - - /// \brief Destructor of BpGraphCopy - /// - /// Destructor of BpGraphCopy. - ~BpGraphCopy() { - for (int i = 0; i < int(_node_maps.size()); ++i) { - delete _node_maps[i]; - } - for (int i = 0; i < int(_red_maps.size()); ++i) { - delete _red_maps[i]; - } - for (int i = 0; i < int(_blue_maps.size()); ++i) { - delete _blue_maps[i]; - } - for (int i = 0; i < int(_arc_maps.size()); ++i) { - delete _arc_maps[i]; - } - for (int i = 0; i < int(_edge_maps.size()); ++i) { - delete _edge_maps[i]; - } - } - - /// \brief Copy the node references into the given map. - /// - /// This function copies the node references into the given map. - /// The parameter should be a map, whose key type is the Node type of - /// the source graph, while the value type is the Node type of the - /// destination graph. - template - BpGraphCopy& nodeRef(NodeRef& map) { - _node_maps.push_back(new _core_bits::RefCopy(map)); - return *this; - } - - /// \brief Copy the node cross references into the given map. - /// - /// This function copies the node cross references (reverse references) - /// into the given map. The parameter should be a map, whose key type - /// is the Node type of the destination graph, while the value type is - /// the Node type of the source graph. - template - BpGraphCopy& nodeCrossRef(NodeCrossRef& map) { - _node_maps.push_back(new _core_bits::CrossRefCopy(map)); - return *this; - } - - /// \brief Make a copy of the given node map. - /// - /// This function makes a copy of the given node map for the newly - /// created graph. - /// The key type of the new map \c tmap should be the Node type of the - /// destination graph, and the key type of the original map \c map - /// should be the Node type of the source graph. - template - BpGraphCopy& nodeMap(const FromMap& map, ToMap& tmap) { - _node_maps.push_back(new _core_bits::MapCopy(map, tmap)); - return *this; - } - - /// \brief Make a copy of the given node. - /// - /// This function makes a copy of the given node. - BpGraphCopy& node(const Node& node, TNode& tnode) { - _node_maps.push_back(new _core_bits::ItemCopy(node, tnode)); - return *this; - } - - /// \brief Copy the red node references into the given map. - /// - /// This function copies the red node references into the given - /// map. The parameter should be a map, whose key type is the - /// Node type of the source graph with the red item set, while the - /// value type is the Node type of the destination graph. - template - BpGraphCopy& redRef(RedRef& map) { - _red_maps.push_back(new _core_bits::RefCopy(map)); - return *this; - } - - /// \brief Copy the red node cross references into the given map. - /// - /// This function copies the red node cross references (reverse - /// references) into the given map. The parameter should be a map, - /// whose key type is the Node type of the destination graph with - /// the red item set, while the value type is the Node type of the - /// source graph. - template - BpGraphCopy& redCrossRef(RedCrossRef& map) { - _red_maps.push_back(new _core_bits::CrossRefCopy(map)); - return *this; - } - - /// \brief Make a copy of the given red node map. - /// - /// This function makes a copy of the given red node map for the newly - /// created graph. - /// The key type of the new map \c tmap should be the Node type of - /// the destination graph with the red items, and the key type of - /// the original map \c map should be the Node type of the source - /// graph. - template - BpGraphCopy& redNodeMap(const FromMap& map, ToMap& tmap) { - _red_maps.push_back(new _core_bits::MapCopy(map, tmap)); - return *this; - } - - /// \brief Make a copy of the given red node. - /// - /// This function makes a copy of the given red node. - BpGraphCopy& redNode(const RedNode& node, TRedNode& tnode) { - _red_maps.push_back(new _core_bits::ItemCopy(node, tnode)); - return *this; - } - - /// \brief Copy the blue node references into the given map. - /// - /// This function copies the blue node references into the given - /// map. The parameter should be a map, whose key type is the - /// Node type of the source graph with the blue item set, while the - /// value type is the Node type of the destination graph. - template - BpGraphCopy& blueRef(BlueRef& map) { - _blue_maps.push_back(new _core_bits::RefCopy(map)); - return *this; - } - - /// \brief Copy the blue node cross references into the given map. - /// - /// This function copies the blue node cross references (reverse - /// references) into the given map. The parameter should be a map, - /// whose key type is the Node type of the destination graph with - /// the blue item set, while the value type is the Node type of the - /// source graph. - template - BpGraphCopy& blueCrossRef(BlueCrossRef& map) { - _blue_maps.push_back(new _core_bits::CrossRefCopy(map)); - return *this; - } - - /// \brief Make a copy of the given blue node map. - /// - /// This function makes a copy of the given blue node map for the newly - /// created graph. - /// The key type of the new map \c tmap should be the Node type of - /// the destination graph with the blue items, and the key type of - /// the original map \c map should be the Node type of the source - /// graph. - template - BpGraphCopy& blueNodeMap(const FromMap& map, ToMap& tmap) { - _blue_maps.push_back(new _core_bits::MapCopy(map, tmap)); - return *this; - } - - /// \brief Make a copy of the given blue node. - /// - /// This function makes a copy of the given blue node. - BpGraphCopy& blueNode(const BlueNode& node, TBlueNode& tnode) { - _blue_maps.push_back(new _core_bits::ItemCopy(node, tnode)); - return *this; - } - - /// \brief Copy the arc references into the given map. - /// - /// This function copies the arc references into the given map. - /// The parameter should be a map, whose key type is the Arc type of - /// the source graph, while the value type is the Arc type of the - /// destination graph. - template - BpGraphCopy& arcRef(ArcRef& map) { - _arc_maps.push_back(new _core_bits::RefCopy(map)); - return *this; - } - - /// \brief Copy the arc cross references into the given map. - /// - /// This function copies the arc cross references (reverse references) - /// into the given map. The parameter should be a map, whose key type - /// is the Arc type of the destination graph, while the value type is - /// the Arc type of the source graph. - template - BpGraphCopy& arcCrossRef(ArcCrossRef& map) { - _arc_maps.push_back(new _core_bits::CrossRefCopy(map)); - return *this; - } - - /// \brief Make a copy of the given arc map. - /// - /// This function makes a copy of the given arc map for the newly - /// created graph. - /// The key type of the new map \c tmap should be the Arc type of the - /// destination graph, and the key type of the original map \c map - /// should be the Arc type of the source graph. - template - BpGraphCopy& arcMap(const FromMap& map, ToMap& tmap) { - _arc_maps.push_back(new _core_bits::MapCopy(map, tmap)); - return *this; - } - - /// \brief Make a copy of the given arc. - /// - /// This function makes a copy of the given arc. - BpGraphCopy& arc(const Arc& arc, TArc& tarc) { - _arc_maps.push_back(new _core_bits::ItemCopy(arc, tarc)); - return *this; - } - - /// \brief Copy the edge references into the given map. - /// - /// This function copies the edge references into the given map. - /// The parameter should be a map, whose key type is the Edge type of - /// the source graph, while the value type is the Edge type of the - /// destination graph. - template - BpGraphCopy& edgeRef(EdgeRef& map) { - _edge_maps.push_back(new _core_bits::RefCopy(map)); - return *this; - } - - /// \brief Copy the edge cross references into the given map. - /// - /// This function copies the edge cross references (reverse references) - /// into the given map. The parameter should be a map, whose key type - /// is the Edge type of the destination graph, while the value type is - /// the Edge type of the source graph. - template - BpGraphCopy& edgeCrossRef(EdgeCrossRef& map) { - _edge_maps.push_back(new _core_bits::CrossRefCopy(map)); - return *this; - } - - /// \brief Make a copy of the given edge map. - /// - /// This function makes a copy of the given edge map for the newly - /// created graph. - /// The key type of the new map \c tmap should be the Edge type of the - /// destination graph, and the key type of the original map \c map - /// should be the Edge type of the source graph. - template - BpGraphCopy& edgeMap(const FromMap& map, ToMap& tmap) { - _edge_maps.push_back(new _core_bits::MapCopy(map, tmap)); - return *this; - } - - /// \brief Make a copy of the given edge. - /// - /// This function makes a copy of the given edge. - BpGraphCopy& edge(const Edge& edge, TEdge& tedge) { - _edge_maps.push_back(new _core_bits::ItemCopy(edge, tedge)); - return *this; - } - - /// \brief Execute copying. - /// - /// This function executes the copying of the graph along with the - /// copying of the assigned data. - void run() { - RedNodeRefMap redNodeRefMap(_from); - BlueNodeRefMap blueNodeRefMap(_from); - NodeRefMap nodeRefMap(_from, redNodeRefMap, blueNodeRefMap); - EdgeRefMap edgeRefMap(_from); - ArcRefMap arcRefMap(_from, _to, edgeRefMap); - _core_bits::BpGraphCopySelector:: - copy(_from, _to, redNodeRefMap, blueNodeRefMap, edgeRefMap); - for (int i = 0; i < int(_node_maps.size()); ++i) { - _node_maps[i]->copy(_from, nodeRefMap); - } - for (int i = 0; i < int(_red_maps.size()); ++i) { - _red_maps[i]->copy(_from, redNodeRefMap); - } - for (int i = 0; i < int(_blue_maps.size()); ++i) { - _blue_maps[i]->copy(_from, blueNodeRefMap); - } - for (int i = 0; i < int(_edge_maps.size()); ++i) { - _edge_maps[i]->copy(_from, edgeRefMap); - } - for (int i = 0; i < int(_arc_maps.size()); ++i) { - _arc_maps[i]->copy(_from, arcRefMap); - } - } - - private: - - const From& _from; - To& _to; - - std::vector<_core_bits::MapCopyBase* > - _node_maps; - - std::vector<_core_bits::MapCopyBase* > - _red_maps; - - std::vector<_core_bits::MapCopyBase* > - _blue_maps; - - std::vector<_core_bits::MapCopyBase* > - _arc_maps; - - std::vector<_core_bits::MapCopyBase* > - _edge_maps; - - }; - - /// \brief Copy a graph to another graph. - /// - /// This function copies a graph to another graph. - /// The complete usage of it is detailed in the BpGraphCopy class, - /// but a short example shows a basic work: - ///\code - /// graphCopy(src, trg).nodeRef(nr).edgeCrossRef(ecr).run(); - ///\endcode - /// - /// After the copy the \c nr map will contain the mapping from the - /// nodes of the \c from graph to the nodes of the \c to graph and - /// \c ecr will contain the mapping from the edges of the \c to graph - /// to the edges of the \c from graph. - /// - /// \see BpGraphCopy - template - BpGraphCopy - bpGraphCopy(const From& from, To& to) { - return BpGraphCopy(from, to); - } - - namespace _core_bits { - - template - struct FindArcSelector { - typedef typename Graph::Node Node; - typedef typename Graph::Arc Arc; - static Arc find(const Graph &g, Node u, Node v, Arc e) { - if (e == INVALID) { - g.firstOut(e, u); - } else { - g.nextOut(e); - } - while (e != INVALID && g.target(e) != v) { - g.nextOut(e); - } - return e; - } - }; - - template - struct FindArcSelector< - Graph, - typename enable_if::type> - { - typedef typename Graph::Node Node; - typedef typename Graph::Arc Arc; - static Arc find(const Graph &g, Node u, Node v, Arc prev) { - return g.findArc(u, v, prev); - } - }; - } - - /// \brief Find an arc between two nodes of a digraph. - /// - /// This function finds an arc from node \c u to node \c v in the - /// digraph \c g. - /// - /// If \c prev is \ref INVALID (this is the default value), then - /// it finds the first arc from \c u to \c v. Otherwise it looks for - /// the next arc from \c u to \c v after \c prev. - /// \return The found arc or \ref INVALID if there is no such an arc. - /// - /// Thus you can iterate through each arc from \c u to \c v as it follows. - ///\code - /// for(Arc e = findArc(g,u,v); e != INVALID; e = findArc(g,u,v,e)) { - /// ... - /// } - ///\endcode - /// - /// \note \ref ConArcIt provides iterator interface for the same - /// functionality. - /// - ///\sa ConArcIt - ///\sa ArcLookUp, AllArcLookUp, DynArcLookUp - template - inline typename Graph::Arc - findArc(const Graph &g, typename Graph::Node u, typename Graph::Node v, - typename Graph::Arc prev = INVALID) { - return _core_bits::FindArcSelector::find(g, u, v, prev); - } - - /// \brief Iterator for iterating on parallel arcs connecting the same nodes. - /// - /// Iterator for iterating on parallel arcs connecting the same nodes. It is - /// a higher level interface for the \ref findArc() function. You can - /// use it the following way: - ///\code - /// for (ConArcIt it(g, src, trg); it != INVALID; ++it) { - /// ... - /// } - ///\endcode - /// - ///\sa findArc() - ///\sa ArcLookUp, AllArcLookUp, DynArcLookUp - template - class ConArcIt : public GR::Arc { - typedef typename GR::Arc Parent; - - public: - - typedef typename GR::Arc Arc; - typedef typename GR::Node Node; - - /// \brief Constructor. - /// - /// Construct a new ConArcIt iterating on the arcs that - /// connects nodes \c u and \c v. - ConArcIt(const GR& g, Node u, Node v) : _graph(g) { - Parent::operator=(findArc(_graph, u, v)); - } - - /// \brief Constructor. - /// - /// Construct a new ConArcIt that continues the iterating from arc \c a. - ConArcIt(const GR& g, Arc a) : Parent(a), _graph(g) {} - - /// \brief Increment operator. - /// - /// It increments the iterator and gives back the next arc. - ConArcIt& operator++() { - Parent::operator=(findArc(_graph, _graph.source(*this), - _graph.target(*this), *this)); - return *this; - } - private: - const GR& _graph; - }; - - namespace _core_bits { - - template - struct FindEdgeSelector { - typedef typename Graph::Node Node; - typedef typename Graph::Edge Edge; - static Edge find(const Graph &g, Node u, Node v, Edge e) { - bool b; - if (u != v) { - if (e == INVALID) { - g.firstInc(e, b, u); - } else { - b = g.u(e) == u; - g.nextInc(e, b); - } - while (e != INVALID && (b ? g.v(e) : g.u(e)) != v) { - g.nextInc(e, b); - } - } else { - if (e == INVALID) { - g.firstInc(e, b, u); - } else { - b = true; - g.nextInc(e, b); - } - while (e != INVALID && (!b || g.v(e) != v)) { - g.nextInc(e, b); - } - } - return e; - } - }; - - template - struct FindEdgeSelector< - Graph, - typename enable_if::type> - { - typedef typename Graph::Node Node; - typedef typename Graph::Edge Edge; - static Edge find(const Graph &g, Node u, Node v, Edge prev) { - return g.findEdge(u, v, prev); - } - }; - } - - /// \brief Find an edge between two nodes of a graph. - /// - /// This function finds an edge from node \c u to node \c v in graph \c g. - /// If node \c u and node \c v is equal then each loop edge - /// will be enumerated once. - /// - /// If \c prev is \ref INVALID (this is the default value), then - /// it finds the first edge from \c u to \c v. Otherwise it looks for - /// the next edge from \c u to \c v after \c prev. - /// \return The found edge or \ref INVALID if there is no such an edge. - /// - /// Thus you can iterate through each edge between \c u and \c v - /// as it follows. - ///\code - /// for(Edge e = findEdge(g,u,v); e != INVALID; e = findEdge(g,u,v,e)) { - /// ... - /// } - ///\endcode - /// - /// \note \ref ConEdgeIt provides iterator interface for the same - /// functionality. - /// - ///\sa ConEdgeIt - template - inline typename Graph::Edge - findEdge(const Graph &g, typename Graph::Node u, typename Graph::Node v, - typename Graph::Edge p = INVALID) { - return _core_bits::FindEdgeSelector::find(g, u, v, p); - } - - /// \brief Iterator for iterating on parallel edges connecting the same nodes. - /// - /// Iterator for iterating on parallel edges connecting the same nodes. - /// It is a higher level interface for the findEdge() function. You can - /// use it the following way: - ///\code - /// for (ConEdgeIt it(g, u, v); it != INVALID; ++it) { - /// ... - /// } - ///\endcode - /// - ///\sa findEdge() - template - class ConEdgeIt : public GR::Edge { - typedef typename GR::Edge Parent; - - public: - - typedef typename GR::Edge Edge; - typedef typename GR::Node Node; - - /// \brief Constructor. - /// - /// Construct a new ConEdgeIt iterating on the edges that - /// connects nodes \c u and \c v. - ConEdgeIt(const GR& g, Node u, Node v) : _graph(g), _u(u), _v(v) { - Parent::operator=(findEdge(_graph, _u, _v)); - } - - /// \brief Constructor. - /// - /// Construct a new ConEdgeIt that continues iterating from edge \c e. - ConEdgeIt(const GR& g, Edge e) : Parent(e), _graph(g) {} - - /// \brief Increment operator. - /// - /// It increments the iterator and gives back the next edge. - ConEdgeIt& operator++() { - Parent::operator=(findEdge(_graph, _u, _v, *this)); - return *this; - } - private: - const GR& _graph; - Node _u, _v; - }; - - - ///Dynamic arc look-up between given endpoints. - - ///Using this class, you can find an arc in a digraph from a given - ///source to a given target in amortized time O(logd), - ///where d is the out-degree of the source node. - /// - ///It is possible to find \e all parallel arcs between two nodes with - ///the \c operator() member. - /// - ///This is a dynamic data structure. Consider to use \ref ArcLookUp or - ///\ref AllArcLookUp if your digraph is not changed so frequently. - /// - ///This class uses a self-adjusting binary search tree, the Splay tree - ///of Sleator and Tarjan to guarantee the logarithmic amortized - ///time bound for arc look-ups. This class also guarantees the - ///optimal time bound in a constant factor for any distribution of - ///queries. - /// - ///\tparam GR The type of the underlying digraph. - /// - ///\sa ArcLookUp - ///\sa AllArcLookUp - template - class DynArcLookUp - : protected ItemSetTraits::ItemNotifier::ObserverBase - { - typedef typename ItemSetTraits - ::ItemNotifier::ObserverBase Parent; - - TEMPLATE_DIGRAPH_TYPEDEFS(GR); - - public: - - /// The Digraph type - typedef GR Digraph; - - protected: - - class AutoNodeMap : public ItemSetTraits::template Map::Type - { - typedef typename ItemSetTraits::template Map::Type Parent; - - public: - - AutoNodeMap(const GR& digraph) : Parent(digraph, INVALID) {} - - virtual void add(const Node& node) { - Parent::add(node); - Parent::set(node, INVALID); - } - - virtual void add(const std::vector& nodes) { - Parent::add(nodes); - for (int i = 0; i < int(nodes.size()); ++i) { - Parent::set(nodes[i], INVALID); - } - } - - virtual void build() { - Parent::build(); - Node it; - typename Parent::Notifier* nf = Parent::notifier(); - for (nf->first(it); it != INVALID; nf->next(it)) { - Parent::set(it, INVALID); - } - } - }; - - class ArcLess { - const Digraph &g; - public: - ArcLess(const Digraph &_g) : g(_g) {} - bool operator()(Arc a,Arc b) const - { - return g.target(a) _parent; - typename Digraph::template ArcMap _left; - typename Digraph::template ArcMap _right; - - public: - - ///Constructor - - ///Constructor. - /// - ///It builds up the search database. - DynArcLookUp(const Digraph &g) - : _g(g),_head(g),_parent(g),_left(g),_right(g) - { - Parent::attach(_g.notifier(typename Digraph::Arc())); - refresh(); - } - - protected: - - virtual void add(const Arc& arc) { - insert(arc); - } - - virtual void add(const std::vector& arcs) { - for (int i = 0; i < int(arcs.size()); ++i) { - insert(arcs[i]); - } - } - - virtual void erase(const Arc& arc) { - remove(arc); - } - - virtual void erase(const std::vector& arcs) { - for (int i = 0; i < int(arcs.size()); ++i) { - remove(arcs[i]); - } - } - - virtual void build() { - refresh(); - } - - virtual void clear() { - for(NodeIt n(_g);n!=INVALID;++n) { - _head[n] = INVALID; - } - } - - void insert(Arc arc) { - Node s = _g.source(arc); - Node t = _g.target(arc); - _left[arc] = INVALID; - _right[arc] = INVALID; - - Arc e = _head[s]; - if (e == INVALID) { - _head[s] = arc; - _parent[arc] = INVALID; - return; - } - while (true) { - if (t < _g.target(e)) { - if (_left[e] == INVALID) { - _left[e] = arc; - _parent[arc] = e; - splay(arc); - return; - } else { - e = _left[e]; - } - } else { - if (_right[e] == INVALID) { - _right[e] = arc; - _parent[arc] = e; - splay(arc); - return; - } else { - e = _right[e]; - } - } - } - } - - void remove(Arc arc) { - if (_left[arc] == INVALID) { - if (_right[arc] != INVALID) { - _parent[_right[arc]] = _parent[arc]; - } - if (_parent[arc] != INVALID) { - if (_left[_parent[arc]] == arc) { - _left[_parent[arc]] = _right[arc]; - } else { - _right[_parent[arc]] = _right[arc]; - } - } else { - _head[_g.source(arc)] = _right[arc]; - } - } else if (_right[arc] == INVALID) { - _parent[_left[arc]] = _parent[arc]; - if (_parent[arc] != INVALID) { - if (_left[_parent[arc]] == arc) { - _left[_parent[arc]] = _left[arc]; - } else { - _right[_parent[arc]] = _left[arc]; - } - } else { - _head[_g.source(arc)] = _left[arc]; - } - } else { - Arc e = _left[arc]; - if (_right[e] != INVALID) { - e = _right[e]; - while (_right[e] != INVALID) { - e = _right[e]; - } - Arc s = _parent[e]; - _right[_parent[e]] = _left[e]; - if (_left[e] != INVALID) { - _parent[_left[e]] = _parent[e]; - } - - _left[e] = _left[arc]; - _parent[_left[arc]] = e; - _right[e] = _right[arc]; - _parent[_right[arc]] = e; - - _parent[e] = _parent[arc]; - if (_parent[arc] != INVALID) { - if (_left[_parent[arc]] == arc) { - _left[_parent[arc]] = e; - } else { - _right[_parent[arc]] = e; - } - } - splay(s); - } else { - _right[e] = _right[arc]; - _parent[_right[arc]] = e; - _parent[e] = _parent[arc]; - - if (_parent[arc] != INVALID) { - if (_left[_parent[arc]] == arc) { - _left[_parent[arc]] = e; - } else { - _right[_parent[arc]] = e; - } - } else { - _head[_g.source(arc)] = e; - } - } - } - } - - Arc refreshRec(std::vector &v,int a,int b) - { - int m=(a+b)/2; - Arc me=v[m]; - if (a < m) { - Arc left = refreshRec(v,a,m-1); - _left[me] = left; - _parent[left] = me; - } else { - _left[me] = INVALID; - } - if (m < b) { - Arc right = refreshRec(v,m+1,b); - _right[me] = right; - _parent[right] = me; - } else { - _right[me] = INVALID; - } - return me; - } - - void refresh() { - for(NodeIt n(_g);n!=INVALID;++n) { - std::vector v; - for(OutArcIt a(_g,n);a!=INVALID;++a) v.push_back(a); - if (!v.empty()) { - std::sort(v.begin(),v.end(),ArcLess(_g)); - Arc head = refreshRec(v,0,v.size()-1); - _head[n] = head; - _parent[head] = INVALID; - } - else _head[n] = INVALID; - } - } - - void zig(Arc v) { - Arc w = _parent[v]; - _parent[v] = _parent[w]; - _parent[w] = v; - _left[w] = _right[v]; - _right[v] = w; - if (_parent[v] != INVALID) { - if (_right[_parent[v]] == w) { - _right[_parent[v]] = v; - } else { - _left[_parent[v]] = v; - } - } - if (_left[w] != INVALID){ - _parent[_left[w]] = w; - } - } - - void zag(Arc v) { - Arc w = _parent[v]; - _parent[v] = _parent[w]; - _parent[w] = v; - _right[w] = _left[v]; - _left[v] = w; - if (_parent[v] != INVALID){ - if (_left[_parent[v]] == w) { - _left[_parent[v]] = v; - } else { - _right[_parent[v]] = v; - } - } - if (_right[w] != INVALID){ - _parent[_right[w]] = w; - } - } - - void splay(Arc v) { - while (_parent[v] != INVALID) { - if (v == _left[_parent[v]]) { - if (_parent[_parent[v]] == INVALID) { - zig(v); - } else { - if (_parent[v] == _left[_parent[_parent[v]]]) { - zig(_parent[v]); - zig(v); - } else { - zig(v); - zag(v); - } - } - } else { - if (_parent[_parent[v]] == INVALID) { - zag(v); - } else { - if (_parent[v] == _left[_parent[_parent[v]]]) { - zag(v); - zig(v); - } else { - zag(_parent[v]); - zag(v); - } - } - } - } - _head[_g.source(v)] = v; - } - - - public: - - ///Find an arc between two nodes. - - ///Find an arc between two nodes. - ///\param s The source node. - ///\param t The target node. - ///\param p The previous arc between \c s and \c t. It it is INVALID or - ///not given, the operator finds the first appropriate arc. - ///\return An arc from \c s to \c t after \c p or - ///\ref INVALID if there is no more. - /// - ///For example, you can count the number of arcs from \c u to \c v in the - ///following way. - ///\code - ///DynArcLookUp ae(g); - ///... - ///int n = 0; - ///for(Arc a = ae(u,v); a != INVALID; a = ae(u,v,a)) n++; - ///\endcode - /// - ///Finding the arcs take at most O(logd) - ///amortized time, specifically, the time complexity of the lookups - ///is equal to the optimal search tree implementation for the - ///current query distribution in a constant factor. - /// - ///\note This is a dynamic data structure, therefore the data - ///structure is updated after each graph alteration. Thus although - ///this data structure is theoretically faster than \ref ArcLookUp - ///and \ref AllArcLookUp, it often provides worse performance than - ///them. - Arc operator()(Node s, Node t, Arc p = INVALID) const { - if (p == INVALID) { - Arc a = _head[s]; - if (a == INVALID) return INVALID; - Arc r = INVALID; - while (true) { - if (_g.target(a) < t) { - if (_right[a] == INVALID) { - const_cast(*this).splay(a); - return r; - } else { - a = _right[a]; - } - } else { - if (_g.target(a) == t) { - r = a; - } - if (_left[a] == INVALID) { - const_cast(*this).splay(a); - return r; - } else { - a = _left[a]; - } - } - } - } else { - Arc a = p; - if (_right[a] != INVALID) { - a = _right[a]; - while (_left[a] != INVALID) { - a = _left[a]; - } - const_cast(*this).splay(a); - } else { - while (_parent[a] != INVALID && _right[_parent[a]] == a) { - a = _parent[a]; - } - if (_parent[a] == INVALID) { - return INVALID; - } else { - a = _parent[a]; - const_cast(*this).splay(a); - } - } - if (_g.target(a) == t) return a; - else return INVALID; - } - } - - }; - - ///Fast arc look-up between given endpoints. - - ///Using this class, you can find an arc in a digraph from a given - ///source to a given target in time O(logd), - ///where d is the out-degree of the source node. - /// - ///It is not possible to find \e all parallel arcs between two nodes. - ///Use \ref AllArcLookUp for this purpose. - /// - ///\warning This class is static, so you should call refresh() (or at - ///least refresh(Node)) to refresh this data structure whenever the - ///digraph changes. This is a time consuming (superlinearly proportional - ///(O(m logm)) to the number of arcs). - /// - ///\tparam GR The type of the underlying digraph. - /// - ///\sa DynArcLookUp - ///\sa AllArcLookUp - template - class ArcLookUp - { - TEMPLATE_DIGRAPH_TYPEDEFS(GR); - - public: - - /// The Digraph type - typedef GR Digraph; - - protected: - const Digraph &_g; - typename Digraph::template NodeMap _head; - typename Digraph::template ArcMap _left; - typename Digraph::template ArcMap _right; - - class ArcLess { - const Digraph &g; - public: - ArcLess(const Digraph &_g) : g(_g) {} - bool operator()(Arc a,Arc b) const - { - return g.target(a) &v,int a,int b) - { - int m=(a+b)/2; - Arc me=v[m]; - _left[me] = aO(d logd), where d - ///is the number of the outgoing arcs of \c n. - void refresh(Node n) - { - std::vector v; - for(OutArcIt e(_g,n);e!=INVALID;++e) v.push_back(e); - if(v.size()) { - std::sort(v.begin(),v.end(),ArcLess(_g)); - _head[n]=refreshRec(v,0,v.size()-1); - } - else _head[n]=INVALID; - } - ///Refresh the full data structure. - - ///Build up the full search database. In fact, it simply calls - ///\ref refresh(Node) "refresh(n)" for each node \c n. - /// - ///It runs in time O(m logD), where m is - ///the number of the arcs in the digraph and D is the maximum - ///out-degree of the digraph. - void refresh() - { - for(NodeIt n(_g);n!=INVALID;++n) refresh(n); - } - - ///Find an arc between two nodes. - - ///Find an arc between two nodes in time O(logd), - ///where d is the number of outgoing arcs of \c s. - ///\param s The source node. - ///\param t The target node. - ///\return An arc from \c s to \c t if there exists, - ///\ref INVALID otherwise. - /// - ///\warning If you change the digraph, refresh() must be called before using - ///this operator. If you change the outgoing arcs of - ///a single node \c n, then \ref refresh(Node) "refresh(n)" is enough. - Arc operator()(Node s, Node t) const - { - Arc e; - for(e=_head[s]; - e!=INVALID&&_g.target(e)!=t; - e = t < _g.target(e)?_left[e]:_right[e]) ; - return e; - } - - }; - - ///Fast look-up of all arcs between given endpoints. - - ///This class is the same as \ref ArcLookUp, with the addition - ///that it makes it possible to find all parallel arcs between given - ///endpoints. - /// - ///\warning This class is static, so you should call refresh() (or at - ///least refresh(Node)) to refresh this data structure whenever the - ///digraph changes. This is a time consuming (superlinearly proportional - ///(O(m logm)) to the number of arcs). - /// - ///\tparam GR The type of the underlying digraph. - /// - ///\sa DynArcLookUp - ///\sa ArcLookUp - template - class AllArcLookUp : public ArcLookUp - { - using ArcLookUp::_g; - using ArcLookUp::_right; - using ArcLookUp::_left; - using ArcLookUp::_head; - - TEMPLATE_DIGRAPH_TYPEDEFS(GR); - - typename GR::template ArcMap _next; - - Arc refreshNext(Arc head,Arc next=INVALID) - { - if(head==INVALID) return next; - else { - next=refreshNext(_right[head],next); - _next[head]=( next!=INVALID && _g.target(next)==_g.target(head)) - ? next : INVALID; - return refreshNext(_left[head],head); - } - } - - void refreshNext() - { - for(NodeIt n(_g);n!=INVALID;++n) refreshNext(_head[n]); - } - - public: - - /// The Digraph type - typedef GR Digraph; - - ///Constructor - - ///Constructor. - /// - ///It builds up the search database, which remains valid until the digraph - ///changes. - AllArcLookUp(const Digraph &g) : ArcLookUp(g), _next(g) {refreshNext();} - - ///Refresh the data structure at a node. - - ///Build up the search database of node \c n. - /// - ///It runs in time O(d logd), where d is - ///the number of the outgoing arcs of \c n. - void refresh(Node n) - { - ArcLookUp::refresh(n); - refreshNext(_head[n]); - } - - ///Refresh the full data structure. - - ///Build up the full search database. In fact, it simply calls - ///\ref refresh(Node) "refresh(n)" for each node \c n. - /// - ///It runs in time O(m logD), where m is - ///the number of the arcs in the digraph and D is the maximum - ///out-degree of the digraph. - void refresh() - { - for(NodeIt n(_g);n!=INVALID;++n) refresh(_head[n]); - } - - ///Find an arc between two nodes. - - ///Find an arc between two nodes. - ///\param s The source node. - ///\param t The target node. - ///\param prev The previous arc between \c s and \c t. It it is INVALID or - ///not given, the operator finds the first appropriate arc. - ///\return An arc from \c s to \c t after \c prev or - ///\ref INVALID if there is no more. - /// - ///For example, you can count the number of arcs from \c u to \c v in the - ///following way. - ///\code - ///AllArcLookUp ae(g); - ///... - ///int n = 0; - ///for(Arc a = ae(u,v); a != INVALID; a=ae(u,v,a)) n++; - ///\endcode - /// - ///Finding the first arc take O(logd) time, - ///where d is the number of outgoing arcs of \c s. Then the - ///consecutive arcs are found in constant time. - /// - ///\warning If you change the digraph, refresh() must be called before using - ///this operator. If you change the outgoing arcs of - ///a single node \c n, then \ref refresh(Node) "refresh(n)" is enough. - /// - Arc operator()(Node s, Node t, Arc prev=INVALID) const - { - if(prev==INVALID) - { - Arc f=INVALID; - Arc e; - for(e=_head[s]; - e!=INVALID&&_g.target(e)!=t; - e = t < _g.target(e)?_left[e]:_right[e]) ; - while(e!=INVALID) - if(_g.target(e)==t) - { - f = e; - e = _left[e]; - } - else e = _right[e]; - return f; - } - else return _next[prev]; - } - - }; - - /// @} - -} //namespace lemon - -#endif diff --git a/deps/lemon/lemon/cost_scaling.h b/deps/lemon/lemon/cost_scaling.h deleted file mode 100644 index efecdfe77..000000000 --- a/deps/lemon/lemon/cost_scaling.h +++ /dev/null @@ -1,1607 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_COST_SCALING_H -#define LEMON_COST_SCALING_H - -/// \ingroup min_cost_flow_algs -/// \file -/// \brief Cost scaling algorithm for finding a minimum cost flow. - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -namespace lemon { - - /// \brief Default traits class of CostScaling algorithm. - /// - /// Default traits class of CostScaling algorithm. - /// \tparam GR Digraph type. - /// \tparam V The number type used for flow amounts, capacity bounds - /// and supply values. By default it is \c int. - /// \tparam C The number type used for costs and potentials. - /// By default it is the same as \c V. -#ifdef DOXYGEN - template -#else - template < typename GR, typename V = int, typename C = V, - bool integer = std::numeric_limits::is_integer > -#endif - struct CostScalingDefaultTraits - { - /// The type of the digraph - typedef GR Digraph; - /// The type of the flow amounts, capacity bounds and supply values - typedef V Value; - /// The type of the arc costs - typedef C Cost; - - /// \brief The large cost type used for internal computations - /// - /// The large cost type used for internal computations. - /// It is \c long \c long if the \c Cost type is integer, - /// otherwise it is \c double. - /// \c Cost must be convertible to \c LargeCost. - typedef double LargeCost; - }; - - // Default traits class for integer cost types - template - struct CostScalingDefaultTraits - { - typedef GR Digraph; - typedef V Value; - typedef C Cost; -#ifdef LEMON_HAVE_LONG_LONG - typedef long long LargeCost; -#else - typedef long LargeCost; -#endif - }; - - - /// \addtogroup min_cost_flow_algs - /// @{ - - /// \brief Implementation of the Cost Scaling algorithm for - /// finding a \ref min_cost_flow "minimum cost flow". - /// - /// \ref CostScaling implements a cost scaling algorithm that performs - /// push/augment and relabel operations for finding a \ref min_cost_flow - /// "minimum cost flow" \cite amo93networkflows, - /// \cite goldberg90approximation, - /// \cite goldberg97efficient, \cite bunnagel98efficient. - /// It is a highly efficient primal-dual solution method, which - /// can be viewed as the generalization of the \ref Preflow - /// "preflow push-relabel" algorithm for the maximum flow problem. - /// It is a polynomial algorithm, its running time complexity is - /// \f$O(n^2m\log(nK))\f$, where K denotes the maximum arc cost. - /// - /// In general, \ref NetworkSimplex and \ref CostScaling are the fastest - /// implementations available in LEMON for solving this problem. - /// (For more information, see \ref min_cost_flow_algs "the module page".) - /// - /// Most of the parameters of the problem (except for the digraph) - /// can be given using separate functions, and the algorithm can be - /// executed using the \ref run() function. If some parameters are not - /// specified, then default values will be used. - /// - /// \tparam GR The digraph type the algorithm runs on. - /// \tparam V The number type used for flow amounts, capacity bounds - /// and supply values in the algorithm. By default, it is \c int. - /// \tparam C The number type used for costs and potentials in the - /// algorithm. By default, it is the same as \c V. - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref CostScalingDefaultTraits - /// "CostScalingDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. - /// - /// \warning Both \c V and \c C must be signed number types. - /// \warning All input data (capacities, supply values, and costs) must - /// be integer. - /// \warning This algorithm does not support negative costs for - /// arcs having infinite upper bound. - /// - /// \note %CostScaling provides three different internal methods, - /// from which the most efficient one is used by default. - /// For more information, see \ref Method. -#ifdef DOXYGEN - template -#else - template < typename GR, typename V = int, typename C = V, - typename TR = CostScalingDefaultTraits > -#endif - class CostScaling - { - public: - - /// The type of the digraph - typedef typename TR::Digraph Digraph; - /// The type of the flow amounts, capacity bounds and supply values - typedef typename TR::Value Value; - /// The type of the arc costs - typedef typename TR::Cost Cost; - - /// \brief The large cost type - /// - /// The large cost type used for internal computations. - /// By default, it is \c long \c long if the \c Cost type is integer, - /// otherwise it is \c double. - typedef typename TR::LargeCost LargeCost; - - /// \brief The \ref lemon::CostScalingDefaultTraits "traits class" - /// of the algorithm - typedef TR Traits; - - public: - - /// \brief Problem type constants for the \c run() function. - /// - /// Enum type containing the problem type constants that can be - /// returned by the \ref run() function of the algorithm. - enum ProblemType { - /// The problem has no feasible solution (flow). - INFEASIBLE, - /// The problem has optimal solution (i.e. it is feasible and - /// bounded), and the algorithm has found optimal flow and node - /// potentials (primal and dual solutions). - OPTIMAL, - /// The digraph contains an arc of negative cost and infinite - /// upper bound. It means that the objective function is unbounded - /// on that arc, however, note that it could actually be bounded - /// over the feasible flows, but this algroithm cannot handle - /// these cases. - UNBOUNDED - }; - - /// \brief Constants for selecting the internal method. - /// - /// Enum type containing constants for selecting the internal method - /// for the \ref run() function. - /// - /// \ref CostScaling provides three internal methods that differ mainly - /// in their base operations, which are used in conjunction with the - /// relabel operation. - /// By default, the so called \ref PARTIAL_AUGMENT - /// "Partial Augment-Relabel" method is used, which turned out to be - /// the most efficient and the most robust on various test inputs. - /// However, the other methods can be selected using the \ref run() - /// function with the proper parameter. - enum Method { - /// Local push operations are used, i.e. flow is moved only on one - /// admissible arc at once. - PUSH, - /// Augment operations are used, i.e. flow is moved on admissible - /// paths from a node with excess to a node with deficit. - AUGMENT, - /// Partial augment operations are used, i.e. flow is moved on - /// admissible paths started from a node with excess, but the - /// lengths of these paths are limited. This method can be viewed - /// as a combined version of the previous two operations. - PARTIAL_AUGMENT - }; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(GR); - - typedef std::vector IntVector; - typedef std::vector ValueVector; - typedef std::vector CostVector; - typedef std::vector LargeCostVector; - typedef std::vector BoolVector; - // Note: vector is used instead of vector - // for efficiency reasons - - private: - - template - class StaticVectorMap { - public: - typedef KT Key; - typedef VT Value; - - StaticVectorMap(std::vector& v) : _v(v) {} - - const Value& operator[](const Key& key) const { - return _v[StaticDigraph::id(key)]; - } - - Value& operator[](const Key& key) { - return _v[StaticDigraph::id(key)]; - } - - void set(const Key& key, const Value& val) { - _v[StaticDigraph::id(key)] = val; - } - - private: - std::vector& _v; - }; - - typedef StaticVectorMap LargeCostArcMap; - - private: - - // Data related to the underlying digraph - const GR &_graph; - int _node_num; - int _arc_num; - int _res_node_num; - int _res_arc_num; - int _root; - - // Parameters of the problem - bool _has_lower; - Value _sum_supply; - int _sup_node_num; - - // Data structures for storing the digraph - IntNodeMap _node_id; - IntArcMap _arc_idf; - IntArcMap _arc_idb; - IntVector _first_out; - BoolVector _forward; - IntVector _source; - IntVector _target; - IntVector _reverse; - - // Node and arc data - ValueVector _lower; - ValueVector _upper; - CostVector _scost; - ValueVector _supply; - - ValueVector _res_cap; - LargeCostVector _cost; - LargeCostVector _pi; - ValueVector _excess; - IntVector _next_out; - std::deque _active_nodes; - - // Data for scaling - LargeCost _epsilon; - int _alpha; - - IntVector _buckets; - IntVector _bucket_next; - IntVector _bucket_prev; - IntVector _rank; - int _max_rank; - - public: - - /// \brief Constant for infinite upper bounds (capacities). - /// - /// Constant for infinite upper bounds (capacities). - /// It is \c std::numeric_limits::infinity() if available, - /// \c std::numeric_limits::max() otherwise. - const Value INF; - - public: - - /// \name Named Template Parameters - /// @{ - - template - struct SetLargeCostTraits : public Traits { - typedef T LargeCost; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c LargeCost type. - /// - /// \ref named-templ-param "Named parameter" for setting \c LargeCost - /// type, which is used for internal computations in the algorithm. - /// \c Cost must be convertible to \c LargeCost. - template - struct SetLargeCost - : public CostScaling > { - typedef CostScaling > Create; - }; - - /// @} - - protected: - - CostScaling() {} - - public: - - /// \brief Constructor. - /// - /// The constructor of the class. - /// - /// \param graph The digraph the algorithm runs on. - CostScaling(const GR& graph) : - _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph), - INF(std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max()) - { - // Check the number types - LEMON_ASSERT(std::numeric_limits::is_signed, - "The flow type of CostScaling must be signed"); - LEMON_ASSERT(std::numeric_limits::is_signed, - "The cost type of CostScaling must be signed"); - - // Reset data structures - reset(); - } - - /// \name Parameters - /// The parameters of the algorithm can be specified using these - /// functions. - - /// @{ - - /// \brief Set the lower bounds on the arcs. - /// - /// This function sets the lower bounds on the arcs. - /// If it is not used before calling \ref run(), the lower bounds - /// will be set to zero on all arcs. - /// - /// \param map An arc map storing the lower bounds. - /// Its \c Value type must be convertible to the \c Value type - /// of the algorithm. - /// - /// \return (*this) - template - CostScaling& lowerMap(const LowerMap& map) { - _has_lower = true; - for (ArcIt a(_graph); a != INVALID; ++a) { - _lower[_arc_idf[a]] = map[a]; - } - return *this; - } - - /// \brief Set the upper bounds (capacities) on the arcs. - /// - /// This function sets the upper bounds (capacities) on the arcs. - /// If it is not used before calling \ref run(), the upper bounds - /// will be set to \ref INF on all arcs (i.e. the flow value will be - /// unbounded from above). - /// - /// \param map An arc map storing the upper bounds. - /// Its \c Value type must be convertible to the \c Value type - /// of the algorithm. - /// - /// \return (*this) - template - CostScaling& upperMap(const UpperMap& map) { - for (ArcIt a(_graph); a != INVALID; ++a) { - _upper[_arc_idf[a]] = map[a]; - } - return *this; - } - - /// \brief Set the costs of the arcs. - /// - /// This function sets the costs of the arcs. - /// If it is not used before calling \ref run(), the costs - /// will be set to \c 1 on all arcs. - /// - /// \param map An arc map storing the costs. - /// Its \c Value type must be convertible to the \c Cost type - /// of the algorithm. - /// - /// \return (*this) - template - CostScaling& costMap(const CostMap& map) { - for (ArcIt a(_graph); a != INVALID; ++a) { - _scost[_arc_idf[a]] = map[a]; - _scost[_arc_idb[a]] = -map[a]; - } - return *this; - } - - /// \brief Set the supply values of the nodes. - /// - /// This function sets the supply values of the nodes. - /// If neither this function nor \ref stSupply() is used before - /// calling \ref run(), the supply of each node will be set to zero. - /// - /// \param map A node map storing the supply values. - /// Its \c Value type must be convertible to the \c Value type - /// of the algorithm. - /// - /// \return (*this) - template - CostScaling& supplyMap(const SupplyMap& map) { - for (NodeIt n(_graph); n != INVALID; ++n) { - _supply[_node_id[n]] = map[n]; - } - return *this; - } - - /// \brief Set single source and target nodes and a supply value. - /// - /// This function sets a single source node and a single target node - /// and the required flow value. - /// If neither this function nor \ref supplyMap() is used before - /// calling \ref run(), the supply of each node will be set to zero. - /// - /// Using this function has the same effect as using \ref supplyMap() - /// with a map in which \c k is assigned to \c s, \c -k is - /// assigned to \c t and all other nodes have zero supply value. - /// - /// \param s The source node. - /// \param t The target node. - /// \param k The required amount of flow from node \c s to node \c t - /// (i.e. the supply of \c s and the demand of \c t). - /// - /// \return (*this) - CostScaling& stSupply(const Node& s, const Node& t, Value k) { - for (int i = 0; i != _res_node_num; ++i) { - _supply[i] = 0; - } - _supply[_node_id[s]] = k; - _supply[_node_id[t]] = -k; - return *this; - } - - /// @} - - /// \name Execution control - /// The algorithm can be executed using \ref run(). - - /// @{ - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. - /// The paramters can be specified using functions \ref lowerMap(), - /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). - /// For example, - /// \code - /// CostScaling cs(graph); - /// cs.lowerMap(lower).upperMap(upper).costMap(cost) - /// .supplyMap(sup).run(); - /// \endcode - /// - /// This function can be called more than once. All the given parameters - /// are kept for the next call, unless \ref resetParams() or \ref reset() - /// is used, thus only the modified parameters have to be set again. - /// If the underlying digraph was also modified after the construction - /// of the class (or the last \ref reset() call), then the \ref reset() - /// function must be called. - /// - /// \param method The internal method that will be used in the - /// algorithm. For more information, see \ref Method. - /// \param factor The cost scaling factor. It must be at least two. - /// - /// \return \c INFEASIBLE if no feasible flow exists, - /// \n \c OPTIMAL if the problem has optimal solution - /// (i.e. it is feasible and bounded), and the algorithm has found - /// optimal flow and node potentials (primal and dual solutions), - /// \n \c UNBOUNDED if the digraph contains an arc of negative cost - /// and infinite upper bound. It means that the objective function - /// is unbounded on that arc, however, note that it could actually be - /// bounded over the feasible flows, but this algroithm cannot handle - /// these cases. - /// - /// \see ProblemType, Method - /// \see resetParams(), reset() - ProblemType run(Method method = PARTIAL_AUGMENT, int factor = 16) { - LEMON_ASSERT(factor >= 2, "The scaling factor must be at least 2"); - _alpha = factor; - ProblemType pt = init(); - if (pt != OPTIMAL) return pt; - start(method); - return OPTIMAL; - } - - /// \brief Reset all the parameters that have been given before. - /// - /// This function resets all the paramaters that have been given - /// before using functions \ref lowerMap(), \ref upperMap(), - /// \ref costMap(), \ref supplyMap(), \ref stSupply(). - /// - /// It is useful for multiple \ref run() calls. Basically, all the given - /// parameters are kept for the next \ref run() call, unless - /// \ref resetParams() or \ref reset() is used. - /// If the underlying digraph was also modified after the construction - /// of the class or the last \ref reset() call, then the \ref reset() - /// function must be used, otherwise \ref resetParams() is sufficient. - /// - /// For example, - /// \code - /// CostScaling cs(graph); - /// - /// // First run - /// cs.lowerMap(lower).upperMap(upper).costMap(cost) - /// .supplyMap(sup).run(); - /// - /// // Run again with modified cost map (resetParams() is not called, - /// // so only the cost map have to be set again) - /// cost[e] += 100; - /// cs.costMap(cost).run(); - /// - /// // Run again from scratch using resetParams() - /// // (the lower bounds will be set to zero on all arcs) - /// cs.resetParams(); - /// cs.upperMap(capacity).costMap(cost) - /// .supplyMap(sup).run(); - /// \endcode - /// - /// \return (*this) - /// - /// \see reset(), run() - CostScaling& resetParams() { - for (int i = 0; i != _res_node_num; ++i) { - _supply[i] = 0; - } - int limit = _first_out[_root]; - for (int j = 0; j != limit; ++j) { - _lower[j] = 0; - _upper[j] = INF; - _scost[j] = _forward[j] ? 1 : -1; - } - for (int j = limit; j != _res_arc_num; ++j) { - _lower[j] = 0; - _upper[j] = INF; - _scost[j] = 0; - _scost[_reverse[j]] = 0; - } - _has_lower = false; - return *this; - } - - /// \brief Reset the internal data structures and all the parameters - /// that have been given before. - /// - /// This function resets the internal data structures and all the - /// paramaters that have been given before using functions \ref lowerMap(), - /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). - /// - /// It is useful for multiple \ref run() calls. By default, all the given - /// parameters are kept for the next \ref run() call, unless - /// \ref resetParams() or \ref reset() is used. - /// If the underlying digraph was also modified after the construction - /// of the class or the last \ref reset() call, then the \ref reset() - /// function must be used, otherwise \ref resetParams() is sufficient. - /// - /// See \ref resetParams() for examples. - /// - /// \return (*this) - /// - /// \see resetParams(), run() - CostScaling& reset() { - // Resize vectors - _node_num = countNodes(_graph); - _arc_num = countArcs(_graph); - _res_node_num = _node_num + 1; - _res_arc_num = 2 * (_arc_num + _node_num); - _root = _node_num; - - _first_out.resize(_res_node_num + 1); - _forward.resize(_res_arc_num); - _source.resize(_res_arc_num); - _target.resize(_res_arc_num); - _reverse.resize(_res_arc_num); - - _lower.resize(_res_arc_num); - _upper.resize(_res_arc_num); - _scost.resize(_res_arc_num); - _supply.resize(_res_node_num); - - _res_cap.resize(_res_arc_num); - _cost.resize(_res_arc_num); - _pi.resize(_res_node_num); - _excess.resize(_res_node_num); - _next_out.resize(_res_node_num); - - // Copy the graph - int i = 0, j = 0, k = 2 * _arc_num + _node_num; - for (NodeIt n(_graph); n != INVALID; ++n, ++i) { - _node_id[n] = i; - } - i = 0; - for (NodeIt n(_graph); n != INVALID; ++n, ++i) { - _first_out[i] = j; - for (OutArcIt a(_graph, n); a != INVALID; ++a, ++j) { - _arc_idf[a] = j; - _forward[j] = true; - _source[j] = i; - _target[j] = _node_id[_graph.runningNode(a)]; - } - for (InArcIt a(_graph, n); a != INVALID; ++a, ++j) { - _arc_idb[a] = j; - _forward[j] = false; - _source[j] = i; - _target[j] = _node_id[_graph.runningNode(a)]; - } - _forward[j] = false; - _source[j] = i; - _target[j] = _root; - _reverse[j] = k; - _forward[k] = true; - _source[k] = _root; - _target[k] = i; - _reverse[k] = j; - ++j; ++k; - } - _first_out[i] = j; - _first_out[_res_node_num] = k; - for (ArcIt a(_graph); a != INVALID; ++a) { - int fi = _arc_idf[a]; - int bi = _arc_idb[a]; - _reverse[fi] = bi; - _reverse[bi] = fi; - } - - // Reset parameters - resetParams(); - return *this; - } - - /// @} - - /// \name Query Functions - /// The results of the algorithm can be obtained using these - /// functions.\n - /// The \ref run() function must be called before using them. - - /// @{ - - /// \brief Return the total cost of the found flow. - /// - /// This function returns the total cost of the found flow. - /// Its complexity is O(m). - /// - /// \note The return type of the function can be specified as a - /// template parameter. For example, - /// \code - /// cs.totalCost(); - /// \endcode - /// It is useful if the total cost cannot be stored in the \c Cost - /// type of the algorithm, which is the default return type of the - /// function. - /// - /// \pre \ref run() must be called before using this function. - template - Number totalCost() const { - Number c = 0; - for (ArcIt a(_graph); a != INVALID; ++a) { - int i = _arc_idb[a]; - c += static_cast(_res_cap[i]) * - (-static_cast(_scost[i])); - } - return c; - } - -#ifndef DOXYGEN - Cost totalCost() const { - return totalCost(); - } -#endif - - /// \brief Return the flow on the given arc. - /// - /// This function returns the flow on the given arc. - /// - /// \pre \ref run() must be called before using this function. - Value flow(const Arc& a) const { - return _res_cap[_arc_idb[a]]; - } - - /// \brief Copy the flow values (the primal solution) into the - /// given map. - /// - /// This function copies the flow value on each arc into the given - /// map. The \c Value type of the algorithm must be convertible to - /// the \c Value type of the map. - /// - /// \pre \ref run() must be called before using this function. - template - void flowMap(FlowMap &map) const { - for (ArcIt a(_graph); a != INVALID; ++a) { - map.set(a, _res_cap[_arc_idb[a]]); - } - } - - /// \brief Return the potential (dual value) of the given node. - /// - /// This function returns the potential (dual value) of the - /// given node. - /// - /// \pre \ref run() must be called before using this function. - Cost potential(const Node& n) const { - return static_cast(_pi[_node_id[n]]); - } - - /// \brief Copy the potential values (the dual solution) into the - /// given map. - /// - /// This function copies the potential (dual value) of each node - /// into the given map. - /// The \c Cost type of the algorithm must be convertible to the - /// \c Value type of the map. - /// - /// \pre \ref run() must be called before using this function. - template - void potentialMap(PotentialMap &map) const { - for (NodeIt n(_graph); n != INVALID; ++n) { - map.set(n, static_cast(_pi[_node_id[n]])); - } - } - - /// @} - - private: - - // Initialize the algorithm - ProblemType init() { - if (_res_node_num <= 1) return INFEASIBLE; - - // Check the sum of supply values - _sum_supply = 0; - for (int i = 0; i != _root; ++i) { - _sum_supply += _supply[i]; - } - if (_sum_supply > 0) return INFEASIBLE; - - // Check lower and upper bounds - LEMON_DEBUG(checkBoundMaps(), - "Upper bounds must be greater or equal to the lower bounds"); - - - // Initialize vectors - for (int i = 0; i != _res_node_num; ++i) { - _pi[i] = 0; - _excess[i] = _supply[i]; - } - - // Remove infinite upper bounds and check negative arcs - const Value MAX = std::numeric_limits::max(); - int last_out; - if (_has_lower) { - for (int i = 0; i != _root; ++i) { - last_out = _first_out[i+1]; - for (int j = _first_out[i]; j != last_out; ++j) { - if (_forward[j]) { - Value c = _scost[j] < 0 ? _upper[j] : _lower[j]; - if (c >= MAX) return UNBOUNDED; - _excess[i] -= c; - _excess[_target[j]] += c; - } - } - } - } else { - for (int i = 0; i != _root; ++i) { - last_out = _first_out[i+1]; - for (int j = _first_out[i]; j != last_out; ++j) { - if (_forward[j] && _scost[j] < 0) { - Value c = _upper[j]; - if (c >= MAX) return UNBOUNDED; - _excess[i] -= c; - _excess[_target[j]] += c; - } - } - } - } - Value ex, max_cap = 0; - for (int i = 0; i != _res_node_num; ++i) { - ex = _excess[i]; - _excess[i] = 0; - if (ex < 0) max_cap -= ex; - } - for (int j = 0; j != _res_arc_num; ++j) { - if (_upper[j] >= MAX) _upper[j] = max_cap; - } - - // Initialize the large cost vector and the epsilon parameter - _epsilon = 0; - LargeCost lc; - for (int i = 0; i != _root; ++i) { - last_out = _first_out[i+1]; - for (int j = _first_out[i]; j != last_out; ++j) { - lc = static_cast(_scost[j]) * _res_node_num * _alpha; - _cost[j] = lc; - if (lc > _epsilon) _epsilon = lc; - } - } - _epsilon /= _alpha; - - // Initialize maps for Circulation and remove non-zero lower bounds - ConstMap low(0); - typedef typename Digraph::template ArcMap ValueArcMap; - typedef typename Digraph::template NodeMap ValueNodeMap; - ValueArcMap cap(_graph), flow(_graph); - ValueNodeMap sup(_graph); - for (NodeIt n(_graph); n != INVALID; ++n) { - sup[n] = _supply[_node_id[n]]; - } - if (_has_lower) { - for (ArcIt a(_graph); a != INVALID; ++a) { - int j = _arc_idf[a]; - Value c = _lower[j]; - cap[a] = _upper[j] - c; - sup[_graph.source(a)] -= c; - sup[_graph.target(a)] += c; - } - } else { - for (ArcIt a(_graph); a != INVALID; ++a) { - cap[a] = _upper[_arc_idf[a]]; - } - } - - _sup_node_num = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - if (sup[n] > 0) ++_sup_node_num; - } - - // Find a feasible flow using Circulation - Circulation, ValueArcMap, ValueNodeMap> - circ(_graph, low, cap, sup); - if (!circ.flowMap(flow).run()) return INFEASIBLE; - - // Set residual capacities and handle GEQ supply type - if (_sum_supply < 0) { - for (ArcIt a(_graph); a != INVALID; ++a) { - Value fa = flow[a]; - _res_cap[_arc_idf[a]] = cap[a] - fa; - _res_cap[_arc_idb[a]] = fa; - sup[_graph.source(a)] -= fa; - sup[_graph.target(a)] += fa; - } - for (NodeIt n(_graph); n != INVALID; ++n) { - _excess[_node_id[n]] = sup[n]; - } - for (int a = _first_out[_root]; a != _res_arc_num; ++a) { - int u = _target[a]; - int ra = _reverse[a]; - _res_cap[a] = -_sum_supply + 1; - _res_cap[ra] = -_excess[u]; - _cost[a] = 0; - _cost[ra] = 0; - _excess[u] = 0; - } - } else { - for (ArcIt a(_graph); a != INVALID; ++a) { - Value fa = flow[a]; - _res_cap[_arc_idf[a]] = cap[a] - fa; - _res_cap[_arc_idb[a]] = fa; - } - for (int a = _first_out[_root]; a != _res_arc_num; ++a) { - int ra = _reverse[a]; - _res_cap[a] = 0; - _res_cap[ra] = 0; - _cost[a] = 0; - _cost[ra] = 0; - } - } - - // Initialize data structures for buckets - _max_rank = _alpha * _res_node_num; - _buckets.resize(_max_rank); - _bucket_next.resize(_res_node_num + 1); - _bucket_prev.resize(_res_node_num + 1); - _rank.resize(_res_node_num + 1); - - return OPTIMAL; - } - - // Check if the upper bound is greater than or equal to the lower bound - // on each forward arc. - bool checkBoundMaps() { - for (int j = 0; j != _res_arc_num; ++j) { - if (_forward[j] && _upper[j] < _lower[j]) return false; - } - return true; - } - - // Execute the algorithm and transform the results - void start(Method method) { - const int MAX_PARTIAL_PATH_LENGTH = 4; - - switch (method) { - case PUSH: - startPush(); - break; - case AUGMENT: - startAugment(_res_node_num - 1); - break; - case PARTIAL_AUGMENT: - startAugment(MAX_PARTIAL_PATH_LENGTH); - break; - } - - // Compute node potentials (dual solution) - for (int i = 0; i != _res_node_num; ++i) { - _pi[i] = static_cast(_pi[i] / (_res_node_num * _alpha)); - } - bool optimal = true; - for (int i = 0; optimal && i != _res_node_num; ++i) { - LargeCost pi_i = _pi[i]; - int last_out = _first_out[i+1]; - for (int j = _first_out[i]; j != last_out; ++j) { - if (_res_cap[j] > 0 && _scost[j] + pi_i - _pi[_target[j]] < 0) { - optimal = false; - break; - } - } - } - - if (!optimal) { - // Compute node potentials for the original costs with BellmanFord - // (if it is necessary) - typedef std::pair IntPair; - StaticDigraph sgr; - std::vector arc_vec; - std::vector cost_vec; - LargeCostArcMap cost_map(cost_vec); - - arc_vec.clear(); - cost_vec.clear(); - for (int j = 0; j != _res_arc_num; ++j) { - if (_res_cap[j] > 0) { - int u = _source[j], v = _target[j]; - arc_vec.push_back(IntPair(u, v)); - cost_vec.push_back(_scost[j] + _pi[u] - _pi[v]); - } - } - sgr.build(_res_node_num, arc_vec.begin(), arc_vec.end()); - - typename BellmanFord::Create - bf(sgr, cost_map); - bf.init(0); - bf.start(); - - for (int i = 0; i != _res_node_num; ++i) { - _pi[i] += bf.dist(sgr.node(i)); - } - } - - // Shift potentials to meet the requirements of the GEQ type - // optimality conditions - LargeCost max_pot = _pi[_root]; - for (int i = 0; i != _res_node_num; ++i) { - if (_pi[i] > max_pot) max_pot = _pi[i]; - } - if (max_pot != 0) { - for (int i = 0; i != _res_node_num; ++i) { - _pi[i] -= max_pot; - } - } - - // Handle non-zero lower bounds - if (_has_lower) { - int limit = _first_out[_root]; - for (int j = 0; j != limit; ++j) { - if (_forward[j]) _res_cap[_reverse[j]] += _lower[j]; - } - } - } - - // Initialize a cost scaling phase - void initPhase() { - // Saturate arcs not satisfying the optimality condition - for (int u = 0; u != _res_node_num; ++u) { - int last_out = _first_out[u+1]; - LargeCost pi_u = _pi[u]; - for (int a = _first_out[u]; a != last_out; ++a) { - Value delta = _res_cap[a]; - if (delta > 0) { - int v = _target[a]; - if (_cost[a] + pi_u - _pi[v] < 0) { - _excess[u] -= delta; - _excess[v] += delta; - _res_cap[a] = 0; - _res_cap[_reverse[a]] += delta; - } - } - } - } - - // Find active nodes (i.e. nodes with positive excess) - for (int u = 0; u != _res_node_num; ++u) { - if (_excess[u] > 0) _active_nodes.push_back(u); - } - - // Initialize the next arcs - for (int u = 0; u != _res_node_num; ++u) { - _next_out[u] = _first_out[u]; - } - } - - // Price (potential) refinement heuristic - bool priceRefinement() { - - // Stack for stroing the topological order - IntVector stack(_res_node_num); - int stack_top; - - // Perform phases - while (topologicalSort(stack, stack_top)) { - - // Compute node ranks in the acyclic admissible network and - // store the nodes in buckets - for (int i = 0; i != _res_node_num; ++i) { - _rank[i] = 0; - } - const int bucket_end = _root + 1; - for (int r = 0; r != _max_rank; ++r) { - _buckets[r] = bucket_end; - } - int top_rank = 0; - for ( ; stack_top >= 0; --stack_top) { - int u = stack[stack_top], v; - int rank_u = _rank[u]; - - LargeCost rc, pi_u = _pi[u]; - int last_out = _first_out[u+1]; - for (int a = _first_out[u]; a != last_out; ++a) { - if (_res_cap[a] > 0) { - v = _target[a]; - rc = _cost[a] + pi_u - _pi[v]; - if (rc < 0) { - LargeCost nrc = static_cast((-rc - 0.5) / _epsilon); - if (nrc < LargeCost(_max_rank)) { - int new_rank_v = rank_u + static_cast(nrc); - if (new_rank_v > _rank[v]) { - _rank[v] = new_rank_v; - } - } - } - } - } - - if (rank_u > 0) { - top_rank = std::max(top_rank, rank_u); - int bfirst = _buckets[rank_u]; - _bucket_next[u] = bfirst; - _bucket_prev[bfirst] = u; - _buckets[rank_u] = u; - } - } - - // Check if the current flow is epsilon-optimal - if (top_rank == 0) { - return true; - } - - // Process buckets in top-down order - for (int rank = top_rank; rank > 0; --rank) { - while (_buckets[rank] != bucket_end) { - // Remove the first node from the current bucket - int u = _buckets[rank]; - _buckets[rank] = _bucket_next[u]; - - // Search the outgoing arcs of u - LargeCost rc, pi_u = _pi[u]; - int last_out = _first_out[u+1]; - int v, old_rank_v, new_rank_v; - for (int a = _first_out[u]; a != last_out; ++a) { - if (_res_cap[a] > 0) { - v = _target[a]; - old_rank_v = _rank[v]; - - if (old_rank_v < rank) { - - // Compute the new rank of node v - rc = _cost[a] + pi_u - _pi[v]; - if (rc < 0) { - new_rank_v = rank; - } else { - LargeCost nrc = rc / _epsilon; - new_rank_v = 0; - if (nrc < LargeCost(_max_rank)) { - new_rank_v = rank - 1 - static_cast(nrc); - } - } - - // Change the rank of node v - if (new_rank_v > old_rank_v) { - _rank[v] = new_rank_v; - - // Remove v from its old bucket - if (old_rank_v > 0) { - if (_buckets[old_rank_v] == v) { - _buckets[old_rank_v] = _bucket_next[v]; - } else { - int pv = _bucket_prev[v], nv = _bucket_next[v]; - _bucket_next[pv] = nv; - _bucket_prev[nv] = pv; - } - } - - // Insert v into its new bucket - int nv = _buckets[new_rank_v]; - _bucket_next[v] = nv; - _bucket_prev[nv] = v; - _buckets[new_rank_v] = v; - } - } - } - } - - // Refine potential of node u - _pi[u] -= rank * _epsilon; - } - } - - } - - return false; - } - - // Find and cancel cycles in the admissible network and - // determine topological order using DFS - bool topologicalSort(IntVector &stack, int &stack_top) { - const int MAX_CYCLE_CANCEL = 1; - - BoolVector reached(_res_node_num, false); - BoolVector processed(_res_node_num, false); - IntVector pred(_res_node_num); - for (int i = 0; i != _res_node_num; ++i) { - _next_out[i] = _first_out[i]; - } - stack_top = -1; - - int cycle_cnt = 0; - for (int start = 0; start != _res_node_num; ++start) { - if (reached[start]) continue; - - // Start DFS search from this start node - pred[start] = -1; - int tip = start, v; - while (true) { - // Check the outgoing arcs of the current tip node - reached[tip] = true; - LargeCost pi_tip = _pi[tip]; - int a, last_out = _first_out[tip+1]; - for (a = _next_out[tip]; a != last_out; ++a) { - if (_res_cap[a] > 0) { - v = _target[a]; - if (_cost[a] + pi_tip - _pi[v] < 0) { - if (!reached[v]) { - // A new node is reached - reached[v] = true; - pred[v] = tip; - _next_out[tip] = a; - tip = v; - a = _next_out[tip]; - last_out = _first_out[tip+1]; - break; - } - else if (!processed[v]) { - // A cycle is found - ++cycle_cnt; - _next_out[tip] = a; - - // Find the minimum residual capacity along the cycle - Value d, delta = _res_cap[a]; - int u, delta_node = tip; - for (u = tip; u != v; ) { - u = pred[u]; - d = _res_cap[_next_out[u]]; - if (d <= delta) { - delta = d; - delta_node = u; - } - } - - // Augment along the cycle - _res_cap[a] -= delta; - _res_cap[_reverse[a]] += delta; - for (u = tip; u != v; ) { - u = pred[u]; - int ca = _next_out[u]; - _res_cap[ca] -= delta; - _res_cap[_reverse[ca]] += delta; - } - - // Check the maximum number of cycle canceling - if (cycle_cnt >= MAX_CYCLE_CANCEL) { - return false; - } - - // Roll back search to delta_node - if (delta_node != tip) { - for (u = tip; u != delta_node; u = pred[u]) { - reached[u] = false; - } - tip = delta_node; - a = _next_out[tip] + 1; - last_out = _first_out[tip+1]; - break; - } - } - } - } - } - - // Step back to the previous node - if (a == last_out) { - processed[tip] = true; - stack[++stack_top] = tip; - tip = pred[tip]; - if (tip < 0) { - // Finish DFS from the current start node - break; - } - ++_next_out[tip]; - } - } - - } - - return (cycle_cnt == 0); - } - - // Global potential update heuristic - void globalUpdate() { - const int bucket_end = _root + 1; - - // Initialize buckets - for (int r = 0; r != _max_rank; ++r) { - _buckets[r] = bucket_end; - } - Value total_excess = 0; - int b0 = bucket_end; - for (int i = 0; i != _res_node_num; ++i) { - if (_excess[i] < 0) { - _rank[i] = 0; - _bucket_next[i] = b0; - _bucket_prev[b0] = i; - b0 = i; - } else { - total_excess += _excess[i]; - _rank[i] = _max_rank; - } - } - if (total_excess == 0) return; - _buckets[0] = b0; - - // Search the buckets - int r = 0; - for ( ; r != _max_rank; ++r) { - while (_buckets[r] != bucket_end) { - // Remove the first node from the current bucket - int u = _buckets[r]; - _buckets[r] = _bucket_next[u]; - - // Search the incoming arcs of u - LargeCost pi_u = _pi[u]; - int last_out = _first_out[u+1]; - for (int a = _first_out[u]; a != last_out; ++a) { - int ra = _reverse[a]; - if (_res_cap[ra] > 0) { - int v = _source[ra]; - int old_rank_v = _rank[v]; - if (r < old_rank_v) { - // Compute the new rank of v - LargeCost nrc = (_cost[ra] + _pi[v] - pi_u) / _epsilon; - int new_rank_v = old_rank_v; - if (nrc < LargeCost(_max_rank)) { - new_rank_v = r + 1 + static_cast(nrc); - } - - // Change the rank of v - if (new_rank_v < old_rank_v) { - _rank[v] = new_rank_v; - _next_out[v] = _first_out[v]; - - // Remove v from its old bucket - if (old_rank_v < _max_rank) { - if (_buckets[old_rank_v] == v) { - _buckets[old_rank_v] = _bucket_next[v]; - } else { - int pv = _bucket_prev[v], nv = _bucket_next[v]; - _bucket_next[pv] = nv; - _bucket_prev[nv] = pv; - } - } - - // Insert v into its new bucket - int nv = _buckets[new_rank_v]; - _bucket_next[v] = nv; - _bucket_prev[nv] = v; - _buckets[new_rank_v] = v; - } - } - } - } - - // Finish search if there are no more active nodes - if (_excess[u] > 0) { - total_excess -= _excess[u]; - if (total_excess <= 0) break; - } - } - if (total_excess <= 0) break; - } - - // Relabel nodes - for (int u = 0; u != _res_node_num; ++u) { - int k = std::min(_rank[u], r); - if (k > 0) { - _pi[u] -= _epsilon * k; - _next_out[u] = _first_out[u]; - } - } - } - - /// Execute the algorithm performing augment and relabel operations - void startAugment(int max_length) { - // Paramters for heuristics - const int PRICE_REFINEMENT_LIMIT = 2; - const double GLOBAL_UPDATE_FACTOR = 1.0; - const int global_update_skip = static_cast(GLOBAL_UPDATE_FACTOR * - (_res_node_num + _sup_node_num * _sup_node_num)); - int next_global_update_limit = global_update_skip; - - // Perform cost scaling phases - IntVector path; - BoolVector path_arc(_res_arc_num, false); - int relabel_cnt = 0; - int eps_phase_cnt = 0; - for ( ; _epsilon >= 1; _epsilon = _epsilon < _alpha && _epsilon > 1 ? - 1 : _epsilon / _alpha ) - { - ++eps_phase_cnt; - - // Price refinement heuristic - if (eps_phase_cnt >= PRICE_REFINEMENT_LIMIT) { - if (priceRefinement()) continue; - } - - // Initialize current phase - initPhase(); - - // Perform partial augment and relabel operations - while (true) { - // Select an active node (FIFO selection) - while (_active_nodes.size() > 0 && - _excess[_active_nodes.front()] <= 0) { - _active_nodes.pop_front(); - } - if (_active_nodes.size() == 0) break; - int start = _active_nodes.front(); - - // Find an augmenting path from the start node - int tip = start; - while (int(path.size()) < max_length && _excess[tip] >= 0) { - int u; - LargeCost rc, min_red_cost = std::numeric_limits::max(); - LargeCost pi_tip = _pi[tip]; - int last_out = _first_out[tip+1]; - for (int a = _next_out[tip]; a != last_out; ++a) { - if (_res_cap[a] > 0) { - u = _target[a]; - rc = _cost[a] + pi_tip - _pi[u]; - if (rc < 0) { - path.push_back(a); - _next_out[tip] = a; - if (path_arc[a]) { - goto augment; // a cycle is found, stop path search - } - tip = u; - path_arc[a] = true; - goto next_step; - } - else if (rc < min_red_cost) { - min_red_cost = rc; - } - } - } - - // Relabel tip node - if (tip != start) { - int ra = _reverse[path.back()]; - min_red_cost = - std::min(min_red_cost, _cost[ra] + pi_tip - _pi[_target[ra]]); - } - last_out = _next_out[tip]; - for (int a = _first_out[tip]; a != last_out; ++a) { - if (_res_cap[a] > 0) { - rc = _cost[a] + pi_tip - _pi[_target[a]]; - if (rc < min_red_cost) { - min_red_cost = rc; - } - } - } - _pi[tip] -= min_red_cost + _epsilon; - _next_out[tip] = _first_out[tip]; - ++relabel_cnt; - - // Step back - if (tip != start) { - int pa = path.back(); - path_arc[pa] = false; - tip = _source[pa]; - path.pop_back(); - } - - next_step: ; - } - - // Augment along the found path (as much flow as possible) - augment: - Value delta; - int pa, u, v = start; - for (int i = 0; i != int(path.size()); ++i) { - pa = path[i]; - u = v; - v = _target[pa]; - path_arc[pa] = false; - delta = std::min(_res_cap[pa], _excess[u]); - _res_cap[pa] -= delta; - _res_cap[_reverse[pa]] += delta; - _excess[u] -= delta; - _excess[v] += delta; - if (_excess[v] > 0 && _excess[v] <= delta) { - _active_nodes.push_back(v); - } - } - path.clear(); - - // Global update heuristic - if (relabel_cnt >= next_global_update_limit) { - globalUpdate(); - next_global_update_limit += global_update_skip; - } - } - - } - - } - - /// Execute the algorithm performing push and relabel operations - void startPush() { - // Paramters for heuristics - const int PRICE_REFINEMENT_LIMIT = 2; - const double GLOBAL_UPDATE_FACTOR = 2.0; - - const int global_update_skip = static_cast(GLOBAL_UPDATE_FACTOR * - (_res_node_num + _sup_node_num * _sup_node_num)); - int next_global_update_limit = global_update_skip; - - // Perform cost scaling phases - BoolVector hyper(_res_node_num, false); - LargeCostVector hyper_cost(_res_node_num); - int relabel_cnt = 0; - int eps_phase_cnt = 0; - for ( ; _epsilon >= 1; _epsilon = _epsilon < _alpha && _epsilon > 1 ? - 1 : _epsilon / _alpha ) - { - ++eps_phase_cnt; - - // Price refinement heuristic - if (eps_phase_cnt >= PRICE_REFINEMENT_LIMIT) { - if (priceRefinement()) continue; - } - - // Initialize current phase - initPhase(); - - // Perform push and relabel operations - while (_active_nodes.size() > 0) { - LargeCost min_red_cost, rc, pi_n; - Value delta; - int n, t, a, last_out = _res_arc_num; - - next_node: - // Select an active node (FIFO selection) - n = _active_nodes.front(); - last_out = _first_out[n+1]; - pi_n = _pi[n]; - - // Perform push operations if there are admissible arcs - if (_excess[n] > 0) { - for (a = _next_out[n]; a != last_out; ++a) { - if (_res_cap[a] > 0 && - _cost[a] + pi_n - _pi[_target[a]] < 0) { - delta = std::min(_res_cap[a], _excess[n]); - t = _target[a]; - - // Push-look-ahead heuristic - Value ahead = -_excess[t]; - int last_out_t = _first_out[t+1]; - LargeCost pi_t = _pi[t]; - for (int ta = _next_out[t]; ta != last_out_t; ++ta) { - if (_res_cap[ta] > 0 && - _cost[ta] + pi_t - _pi[_target[ta]] < 0) - ahead += _res_cap[ta]; - if (ahead >= delta) break; - } - if (ahead < 0) ahead = 0; - - // Push flow along the arc - if (ahead < delta && !hyper[t]) { - _res_cap[a] -= ahead; - _res_cap[_reverse[a]] += ahead; - _excess[n] -= ahead; - _excess[t] += ahead; - _active_nodes.push_front(t); - hyper[t] = true; - hyper_cost[t] = _cost[a] + pi_n - pi_t; - _next_out[n] = a; - goto next_node; - } else { - _res_cap[a] -= delta; - _res_cap[_reverse[a]] += delta; - _excess[n] -= delta; - _excess[t] += delta; - if (_excess[t] > 0 && _excess[t] <= delta) - _active_nodes.push_back(t); - } - - if (_excess[n] == 0) { - _next_out[n] = a; - goto remove_nodes; - } - } - } - _next_out[n] = a; - } - - // Relabel the node if it is still active (or hyper) - if (_excess[n] > 0 || hyper[n]) { - min_red_cost = hyper[n] ? -hyper_cost[n] : - std::numeric_limits::max(); - for (int a = _first_out[n]; a != last_out; ++a) { - if (_res_cap[a] > 0) { - rc = _cost[a] + pi_n - _pi[_target[a]]; - if (rc < min_red_cost) { - min_red_cost = rc; - } - } - } - _pi[n] -= min_red_cost + _epsilon; - _next_out[n] = _first_out[n]; - hyper[n] = false; - ++relabel_cnt; - } - - // Remove nodes that are not active nor hyper - remove_nodes: - while ( _active_nodes.size() > 0 && - _excess[_active_nodes.front()] <= 0 && - !hyper[_active_nodes.front()] ) { - _active_nodes.pop_front(); - } - - // Global update heuristic - if (relabel_cnt >= next_global_update_limit) { - globalUpdate(); - for (int u = 0; u != _res_node_num; ++u) - hyper[u] = false; - next_global_update_limit += global_update_skip; - } - } - } - } - - }; //class CostScaling - - ///@} - -} //namespace lemon - -#endif //LEMON_COST_SCALING_H diff --git a/deps/lemon/lemon/counter.h b/deps/lemon/lemon/counter.h deleted file mode 100644 index a00499189..000000000 --- a/deps/lemon/lemon/counter.h +++ /dev/null @@ -1,249 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_COUNTER_H -#define LEMON_COUNTER_H - -#include -#include - -///\ingroup timecount -///\file -///\brief Tools for counting steps and events - -namespace lemon -{ - - template class _NoSubCounter; - - template - class _SubCounter - { - P &_parent; - std::string _title; - std::ostream &_os; - int count; - public: - - typedef _SubCounter<_SubCounter

> SubCounter; - typedef _NoSubCounter<_SubCounter

> NoSubCounter; - - _SubCounter(P &parent) - : _parent(parent), _title(), _os(std::cerr), count(0) {} - _SubCounter(P &parent,std::string title,std::ostream &os=std::cerr) - : _parent(parent), _title(title), _os(os), count(0) {} - _SubCounter(P &parent,const char *title,std::ostream &os=std::cerr) - : _parent(parent), _title(title), _os(os), count(0) {} - ~_SubCounter() { - _os << _title << count < - class _NoSubCounter - { - P &_parent; - public: - typedef _NoSubCounter<_NoSubCounter

> SubCounter; - typedef _NoSubCounter<_NoSubCounter

> NoSubCounter; - - _NoSubCounter(P &parent) :_parent(parent) {} - _NoSubCounter(P &parent,std::string,std::ostream &) - :_parent(parent) {} - _NoSubCounter(P &parent,std::string) - :_parent(parent) {} - _NoSubCounter(P &parent,const char *,std::ostream &) - :_parent(parent) {} - _NoSubCounter(P &parent,const char *) - :_parent(parent) {} - ~_NoSubCounter() {} - _NoSubCounter &operator++() { ++_parent; return *this;} - int operator++(int) { _parent++; return 0;} - _NoSubCounter &operator--() { --_parent; return *this;} - int operator--(int) { _parent--; return 0;} - _NoSubCounter &operator+=(int c) { _parent+=c; return *this;} - _NoSubCounter &operator-=(int c) { _parent-=c; return *this;} - operator int() {return 0;} - }; - - - /// \addtogroup timecount - /// @{ - - /// A counter class - - /// This class makes it easier to count certain events (e.g. for debug - /// reasons). - /// You can increment or decrement the counter using \c operator++, - /// \c operator--, \c operator+= and \c operator-=. You can also - /// define subcounters for the different phases of the algorithm or - /// for different types of operations. - /// A report containing the given title and the value of the counter - /// is automatically printed on destruction. - /// - /// The following example shows the usage of counters and subcounters. - /// \code - /// // Bubble sort - /// std::vector v; - /// ... - /// Counter op("Operations: "); - /// Counter::SubCounter as(op, "Assignments: "); - /// Counter::SubCounter co(op, "Comparisons: "); - /// for (int i = v.size()-1; i > 0; --i) { - /// for (int j = 0; j < i; ++j) { - /// if (v[j] > v[j+1]) { - /// T tmp = v[j]; - /// v[j] = v[j+1]; - /// v[j+1] = tmp; - /// as += 3; // three assignments - /// } - /// ++co; // one comparison - /// } - /// } - /// \endcode - /// - /// This code prints out something like that: - /// \code - /// Comparisons: 45 - /// Assignments: 57 - /// Operations: 102 - /// \endcode - /// - /// \sa NoCounter - class Counter - { - std::string _title; - std::ostream &_os; - int count; - public: - - /// SubCounter class - - /// This class can be used to setup subcounters for a \ref Counter - /// to have finer reports. A subcounter provides exactly the same - /// operations as the main \ref Counter, but it also increments and - /// decrements the value of its parent. - /// Subcounters can also have subcounters. - /// - /// The parent counter must be given as the first parameter of the - /// constructor. Apart from that a title and an \c ostream object - /// can also be given just like for the main \ref Counter. - /// - /// A report containing the given title and the value of the - /// subcounter is automatically printed on destruction. If you - /// would like to turn off this report, use \ref NoSubCounter - /// instead. - /// - /// \sa NoSubCounter - typedef _SubCounter SubCounter; - - /// SubCounter class without printing report on destruction - - /// This class can be used to setup subcounters for a \ref Counter. - /// It is the same as \ref SubCounter but it does not print report - /// on destruction. (It modifies the value of its parent, so 'No' - /// only means 'do not print'.) - /// - /// Replacing \ref SubCounter "SubCounter"s with \ref NoSubCounter - /// "NoSubCounter"s makes it possible to turn off reporting - /// subcounter values without actually removing the definitions - /// and the increment or decrement operators. - /// - /// \sa SubCounter - typedef _NoSubCounter NoSubCounter; - - /// Constructor. - Counter() : _title(), _os(std::cerr), count(0) {} - /// Constructor. - Counter(std::string title,std::ostream &os=std::cerr) - : _title(title), _os(os), count(0) {} - /// Constructor. - Counter(const char *title,std::ostream &os=std::cerr) - : _title(title), _os(os), count(0) {} - /// Destructor. Prints the given title and the value of the counter. - ~Counter() { - _os << _title << count < SubCounter; - typedef _NoSubCounter NoSubCounter; - - NoCounter() {} - NoCounter(std::string,std::ostream &) {} - NoCounter(const char *,std::ostream &) {} - NoCounter(std::string) {} - NoCounter(const char *) {} - NoCounter &operator++() { return *this; } - int operator++(int) { return 0; } - NoCounter &operator--() { return *this; } - int operator--(int) { return 0; } - NoCounter &operator+=(int) { return *this;} - NoCounter &operator-=(int) { return *this;} - void reset(int) {} - void reset() {} - operator int() {return 0;} - }; - - ///@} -} - -#endif diff --git a/deps/lemon/lemon/cplex.cc b/deps/lemon/lemon/cplex.cc deleted file mode 100644 index 029a3efc5..000000000 --- a/deps/lemon/lemon/cplex.cc +++ /dev/null @@ -1,994 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include - -#include - -extern "C" { -#include -} - - -///\file -///\brief Implementation of the LEMON-CPLEX lp solver interface. -namespace lemon { - - CplexEnv::LicenseError::LicenseError(int status) { - if (!CPXgeterrorstring(0, status, _message)) { - std::strcpy(_message, "Cplex unknown error"); - } - } - - CplexEnv::CplexEnv() { - int status; - _cnt = new int; - (*_cnt) = 1; - _env = CPXopenCPLEX(&status); - if (_env == 0) { - delete _cnt; - _cnt = 0; - throw LicenseError(status); - } - } - - CplexEnv::CplexEnv(const CplexEnv& other) { - _env = other._env; - _cnt = other._cnt; - ++(*_cnt); - } - - CplexEnv& CplexEnv::operator=(const CplexEnv& other) { - _env = other._env; - _cnt = other._cnt; - ++(*_cnt); - return *this; - } - - CplexEnv::~CplexEnv() { - --(*_cnt); - if (*_cnt == 0) { - delete _cnt; - CPXcloseCPLEX(&_env); - } - } - - CplexBase::CplexBase() : LpBase() { - int status; - _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); - messageLevel(MESSAGE_NOTHING); - } - - CplexBase::CplexBase(const CplexEnv& env) - : LpBase(), _env(env) { - int status; - _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); - messageLevel(MESSAGE_NOTHING); - } - - CplexBase::CplexBase(const CplexBase& cplex) - : LpBase() { - int status; - _prob = CPXcloneprob(cplexEnv(), cplex._prob, &status); - rows = cplex.rows; - cols = cplex.cols; - messageLevel(MESSAGE_NOTHING); - } - - CplexBase::~CplexBase() { - CPXfreeprob(cplexEnv(),&_prob); - } - - int CplexBase::_addCol() { - int i = CPXgetnumcols(cplexEnv(), _prob); - double lb = -INF, ub = INF; - CPXnewcols(cplexEnv(), _prob, 1, 0, &lb, &ub, 0, 0); - return i; - } - - - int CplexBase::_addRow() { - int i = CPXgetnumrows(cplexEnv(), _prob); - const double ub = INF; - const char s = 'L'; - CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0); - return i; - } - - int CplexBase::_addRow(Value lb, ExprIterator b, - ExprIterator e, Value ub) { - int i = CPXgetnumrows(cplexEnv(), _prob); - if (lb == -INF) { - const char s = 'L'; - CPXnewrows(cplexEnv(), _prob, 1, &ub, &s, 0, 0); - } else if (ub == INF) { - const char s = 'G'; - CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, 0, 0); - } else if (lb == ub){ - const char s = 'E'; - CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, 0, 0); - } else { - const char s = 'R'; - double len = ub - lb; - CPXnewrows(cplexEnv(), _prob, 1, &lb, &s, &len, 0); - } - - std::vector indices; - std::vector rowlist; - std::vector values; - - for(ExprIterator it=b; it!=e; ++it) { - indices.push_back(it->first); - values.push_back(it->second); - rowlist.push_back(i); - } - - CPXchgcoeflist(cplexEnv(), _prob, values.size(), - &rowlist.front(), &indices.front(), &values.front()); - - return i; - } - - void CplexBase::_eraseCol(int i) { - CPXdelcols(cplexEnv(), _prob, i, i); - } - - void CplexBase::_eraseRow(int i) { - CPXdelrows(cplexEnv(), _prob, i, i); - } - - void CplexBase::_eraseColId(int i) { - cols.eraseIndex(i); - cols.shiftIndices(i); - } - void CplexBase::_eraseRowId(int i) { - rows.eraseIndex(i); - rows.shiftIndices(i); - } - - void CplexBase::_getColName(int col, std::string &name) const { - int size; - CPXgetcolname(cplexEnv(), _prob, 0, 0, 0, &size, col, col); - if (size == 0) { - name.clear(); - return; - } - - size *= -1; - std::vector buf(size); - char *cname; - int tmp; - CPXgetcolname(cplexEnv(), _prob, &cname, &buf.front(), size, - &tmp, col, col); - name = cname; - } - - void CplexBase::_setColName(int col, const std::string &name) { - char *cname; - cname = const_cast(name.c_str()); - CPXchgcolname(cplexEnv(), _prob, 1, &col, &cname); - } - - int CplexBase::_colByName(const std::string& name) const { - int index; - if (CPXgetcolindex(cplexEnv(), _prob, - const_cast(name.c_str()), &index) == 0) { - return index; - } - return -1; - } - - void CplexBase::_getRowName(int row, std::string &name) const { - int size; - CPXgetrowname(cplexEnv(), _prob, 0, 0, 0, &size, row, row); - if (size == 0) { - name.clear(); - return; - } - - size *= -1; - std::vector buf(size); - char *cname; - int tmp; - CPXgetrowname(cplexEnv(), _prob, &cname, &buf.front(), size, - &tmp, row, row); - name = cname; - } - - void CplexBase::_setRowName(int row, const std::string &name) { - char *cname; - cname = const_cast(name.c_str()); - CPXchgrowname(cplexEnv(), _prob, 1, &row, &cname); - } - - int CplexBase::_rowByName(const std::string& name) const { - int index; - if (CPXgetrowindex(cplexEnv(), _prob, - const_cast(name.c_str()), &index) == 0) { - return index; - } - return -1; - } - - void CplexBase::_setRowCoeffs(int i, ExprIterator b, - ExprIterator e) - { - std::vector indices; - std::vector rowlist; - std::vector values; - - for(ExprIterator it=b; it!=e; ++it) { - indices.push_back(it->first); - values.push_back(it->second); - rowlist.push_back(i); - } - - CPXchgcoeflist(cplexEnv(), _prob, values.size(), - &rowlist.front(), &indices.front(), &values.front()); - } - - void CplexBase::_getRowCoeffs(int i, InsertIterator b) const { - int tmp1, tmp2, tmp3, length; - CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i); - - length = -length; - std::vector indices(length); - std::vector values(length); - - CPXgetrows(cplexEnv(), _prob, &tmp1, &tmp2, - &indices.front(), &values.front(), - length, &tmp3, i, i); - - for (int i = 0; i < length; ++i) { - *b = std::make_pair(indices[i], values[i]); - ++b; - } - } - - void CplexBase::_setColCoeffs(int i, ExprIterator b, ExprIterator e) { - std::vector indices; - std::vector collist; - std::vector values; - - for(ExprIterator it=b; it!=e; ++it) { - indices.push_back(it->first); - values.push_back(it->second); - collist.push_back(i); - } - - CPXchgcoeflist(cplexEnv(), _prob, values.size(), - &indices.front(), &collist.front(), &values.front()); - } - - void CplexBase::_getColCoeffs(int i, InsertIterator b) const { - - int tmp1, tmp2, tmp3, length; - CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, 0, 0, 0, &length, i, i); - - length = -length; - std::vector indices(length); - std::vector values(length); - - CPXgetcols(cplexEnv(), _prob, &tmp1, &tmp2, - &indices.front(), &values.front(), - length, &tmp3, i, i); - - for (int i = 0; i < length; ++i) { - *b = std::make_pair(indices[i], values[i]); - ++b; - } - - } - - void CplexBase::_setCoeff(int row, int col, Value value) { - CPXchgcoef(cplexEnv(), _prob, row, col, value); - } - - CplexBase::Value CplexBase::_getCoeff(int row, int col) const { - CplexBase::Value value; - CPXgetcoef(cplexEnv(), _prob, row, col, &value); - return value; - } - - void CplexBase::_setColLowerBound(int i, Value value) { - const char s = 'L'; - CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value); - } - - CplexBase::Value CplexBase::_getColLowerBound(int i) const { - CplexBase::Value res; - CPXgetlb(cplexEnv(), _prob, &res, i, i); - return res <= -CPX_INFBOUND ? -INF : res; - } - - void CplexBase::_setColUpperBound(int i, Value value) - { - const char s = 'U'; - CPXchgbds(cplexEnv(), _prob, 1, &i, &s, &value); - } - - CplexBase::Value CplexBase::_getColUpperBound(int i) const { - CplexBase::Value res; - CPXgetub(cplexEnv(), _prob, &res, i, i); - return res >= CPX_INFBOUND ? INF : res; - } - - CplexBase::Value CplexBase::_getRowLowerBound(int i) const { - char s; - CPXgetsense(cplexEnv(), _prob, &s, i, i); - CplexBase::Value res; - - switch (s) { - case 'G': - case 'R': - case 'E': - CPXgetrhs(cplexEnv(), _prob, &res, i, i); - return res <= -CPX_INFBOUND ? -INF : res; - default: - return -INF; - } - } - - CplexBase::Value CplexBase::_getRowUpperBound(int i) const { - char s; - CPXgetsense(cplexEnv(), _prob, &s, i, i); - CplexBase::Value res; - - switch (s) { - case 'L': - case 'E': - CPXgetrhs(cplexEnv(), _prob, &res, i, i); - return res >= CPX_INFBOUND ? INF : res; - case 'R': - CPXgetrhs(cplexEnv(), _prob, &res, i, i); - { - double rng; - CPXgetrngval(cplexEnv(), _prob, &rng, i, i); - res += rng; - } - return res >= CPX_INFBOUND ? INF : res; - default: - return INF; - } - } - - //This is easier to implement - void CplexBase::_set_row_bounds(int i, Value lb, Value ub) { - if (lb == -INF) { - const char s = 'L'; - CPXchgsense(cplexEnv(), _prob, 1, &i, &s); - CPXchgrhs(cplexEnv(), _prob, 1, &i, &ub); - } else if (ub == INF) { - const char s = 'G'; - CPXchgsense(cplexEnv(), _prob, 1, &i, &s); - CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb); - } else if (lb == ub){ - const char s = 'E'; - CPXchgsense(cplexEnv(), _prob, 1, &i, &s); - CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb); - } else { - const char s = 'R'; - CPXchgsense(cplexEnv(), _prob, 1, &i, &s); - CPXchgrhs(cplexEnv(), _prob, 1, &i, &lb); - double len = ub - lb; - CPXchgrngval(cplexEnv(), _prob, 1, &i, &len); - } - } - - void CplexBase::_setRowLowerBound(int i, Value lb) - { - LEMON_ASSERT(lb != INF, "Invalid bound"); - _set_row_bounds(i, lb, CplexBase::_getRowUpperBound(i)); - } - - void CplexBase::_setRowUpperBound(int i, Value ub) - { - - LEMON_ASSERT(ub != -INF, "Invalid bound"); - _set_row_bounds(i, CplexBase::_getRowLowerBound(i), ub); - } - - void CplexBase::_setObjCoeffs(ExprIterator b, ExprIterator e) - { - std::vector indices; - std::vector values; - for(ExprIterator it=b; it!=e; ++it) { - indices.push_back(it->first); - values.push_back(it->second); - } - CPXchgobj(cplexEnv(), _prob, values.size(), - &indices.front(), &values.front()); - - } - - void CplexBase::_getObjCoeffs(InsertIterator b) const - { - int num = CPXgetnumcols(cplexEnv(), _prob); - std::vector x(num); - - CPXgetobj(cplexEnv(), _prob, &x.front(), 0, num - 1); - for (int i = 0; i < num; ++i) { - if (x[i] != 0.0) { - *b = std::make_pair(i, x[i]); - ++b; - } - } - } - - void CplexBase::_setObjCoeff(int i, Value obj_coef) - { - CPXchgobj(cplexEnv(), _prob, 1, &i, &obj_coef); - } - - CplexBase::Value CplexBase::_getObjCoeff(int i) const - { - Value x; - CPXgetobj(cplexEnv(), _prob, &x, i, i); - return x; - } - - void CplexBase::_setSense(CplexBase::Sense sense) { - switch (sense) { - case MIN: - CPXchgobjsen(cplexEnv(), _prob, CPX_MIN); - break; - case MAX: - CPXchgobjsen(cplexEnv(), _prob, CPX_MAX); - break; - } - } - - CplexBase::Sense CplexBase::_getSense() const { - switch (CPXgetobjsen(cplexEnv(), _prob)) { - case CPX_MIN: - return MIN; - case CPX_MAX: - return MAX; - default: - LEMON_ASSERT(false, "Invalid sense"); - return CplexBase::Sense(); - } - } - - void CplexBase::_clear() { - CPXfreeprob(cplexEnv(),&_prob); - int status; - _prob = CPXcreateprob(cplexEnv(), &status, "Cplex problem"); - } - - void CplexBase::_messageLevel(MessageLevel level) { - switch (level) { - case MESSAGE_NOTHING: - _message_enabled = false; - break; - case MESSAGE_ERROR: - case MESSAGE_WARNING: - case MESSAGE_NORMAL: - case MESSAGE_VERBOSE: - _message_enabled = true; - break; - } - } - - void CplexBase::_applyMessageLevel() { - CPXsetintparam(cplexEnv(), CPX_PARAM_SCRIND, - _message_enabled ? CPX_ON : CPX_OFF); - } - - void CplexBase::_write(std::string file, std::string format) const - { - if(format == "MPS" || format == "LP") - CPXwriteprob(cplexEnv(), cplexLp(), file.c_str(), format.c_str()); - else if(format == "SOL") - CPXsolwrite(cplexEnv(), cplexLp(), file.c_str()); - else throw UnsupportedFormatError(format); - } - - - - // CplexLp members - - CplexLp::CplexLp() - : LpBase(), LpSolver(), CplexBase() {} - - CplexLp::CplexLp(const CplexEnv& env) - : LpBase(), LpSolver(), CplexBase(env) {} - - CplexLp::CplexLp(const CplexLp& other) - : LpBase(), LpSolver(), CplexBase(other) {} - - CplexLp::~CplexLp() {} - - CplexLp* CplexLp::newSolver() const { return new CplexLp; } - CplexLp* CplexLp::cloneSolver() const {return new CplexLp(*this); } - - const char* CplexLp::_solverName() const { return "CplexLp"; } - - void CplexLp::_clear_temporals() { - _col_status.clear(); - _row_status.clear(); - _primal_ray.clear(); - _dual_ray.clear(); - } - - // The routine returns zero unless an error occurred during the - // optimization. Examples of errors include exhausting available - // memory (CPXERR_NO_MEMORY) or encountering invalid data in the - // CPLEX problem object (CPXERR_NO_PROBLEM). Exceeding a - // user-specified CPLEX limit, or proving the model infeasible or - // unbounded, are not considered errors. Note that a zero return - // value does not necessarily mean that a solution exists. Use query - // routines CPXsolninfo, CPXgetstat, and CPXsolution to obtain - // further information about the status of the optimization. - CplexLp::SolveExitStatus CplexLp::convertStatus(int status) { -#if CPX_VERSION >= 800 - if (status == 0) { - switch (CPXgetstat(cplexEnv(), _prob)) { - case CPX_STAT_OPTIMAL: - case CPX_STAT_INFEASIBLE: - case CPX_STAT_UNBOUNDED: - return SOLVED; - default: - return UNSOLVED; - } - } else { - return UNSOLVED; - } -#else - if (status == 0) { - //We want to exclude some cases - switch (CPXgetstat(cplexEnv(), _prob)) { - case CPX_OBJ_LIM: - case CPX_IT_LIM_FEAS: - case CPX_IT_LIM_INFEAS: - case CPX_TIME_LIM_FEAS: - case CPX_TIME_LIM_INFEAS: - return UNSOLVED; - default: - return SOLVED; - } - } else { - return UNSOLVED; - } -#endif - } - - CplexLp::SolveExitStatus CplexLp::_solve() { - _clear_temporals(); - _applyMessageLevel(); - return convertStatus(CPXlpopt(cplexEnv(), _prob)); - } - - CplexLp::SolveExitStatus CplexLp::solvePrimal() { - _clear_temporals(); - _applyMessageLevel(); - return convertStatus(CPXprimopt(cplexEnv(), _prob)); - } - - CplexLp::SolveExitStatus CplexLp::solveDual() { - _clear_temporals(); - _applyMessageLevel(); - return convertStatus(CPXdualopt(cplexEnv(), _prob)); - } - - CplexLp::SolveExitStatus CplexLp::solveBarrier() { - _clear_temporals(); - _applyMessageLevel(); - return convertStatus(CPXbaropt(cplexEnv(), _prob)); - } - - CplexLp::Value CplexLp::_getPrimal(int i) const { - Value x; - CPXgetx(cplexEnv(), _prob, &x, i, i); - return x; - } - - CplexLp::Value CplexLp::_getDual(int i) const { - Value y; - CPXgetpi(cplexEnv(), _prob, &y, i, i); - return y; - } - - CplexLp::Value CplexLp::_getPrimalValue() const { - Value objval; - CPXgetobjval(cplexEnv(), _prob, &objval); - return objval; - } - - CplexLp::VarStatus CplexLp::_getColStatus(int i) const { - if (_col_status.empty()) { - _col_status.resize(CPXgetnumcols(cplexEnv(), _prob)); - CPXgetbase(cplexEnv(), _prob, &_col_status.front(), 0); - } - switch (_col_status[i]) { - case CPX_BASIC: - return BASIC; - case CPX_FREE_SUPER: - return FREE; - case CPX_AT_LOWER: - return LOWER; - case CPX_AT_UPPER: - return UPPER; - default: - LEMON_ASSERT(false, "Wrong column status"); - return CplexLp::VarStatus(); - } - } - - CplexLp::VarStatus CplexLp::_getRowStatus(int i) const { - if (_row_status.empty()) { - _row_status.resize(CPXgetnumrows(cplexEnv(), _prob)); - CPXgetbase(cplexEnv(), _prob, 0, &_row_status.front()); - } - switch (_row_status[i]) { - case CPX_BASIC: - return BASIC; - case CPX_AT_LOWER: - { - char s; - CPXgetsense(cplexEnv(), _prob, &s, i, i); - return s != 'L' ? LOWER : UPPER; - } - case CPX_AT_UPPER: - return UPPER; - default: - LEMON_ASSERT(false, "Wrong row status"); - return CplexLp::VarStatus(); - } - } - - CplexLp::Value CplexLp::_getPrimalRay(int i) const { - if (_primal_ray.empty()) { - _primal_ray.resize(CPXgetnumcols(cplexEnv(), _prob)); - CPXgetray(cplexEnv(), _prob, &_primal_ray.front()); - } - return _primal_ray[i]; - } - - CplexLp::Value CplexLp::_getDualRay(int i) const { - if (_dual_ray.empty()) { - - } - return _dual_ray[i]; - } - - // Cplex 7.0 status values - // This table lists the statuses, returned by the CPXgetstat() - // routine, for solutions to LP problems or mixed integer problems. If - // no solution exists, the return value is zero. - - // For Simplex, Barrier - // 1 CPX_OPTIMAL - // Optimal solution found - // 2 CPX_INFEASIBLE - // Problem infeasible - // 3 CPX_UNBOUNDED - // Problem unbounded - // 4 CPX_OBJ_LIM - // Objective limit exceeded in Phase II - // 5 CPX_IT_LIM_FEAS - // Iteration limit exceeded in Phase II - // 6 CPX_IT_LIM_INFEAS - // Iteration limit exceeded in Phase I - // 7 CPX_TIME_LIM_FEAS - // Time limit exceeded in Phase II - // 8 CPX_TIME_LIM_INFEAS - // Time limit exceeded in Phase I - // 9 CPX_NUM_BEST_FEAS - // Problem non-optimal, singularities in Phase II - // 10 CPX_NUM_BEST_INFEAS - // Problem non-optimal, singularities in Phase I - // 11 CPX_OPTIMAL_INFEAS - // Optimal solution found, unscaled infeasibilities - // 12 CPX_ABORT_FEAS - // Aborted in Phase II - // 13 CPX_ABORT_INFEAS - // Aborted in Phase I - // 14 CPX_ABORT_DUAL_INFEAS - // Aborted in barrier, dual infeasible - // 15 CPX_ABORT_PRIM_INFEAS - // Aborted in barrier, primal infeasible - // 16 CPX_ABORT_PRIM_DUAL_INFEAS - // Aborted in barrier, primal and dual infeasible - // 17 CPX_ABORT_PRIM_DUAL_FEAS - // Aborted in barrier, primal and dual feasible - // 18 CPX_ABORT_CROSSOVER - // Aborted in crossover - // 19 CPX_INForUNBD - // Infeasible or unbounded - // 20 CPX_PIVOT - // User pivot used - // - // Pending return values - // ??case CPX_ABORT_DUAL_INFEAS - // ??case CPX_ABORT_CROSSOVER - // ??case CPX_INForUNBD - // ??case CPX_PIVOT - - //Some more interesting stuff: - - // CPX_PARAM_PROBMETHOD 1062 int LPMETHOD - // 0 Automatic - // 1 Primal Simplex - // 2 Dual Simplex - // 3 Network Simplex - // 4 Standard Barrier - // Default: 0 - // Description: Method for linear optimization. - // Determines which algorithm is used when CPXlpopt() (or "optimize" - // in the Interactive Optimizer) is called. Currently the behavior of - // the "Automatic" setting is that CPLEX simply invokes the dual - // simplex method, but this capability may be expanded in the future - // so that CPLEX chooses the method based on problem characteristics -#if CPX_VERSION < 900 - void statusSwitch(CPXENVptr cplexEnv(),int& stat){ - int lpmethod; - CPXgetintparam (cplexEnv(),CPX_PARAM_PROBMETHOD,&lpmethod); - if (lpmethod==2){ - if (stat==CPX_UNBOUNDED){ - stat=CPX_INFEASIBLE; - } - else{ - if (stat==CPX_INFEASIBLE) - stat=CPX_UNBOUNDED; - } - } - } -#else - void statusSwitch(CPXENVptr,int&){} -#endif - - CplexLp::ProblemType CplexLp::_getPrimalType() const { - // Unboundedness not treated well: the following is from cplex 9.0 doc - // About Unboundedness - - // The treatment of models that are unbounded involves a few - // subtleties. Specifically, a declaration of unboundedness means that - // ILOG CPLEX has determined that the model has an unbounded - // ray. Given any feasible solution x with objective z, a multiple of - // the unbounded ray can be added to x to give a feasible solution - // with objective z-1 (or z+1 for maximization models). Thus, if a - // feasible solution exists, then the optimal objective is - // unbounded. Note that ILOG CPLEX has not necessarily concluded that - // a feasible solution exists. Users can call the routine CPXsolninfo - // to determine whether ILOG CPLEX has also concluded that the model - // has a feasible solution. - - int stat = CPXgetstat(cplexEnv(), _prob); -#if CPX_VERSION >= 800 - switch (stat) - { - case CPX_STAT_OPTIMAL: - return OPTIMAL; - case CPX_STAT_UNBOUNDED: - return UNBOUNDED; - case CPX_STAT_INFEASIBLE: - return INFEASIBLE; - default: - return UNDEFINED; - } -#else - statusSwitch(cplexEnv(),stat); - //CPXgetstat(cplexEnv(), _prob); - switch (stat) { - case 0: - return UNDEFINED; //Undefined - case CPX_OPTIMAL://Optimal - return OPTIMAL; - case CPX_UNBOUNDED://Unbounded - return INFEASIBLE;//In case of dual simplex - //return UNBOUNDED; - case CPX_INFEASIBLE://Infeasible - // case CPX_IT_LIM_INFEAS: - // case CPX_TIME_LIM_INFEAS: - // case CPX_NUM_BEST_INFEAS: - // case CPX_OPTIMAL_INFEAS: - // case CPX_ABORT_INFEAS: - // case CPX_ABORT_PRIM_INFEAS: - // case CPX_ABORT_PRIM_DUAL_INFEAS: - return UNBOUNDED;//In case of dual simplex - //return INFEASIBLE; - // case CPX_OBJ_LIM: - // case CPX_IT_LIM_FEAS: - // case CPX_TIME_LIM_FEAS: - // case CPX_NUM_BEST_FEAS: - // case CPX_ABORT_FEAS: - // case CPX_ABORT_PRIM_DUAL_FEAS: - // return FEASIBLE; - default: - return UNDEFINED; //Everything else comes here - //FIXME error - } -#endif - } - - // Cplex 9.0 status values - // CPX_STAT_ABORT_DUAL_OBJ_LIM - // CPX_STAT_ABORT_IT_LIM - // CPX_STAT_ABORT_OBJ_LIM - // CPX_STAT_ABORT_PRIM_OBJ_LIM - // CPX_STAT_ABORT_TIME_LIM - // CPX_STAT_ABORT_USER - // CPX_STAT_FEASIBLE_RELAXED - // CPX_STAT_INFEASIBLE - // CPX_STAT_INForUNBD - // CPX_STAT_NUM_BEST - // CPX_STAT_OPTIMAL - // CPX_STAT_OPTIMAL_FACE_UNBOUNDED - // CPX_STAT_OPTIMAL_INFEAS - // CPX_STAT_OPTIMAL_RELAXED - // CPX_STAT_UNBOUNDED - - CplexLp::ProblemType CplexLp::_getDualType() const { - int stat = CPXgetstat(cplexEnv(), _prob); -#if CPX_VERSION >= 800 - switch (stat) { - case CPX_STAT_OPTIMAL: - return OPTIMAL; - case CPX_STAT_UNBOUNDED: - return INFEASIBLE; - default: - return UNDEFINED; - } -#else - statusSwitch(cplexEnv(),stat); - switch (stat) { - case 0: - return UNDEFINED; //Undefined - case CPX_OPTIMAL://Optimal - return OPTIMAL; - case CPX_UNBOUNDED: - return INFEASIBLE; - default: - return UNDEFINED; //Everything else comes here - //FIXME error - } -#endif - } - - // CplexMip members - - CplexMip::CplexMip() - : LpBase(), MipSolver(), CplexBase() { - -#if CPX_VERSION < 800 - CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); -#else - CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP); -#endif - } - - CplexMip::CplexMip(const CplexEnv& env) - : LpBase(), MipSolver(), CplexBase(env) { - -#if CPX_VERSION < 800 - CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MIP); -#else - CPXchgprobtype(cplexEnv(), _prob, CPXPROB_MILP); -#endif - - } - - CplexMip::CplexMip(const CplexMip& other) - : LpBase(), MipSolver(), CplexBase(other) {} - - CplexMip::~CplexMip() {} - - CplexMip* CplexMip::newSolver() const { return new CplexMip; } - CplexMip* CplexMip::cloneSolver() const {return new CplexMip(*this); } - - const char* CplexMip::_solverName() const { return "CplexMip"; } - - void CplexMip::_setColType(int i, CplexMip::ColTypes col_type) { - - // Note If a variable is to be changed to binary, a call to CPXchgbds - // should also be made to change the bounds to 0 and 1. - - switch (col_type){ - case INTEGER: { - const char t = 'I'; - CPXchgctype (cplexEnv(), _prob, 1, &i, &t); - } break; - case REAL: { - const char t = 'C'; - CPXchgctype (cplexEnv(), _prob, 1, &i, &t); - } break; - default: - break; - } - } - - CplexMip::ColTypes CplexMip::_getColType(int i) const { - char t; - CPXgetctype (cplexEnv(), _prob, &t, i, i); - switch (t) { - case 'I': - return INTEGER; - case 'C': - return REAL; - default: - LEMON_ASSERT(false, "Invalid column type"); - return ColTypes(); - } - - } - - CplexMip::SolveExitStatus CplexMip::_solve() { - int status; - _applyMessageLevel(); - status = CPXmipopt (cplexEnv(), _prob); - if (status==0) - return SOLVED; - else - return UNSOLVED; - - } - - - CplexMip::ProblemType CplexMip::_getType() const { - - int stat = CPXgetstat(cplexEnv(), _prob); - - //Fortunately, MIP statuses did not change for cplex 8.0 - switch (stat) { - case CPXMIP_OPTIMAL: - // Optimal integer solution has been found. - case CPXMIP_OPTIMAL_TOL: - // Optimal soluton with the tolerance defined by epgap or epagap has - // been found. - return OPTIMAL; - //This also exists in later issues - // case CPXMIP_UNBOUNDED: - //return UNBOUNDED; - case CPXMIP_INFEASIBLE: - return INFEASIBLE; - default: - return UNDEFINED; - } - //Unboundedness not treated well: the following is from cplex 9.0 doc - // About Unboundedness - - // The treatment of models that are unbounded involves a few - // subtleties. Specifically, a declaration of unboundedness means that - // ILOG CPLEX has determined that the model has an unbounded - // ray. Given any feasible solution x with objective z, a multiple of - // the unbounded ray can be added to x to give a feasible solution - // with objective z-1 (or z+1 for maximization models). Thus, if a - // feasible solution exists, then the optimal objective is - // unbounded. Note that ILOG CPLEX has not necessarily concluded that - // a feasible solution exists. Users can call the routine CPXsolninfo - // to determine whether ILOG CPLEX has also concluded that the model - // has a feasible solution. - } - - CplexMip::Value CplexMip::_getSol(int i) const { - Value x; - CPXgetmipx(cplexEnv(), _prob, &x, i, i); - return x; - } - - CplexMip::Value CplexMip::_getSolValue() const { - Value objval; - CPXgetmipobjval(cplexEnv(), _prob, &objval); - return objval; - } - -} //namespace lemon - diff --git a/deps/lemon/lemon/cplex.h b/deps/lemon/lemon/cplex.h deleted file mode 100644 index c17e7926a..000000000 --- a/deps/lemon/lemon/cplex.h +++ /dev/null @@ -1,292 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_CPLEX_H -#define LEMON_CPLEX_H - -///\file -///\brief Header of the LEMON-CPLEX lp solver interface. - -#include - -struct cpxenv; -struct cpxlp; - -namespace lemon { - - /// \brief Reference counted wrapper around cpxenv pointer - /// - /// The cplex uses environment object which is responsible for - /// checking the proper license usage. This class provides a simple - /// interface for share the environment object between different - /// problems. - class CplexEnv { - friend class CplexBase; - private: - cpxenv* _env; - mutable int* _cnt; - - public: - - /// \brief This exception is thrown when the license check is not - /// sufficient - class LicenseError : public Exception { - friend class CplexEnv; - private: - - LicenseError(int status); - char _message[510]; - - public: - - /// The short error message - virtual const char* what() const throw() { - return _message; - } - }; - - /// Constructor - CplexEnv(); - /// Shallow copy constructor - CplexEnv(const CplexEnv&); - /// Shallow assignement - CplexEnv& operator=(const CplexEnv&); - /// Destructor - virtual ~CplexEnv(); - - protected: - - cpxenv* cplexEnv() { return _env; } - const cpxenv* cplexEnv() const { return _env; } - }; - - /// \brief Base interface for the CPLEX LP and MIP solver - /// - /// This class implements the common interface of the CPLEX LP and - /// MIP solvers. - /// \ingroup lp_group - class CplexBase : virtual public LpBase { - protected: - - CplexEnv _env; - cpxlp* _prob; - - CplexBase(); - CplexBase(const CplexEnv&); - CplexBase(const CplexBase &); - virtual ~CplexBase(); - - virtual int _addCol(); - virtual int _addRow(); - virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); - - virtual void _eraseCol(int i); - virtual void _eraseRow(int i); - - virtual void _eraseColId(int i); - virtual void _eraseRowId(int i); - - virtual void _getColName(int col, std::string& name) const; - virtual void _setColName(int col, const std::string& name); - virtual int _colByName(const std::string& name) const; - - virtual void _getRowName(int row, std::string& name) const; - virtual void _setRowName(int row, const std::string& name); - virtual int _rowByName(const std::string& name) const; - - virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); - virtual void _getRowCoeffs(int i, InsertIterator b) const; - - virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); - virtual void _getColCoeffs(int i, InsertIterator b) const; - - virtual void _setCoeff(int row, int col, Value value); - virtual Value _getCoeff(int row, int col) const; - - virtual void _setColLowerBound(int i, Value value); - virtual Value _getColLowerBound(int i) const; - - virtual void _setColUpperBound(int i, Value value); - virtual Value _getColUpperBound(int i) const; - - private: - void _set_row_bounds(int i, Value lb, Value ub); - protected: - - virtual void _setRowLowerBound(int i, Value value); - virtual Value _getRowLowerBound(int i) const; - - virtual void _setRowUpperBound(int i, Value value); - virtual Value _getRowUpperBound(int i) const; - - virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); - virtual void _getObjCoeffs(InsertIterator b) const; - - virtual void _setObjCoeff(int i, Value obj_coef); - virtual Value _getObjCoeff(int i) const; - - virtual void _setSense(Sense sense); - virtual Sense _getSense() const; - - virtual void _clear(); - - virtual void _messageLevel(MessageLevel level); - void _applyMessageLevel(); - - bool _message_enabled; - - void _write(std::string file, std::string format) const; - - public: - - /// Returns the used \c CplexEnv instance - const CplexEnv& env() const { return _env; } - - /// \brief Returns the const cpxenv pointer - /// - /// \note The cpxenv might be destructed with the solver. - const cpxenv* cplexEnv() const { return _env.cplexEnv(); } - - /// \brief Returns the const cpxenv pointer - /// - /// \note The cpxenv might be destructed with the solver. - cpxenv* cplexEnv() { return _env.cplexEnv(); } - - /// Returns the cplex problem object - cpxlp* cplexLp() { return _prob; } - /// Returns the cplex problem object - const cpxlp* cplexLp() const { return _prob; } - -#ifdef DOXYGEN - /// Write the problem or the solution to a file in the given format - - /// This function writes the problem or the solution - /// to a file in the given format. - /// Trying to write in an unsupported format will trigger - /// \ref lemon::LpBase::UnsupportedFormatError "UnsupportedFormatError". - /// \param file The file path - /// \param format The output file format. - /// Supportted formats are "MPS", "LP" and "SOL". - void write(std::string file, std::string format = "MPS") const {} -#endif - - }; - - /// \brief Interface for the CPLEX LP solver - /// - /// This class implements an interface for the CPLEX LP solver. - ///\ingroup lp_group - class CplexLp : public LpSolver, public CplexBase { - public: - /// \e - CplexLp(); - /// \e - CplexLp(const CplexEnv&); - /// \e - CplexLp(const CplexLp&); - /// \e - virtual ~CplexLp(); - - /// \e - virtual CplexLp* cloneSolver() const; - /// \e - virtual CplexLp* newSolver() const; - - private: - - // these values cannot retrieved element by element - mutable std::vector _col_status; - mutable std::vector _row_status; - - mutable std::vector _primal_ray; - mutable std::vector _dual_ray; - - void _clear_temporals(); - - SolveExitStatus convertStatus(int status); - - protected: - - virtual const char* _solverName() const; - - virtual SolveExitStatus _solve(); - virtual Value _getPrimal(int i) const; - virtual Value _getDual(int i) const; - virtual Value _getPrimalValue() const; - - virtual VarStatus _getColStatus(int i) const; - virtual VarStatus _getRowStatus(int i) const; - - virtual Value _getPrimalRay(int i) const; - virtual Value _getDualRay(int i) const; - - virtual ProblemType _getPrimalType() const; - virtual ProblemType _getDualType() const; - - public: - - /// Solve with primal simplex method - SolveExitStatus solvePrimal(); - - /// Solve with dual simplex method - SolveExitStatus solveDual(); - - /// Solve with barrier method - SolveExitStatus solveBarrier(); - - }; - - /// \brief Interface for the CPLEX MIP solver - /// - /// This class implements an interface for the CPLEX MIP solver. - ///\ingroup lp_group - class CplexMip : public MipSolver, public CplexBase { - public: - /// \e - CplexMip(); - /// \e - CplexMip(const CplexEnv&); - /// \e - CplexMip(const CplexMip&); - /// \e - virtual ~CplexMip(); - - /// \e - virtual CplexMip* cloneSolver() const; - /// \e - virtual CplexMip* newSolver() const; - - protected: - - - virtual const char* _solverName() const; - - virtual ColTypes _getColType(int col) const; - virtual void _setColType(int col, ColTypes col_type); - - virtual SolveExitStatus _solve(); - virtual ProblemType _getType() const; - virtual Value _getSol(int i) const; - virtual Value _getSolValue() const; - - }; - -} //END OF NAMESPACE LEMON - -#endif //LEMON_CPLEX_H - diff --git a/deps/lemon/lemon/cycle_canceling.h b/deps/lemon/lemon/cycle_canceling.h deleted file mode 100644 index 646d299e3..000000000 --- a/deps/lemon/lemon/cycle_canceling.h +++ /dev/null @@ -1,1230 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_CYCLE_CANCELING_H -#define LEMON_CYCLE_CANCELING_H - -/// \ingroup min_cost_flow_algs -/// \file -/// \brief Cycle-canceling algorithms for finding a minimum cost flow. - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace lemon { - - /// \addtogroup min_cost_flow_algs - /// @{ - - /// \brief Implementation of cycle-canceling algorithms for - /// finding a \ref min_cost_flow "minimum cost flow". - /// - /// \ref CycleCanceling implements three different cycle-canceling - /// algorithms for finding a \ref min_cost_flow "minimum cost flow" - /// \cite amo93networkflows, \cite klein67primal, - /// \cite goldberg89cyclecanceling. - /// The most efficent one is the \ref CANCEL_AND_TIGHTEN - /// "Cancel-and-Tighten" algorithm, thus it is the default method. - /// It runs in strongly polynomial time \f$O(n^2 m^2 \log n)\f$, - /// but in practice, it is typically orders of magnitude slower than - /// the scaling algorithms and \ref NetworkSimplex. - /// (For more information, see \ref min_cost_flow_algs "the module page".) - /// - /// Most of the parameters of the problem (except for the digraph) - /// can be given using separate functions, and the algorithm can be - /// executed using the \ref run() function. If some parameters are not - /// specified, then default values will be used. - /// - /// \tparam GR The digraph type the algorithm runs on. - /// \tparam V The number type used for flow amounts, capacity bounds - /// and supply values in the algorithm. By default, it is \c int. - /// \tparam C The number type used for costs and potentials in the - /// algorithm. By default, it is the same as \c V. - /// - /// \warning Both \c V and \c C must be signed number types. - /// \warning All input data (capacities, supply values, and costs) must - /// be integer. - /// \warning This algorithm does not support negative costs for - /// arcs having infinite upper bound. - /// - /// \note For more information about the three available methods, - /// see \ref Method. -#ifdef DOXYGEN - template -#else - template -#endif - class CycleCanceling - { - public: - - /// The type of the digraph - typedef GR Digraph; - /// The type of the flow amounts, capacity bounds and supply values - typedef V Value; - /// The type of the arc costs - typedef C Cost; - - public: - - /// \brief Problem type constants for the \c run() function. - /// - /// Enum type containing the problem type constants that can be - /// returned by the \ref run() function of the algorithm. - enum ProblemType { - /// The problem has no feasible solution (flow). - INFEASIBLE, - /// The problem has optimal solution (i.e. it is feasible and - /// bounded), and the algorithm has found optimal flow and node - /// potentials (primal and dual solutions). - OPTIMAL, - /// The digraph contains an arc of negative cost and infinite - /// upper bound. It means that the objective function is unbounded - /// on that arc, however, note that it could actually be bounded - /// over the feasible flows, but this algroithm cannot handle - /// these cases. - UNBOUNDED - }; - - /// \brief Constants for selecting the used method. - /// - /// Enum type containing constants for selecting the used method - /// for the \ref run() function. - /// - /// \ref CycleCanceling provides three different cycle-canceling - /// methods. By default, \ref CANCEL_AND_TIGHTEN "Cancel-and-Tighten" - /// is used, which is by far the most efficient and the most robust. - /// However, the other methods can be selected using the \ref run() - /// function with the proper parameter. - enum Method { - /// A simple cycle-canceling method, which uses the - /// \ref BellmanFord "Bellman-Ford" algorithm for detecting negative - /// cycles in the residual network. - /// The number of Bellman-Ford iterations is bounded by a successively - /// increased limit. - SIMPLE_CYCLE_CANCELING, - /// The "Minimum Mean Cycle-Canceling" algorithm, which is a - /// well-known strongly polynomial method - /// \cite goldberg89cyclecanceling. It improves along a - /// \ref min_mean_cycle "minimum mean cycle" in each iteration. - /// Its running time complexity is \f$O(n^2 m^3 \log n)\f$. - MINIMUM_MEAN_CYCLE_CANCELING, - /// The "Cancel-and-Tighten" algorithm, which can be viewed as an - /// improved version of the previous method - /// \cite goldberg89cyclecanceling. - /// It is faster both in theory and in practice, its running time - /// complexity is \f$O(n^2 m^2 \log n)\f$. - CANCEL_AND_TIGHTEN - }; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(GR); - - typedef std::vector IntVector; - typedef std::vector DoubleVector; - typedef std::vector ValueVector; - typedef std::vector CostVector; - typedef std::vector BoolVector; - // Note: vector is used instead of vector for efficiency reasons - - private: - - template - class StaticVectorMap { - public: - typedef KT Key; - typedef VT Value; - - StaticVectorMap(std::vector& v) : _v(v) {} - - const Value& operator[](const Key& key) const { - return _v[StaticDigraph::id(key)]; - } - - Value& operator[](const Key& key) { - return _v[StaticDigraph::id(key)]; - } - - void set(const Key& key, const Value& val) { - _v[StaticDigraph::id(key)] = val; - } - - private: - std::vector& _v; - }; - - typedef StaticVectorMap CostNodeMap; - typedef StaticVectorMap CostArcMap; - - private: - - - // Data related to the underlying digraph - const GR &_graph; - int _node_num; - int _arc_num; - int _res_node_num; - int _res_arc_num; - int _root; - - // Parameters of the problem - bool _has_lower; - Value _sum_supply; - - // Data structures for storing the digraph - IntNodeMap _node_id; - IntArcMap _arc_idf; - IntArcMap _arc_idb; - IntVector _first_out; - BoolVector _forward; - IntVector _source; - IntVector _target; - IntVector _reverse; - - // Node and arc data - ValueVector _lower; - ValueVector _upper; - CostVector _cost; - ValueVector _supply; - - ValueVector _res_cap; - CostVector _pi; - - // Data for a StaticDigraph structure - typedef std::pair IntPair; - StaticDigraph _sgr; - std::vector _arc_vec; - std::vector _cost_vec; - IntVector _id_vec; - CostArcMap _cost_map; - CostNodeMap _pi_map; - - public: - - /// \brief Constant for infinite upper bounds (capacities). - /// - /// Constant for infinite upper bounds (capacities). - /// It is \c std::numeric_limits::infinity() if available, - /// \c std::numeric_limits::max() otherwise. - const Value INF; - - public: - - /// \brief Constructor. - /// - /// The constructor of the class. - /// - /// \param graph The digraph the algorithm runs on. - CycleCanceling(const GR& graph) : - _graph(graph), _node_id(graph), _arc_idf(graph), _arc_idb(graph), - _cost_map(_cost_vec), _pi_map(_pi), - INF(std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max()) - { - // Check the number types - LEMON_ASSERT(std::numeric_limits::is_signed, - "The flow type of CycleCanceling must be signed"); - LEMON_ASSERT(std::numeric_limits::is_signed, - "The cost type of CycleCanceling must be signed"); - - // Reset data structures - reset(); - } - - /// \name Parameters - /// The parameters of the algorithm can be specified using these - /// functions. - - /// @{ - - /// \brief Set the lower bounds on the arcs. - /// - /// This function sets the lower bounds on the arcs. - /// If it is not used before calling \ref run(), the lower bounds - /// will be set to zero on all arcs. - /// - /// \param map An arc map storing the lower bounds. - /// Its \c Value type must be convertible to the \c Value type - /// of the algorithm. - /// - /// \return (*this) - template - CycleCanceling& lowerMap(const LowerMap& map) { - _has_lower = true; - for (ArcIt a(_graph); a != INVALID; ++a) { - _lower[_arc_idf[a]] = map[a]; - } - return *this; - } - - /// \brief Set the upper bounds (capacities) on the arcs. - /// - /// This function sets the upper bounds (capacities) on the arcs. - /// If it is not used before calling \ref run(), the upper bounds - /// will be set to \ref INF on all arcs (i.e. the flow value will be - /// unbounded from above). - /// - /// \param map An arc map storing the upper bounds. - /// Its \c Value type must be convertible to the \c Value type - /// of the algorithm. - /// - /// \return (*this) - template - CycleCanceling& upperMap(const UpperMap& map) { - for (ArcIt a(_graph); a != INVALID; ++a) { - _upper[_arc_idf[a]] = map[a]; - } - return *this; - } - - /// \brief Set the costs of the arcs. - /// - /// This function sets the costs of the arcs. - /// If it is not used before calling \ref run(), the costs - /// will be set to \c 1 on all arcs. - /// - /// \param map An arc map storing the costs. - /// Its \c Value type must be convertible to the \c Cost type - /// of the algorithm. - /// - /// \return (*this) - template - CycleCanceling& costMap(const CostMap& map) { - for (ArcIt a(_graph); a != INVALID; ++a) { - _cost[_arc_idf[a]] = map[a]; - _cost[_arc_idb[a]] = -map[a]; - } - return *this; - } - - /// \brief Set the supply values of the nodes. - /// - /// This function sets the supply values of the nodes. - /// If neither this function nor \ref stSupply() is used before - /// calling \ref run(), the supply of each node will be set to zero. - /// - /// \param map A node map storing the supply values. - /// Its \c Value type must be convertible to the \c Value type - /// of the algorithm. - /// - /// \return (*this) - template - CycleCanceling& supplyMap(const SupplyMap& map) { - for (NodeIt n(_graph); n != INVALID; ++n) { - _supply[_node_id[n]] = map[n]; - } - return *this; - } - - /// \brief Set single source and target nodes and a supply value. - /// - /// This function sets a single source node and a single target node - /// and the required flow value. - /// If neither this function nor \ref supplyMap() is used before - /// calling \ref run(), the supply of each node will be set to zero. - /// - /// Using this function has the same effect as using \ref supplyMap() - /// with a map in which \c k is assigned to \c s, \c -k is - /// assigned to \c t and all other nodes have zero supply value. - /// - /// \param s The source node. - /// \param t The target node. - /// \param k The required amount of flow from node \c s to node \c t - /// (i.e. the supply of \c s and the demand of \c t). - /// - /// \return (*this) - CycleCanceling& stSupply(const Node& s, const Node& t, Value k) { - for (int i = 0; i != _res_node_num; ++i) { - _supply[i] = 0; - } - _supply[_node_id[s]] = k; - _supply[_node_id[t]] = -k; - return *this; - } - - /// @} - - /// \name Execution control - /// The algorithm can be executed using \ref run(). - - /// @{ - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. - /// The paramters can be specified using functions \ref lowerMap(), - /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). - /// For example, - /// \code - /// CycleCanceling cc(graph); - /// cc.lowerMap(lower).upperMap(upper).costMap(cost) - /// .supplyMap(sup).run(); - /// \endcode - /// - /// This function can be called more than once. All the given parameters - /// are kept for the next call, unless \ref resetParams() or \ref reset() - /// is used, thus only the modified parameters have to be set again. - /// If the underlying digraph was also modified after the construction - /// of the class (or the last \ref reset() call), then the \ref reset() - /// function must be called. - /// - /// \param method The cycle-canceling method that will be used. - /// For more information, see \ref Method. - /// - /// \return \c INFEASIBLE if no feasible flow exists, - /// \n \c OPTIMAL if the problem has optimal solution - /// (i.e. it is feasible and bounded), and the algorithm has found - /// optimal flow and node potentials (primal and dual solutions), - /// \n \c UNBOUNDED if the digraph contains an arc of negative cost - /// and infinite upper bound. It means that the objective function - /// is unbounded on that arc, however, note that it could actually be - /// bounded over the feasible flows, but this algroithm cannot handle - /// these cases. - /// - /// \see ProblemType, Method - /// \see resetParams(), reset() - ProblemType run(Method method = CANCEL_AND_TIGHTEN) { - ProblemType pt = init(); - if (pt != OPTIMAL) return pt; - start(method); - return OPTIMAL; - } - - /// \brief Reset all the parameters that have been given before. - /// - /// This function resets all the paramaters that have been given - /// before using functions \ref lowerMap(), \ref upperMap(), - /// \ref costMap(), \ref supplyMap(), \ref stSupply(). - /// - /// It is useful for multiple \ref run() calls. Basically, all the given - /// parameters are kept for the next \ref run() call, unless - /// \ref resetParams() or \ref reset() is used. - /// If the underlying digraph was also modified after the construction - /// of the class or the last \ref reset() call, then the \ref reset() - /// function must be used, otherwise \ref resetParams() is sufficient. - /// - /// For example, - /// \code - /// CycleCanceling cs(graph); - /// - /// // First run - /// cc.lowerMap(lower).upperMap(upper).costMap(cost) - /// .supplyMap(sup).run(); - /// - /// // Run again with modified cost map (resetParams() is not called, - /// // so only the cost map have to be set again) - /// cost[e] += 100; - /// cc.costMap(cost).run(); - /// - /// // Run again from scratch using resetParams() - /// // (the lower bounds will be set to zero on all arcs) - /// cc.resetParams(); - /// cc.upperMap(capacity).costMap(cost) - /// .supplyMap(sup).run(); - /// \endcode - /// - /// \return (*this) - /// - /// \see reset(), run() - CycleCanceling& resetParams() { - for (int i = 0; i != _res_node_num; ++i) { - _supply[i] = 0; - } - int limit = _first_out[_root]; - for (int j = 0; j != limit; ++j) { - _lower[j] = 0; - _upper[j] = INF; - _cost[j] = _forward[j] ? 1 : -1; - } - for (int j = limit; j != _res_arc_num; ++j) { - _lower[j] = 0; - _upper[j] = INF; - _cost[j] = 0; - _cost[_reverse[j]] = 0; - } - _has_lower = false; - return *this; - } - - /// \brief Reset the internal data structures and all the parameters - /// that have been given before. - /// - /// This function resets the internal data structures and all the - /// paramaters that have been given before using functions \ref lowerMap(), - /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(). - /// - /// It is useful for multiple \ref run() calls. Basically, all the given - /// parameters are kept for the next \ref run() call, unless - /// \ref resetParams() or \ref reset() is used. - /// If the underlying digraph was also modified after the construction - /// of the class or the last \ref reset() call, then the \ref reset() - /// function must be used, otherwise \ref resetParams() is sufficient. - /// - /// See \ref resetParams() for examples. - /// - /// \return (*this) - /// - /// \see resetParams(), run() - CycleCanceling& reset() { - // Resize vectors - _node_num = countNodes(_graph); - _arc_num = countArcs(_graph); - _res_node_num = _node_num + 1; - _res_arc_num = 2 * (_arc_num + _node_num); - _root = _node_num; - - _first_out.resize(_res_node_num + 1); - _forward.resize(_res_arc_num); - _source.resize(_res_arc_num); - _target.resize(_res_arc_num); - _reverse.resize(_res_arc_num); - - _lower.resize(_res_arc_num); - _upper.resize(_res_arc_num); - _cost.resize(_res_arc_num); - _supply.resize(_res_node_num); - - _res_cap.resize(_res_arc_num); - _pi.resize(_res_node_num); - - _arc_vec.reserve(_res_arc_num); - _cost_vec.reserve(_res_arc_num); - _id_vec.reserve(_res_arc_num); - - // Copy the graph - int i = 0, j = 0, k = 2 * _arc_num + _node_num; - for (NodeIt n(_graph); n != INVALID; ++n, ++i) { - _node_id[n] = i; - } - i = 0; - for (NodeIt n(_graph); n != INVALID; ++n, ++i) { - _first_out[i] = j; - for (OutArcIt a(_graph, n); a != INVALID; ++a, ++j) { - _arc_idf[a] = j; - _forward[j] = true; - _source[j] = i; - _target[j] = _node_id[_graph.runningNode(a)]; - } - for (InArcIt a(_graph, n); a != INVALID; ++a, ++j) { - _arc_idb[a] = j; - _forward[j] = false; - _source[j] = i; - _target[j] = _node_id[_graph.runningNode(a)]; - } - _forward[j] = false; - _source[j] = i; - _target[j] = _root; - _reverse[j] = k; - _forward[k] = true; - _source[k] = _root; - _target[k] = i; - _reverse[k] = j; - ++j; ++k; - } - _first_out[i] = j; - _first_out[_res_node_num] = k; - for (ArcIt a(_graph); a != INVALID; ++a) { - int fi = _arc_idf[a]; - int bi = _arc_idb[a]; - _reverse[fi] = bi; - _reverse[bi] = fi; - } - - // Reset parameters - resetParams(); - return *this; - } - - /// @} - - /// \name Query Functions - /// The results of the algorithm can be obtained using these - /// functions.\n - /// The \ref run() function must be called before using them. - - /// @{ - - /// \brief Return the total cost of the found flow. - /// - /// This function returns the total cost of the found flow. - /// Its complexity is O(m). - /// - /// \note The return type of the function can be specified as a - /// template parameter. For example, - /// \code - /// cc.totalCost(); - /// \endcode - /// It is useful if the total cost cannot be stored in the \c Cost - /// type of the algorithm, which is the default return type of the - /// function. - /// - /// \pre \ref run() must be called before using this function. - template - Number totalCost() const { - Number c = 0; - for (ArcIt a(_graph); a != INVALID; ++a) { - int i = _arc_idb[a]; - c += static_cast(_res_cap[i]) * - (-static_cast(_cost[i])); - } - return c; - } - -#ifndef DOXYGEN - Cost totalCost() const { - return totalCost(); - } -#endif - - /// \brief Return the flow on the given arc. - /// - /// This function returns the flow on the given arc. - /// - /// \pre \ref run() must be called before using this function. - Value flow(const Arc& a) const { - return _res_cap[_arc_idb[a]]; - } - - /// \brief Copy the flow values (the primal solution) into the - /// given map. - /// - /// This function copies the flow value on each arc into the given - /// map. The \c Value type of the algorithm must be convertible to - /// the \c Value type of the map. - /// - /// \pre \ref run() must be called before using this function. - template - void flowMap(FlowMap &map) const { - for (ArcIt a(_graph); a != INVALID; ++a) { - map.set(a, _res_cap[_arc_idb[a]]); - } - } - - /// \brief Return the potential (dual value) of the given node. - /// - /// This function returns the potential (dual value) of the - /// given node. - /// - /// \pre \ref run() must be called before using this function. - Cost potential(const Node& n) const { - return static_cast(_pi[_node_id[n]]); - } - - /// \brief Copy the potential values (the dual solution) into the - /// given map. - /// - /// This function copies the potential (dual value) of each node - /// into the given map. - /// The \c Cost type of the algorithm must be convertible to the - /// \c Value type of the map. - /// - /// \pre \ref run() must be called before using this function. - template - void potentialMap(PotentialMap &map) const { - for (NodeIt n(_graph); n != INVALID; ++n) { - map.set(n, static_cast(_pi[_node_id[n]])); - } - } - - /// @} - - private: - - // Initialize the algorithm - ProblemType init() { - if (_res_node_num <= 1) return INFEASIBLE; - - // Check the sum of supply values - _sum_supply = 0; - for (int i = 0; i != _root; ++i) { - _sum_supply += _supply[i]; - } - if (_sum_supply > 0) return INFEASIBLE; - - // Check lower and upper bounds - LEMON_DEBUG(checkBoundMaps(), - "Upper bounds must be greater or equal to the lower bounds"); - - - // Initialize vectors - for (int i = 0; i != _res_node_num; ++i) { - _pi[i] = 0; - } - ValueVector excess(_supply); - - // Remove infinite upper bounds and check negative arcs - const Value MAX = std::numeric_limits::max(); - int last_out; - if (_has_lower) { - for (int i = 0; i != _root; ++i) { - last_out = _first_out[i+1]; - for (int j = _first_out[i]; j != last_out; ++j) { - if (_forward[j]) { - Value c = _cost[j] < 0 ? _upper[j] : _lower[j]; - if (c >= MAX) return UNBOUNDED; - excess[i] -= c; - excess[_target[j]] += c; - } - } - } - } else { - for (int i = 0; i != _root; ++i) { - last_out = _first_out[i+1]; - for (int j = _first_out[i]; j != last_out; ++j) { - if (_forward[j] && _cost[j] < 0) { - Value c = _upper[j]; - if (c >= MAX) return UNBOUNDED; - excess[i] -= c; - excess[_target[j]] += c; - } - } - } - } - Value ex, max_cap = 0; - for (int i = 0; i != _res_node_num; ++i) { - ex = excess[i]; - if (ex < 0) max_cap -= ex; - } - for (int j = 0; j != _res_arc_num; ++j) { - if (_upper[j] >= MAX) _upper[j] = max_cap; - } - - // Initialize maps for Circulation and remove non-zero lower bounds - ConstMap low(0); - typedef typename Digraph::template ArcMap ValueArcMap; - typedef typename Digraph::template NodeMap ValueNodeMap; - ValueArcMap cap(_graph), flow(_graph); - ValueNodeMap sup(_graph); - for (NodeIt n(_graph); n != INVALID; ++n) { - sup[n] = _supply[_node_id[n]]; - } - if (_has_lower) { - for (ArcIt a(_graph); a != INVALID; ++a) { - int j = _arc_idf[a]; - Value c = _lower[j]; - cap[a] = _upper[j] - c; - sup[_graph.source(a)] -= c; - sup[_graph.target(a)] += c; - } - } else { - for (ArcIt a(_graph); a != INVALID; ++a) { - cap[a] = _upper[_arc_idf[a]]; - } - } - - // Find a feasible flow using Circulation - Circulation, ValueArcMap, ValueNodeMap> - circ(_graph, low, cap, sup); - if (!circ.flowMap(flow).run()) return INFEASIBLE; - - // Set residual capacities and handle GEQ supply type - if (_sum_supply < 0) { - for (ArcIt a(_graph); a != INVALID; ++a) { - Value fa = flow[a]; - _res_cap[_arc_idf[a]] = cap[a] - fa; - _res_cap[_arc_idb[a]] = fa; - sup[_graph.source(a)] -= fa; - sup[_graph.target(a)] += fa; - } - for (NodeIt n(_graph); n != INVALID; ++n) { - excess[_node_id[n]] = sup[n]; - } - for (int a = _first_out[_root]; a != _res_arc_num; ++a) { - int u = _target[a]; - int ra = _reverse[a]; - _res_cap[a] = -_sum_supply + 1; - _res_cap[ra] = -excess[u]; - _cost[a] = 0; - _cost[ra] = 0; - } - } else { - for (ArcIt a(_graph); a != INVALID; ++a) { - Value fa = flow[a]; - _res_cap[_arc_idf[a]] = cap[a] - fa; - _res_cap[_arc_idb[a]] = fa; - } - for (int a = _first_out[_root]; a != _res_arc_num; ++a) { - int ra = _reverse[a]; - _res_cap[a] = 1; - _res_cap[ra] = 0; - _cost[a] = 0; - _cost[ra] = 0; - } - } - - return OPTIMAL; - } - - // Check if the upper bound is greater than or equal to the lower bound - // on each forward arc. - bool checkBoundMaps() { - for (int j = 0; j != _res_arc_num; ++j) { - if (_forward[j] && _upper[j] < _lower[j]) return false; - } - return true; - } - - // Build a StaticDigraph structure containing the current - // residual network - void buildResidualNetwork() { - _arc_vec.clear(); - _cost_vec.clear(); - _id_vec.clear(); - for (int j = 0; j != _res_arc_num; ++j) { - if (_res_cap[j] > 0) { - _arc_vec.push_back(IntPair(_source[j], _target[j])); - _cost_vec.push_back(_cost[j]); - _id_vec.push_back(j); - } - } - _sgr.build(_res_node_num, _arc_vec.begin(), _arc_vec.end()); - } - - // Execute the algorithm and transform the results - void start(Method method) { - // Execute the algorithm - switch (method) { - case SIMPLE_CYCLE_CANCELING: - startSimpleCycleCanceling(); - break; - case MINIMUM_MEAN_CYCLE_CANCELING: - startMinMeanCycleCanceling(); - break; - case CANCEL_AND_TIGHTEN: - startCancelAndTighten(); - break; - } - - // Compute node potentials - if (method != SIMPLE_CYCLE_CANCELING) { - buildResidualNetwork(); - typename BellmanFord - ::template SetDistMap::Create bf(_sgr, _cost_map); - bf.distMap(_pi_map); - bf.init(0); - bf.start(); - } - - // Handle non-zero lower bounds - if (_has_lower) { - int limit = _first_out[_root]; - for (int j = 0; j != limit; ++j) { - if (_forward[j]) _res_cap[_reverse[j]] += _lower[j]; - } - } - } - - // Execute the "Simple Cycle Canceling" method - void startSimpleCycleCanceling() { - // Constants for computing the iteration limits - const int BF_FIRST_LIMIT = 2; - const double BF_LIMIT_FACTOR = 1.5; - - typedef StaticVectorMap FilterMap; - typedef FilterArcs ResDigraph; - typedef StaticVectorMap PredMap; - typedef typename BellmanFord - ::template SetDistMap - ::template SetPredMap::Create BF; - - // Build the residual network - _arc_vec.clear(); - _cost_vec.clear(); - for (int j = 0; j != _res_arc_num; ++j) { - _arc_vec.push_back(IntPair(_source[j], _target[j])); - _cost_vec.push_back(_cost[j]); - } - _sgr.build(_res_node_num, _arc_vec.begin(), _arc_vec.end()); - - FilterMap filter_map(_res_cap); - ResDigraph rgr(_sgr, filter_map); - std::vector cycle; - std::vector pred(_res_arc_num); - PredMap pred_map(pred); - BF bf(rgr, _cost_map); - bf.distMap(_pi_map).predMap(pred_map); - - int length_bound = BF_FIRST_LIMIT; - bool optimal = false; - while (!optimal) { - bf.init(0); - int iter_num = 0; - bool cycle_found = false; - while (!cycle_found) { - // Perform some iterations of the Bellman-Ford algorithm - int curr_iter_num = iter_num + length_bound <= _node_num ? - length_bound : _node_num - iter_num; - iter_num += curr_iter_num; - int real_iter_num = curr_iter_num; - for (int i = 0; i < curr_iter_num; ++i) { - if (bf.processNextWeakRound()) { - real_iter_num = i; - break; - } - } - if (real_iter_num < curr_iter_num) { - // Optimal flow is found - optimal = true; - break; - } else { - // Search for node disjoint negative cycles - std::vector state(_res_node_num, 0); - int id = 0; - for (int u = 0; u != _res_node_num; ++u) { - if (state[u] != 0) continue; - ++id; - int v = u; - for (; v != -1 && state[v] == 0; v = pred[v] == INVALID ? - -1 : rgr.id(rgr.source(pred[v]))) { - state[v] = id; - } - if (v != -1 && state[v] == id) { - // A negative cycle is found - cycle_found = true; - cycle.clear(); - StaticDigraph::Arc a = pred[v]; - Value d, delta = _res_cap[rgr.id(a)]; - cycle.push_back(rgr.id(a)); - while (rgr.id(rgr.source(a)) != v) { - a = pred_map[rgr.source(a)]; - d = _res_cap[rgr.id(a)]; - if (d < delta) delta = d; - cycle.push_back(rgr.id(a)); - } - - // Augment along the cycle - for (int i = 0; i < int(cycle.size()); ++i) { - int j = cycle[i]; - _res_cap[j] -= delta; - _res_cap[_reverse[j]] += delta; - } - } - } - } - - // Increase iteration limit if no cycle is found - if (!cycle_found) { - length_bound = static_cast(length_bound * BF_LIMIT_FACTOR); - } - } - } - } - - // Execute the "Minimum Mean Cycle Canceling" method - void startMinMeanCycleCanceling() { - typedef Path SPath; - typedef typename SPath::ArcIt SPathArcIt; - typedef typename HowardMmc - ::template SetPath::Create HwMmc; - typedef typename HartmannOrlinMmc - ::template SetPath::Create HoMmc; - - const double HW_ITER_LIMIT_FACTOR = 1.0; - const int HW_ITER_LIMIT_MIN_VALUE = 5; - - const int hw_iter_limit = - std::max(static_cast(HW_ITER_LIMIT_FACTOR * _node_num), - HW_ITER_LIMIT_MIN_VALUE); - - SPath cycle; - HwMmc hw_mmc(_sgr, _cost_map); - hw_mmc.cycle(cycle); - buildResidualNetwork(); - while (true) { - - typename HwMmc::TerminationCause hw_tc = - hw_mmc.findCycleMean(hw_iter_limit); - if (hw_tc == HwMmc::ITERATION_LIMIT) { - // Howard's algorithm reached the iteration limit, start a - // strongly polynomial algorithm instead - HoMmc ho_mmc(_sgr, _cost_map); - ho_mmc.cycle(cycle); - // Find a minimum mean cycle (Hartmann-Orlin algorithm) - if (!(ho_mmc.findCycleMean() && ho_mmc.cycleCost() < 0)) break; - ho_mmc.findCycle(); - } else { - // Find a minimum mean cycle (Howard algorithm) - if (!(hw_tc == HwMmc::OPTIMAL && hw_mmc.cycleCost() < 0)) break; - hw_mmc.findCycle(); - } - - // Compute delta value - Value delta = INF; - for (SPathArcIt a(cycle); a != INVALID; ++a) { - Value d = _res_cap[_id_vec[_sgr.id(a)]]; - if (d < delta) delta = d; - } - - // Augment along the cycle - for (SPathArcIt a(cycle); a != INVALID; ++a) { - int j = _id_vec[_sgr.id(a)]; - _res_cap[j] -= delta; - _res_cap[_reverse[j]] += delta; - } - - // Rebuild the residual network - buildResidualNetwork(); - } - } - - // Execute the "Cancel-and-Tighten" method - void startCancelAndTighten() { - // Constants for the min mean cycle computations - const double LIMIT_FACTOR = 1.0; - const int MIN_LIMIT = 5; - const double HW_ITER_LIMIT_FACTOR = 1.0; - const int HW_ITER_LIMIT_MIN_VALUE = 5; - - const int hw_iter_limit = - std::max(static_cast(HW_ITER_LIMIT_FACTOR * _node_num), - HW_ITER_LIMIT_MIN_VALUE); - - // Contruct auxiliary data vectors - DoubleVector pi(_res_node_num, 0.0); - IntVector level(_res_node_num); - BoolVector reached(_res_node_num); - BoolVector processed(_res_node_num); - IntVector pred_node(_res_node_num); - IntVector pred_arc(_res_node_num); - std::vector stack(_res_node_num); - std::vector proc_vector(_res_node_num); - - // Initialize epsilon - double epsilon = 0; - for (int a = 0; a != _res_arc_num; ++a) { - if (_res_cap[a] > 0 && -_cost[a] > epsilon) - epsilon = -_cost[a]; - } - - // Start phases - Tolerance tol; - tol.epsilon(1e-6); - int limit = int(LIMIT_FACTOR * std::sqrt(double(_res_node_num))); - if (limit < MIN_LIMIT) limit = MIN_LIMIT; - int iter = limit; - while (epsilon * _res_node_num >= 1) { - // Find and cancel cycles in the admissible network using DFS - for (int u = 0; u != _res_node_num; ++u) { - reached[u] = false; - processed[u] = false; - } - int stack_head = -1; - int proc_head = -1; - for (int start = 0; start != _res_node_num; ++start) { - if (reached[start]) continue; - - // New start node - reached[start] = true; - pred_arc[start] = -1; - pred_node[start] = -1; - - // Find the first admissible outgoing arc - double p = pi[start]; - int a = _first_out[start]; - int last_out = _first_out[start+1]; - for (; a != last_out && (_res_cap[a] == 0 || - !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ; - if (a == last_out) { - processed[start] = true; - proc_vector[++proc_head] = start; - continue; - } - stack[++stack_head] = a; - - while (stack_head >= 0) { - int sa = stack[stack_head]; - int u = _source[sa]; - int v = _target[sa]; - - if (!reached[v]) { - // A new node is reached - reached[v] = true; - pred_node[v] = u; - pred_arc[v] = sa; - p = pi[v]; - a = _first_out[v]; - last_out = _first_out[v+1]; - for (; a != last_out && (_res_cap[a] == 0 || - !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ; - stack[++stack_head] = a == last_out ? -1 : a; - } else { - if (!processed[v]) { - // A cycle is found - int n, w = u; - Value d, delta = _res_cap[sa]; - for (n = u; n != v; n = pred_node[n]) { - d = _res_cap[pred_arc[n]]; - if (d <= delta) { - delta = d; - w = pred_node[n]; - } - } - - // Augment along the cycle - _res_cap[sa] -= delta; - _res_cap[_reverse[sa]] += delta; - for (n = u; n != v; n = pred_node[n]) { - int pa = pred_arc[n]; - _res_cap[pa] -= delta; - _res_cap[_reverse[pa]] += delta; - } - for (n = u; stack_head > 0 && n != w; n = pred_node[n]) { - --stack_head; - reached[n] = false; - } - u = w; - } - v = u; - - // Find the next admissible outgoing arc - p = pi[v]; - a = stack[stack_head] + 1; - last_out = _first_out[v+1]; - for (; a != last_out && (_res_cap[a] == 0 || - !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ; - stack[stack_head] = a == last_out ? -1 : a; - } - - while (stack_head >= 0 && stack[stack_head] == -1) { - processed[v] = true; - proc_vector[++proc_head] = v; - if (--stack_head >= 0) { - // Find the next admissible outgoing arc - v = _source[stack[stack_head]]; - p = pi[v]; - a = stack[stack_head] + 1; - last_out = _first_out[v+1]; - for (; a != last_out && (_res_cap[a] == 0 || - !tol.negative(_cost[a] + p - pi[_target[a]])); ++a) ; - stack[stack_head] = a == last_out ? -1 : a; - } - } - } - } - - // Tighten potentials and epsilon - if (--iter > 0) { - for (int u = 0; u != _res_node_num; ++u) { - level[u] = 0; - } - for (int i = proc_head; i > 0; --i) { - int u = proc_vector[i]; - double p = pi[u]; - int l = level[u] + 1; - int last_out = _first_out[u+1]; - for (int a = _first_out[u]; a != last_out; ++a) { - int v = _target[a]; - if (_res_cap[a] > 0 && tol.negative(_cost[a] + p - pi[v]) && - l > level[v]) level[v] = l; - } - } - - // Modify potentials - double q = std::numeric_limits::max(); - for (int u = 0; u != _res_node_num; ++u) { - int lu = level[u]; - double p, pu = pi[u]; - int last_out = _first_out[u+1]; - for (int a = _first_out[u]; a != last_out; ++a) { - if (_res_cap[a] == 0) continue; - int v = _target[a]; - int ld = lu - level[v]; - if (ld > 0) { - p = (_cost[a] + pu - pi[v] + epsilon) / (ld + 1); - if (p < q) q = p; - } - } - } - for (int u = 0; u != _res_node_num; ++u) { - pi[u] -= q * level[u]; - } - - // Modify epsilon - epsilon = 0; - for (int u = 0; u != _res_node_num; ++u) { - double curr, pu = pi[u]; - int last_out = _first_out[u+1]; - for (int a = _first_out[u]; a != last_out; ++a) { - if (_res_cap[a] == 0) continue; - curr = _cost[a] + pu - pi[_target[a]]; - if (-curr > epsilon) epsilon = -curr; - } - } - } else { - typedef HowardMmc HwMmc; - typedef HartmannOrlinMmc HoMmc; - typedef typename BellmanFord - ::template SetDistMap::Create BF; - - // Set epsilon to the minimum cycle mean - Cost cycle_cost = 0; - int cycle_size = 1; - buildResidualNetwork(); - HwMmc hw_mmc(_sgr, _cost_map); - if (hw_mmc.findCycleMean(hw_iter_limit) == HwMmc::ITERATION_LIMIT) { - // Howard's algorithm reached the iteration limit, start a - // strongly polynomial algorithm instead - HoMmc ho_mmc(_sgr, _cost_map); - ho_mmc.findCycleMean(); - epsilon = -ho_mmc.cycleMean(); - cycle_cost = ho_mmc.cycleCost(); - cycle_size = ho_mmc.cycleSize(); - } else { - // Set epsilon - epsilon = -hw_mmc.cycleMean(); - cycle_cost = hw_mmc.cycleCost(); - cycle_size = hw_mmc.cycleSize(); - } - - // Compute feasible potentials for the current epsilon - for (int i = 0; i != int(_cost_vec.size()); ++i) { - _cost_vec[i] = cycle_size * _cost_vec[i] - cycle_cost; - } - BF bf(_sgr, _cost_map); - bf.distMap(_pi_map); - bf.init(0); - bf.start(); - for (int u = 0; u != _res_node_num; ++u) { - pi[u] = static_cast(_pi[u]) / cycle_size; - } - - iter = limit; - } - } - } - - }; //class CycleCanceling - - ///@} - -} //namespace lemon - -#endif //LEMON_CYCLE_CANCELING_H diff --git a/deps/lemon/lemon/dfs.h b/deps/lemon/lemon/dfs.h deleted file mode 100644 index 6e9e84a48..000000000 --- a/deps/lemon/lemon/dfs.h +++ /dev/null @@ -1,1637 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_DFS_H -#define LEMON_DFS_H - -///\ingroup search -///\file -///\brief DFS algorithm. - -#include -#include -#include -#include -#include -#include - -namespace lemon { - - ///Default traits class of Dfs class. - - ///Default traits class of Dfs class. - ///\tparam GR Digraph type. - template - struct DfsDefaultTraits - { - ///The type of the digraph the algorithm runs on. - typedef GR Digraph; - - ///\brief The type of the map that stores the predecessor - ///arcs of the %DFS paths. - /// - ///The type of the map that stores the predecessor - ///arcs of the %DFS paths. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap PredMap; - ///Instantiates a \c PredMap. - - ///This function instantiates a \ref PredMap. - ///\param g is the digraph, to which we would like to define the - ///\ref PredMap. - static PredMap *createPredMap(const Digraph &g) - { - return new PredMap(g); - } - - ///The type of the map that indicates which nodes are processed. - - ///The type of the map that indicates which nodes are processed. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - ///By default, it is a NullMap. - typedef NullMap ProcessedMap; - ///Instantiates a \c ProcessedMap. - - ///This function instantiates a \ref ProcessedMap. - ///\param g is the digraph, to which - ///we would like to define the \ref ProcessedMap. -#ifdef DOXYGEN - static ProcessedMap *createProcessedMap(const Digraph &g) -#else - static ProcessedMap *createProcessedMap(const Digraph &) -#endif - { - return new ProcessedMap(); - } - - ///The type of the map that indicates which nodes are reached. - - ///The type of the map that indicates which nodes are reached. - ///It must conform to - ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. - typedef typename Digraph::template NodeMap ReachedMap; - ///Instantiates a \c ReachedMap. - - ///This function instantiates a \ref ReachedMap. - ///\param g is the digraph, to which - ///we would like to define the \ref ReachedMap. - static ReachedMap *createReachedMap(const Digraph &g) - { - return new ReachedMap(g); - } - - ///The type of the map that stores the distances of the nodes. - - ///The type of the map that stores the distances of the nodes. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap DistMap; - ///Instantiates a \c DistMap. - - ///This function instantiates a \ref DistMap. - ///\param g is the digraph, to which we would like to define the - ///\ref DistMap. - static DistMap *createDistMap(const Digraph &g) - { - return new DistMap(g); - } - }; - - ///%DFS algorithm class. - - ///\ingroup search - ///This class provides an efficient implementation of the %DFS algorithm. - /// - ///There is also a \ref dfs() "function-type interface" for the DFS - ///algorithm, which is convenient in the simplier cases and it can be - ///used easier. - /// - ///\tparam GR The type of the digraph the algorithm runs on. - ///The default type is \ref ListDigraph. - ///\tparam TR The traits class that defines various types used by the - ///algorithm. By default, it is \ref DfsDefaultTraits - ///"DfsDefaultTraits". - ///In most cases, this parameter should not be set directly, - ///consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template > -#endif - class Dfs { - public: - - ///The type of the digraph the algorithm runs on. - typedef typename TR::Digraph Digraph; - - ///\brief The type of the map that stores the predecessor arcs of the - ///DFS paths. - typedef typename TR::PredMap PredMap; - ///The type of the map that stores the distances of the nodes. - typedef typename TR::DistMap DistMap; - ///The type of the map that indicates which nodes are reached. - typedef typename TR::ReachedMap ReachedMap; - ///The type of the map that indicates which nodes are processed. - typedef typename TR::ProcessedMap ProcessedMap; - ///The type of the paths. - typedef PredMapPath Path; - - ///The \ref lemon::DfsDefaultTraits "traits class" of the algorithm. - typedef TR Traits; - - private: - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::OutArcIt OutArcIt; - - //Pointer to the underlying digraph. - const Digraph *G; - //Pointer to the map of predecessor arcs. - PredMap *_pred; - //Indicates if _pred is locally allocated (true) or not. - bool local_pred; - //Pointer to the map of distances. - DistMap *_dist; - //Indicates if _dist is locally allocated (true) or not. - bool local_dist; - //Pointer to the map of reached status of the nodes. - ReachedMap *_reached; - //Indicates if _reached is locally allocated (true) or not. - bool local_reached; - //Pointer to the map of processed status of the nodes. - ProcessedMap *_processed; - //Indicates if _processed is locally allocated (true) or not. - bool local_processed; - - std::vector _stack; - int _stack_head; - - //Creates the maps if necessary. - void create_maps() - { - if(!_pred) { - local_pred = true; - _pred = Traits::createPredMap(*G); - } - if(!_dist) { - local_dist = true; - _dist = Traits::createDistMap(*G); - } - if(!_reached) { - local_reached = true; - _reached = Traits::createReachedMap(*G); - } - if(!_processed) { - local_processed = true; - _processed = Traits::createProcessedMap(*G); - } - } - - protected: - - Dfs() {} - - public: - - typedef Dfs Create; - - ///\name Named Template Parameters - - ///@{ - - template - struct SetPredMapTraits : public Traits { - typedef T PredMap; - static PredMap *createPredMap(const Digraph &) - { - LEMON_ASSERT(false, "PredMap is not initialized"); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c PredMap type. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c PredMap type. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - template - struct SetPredMap : public Dfs > { - typedef Dfs > Create; - }; - - template - struct SetDistMapTraits : public Traits { - typedef T DistMap; - static DistMap *createDistMap(const Digraph &) - { - LEMON_ASSERT(false, "DistMap is not initialized"); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c DistMap type. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c DistMap type. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - template - struct SetDistMap : public Dfs< Digraph, SetDistMapTraits > { - typedef Dfs > Create; - }; - - template - struct SetReachedMapTraits : public Traits { - typedef T ReachedMap; - static ReachedMap *createReachedMap(const Digraph &) - { - LEMON_ASSERT(false, "ReachedMap is not initialized"); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c ReachedMap type. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c ReachedMap type. - ///It must conform to - ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. - template - struct SetReachedMap : public Dfs< Digraph, SetReachedMapTraits > { - typedef Dfs< Digraph, SetReachedMapTraits > Create; - }; - - template - struct SetProcessedMapTraits : public Traits { - typedef T ProcessedMap; - static ProcessedMap *createProcessedMap(const Digraph &) - { - LEMON_ASSERT(false, "ProcessedMap is not initialized"); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c ProcessedMap type. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c ProcessedMap type. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - template - struct SetProcessedMap : public Dfs< Digraph, SetProcessedMapTraits > { - typedef Dfs< Digraph, SetProcessedMapTraits > Create; - }; - - struct SetStandardProcessedMapTraits : public Traits { - typedef typename Digraph::template NodeMap ProcessedMap; - static ProcessedMap *createProcessedMap(const Digraph &g) - { - return new ProcessedMap(g); - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c ProcessedMap type to be Digraph::NodeMap. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c ProcessedMap type to be Digraph::NodeMap. - ///If you don't set it explicitly, it will be automatically allocated. - struct SetStandardProcessedMap : - public Dfs< Digraph, SetStandardProcessedMapTraits > { - typedef Dfs< Digraph, SetStandardProcessedMapTraits > Create; - }; - - ///@} - - public: - - ///Constructor. - - ///Constructor. - ///\param g The digraph the algorithm runs on. - Dfs(const Digraph &g) : - G(&g), - _pred(NULL), local_pred(false), - _dist(NULL), local_dist(false), - _reached(NULL), local_reached(false), - _processed(NULL), local_processed(false) - { } - - ///Destructor. - ~Dfs() - { - if(local_pred) delete _pred; - if(local_dist) delete _dist; - if(local_reached) delete _reached; - if(local_processed) delete _processed; - } - - ///Sets the map that stores the predecessor arcs. - - ///Sets the map that stores the predecessor arcs. - ///If you don't use this function before calling \ref run(Node) "run()" - ///or \ref init(), an instance will be allocated automatically. - ///The destructor deallocates this automatically allocated map, - ///of course. - ///\return (*this) - Dfs &predMap(PredMap &m) - { - if(local_pred) { - delete _pred; - local_pred=false; - } - _pred = &m; - return *this; - } - - ///Sets the map that indicates which nodes are reached. - - ///Sets the map that indicates which nodes are reached. - ///If you don't use this function before calling \ref run(Node) "run()" - ///or \ref init(), an instance will be allocated automatically. - ///The destructor deallocates this automatically allocated map, - ///of course. - ///\return (*this) - Dfs &reachedMap(ReachedMap &m) - { - if(local_reached) { - delete _reached; - local_reached=false; - } - _reached = &m; - return *this; - } - - ///Sets the map that indicates which nodes are processed. - - ///Sets the map that indicates which nodes are processed. - ///If you don't use this function before calling \ref run(Node) "run()" - ///or \ref init(), an instance will be allocated automatically. - ///The destructor deallocates this automatically allocated map, - ///of course. - ///\return (*this) - Dfs &processedMap(ProcessedMap &m) - { - if(local_processed) { - delete _processed; - local_processed=false; - } - _processed = &m; - return *this; - } - - ///Sets the map that stores the distances of the nodes. - - ///Sets the map that stores the distances of the nodes calculated by - ///the algorithm. - ///If you don't use this function before calling \ref run(Node) "run()" - ///or \ref init(), an instance will be allocated automatically. - ///The destructor deallocates this automatically allocated map, - ///of course. - ///\return (*this) - Dfs &distMap(DistMap &m) - { - if(local_dist) { - delete _dist; - local_dist=false; - } - _dist = &m; - return *this; - } - - public: - - ///\name Execution Control - ///The simplest way to execute the DFS algorithm is to use one of the - ///member functions called \ref run(Node) "run()".\n - ///If you need better control on the execution, you have to call - ///\ref init() first, then you can add a source node with \ref addSource() - ///and perform the actual computation with \ref start(). - ///This procedure can be repeated if there are nodes that have not - ///been reached. - - ///@{ - - ///\brief Initializes the internal data structures. - /// - ///Initializes the internal data structures. - void init() - { - create_maps(); - _stack.resize(countNodes(*G)); - _stack_head=-1; - for ( NodeIt u(*G) ; u!=INVALID ; ++u ) { - _pred->set(u,INVALID); - _reached->set(u,false); - _processed->set(u,false); - } - } - - ///Adds a new source node. - - ///Adds a new source node to the set of nodes to be processed. - /// - ///\pre The stack must be empty. Otherwise the algorithm gives - ///wrong results. (One of the outgoing arcs of all the source nodes - ///except for the last one will not be visited and distances will - ///also be wrong.) - void addSource(Node s) - { - LEMON_DEBUG(emptyQueue(), "The stack is not empty."); - if(!(*_reached)[s]) - { - _reached->set(s,true); - _pred->set(s,INVALID); - OutArcIt e(*G,s); - if(e!=INVALID) { - _stack[++_stack_head]=e; - _dist->set(s,_stack_head); - } - else { - _processed->set(s,true); - _dist->set(s,0); - } - } - } - - ///Processes the next arc. - - ///Processes the next arc. - /// - ///\return The processed arc. - /// - ///\pre The stack must not be empty. - Arc processNextArc() - { - Node m; - Arc e=_stack[_stack_head]; - if(!(*_reached)[m=G->target(e)]) { - _pred->set(m,e); - _reached->set(m,true); - ++_stack_head; - _stack[_stack_head] = OutArcIt(*G, m); - _dist->set(m,_stack_head); - } - else { - m=G->source(e); - ++_stack[_stack_head]; - } - while(_stack_head>=0 && _stack[_stack_head]==INVALID) { - _processed->set(m,true); - --_stack_head; - if(_stack_head>=0) { - m=G->source(_stack[_stack_head]); - ++_stack[_stack_head]; - } - } - return e; - } - - ///Next arc to be processed. - - ///Next arc to be processed. - /// - ///\return The next arc to be processed or \c INVALID if the stack - ///is empty. - OutArcIt nextArc() const - { - return _stack_head>=0?_stack[_stack_head]:INVALID; - } - - ///Returns \c false if there are nodes to be processed. - - ///Returns \c false if there are nodes to be processed - ///in the queue (stack). - bool emptyQueue() const { return _stack_head<0; } - - ///Returns the number of the nodes to be processed. - - ///Returns the number of the nodes to be processed - ///in the queue (stack). - int queueSize() const { return _stack_head+1; } - - ///Executes the algorithm. - - ///Executes the algorithm. - /// - ///This method runs the %DFS algorithm from the root node - ///in order to compute the DFS path to each node. - /// - /// The algorithm computes - ///- the %DFS tree, - ///- the distance of each node from the root in the %DFS tree. - /// - ///\pre init() must be called and a root node should be - ///added with addSource() before using this function. - /// - ///\note d.start() is just a shortcut of the following code. - ///\code - /// while ( !d.emptyQueue() ) { - /// d.processNextArc(); - /// } - ///\endcode - void start() - { - while ( !emptyQueue() ) processNextArc(); - } - - ///Executes the algorithm until the given target node is reached. - - ///Executes the algorithm until the given target node is reached. - /// - ///This method runs the %DFS algorithm from the root node - ///in order to compute the DFS path to \c t. - /// - ///The algorithm computes - ///- the %DFS path to \c t, - ///- the distance of \c t from the root in the %DFS tree. - /// - ///\pre init() must be called and a root node should be - ///added with addSource() before using this function. - void start(Node t) - { - while ( !emptyQueue() && !(*_reached)[t] ) - processNextArc(); - } - - ///Executes the algorithm until a condition is met. - - ///Executes the algorithm until a condition is met. - /// - ///This method runs the %DFS algorithm from the root node - ///until an arc \c a with am[a] true is found. - /// - ///\param am A \c bool (or convertible) arc map. The algorithm - ///will stop when it reaches an arc \c a with am[a] true. - /// - ///\return The reached arc \c a with am[a] true or - ///\c INVALID if no such arc was found. - /// - ///\pre init() must be called and a root node should be - ///added with addSource() before using this function. - /// - ///\warning Contrary to \ref Bfs and \ref Dijkstra, \c am is an arc map, - ///not a node map. - template - Arc start(const ArcBoolMap &am) - { - while ( !emptyQueue() && !am[_stack[_stack_head]] ) - processNextArc(); - return emptyQueue() ? INVALID : _stack[_stack_head]; - } - - ///Runs the algorithm from the given source node. - - ///This method runs the %DFS algorithm from node \c s - ///in order to compute the DFS path to each node. - /// - ///The algorithm computes - ///- the %DFS tree, - ///- the distance of each node from the root in the %DFS tree. - /// - ///\note d.run(s) is just a shortcut of the following code. - ///\code - /// d.init(); - /// d.addSource(s); - /// d.start(); - ///\endcode - void run(Node s) { - init(); - addSource(s); - start(); - } - - ///Finds the %DFS path between \c s and \c t. - - ///This method runs the %DFS algorithm from node \c s - ///in order to compute the DFS path to node \c t - ///(it stops searching when \c t is processed) - /// - ///\return \c true if \c t is reachable form \c s. - /// - ///\note Apart from the return value, d.run(s,t) is - ///just a shortcut of the following code. - ///\code - /// d.init(); - /// d.addSource(s); - /// d.start(t); - ///\endcode - bool run(Node s,Node t) { - init(); - addSource(s); - start(t); - return reached(t); - } - - ///Runs the algorithm to visit all nodes in the digraph. - - ///This method runs the %DFS algorithm in order to visit all nodes - ///in the digraph. - /// - ///\note d.run() is just a shortcut of the following code. - ///\code - /// d.init(); - /// for (NodeIt n(digraph); n != INVALID; ++n) { - /// if (!d.reached(n)) { - /// d.addSource(n); - /// d.start(); - /// } - /// } - ///\endcode - void run() { - init(); - for (NodeIt it(*G); it != INVALID; ++it) { - if (!reached(it)) { - addSource(it); - start(); - } - } - } - - ///@} - - ///\name Query Functions - ///The results of the DFS algorithm can be obtained using these - ///functions.\n - ///Either \ref run(Node) "run()" or \ref start() should be called - ///before using them. - - ///@{ - - ///The DFS path to the given node. - - ///Returns the DFS path to the given node from the root(s). - /// - ///\warning \c t should be reached from the root(s). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - Path path(Node t) const { return Path(*G, *_pred, t); } - - ///The distance of the given node from the root(s). - - ///Returns the distance of the given node from the root(s). - /// - ///\warning If node \c v is not reached from the root(s), then - ///the return value of this function is undefined. - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - int dist(Node v) const { return (*_dist)[v]; } - - ///Returns the 'previous arc' of the %DFS tree for the given node. - - ///This function returns the 'previous arc' of the %DFS tree for the - ///node \c v, i.e. it returns the last arc of a %DFS path from a - ///root to \c v. It is \c INVALID if \c v is not reached from the - ///root(s) or if \c v is a root. - /// - ///The %DFS tree used here is equal to the %DFS tree used in - ///\ref predNode() and \ref predMap(). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - Arc predArc(Node v) const { return (*_pred)[v];} - - ///Returns the 'previous node' of the %DFS tree for the given node. - - ///This function returns the 'previous node' of the %DFS - ///tree for the node \c v, i.e. it returns the last but one node - ///of a %DFS path from a root to \c v. It is \c INVALID - ///if \c v is not reached from the root(s) or if \c v is a root. - /// - ///The %DFS tree used here is equal to the %DFS tree used in - ///\ref predArc() and \ref predMap(). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - Node predNode(Node v) const { return (*_pred)[v]==INVALID ? INVALID: - G->source((*_pred)[v]); } - - ///\brief Returns a const reference to the node map that stores the - ///distances of the nodes. - /// - ///Returns a const reference to the node map that stores the - ///distances of the nodes calculated by the algorithm. - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - const DistMap &distMap() const { return *_dist;} - - ///\brief Returns a const reference to the node map that stores the - ///predecessor arcs. - /// - ///Returns a const reference to the node map that stores the predecessor - ///arcs, which form the DFS tree (forest). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - const PredMap &predMap() const { return *_pred;} - - ///Checks if the given node. node is reached from the root(s). - - ///Returns \c true if \c v is reached from the root(s). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - bool reached(Node v) const { return (*_reached)[v]; } - - ///@} - }; - - ///Default traits class of dfs() function. - - ///Default traits class of dfs() function. - ///\tparam GR Digraph type. - template - struct DfsWizardDefaultTraits - { - ///The type of the digraph the algorithm runs on. - typedef GR Digraph; - - ///\brief The type of the map that stores the predecessor - ///arcs of the %DFS paths. - /// - ///The type of the map that stores the predecessor - ///arcs of the %DFS paths. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap PredMap; - ///Instantiates a PredMap. - - ///This function instantiates a PredMap. - ///\param g is the digraph, to which we would like to define the - ///PredMap. - static PredMap *createPredMap(const Digraph &g) - { - return new PredMap(g); - } - - ///The type of the map that indicates which nodes are processed. - - ///The type of the map that indicates which nodes are processed. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - ///By default, it is a NullMap. - typedef NullMap ProcessedMap; - ///Instantiates a ProcessedMap. - - ///This function instantiates a ProcessedMap. - ///\param g is the digraph, to which - ///we would like to define the ProcessedMap. -#ifdef DOXYGEN - static ProcessedMap *createProcessedMap(const Digraph &g) -#else - static ProcessedMap *createProcessedMap(const Digraph &) -#endif - { - return new ProcessedMap(); - } - - ///The type of the map that indicates which nodes are reached. - - ///The type of the map that indicates which nodes are reached. - ///It must conform to - ///the \ref concepts::ReadWriteMap "ReadWriteMap" concept. - typedef typename Digraph::template NodeMap ReachedMap; - ///Instantiates a ReachedMap. - - ///This function instantiates a ReachedMap. - ///\param g is the digraph, to which - ///we would like to define the ReachedMap. - static ReachedMap *createReachedMap(const Digraph &g) - { - return new ReachedMap(g); - } - - ///The type of the map that stores the distances of the nodes. - - ///The type of the map that stores the distances of the nodes. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap DistMap; - ///Instantiates a DistMap. - - ///This function instantiates a DistMap. - ///\param g is the digraph, to which we would like to define - ///the DistMap - static DistMap *createDistMap(const Digraph &g) - { - return new DistMap(g); - } - - ///The type of the DFS paths. - - ///The type of the DFS paths. - ///It must conform to the \ref concepts::Path "Path" concept. - typedef lemon::Path Path; - }; - - /// Default traits class used by DfsWizard - - /// Default traits class used by DfsWizard. - /// \tparam GR The type of the digraph. - template - class DfsWizardBase : public DfsWizardDefaultTraits - { - - typedef DfsWizardDefaultTraits Base; - protected: - //The type of the nodes in the digraph. - typedef typename Base::Digraph::Node Node; - - //Pointer to the digraph the algorithm runs on. - void *_g; - //Pointer to the map of reached nodes. - void *_reached; - //Pointer to the map of processed nodes. - void *_processed; - //Pointer to the map of predecessors arcs. - void *_pred; - //Pointer to the map of distances. - void *_dist; - //Pointer to the DFS path to the target node. - void *_path; - //Pointer to the distance of the target node. - int *_di; - - public: - /// Constructor. - - /// This constructor does not require parameters, it initiates - /// all of the attributes to \c 0. - DfsWizardBase() : _g(0), _reached(0), _processed(0), _pred(0), - _dist(0), _path(0), _di(0) {} - - /// Constructor. - - /// This constructor requires one parameter, - /// others are initiated to \c 0. - /// \param g The digraph the algorithm runs on. - DfsWizardBase(const GR &g) : - _g(reinterpret_cast(const_cast(&g))), - _reached(0), _processed(0), _pred(0), _dist(0), _path(0), _di(0) {} - - }; - - /// Auxiliary class for the function-type interface of DFS algorithm. - - /// This auxiliary class is created to implement the - /// \ref dfs() "function-type interface" of \ref Dfs algorithm. - /// It does not have own \ref run(Node) "run()" method, it uses the - /// functions and features of the plain \ref Dfs. - /// - /// This class should only be used through the \ref dfs() function, - /// which makes it easier to use the algorithm. - /// - /// \tparam TR The traits class that defines various types used by the - /// algorithm. - template - class DfsWizard : public TR - { - typedef TR Base; - - typedef typename TR::Digraph Digraph; - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::OutArcIt OutArcIt; - - typedef typename TR::PredMap PredMap; - typedef typename TR::DistMap DistMap; - typedef typename TR::ReachedMap ReachedMap; - typedef typename TR::ProcessedMap ProcessedMap; - typedef typename TR::Path Path; - - public: - - /// Constructor. - DfsWizard() : TR() {} - - /// Constructor that requires parameters. - - /// Constructor that requires parameters. - /// These parameters will be the default values for the traits class. - /// \param g The digraph the algorithm runs on. - DfsWizard(const Digraph &g) : - TR(g) {} - - ///Copy constructor - DfsWizard(const TR &b) : TR(b) {} - - ~DfsWizard() {} - - ///Runs DFS algorithm from the given source node. - - ///This method runs DFS algorithm from node \c s - ///in order to compute the DFS path to each node. - void run(Node s) - { - Dfs alg(*reinterpret_cast(Base::_g)); - if (Base::_pred) - alg.predMap(*reinterpret_cast(Base::_pred)); - if (Base::_dist) - alg.distMap(*reinterpret_cast(Base::_dist)); - if (Base::_reached) - alg.reachedMap(*reinterpret_cast(Base::_reached)); - if (Base::_processed) - alg.processedMap(*reinterpret_cast(Base::_processed)); - if (s!=INVALID) - alg.run(s); - else - alg.run(); - } - - ///Finds the DFS path between \c s and \c t. - - ///This method runs DFS algorithm from node \c s - ///in order to compute the DFS path to node \c t - ///(it stops searching when \c t is processed). - /// - ///\return \c true if \c t is reachable form \c s. - bool run(Node s, Node t) - { - Dfs alg(*reinterpret_cast(Base::_g)); - if (Base::_pred) - alg.predMap(*reinterpret_cast(Base::_pred)); - if (Base::_dist) - alg.distMap(*reinterpret_cast(Base::_dist)); - if (Base::_reached) - alg.reachedMap(*reinterpret_cast(Base::_reached)); - if (Base::_processed) - alg.processedMap(*reinterpret_cast(Base::_processed)); - alg.run(s,t); - if (Base::_path) - *reinterpret_cast(Base::_path) = alg.path(t); - if (Base::_di) - *Base::_di = alg.dist(t); - return alg.reached(t); - } - - ///Runs DFS algorithm to visit all nodes in the digraph. - - ///This method runs DFS algorithm in order to visit all nodes - ///in the digraph. - void run() - { - run(INVALID); - } - - template - struct SetPredMapBase : public Base { - typedef T PredMap; - static PredMap *createPredMap(const Digraph &) { return 0; }; - SetPredMapBase(const TR &b) : TR(b) {} - }; - - ///\brief \ref named-templ-param "Named parameter" for setting - ///the predecessor map. - /// - ///\ref named-templ-param "Named parameter" function for setting - ///the map that stores the predecessor arcs of the nodes. - template - DfsWizard > predMap(const T &t) - { - Base::_pred=reinterpret_cast(const_cast(&t)); - return DfsWizard >(*this); - } - - template - struct SetReachedMapBase : public Base { - typedef T ReachedMap; - static ReachedMap *createReachedMap(const Digraph &) { return 0; }; - SetReachedMapBase(const TR &b) : TR(b) {} - }; - - ///\brief \ref named-templ-param "Named parameter" for setting - ///the reached map. - /// - ///\ref named-templ-param "Named parameter" function for setting - ///the map that indicates which nodes are reached. - template - DfsWizard > reachedMap(const T &t) - { - Base::_reached=reinterpret_cast(const_cast(&t)); - return DfsWizard >(*this); - } - - template - struct SetDistMapBase : public Base { - typedef T DistMap; - static DistMap *createDistMap(const Digraph &) { return 0; }; - SetDistMapBase(const TR &b) : TR(b) {} - }; - - ///\brief \ref named-templ-param "Named parameter" for setting - ///the distance map. - /// - ///\ref named-templ-param "Named parameter" function for setting - ///the map that stores the distances of the nodes calculated - ///by the algorithm. - template - DfsWizard > distMap(const T &t) - { - Base::_dist=reinterpret_cast(const_cast(&t)); - return DfsWizard >(*this); - } - - template - struct SetProcessedMapBase : public Base { - typedef T ProcessedMap; - static ProcessedMap *createProcessedMap(const Digraph &) { return 0; }; - SetProcessedMapBase(const TR &b) : TR(b) {} - }; - - ///\brief \ref named-func-param "Named parameter" for setting - ///the processed map. - /// - ///\ref named-templ-param "Named parameter" function for setting - ///the map that indicates which nodes are processed. - template - DfsWizard > processedMap(const T &t) - { - Base::_processed=reinterpret_cast(const_cast(&t)); - return DfsWizard >(*this); - } - - template - struct SetPathBase : public Base { - typedef T Path; - SetPathBase(const TR &b) : TR(b) {} - }; - ///\brief \ref named-func-param "Named parameter" - ///for getting the DFS path to the target node. - /// - ///\ref named-func-param "Named parameter" - ///for getting the DFS path to the target node. - template - DfsWizard > path(const T &t) - { - Base::_path=reinterpret_cast(const_cast(&t)); - return DfsWizard >(*this); - } - - ///\brief \ref named-func-param "Named parameter" - ///for getting the distance of the target node. - /// - ///\ref named-func-param "Named parameter" - ///for getting the distance of the target node. - DfsWizard dist(const int &d) - { - Base::_di=const_cast(&d); - return *this; - } - - }; - - ///Function-type interface for DFS algorithm. - - ///\ingroup search - ///Function-type interface for DFS algorithm. - /// - ///This function also has several \ref named-func-param "named parameters", - ///they are declared as the members of class \ref DfsWizard. - ///The following examples show how to use these parameters. - ///\code - /// // Compute the DFS tree - /// dfs(g).predMap(preds).distMap(dists).run(s); - /// - /// // Compute the DFS path from s to t - /// bool reached = dfs(g).path(p).dist(d).run(s,t); - ///\endcode - ///\warning Don't forget to put the \ref DfsWizard::run(Node) "run()" - ///to the end of the parameter list. - ///\sa DfsWizard - ///\sa Dfs - template - DfsWizard > - dfs(const GR &digraph) - { - return DfsWizard >(digraph); - } - -#ifdef DOXYGEN - /// \brief Visitor class for DFS. - /// - /// This class defines the interface of the DfsVisit events, and - /// it could be the base of a real visitor class. - template - struct DfsVisitor { - typedef GR Digraph; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::Node Node; - /// \brief Called for the source node of the DFS. - /// - /// This function is called for the source node of the DFS. - void start(const Node& node) {} - /// \brief Called when the source node is leaved. - /// - /// This function is called when the source node is leaved. - void stop(const Node& node) {} - /// \brief Called when a node is reached first time. - /// - /// This function is called when a node is reached first time. - void reach(const Node& node) {} - /// \brief Called when an arc reaches a new node. - /// - /// This function is called when the DFS finds an arc whose target node - /// is not reached yet. - void discover(const Arc& arc) {} - /// \brief Called when an arc is examined but its target node is - /// already discovered. - /// - /// This function is called when an arc is examined but its target node is - /// already discovered. - void examine(const Arc& arc) {} - /// \brief Called when the DFS steps back from a node. - /// - /// This function is called when the DFS steps back from a node. - void leave(const Node& node) {} - /// \brief Called when the DFS steps back on an arc. - /// - /// This function is called when the DFS steps back on an arc. - void backtrack(const Arc& arc) {} - }; -#else - template - struct DfsVisitor { - typedef GR Digraph; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::Node Node; - void start(const Node&) {} - void stop(const Node&) {} - void reach(const Node&) {} - void discover(const Arc&) {} - void examine(const Arc&) {} - void leave(const Node&) {} - void backtrack(const Arc&) {} - - template - struct Constraints { - void constraints() { - Arc arc; - Node node; - visitor.start(node); - visitor.stop(arc); - visitor.reach(node); - visitor.discover(arc); - visitor.examine(arc); - visitor.leave(node); - visitor.backtrack(arc); - } - _Visitor& visitor; - Constraints() {} - }; - }; -#endif - - /// \brief Default traits class of DfsVisit class. - /// - /// Default traits class of DfsVisit class. - /// \tparam _Digraph The type of the digraph the algorithm runs on. - template - struct DfsVisitDefaultTraits { - - /// \brief The type of the digraph the algorithm runs on. - typedef GR Digraph; - - /// \brief The type of the map that indicates which nodes are reached. - /// - /// The type of the map that indicates which nodes are reached. - /// It must conform to the - /// \ref concepts::ReadWriteMap "ReadWriteMap" concept. - typedef typename Digraph::template NodeMap ReachedMap; - - /// \brief Instantiates a ReachedMap. - /// - /// This function instantiates a ReachedMap. - /// \param digraph is the digraph, to which - /// we would like to define the ReachedMap. - static ReachedMap *createReachedMap(const Digraph &digraph) { - return new ReachedMap(digraph); - } - - }; - - /// \ingroup search - /// - /// \brief DFS algorithm class with visitor interface. - /// - /// This class provides an efficient implementation of the DFS algorithm - /// with visitor interface. - /// - /// The DfsVisit class provides an alternative interface to the Dfs - /// class. It works with callback mechanism, the DfsVisit object calls - /// the member functions of the \c Visitor class on every DFS event. - /// - /// This interface of the DFS algorithm should be used in special cases - /// when extra actions have to be performed in connection with certain - /// events of the DFS algorithm. Otherwise consider to use Dfs or dfs() - /// instead. - /// - /// \tparam GR The type of the digraph the algorithm runs on. - /// The default type is \ref ListDigraph. - /// The value of GR is not used directly by \ref DfsVisit, - /// it is only passed to \ref DfsVisitDefaultTraits. - /// \tparam VS The Visitor type that is used by the algorithm. - /// \ref DfsVisitor "DfsVisitor" is an empty visitor, which - /// does not observe the DFS events. If you want to observe the DFS - /// events, you should implement your own visitor class. - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref DfsVisitDefaultTraits - /// "DfsVisitDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template , - typename TR = DfsVisitDefaultTraits > -#endif - class DfsVisit { - public: - - ///The traits class. - typedef TR Traits; - - ///The type of the digraph the algorithm runs on. - typedef typename Traits::Digraph Digraph; - - ///The visitor type used by the algorithm. - typedef VS Visitor; - - ///The type of the map that indicates which nodes are reached. - typedef typename Traits::ReachedMap ReachedMap; - - private: - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::OutArcIt OutArcIt; - - //Pointer to the underlying digraph. - const Digraph *_digraph; - //Pointer to the visitor object. - Visitor *_visitor; - //Pointer to the map of reached status of the nodes. - ReachedMap *_reached; - //Indicates if _reached is locally allocated (true) or not. - bool local_reached; - - std::vector _stack; - int _stack_head; - - //Creates the maps if necessary. - void create_maps() { - if(!_reached) { - local_reached = true; - _reached = Traits::createReachedMap(*_digraph); - } - } - - protected: - - DfsVisit() {} - - public: - - typedef DfsVisit Create; - - /// \name Named Template Parameters - - ///@{ - template - struct SetReachedMapTraits : public Traits { - typedef T ReachedMap; - static ReachedMap *createReachedMap(const Digraph &digraph) { - LEMON_ASSERT(false, "ReachedMap is not initialized"); - return 0; // ignore warnings - } - }; - /// \brief \ref named-templ-param "Named parameter" for setting - /// ReachedMap type. - /// - /// \ref named-templ-param "Named parameter" for setting ReachedMap type. - template - struct SetReachedMap : public DfsVisit< Digraph, Visitor, - SetReachedMapTraits > { - typedef DfsVisit< Digraph, Visitor, SetReachedMapTraits > Create; - }; - ///@} - - public: - - /// \brief Constructor. - /// - /// Constructor. - /// - /// \param digraph The digraph the algorithm runs on. - /// \param visitor The visitor object of the algorithm. - DfsVisit(const Digraph& digraph, Visitor& visitor) - : _digraph(&digraph), _visitor(&visitor), - _reached(0), local_reached(false) {} - - /// \brief Destructor. - ~DfsVisit() { - if(local_reached) delete _reached; - } - - /// \brief Sets the map that indicates which nodes are reached. - /// - /// Sets the map that indicates which nodes are reached. - /// If you don't use this function before calling \ref run(Node) "run()" - /// or \ref init(), an instance will be allocated automatically. - /// The destructor deallocates this automatically allocated map, - /// of course. - /// \return (*this) - DfsVisit &reachedMap(ReachedMap &m) { - if(local_reached) { - delete _reached; - local_reached=false; - } - _reached = &m; - return *this; - } - - public: - - /// \name Execution Control - /// The simplest way to execute the DFS algorithm is to use one of the - /// member functions called \ref run(Node) "run()".\n - /// If you need better control on the execution, you have to call - /// \ref init() first, then you can add a source node with \ref addSource() - /// and perform the actual computation with \ref start(). - /// This procedure can be repeated if there are nodes that have not - /// been reached. - - /// @{ - - /// \brief Initializes the internal data structures. - /// - /// Initializes the internal data structures. - void init() { - create_maps(); - _stack.resize(countNodes(*_digraph)); - _stack_head = -1; - for (NodeIt u(*_digraph) ; u != INVALID ; ++u) { - _reached->set(u, false); - } - } - - /// \brief Adds a new source node. - /// - /// Adds a new source node to the set of nodes to be processed. - /// - /// \pre The stack must be empty. Otherwise the algorithm gives - /// wrong results. (One of the outgoing arcs of all the source nodes - /// except for the last one will not be visited and distances will - /// also be wrong.) - void addSource(Node s) - { - LEMON_DEBUG(emptyQueue(), "The stack is not empty."); - if(!(*_reached)[s]) { - _reached->set(s,true); - _visitor->start(s); - _visitor->reach(s); - Arc e; - _digraph->firstOut(e, s); - if (e != INVALID) { - _stack[++_stack_head] = e; - } else { - _visitor->leave(s); - _visitor->stop(s); - } - } - } - - /// \brief Processes the next arc. - /// - /// Processes the next arc. - /// - /// \return The processed arc. - /// - /// \pre The stack must not be empty. - Arc processNextArc() { - Arc e = _stack[_stack_head]; - Node m = _digraph->target(e); - if(!(*_reached)[m]) { - _visitor->discover(e); - _visitor->reach(m); - _reached->set(m, true); - _digraph->firstOut(_stack[++_stack_head], m); - } else { - _visitor->examine(e); - m = _digraph->source(e); - _digraph->nextOut(_stack[_stack_head]); - } - while (_stack_head>=0 && _stack[_stack_head] == INVALID) { - _visitor->leave(m); - --_stack_head; - if (_stack_head >= 0) { - _visitor->backtrack(_stack[_stack_head]); - m = _digraph->source(_stack[_stack_head]); - _digraph->nextOut(_stack[_stack_head]); - } else { - _visitor->stop(m); - } - } - return e; - } - - /// \brief Next arc to be processed. - /// - /// Next arc to be processed. - /// - /// \return The next arc to be processed or INVALID if the stack is - /// empty. - Arc nextArc() const { - return _stack_head >= 0 ? _stack[_stack_head] : INVALID; - } - - /// \brief Returns \c false if there are nodes - /// to be processed. - /// - /// Returns \c false if there are nodes - /// to be processed in the queue (stack). - bool emptyQueue() const { return _stack_head < 0; } - - /// \brief Returns the number of the nodes to be processed. - /// - /// Returns the number of the nodes to be processed in the queue (stack). - int queueSize() const { return _stack_head + 1; } - - /// \brief Executes the algorithm. - /// - /// Executes the algorithm. - /// - /// This method runs the %DFS algorithm from the root node - /// in order to compute the %DFS path to each node. - /// - /// The algorithm computes - /// - the %DFS tree, - /// - the distance of each node from the root in the %DFS tree. - /// - /// \pre init() must be called and a root node should be - /// added with addSource() before using this function. - /// - /// \note d.start() is just a shortcut of the following code. - /// \code - /// while ( !d.emptyQueue() ) { - /// d.processNextArc(); - /// } - /// \endcode - void start() { - while ( !emptyQueue() ) processNextArc(); - } - - /// \brief Executes the algorithm until the given target node is reached. - /// - /// Executes the algorithm until the given target node is reached. - /// - /// This method runs the %DFS algorithm from the root node - /// in order to compute the DFS path to \c t. - /// - /// The algorithm computes - /// - the %DFS path to \c t, - /// - the distance of \c t from the root in the %DFS tree. - /// - /// \pre init() must be called and a root node should be added - /// with addSource() before using this function. - void start(Node t) { - while ( !emptyQueue() && !(*_reached)[t] ) - processNextArc(); - } - - /// \brief Executes the algorithm until a condition is met. - /// - /// Executes the algorithm until a condition is met. - /// - /// This method runs the %DFS algorithm from the root node - /// until an arc \c a with am[a] true is found. - /// - /// \param am A \c bool (or convertible) arc map. The algorithm - /// will stop when it reaches an arc \c a with am[a] true. - /// - /// \return The reached arc \c a with am[a] true or - /// \c INVALID if no such arc was found. - /// - /// \pre init() must be called and a root node should be added - /// with addSource() before using this function. - /// - /// \warning Contrary to \ref Bfs and \ref Dijkstra, \c am is an arc map, - /// not a node map. - template - Arc start(const AM &am) { - while ( !emptyQueue() && !am[_stack[_stack_head]] ) - processNextArc(); - return emptyQueue() ? INVALID : _stack[_stack_head]; - } - - /// \brief Runs the algorithm from the given source node. - /// - /// This method runs the %DFS algorithm from node \c s. - /// in order to compute the DFS path to each node. - /// - /// The algorithm computes - /// - the %DFS tree, - /// - the distance of each node from the root in the %DFS tree. - /// - /// \note d.run(s) is just a shortcut of the following code. - ///\code - /// d.init(); - /// d.addSource(s); - /// d.start(); - ///\endcode - void run(Node s) { - init(); - addSource(s); - start(); - } - - /// \brief Finds the %DFS path between \c s and \c t. - - /// This method runs the %DFS algorithm from node \c s - /// in order to compute the DFS path to node \c t - /// (it stops searching when \c t is processed). - /// - /// \return \c true if \c t is reachable form \c s. - /// - /// \note Apart from the return value, d.run(s,t) is - /// just a shortcut of the following code. - ///\code - /// d.init(); - /// d.addSource(s); - /// d.start(t); - ///\endcode - bool run(Node s,Node t) { - init(); - addSource(s); - start(t); - return reached(t); - } - - /// \brief Runs the algorithm to visit all nodes in the digraph. - - /// This method runs the %DFS algorithm in order to visit all nodes - /// in the digraph. - /// - /// \note d.run() is just a shortcut of the following code. - ///\code - /// d.init(); - /// for (NodeIt n(digraph); n != INVALID; ++n) { - /// if (!d.reached(n)) { - /// d.addSource(n); - /// d.start(); - /// } - /// } - ///\endcode - void run() { - init(); - for (NodeIt it(*_digraph); it != INVALID; ++it) { - if (!reached(it)) { - addSource(it); - start(); - } - } - } - - ///@} - - /// \name Query Functions - /// The results of the DFS algorithm can be obtained using these - /// functions.\n - /// Either \ref run(Node) "run()" or \ref start() should be called - /// before using them. - - ///@{ - - /// \brief Checks if the given node is reached from the root(s). - /// - /// Returns \c true if \c v is reached from the root(s). - /// - /// \pre Either \ref run(Node) "run()" or \ref init() - /// must be called before using this function. - bool reached(Node v) const { return (*_reached)[v]; } - - ///@} - - }; - -} //END OF NAMESPACE LEMON - -#endif diff --git a/deps/lemon/lemon/dheap.h b/deps/lemon/lemon/dheap.h deleted file mode 100644 index a3ab62525..000000000 --- a/deps/lemon/lemon/dheap.h +++ /dev/null @@ -1,352 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_DHEAP_H -#define LEMON_DHEAP_H - -///\ingroup heaps -///\file -///\brief D-ary heap implementation. - -#include -#include -#include - -namespace lemon { - - /// \ingroup heaps - /// - ///\brief D-ary heap data structure. - /// - /// This class implements the \e D-ary \e heap data structure. - /// It fully conforms to the \ref concepts::Heap "heap concept". - /// - /// The \ref DHeap "D-ary heap" is a generalization of the - /// \ref BinHeap "binary heap" structure, its nodes have at most - /// \c D children, instead of two. - /// \ref BinHeap and \ref QuadHeap are specialized implementations - /// of this structure for D=2 and D=4, respectively. - /// - /// \tparam PR Type of the priorities of the items. - /// \tparam IM A read-writable item map with \c int values, used - /// internally to handle the cross references. - /// \tparam D The degree of the heap, each node have at most \e D - /// children. The default is 16. Powers of two are suggested to use - /// so that the multiplications and divisions needed to traverse the - /// nodes of the heap could be performed faster. - /// \tparam CMP A functor class for comparing the priorities. - /// The default is \c std::less. - /// - ///\sa BinHeap - ///\sa FouraryHeap -#ifdef DOXYGEN - template -#else - template > -#endif - class DHeap { - public: - /// Type of the item-int map. - typedef IM ItemIntMap; - /// Type of the priorities. - typedef PR Prio; - /// Type of the items stored in the heap. - typedef typename ItemIntMap::Key Item; - /// Type of the item-priority pairs. - typedef std::pair Pair; - /// Functor type for comparing the priorities. - typedef CMP Compare; - - /// \brief Type to represent the states of the items. - /// - /// Each item has a state associated to it. It can be "in heap", - /// "pre-heap" or "post-heap". The latter two are indifferent from the - /// heap's point of view, but may be useful to the user. - /// - /// The item-int map must be initialized in such way that it assigns - /// \c PRE_HEAP (-1) to any element to be put in the heap. - enum State { - IN_HEAP = 0, ///< = 0. - PRE_HEAP = -1, ///< = -1. - POST_HEAP = -2 ///< = -2. - }; - - private: - std::vector _data; - Compare _comp; - ItemIntMap &_iim; - - public: - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - explicit DHeap(ItemIntMap &map) : _iim(map) {} - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - /// \param comp The function object used for comparing the priorities. - DHeap(ItemIntMap &map, const Compare &comp) - : _iim(map), _comp(comp) {} - - /// \brief The number of items stored in the heap. - /// - /// This function returns the number of items stored in the heap. - int size() const { return _data.size(); } - - /// \brief Check if the heap is empty. - /// - /// This function returns \c true if the heap is empty. - bool empty() const { return _data.empty(); } - - /// \brief Make the heap empty. - /// - /// This functon makes the heap empty. - /// It does not change the cross reference map. If you want to reuse - /// a heap that is not surely empty, you should first clear it and - /// then you should set the cross reference map to \c PRE_HEAP - /// for each item. - void clear() { _data.clear(); } - - private: - int parent(int i) { return (i-1)/D; } - int firstChild(int i) { return D*i+1; } - - bool less(const Pair &p1, const Pair &p2) const { - return _comp(p1.second, p2.second); - } - - void bubbleUp(int hole, Pair p) { - int par = parent(hole); - while( hole>0 && less(p,_data[par]) ) { - move(_data[par],hole); - hole = par; - par = parent(hole); - } - move(p, hole); - } - - void bubbleDown(int hole, Pair p, int length) { - if( length>1 ) { - int child = firstChild(hole); - while( child+D<=length ) { - int min=child; - for (int i=1; i0) bubbleDown(0, _data[n], n); - _data.pop_back(); - } - - /// \brief Remove the given item from the heap. - /// - /// This function removes the given item from the heap if it is - /// already stored. - /// \param i The item to delete. - /// \pre \e i must be in the heap. - void erase(const Item &i) { - int h = _iim[i]; - int n = _data.size()-1; - _iim.set(_data[h].first, POST_HEAP); - if( h=0) s=0; - return State(s); - } - - /// \brief Set the state of an item in the heap. - /// - /// This function sets the state of the given item in the heap. - /// It can be used to manually clear the heap when it is important - /// to achive better time complexity. - /// \param i The item. - /// \param st The state. It should not be \c IN_HEAP. - void state(const Item& i, State st) { - switch (st) { - case POST_HEAP: - case PRE_HEAP: - if (state(i) == IN_HEAP) erase(i); - _iim[i] = st; - break; - case IN_HEAP: - break; - } - } - - /// \brief Replace an item in the heap. - /// - /// This function replaces item \c i with item \c j. - /// Item \c i must be in the heap, while \c j must be out of the heap. - /// After calling this method, item \c i will be out of the - /// heap and \c j will be in the heap with the same prioriority - /// as item \c i had before. - void replace(const Item& i, const Item& j) { - int idx=_iim[i]; - _iim.set(i, _iim[j]); - _iim.set(j, idx); - _data[idx].first=j; - } - - }; // class DHeap - -} // namespace lemon - -#endif // LEMON_DHEAP_H diff --git a/deps/lemon/lemon/dijkstra.h b/deps/lemon/lemon/dijkstra.h deleted file mode 100644 index 1564a03e6..000000000 --- a/deps/lemon/lemon/dijkstra.h +++ /dev/null @@ -1,1303 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_DIJKSTRA_H -#define LEMON_DIJKSTRA_H - -///\ingroup shortest_path -///\file -///\brief Dijkstra algorithm. - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace lemon { - - /// \brief Default operation traits for the Dijkstra algorithm class. - /// - /// This operation traits class defines all computational operations and - /// constants which are used in the Dijkstra algorithm. - template - struct DijkstraDefaultOperationTraits { - /// \e - typedef V Value; - /// \brief Gives back the zero value of the type. - static Value zero() { - return static_cast(0); - } - /// \brief Gives back the sum of the given two elements. - static Value plus(const Value& left, const Value& right) { - return left + right; - } - /// \brief Gives back true only if the first value is less than the second. - static bool less(const Value& left, const Value& right) { - return left < right; - } - }; - - ///Default traits class of Dijkstra class. - - ///Default traits class of Dijkstra class. - ///\tparam GR The type of the digraph. - ///\tparam LEN The type of the length map. - template - struct DijkstraDefaultTraits - { - ///The type of the digraph the algorithm runs on. - typedef GR Digraph; - - ///The type of the map that stores the arc lengths. - - ///The type of the map that stores the arc lengths. - ///It must conform to the \ref concepts::ReadMap "ReadMap" concept. - typedef LEN LengthMap; - ///The type of the arc lengths. - typedef typename LEN::Value Value; - - /// Operation traits for %Dijkstra algorithm. - - /// This class defines the operations that are used in the algorithm. - /// \see DijkstraDefaultOperationTraits - typedef DijkstraDefaultOperationTraits OperationTraits; - - /// The cross reference type used by the heap. - - /// The cross reference type used by the heap. - /// Usually it is \c Digraph::NodeMap. - typedef typename Digraph::template NodeMap HeapCrossRef; - ///Instantiates a \c HeapCrossRef. - - ///This function instantiates a \ref HeapCrossRef. - /// \param g is the digraph, to which we would like to define the - /// \ref HeapCrossRef. - static HeapCrossRef *createHeapCrossRef(const Digraph &g) - { - return new HeapCrossRef(g); - } - - ///The heap type used by the %Dijkstra algorithm. - - ///The heap type used by the Dijkstra algorithm. - /// - ///\sa BinHeap - ///\sa Dijkstra - typedef BinHeap > Heap; - ///Instantiates a \c Heap. - - ///This function instantiates a \ref Heap. - static Heap *createHeap(HeapCrossRef& r) - { - return new Heap(r); - } - - ///\brief The type of the map that stores the predecessor - ///arcs of the shortest paths. - /// - ///The type of the map that stores the predecessor - ///arcs of the shortest paths. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap PredMap; - ///Instantiates a \c PredMap. - - ///This function instantiates a \ref PredMap. - ///\param g is the digraph, to which we would like to define the - ///\ref PredMap. - static PredMap *createPredMap(const Digraph &g) - { - return new PredMap(g); - } - - ///The type of the map that indicates which nodes are processed. - - ///The type of the map that indicates which nodes are processed. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - ///By default, it is a NullMap. - typedef NullMap ProcessedMap; - ///Instantiates a \c ProcessedMap. - - ///This function instantiates a \ref ProcessedMap. - ///\param g is the digraph, to which - ///we would like to define the \ref ProcessedMap. -#ifdef DOXYGEN - static ProcessedMap *createProcessedMap(const Digraph &g) -#else - static ProcessedMap *createProcessedMap(const Digraph &) -#endif - { - return new ProcessedMap(); - } - - ///The type of the map that stores the distances of the nodes. - - ///The type of the map that stores the distances of the nodes. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap DistMap; - ///Instantiates a \c DistMap. - - ///This function instantiates a \ref DistMap. - ///\param g is the digraph, to which we would like to define - ///the \ref DistMap. - static DistMap *createDistMap(const Digraph &g) - { - return new DistMap(g); - } - }; - - ///%Dijkstra algorithm class. - - /// \ingroup shortest_path - ///This class provides an efficient implementation of the %Dijkstra algorithm. - /// - ///The %Dijkstra algorithm solves the single-source shortest path problem - ///when all arc lengths are non-negative. If there are negative lengths, - ///the BellmanFord algorithm should be used instead. - /// - ///The arc lengths are passed to the algorithm using a - ///\ref concepts::ReadMap "ReadMap", - ///so it is easy to change it to any kind of length. - ///The type of the length is determined by the - ///\ref concepts::ReadMap::Value "Value" of the length map. - ///It is also possible to change the underlying priority heap. - /// - ///There is also a \ref dijkstra() "function-type interface" for the - ///%Dijkstra algorithm, which is convenient in the simplier cases and - ///it can be used easier. - /// - ///\tparam GR The type of the digraph the algorithm runs on. - ///The default type is \ref ListDigraph. - ///\tparam LEN A \ref concepts::ReadMap "readable" arc map that specifies - ///the lengths of the arcs. - ///It is read once for each arc, so the map may involve in - ///relatively time consuming process to compute the arc lengths if - ///it is necessary. The default map type is \ref - ///concepts::Digraph::ArcMap "GR::ArcMap". - ///\tparam TR The traits class that defines various types used by the - ///algorithm. By default, it is \ref DijkstraDefaultTraits - ///"DijkstraDefaultTraits". - ///In most cases, this parameter should not be set directly, - ///consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template , - typename TR=DijkstraDefaultTraits > -#endif - class Dijkstra { - public: - - ///The type of the digraph the algorithm runs on. - typedef typename TR::Digraph Digraph; - - ///The type of the arc lengths. - typedef typename TR::Value Value; - ///The type of the map that stores the arc lengths. - typedef typename TR::LengthMap LengthMap; - ///\brief The type of the map that stores the predecessor arcs of the - ///shortest paths. - typedef typename TR::PredMap PredMap; - ///The type of the map that stores the distances of the nodes. - typedef typename TR::DistMap DistMap; - ///The type of the map that indicates which nodes are processed. - typedef typename TR::ProcessedMap ProcessedMap; - ///The type of the paths. - typedef PredMapPath Path; - ///The cross reference type used for the current heap. - typedef typename TR::HeapCrossRef HeapCrossRef; - ///The heap type used by the algorithm. - typedef typename TR::Heap Heap; - /// \brief The \ref lemon::DijkstraDefaultOperationTraits - /// "operation traits class" of the algorithm. - typedef typename TR::OperationTraits OperationTraits; - - ///The \ref lemon::DijkstraDefaultTraits "traits class" of the algorithm. - typedef TR Traits; - - private: - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::OutArcIt OutArcIt; - - //Pointer to the underlying digraph. - const Digraph *G; - //Pointer to the length map. - const LengthMap *_length; - //Pointer to the map of predecessors arcs. - PredMap *_pred; - //Indicates if _pred is locally allocated (true) or not. - bool local_pred; - //Pointer to the map of distances. - DistMap *_dist; - //Indicates if _dist is locally allocated (true) or not. - bool local_dist; - //Pointer to the map of processed status of the nodes. - ProcessedMap *_processed; - //Indicates if _processed is locally allocated (true) or not. - bool local_processed; - //Pointer to the heap cross references. - HeapCrossRef *_heap_cross_ref; - //Indicates if _heap_cross_ref is locally allocated (true) or not. - bool local_heap_cross_ref; - //Pointer to the heap. - Heap *_heap; - //Indicates if _heap is locally allocated (true) or not. - bool local_heap; - - //Creates the maps if necessary. - void create_maps() - { - if(!_pred) { - local_pred = true; - _pred = Traits::createPredMap(*G); - } - if(!_dist) { - local_dist = true; - _dist = Traits::createDistMap(*G); - } - if(!_processed) { - local_processed = true; - _processed = Traits::createProcessedMap(*G); - } - if (!_heap_cross_ref) { - local_heap_cross_ref = true; - _heap_cross_ref = Traits::createHeapCrossRef(*G); - } - if (!_heap) { - local_heap = true; - _heap = Traits::createHeap(*_heap_cross_ref); - } - } - - public: - - typedef Dijkstra Create; - - ///\name Named Template Parameters - - ///@{ - - template - struct SetPredMapTraits : public Traits { - typedef T PredMap; - static PredMap *createPredMap(const Digraph &) - { - LEMON_ASSERT(false, "PredMap is not initialized"); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c PredMap type. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c PredMap type. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - template - struct SetPredMap - : public Dijkstra< Digraph, LengthMap, SetPredMapTraits > { - typedef Dijkstra< Digraph, LengthMap, SetPredMapTraits > Create; - }; - - template - struct SetDistMapTraits : public Traits { - typedef T DistMap; - static DistMap *createDistMap(const Digraph &) - { - LEMON_ASSERT(false, "DistMap is not initialized"); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c DistMap type. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c DistMap type. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - template - struct SetDistMap - : public Dijkstra< Digraph, LengthMap, SetDistMapTraits > { - typedef Dijkstra< Digraph, LengthMap, SetDistMapTraits > Create; - }; - - template - struct SetProcessedMapTraits : public Traits { - typedef T ProcessedMap; - static ProcessedMap *createProcessedMap(const Digraph &) - { - LEMON_ASSERT(false, "ProcessedMap is not initialized"); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c ProcessedMap type. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c ProcessedMap type. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - template - struct SetProcessedMap - : public Dijkstra< Digraph, LengthMap, SetProcessedMapTraits > { - typedef Dijkstra< Digraph, LengthMap, SetProcessedMapTraits > Create; - }; - - struct SetStandardProcessedMapTraits : public Traits { - typedef typename Digraph::template NodeMap ProcessedMap; - static ProcessedMap *createProcessedMap(const Digraph &g) - { - return new ProcessedMap(g); - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///\c ProcessedMap type to be Digraph::NodeMap. - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c ProcessedMap type to be Digraph::NodeMap. - ///If you don't set it explicitly, it will be automatically allocated. - struct SetStandardProcessedMap - : public Dijkstra< Digraph, LengthMap, SetStandardProcessedMapTraits > { - typedef Dijkstra< Digraph, LengthMap, SetStandardProcessedMapTraits > - Create; - }; - - template - struct SetHeapTraits : public Traits { - typedef CR HeapCrossRef; - typedef H Heap; - static HeapCrossRef *createHeapCrossRef(const Digraph &) { - LEMON_ASSERT(false, "HeapCrossRef is not initialized"); - return 0; // ignore warnings - } - static Heap *createHeap(HeapCrossRef &) - { - LEMON_ASSERT(false, "Heap is not initialized"); - return 0; // ignore warnings - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///heap and cross reference types - /// - ///\ref named-templ-param "Named parameter" for setting heap and cross - ///reference types. If this named parameter is used, then external - ///heap and cross reference objects must be passed to the algorithm - ///using the \ref heap() function before calling \ref run(Node) "run()" - ///or \ref init(). - ///\sa SetStandardHeap - template > - struct SetHeap - : public Dijkstra< Digraph, LengthMap, SetHeapTraits > { - typedef Dijkstra< Digraph, LengthMap, SetHeapTraits > Create; - }; - - template - struct SetStandardHeapTraits : public Traits { - typedef CR HeapCrossRef; - typedef H Heap; - static HeapCrossRef *createHeapCrossRef(const Digraph &G) { - return new HeapCrossRef(G); - } - static Heap *createHeap(HeapCrossRef &R) - { - return new Heap(R); - } - }; - ///\brief \ref named-templ-param "Named parameter" for setting - ///heap and cross reference types with automatic allocation - /// - ///\ref named-templ-param "Named parameter" for setting heap and cross - ///reference types with automatic allocation. - ///They should have standard constructor interfaces to be able to - ///automatically created by the algorithm (i.e. the digraph should be - ///passed to the constructor of the cross reference and the cross - ///reference should be passed to the constructor of the heap). - ///However, external heap and cross reference objects could also be - ///passed to the algorithm using the \ref heap() function before - ///calling \ref run(Node) "run()" or \ref init(). - ///\sa SetHeap - template > - struct SetStandardHeap - : public Dijkstra< Digraph, LengthMap, SetStandardHeapTraits > { - typedef Dijkstra< Digraph, LengthMap, SetStandardHeapTraits > - Create; - }; - - template - struct SetOperationTraitsTraits : public Traits { - typedef T OperationTraits; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - ///\c OperationTraits type - /// - ///\ref named-templ-param "Named parameter" for setting - ///\c OperationTraits type. - /// For more information, see \ref DijkstraDefaultOperationTraits. - template - struct SetOperationTraits - : public Dijkstra > { - typedef Dijkstra > - Create; - }; - - ///@} - - protected: - - Dijkstra() {} - - public: - - ///Constructor. - - ///Constructor. - ///\param g The digraph the algorithm runs on. - ///\param length The length map used by the algorithm. - Dijkstra(const Digraph& g, const LengthMap& length) : - G(&g), _length(&length), - _pred(NULL), local_pred(false), - _dist(NULL), local_dist(false), - _processed(NULL), local_processed(false), - _heap_cross_ref(NULL), local_heap_cross_ref(false), - _heap(NULL), local_heap(false) - { } - - ///Destructor. - ~Dijkstra() - { - if(local_pred) delete _pred; - if(local_dist) delete _dist; - if(local_processed) delete _processed; - if(local_heap_cross_ref) delete _heap_cross_ref; - if(local_heap) delete _heap; - } - - ///Sets the length map. - - ///Sets the length map. - ///\return (*this) - Dijkstra &lengthMap(const LengthMap &m) - { - _length = &m; - return *this; - } - - ///Sets the map that stores the predecessor arcs. - - ///Sets the map that stores the predecessor arcs. - ///If you don't use this function before calling \ref run(Node) "run()" - ///or \ref init(), an instance will be allocated automatically. - ///The destructor deallocates this automatically allocated map, - ///of course. - ///\return (*this) - Dijkstra &predMap(PredMap &m) - { - if(local_pred) { - delete _pred; - local_pred=false; - } - _pred = &m; - return *this; - } - - ///Sets the map that indicates which nodes are processed. - - ///Sets the map that indicates which nodes are processed. - ///If you don't use this function before calling \ref run(Node) "run()" - ///or \ref init(), an instance will be allocated automatically. - ///The destructor deallocates this automatically allocated map, - ///of course. - ///\return (*this) - Dijkstra &processedMap(ProcessedMap &m) - { - if(local_processed) { - delete _processed; - local_processed=false; - } - _processed = &m; - return *this; - } - - ///Sets the map that stores the distances of the nodes. - - ///Sets the map that stores the distances of the nodes calculated by the - ///algorithm. - ///If you don't use this function before calling \ref run(Node) "run()" - ///or \ref init(), an instance will be allocated automatically. - ///The destructor deallocates this automatically allocated map, - ///of course. - ///\return (*this) - Dijkstra &distMap(DistMap &m) - { - if(local_dist) { - delete _dist; - local_dist=false; - } - _dist = &m; - return *this; - } - - ///Sets the heap and the cross reference used by algorithm. - - ///Sets the heap and the cross reference used by algorithm. - ///If you don't use this function before calling \ref run(Node) "run()" - ///or \ref init(), heap and cross reference instances will be - ///allocated automatically. - ///The destructor deallocates these automatically allocated objects, - ///of course. - ///\return (*this) - Dijkstra &heap(Heap& hp, HeapCrossRef &cr) - { - if(local_heap_cross_ref) { - delete _heap_cross_ref; - local_heap_cross_ref=false; - } - _heap_cross_ref = &cr; - if(local_heap) { - delete _heap; - local_heap=false; - } - _heap = &hp; - return *this; - } - - private: - - void finalizeNodeData(Node v,Value dst) - { - _processed->set(v,true); - _dist->set(v, dst); - } - - public: - - ///\name Execution Control - ///The simplest way to execute the %Dijkstra algorithm is to use - ///one of the member functions called \ref run(Node) "run()".\n - ///If you need better control on the execution, you have to call - ///\ref init() first, then you can add several source nodes with - ///\ref addSource(). Finally the actual path computation can be - ///performed with one of the \ref start() functions. - - ///@{ - - ///\brief Initializes the internal data structures. - /// - ///Initializes the internal data structures. - void init() - { - create_maps(); - _heap->clear(); - for ( NodeIt u(*G) ; u!=INVALID ; ++u ) { - _pred->set(u,INVALID); - _processed->set(u,false); - _heap_cross_ref->set(u,Heap::PRE_HEAP); - } - } - - ///Adds a new source node. - - ///Adds a new source node to the priority heap. - ///The optional second parameter is the initial distance of the node. - /// - ///The function checks if the node has already been added to the heap and - ///it is pushed to the heap only if either it was not in the heap - ///or the shortest path found till then is shorter than \c dst. - void addSource(Node s,Value dst=OperationTraits::zero()) - { - if(_heap->state(s) != Heap::IN_HEAP) { - _heap->push(s,dst); - } else if(OperationTraits::less((*_heap)[s], dst)) { - _heap->set(s,dst); - _pred->set(s,INVALID); - } - } - - ///Processes the next node in the priority heap - - ///Processes the next node in the priority heap. - /// - ///\return The processed node. - /// - ///\warning The priority heap must not be empty. - Node processNextNode() - { - Node v=_heap->top(); - Value oldvalue=_heap->prio(); - _heap->pop(); - finalizeNodeData(v,oldvalue); - - for(OutArcIt e(*G,v); e!=INVALID; ++e) { - Node w=G->target(e); - switch(_heap->state(w)) { - case Heap::PRE_HEAP: - _heap->push(w,OperationTraits::plus(oldvalue, (*_length)[e])); - _pred->set(w,e); - break; - case Heap::IN_HEAP: - { - Value newvalue = OperationTraits::plus(oldvalue, (*_length)[e]); - if ( OperationTraits::less(newvalue, (*_heap)[w]) ) { - _heap->decrease(w, newvalue); - _pred->set(w,e); - } - } - break; - case Heap::POST_HEAP: - break; - } - } - return v; - } - - ///The next node to be processed. - - ///Returns the next node to be processed or \c INVALID if the - ///priority heap is empty. - Node nextNode() const - { - return !_heap->empty()?_heap->top():INVALID; - } - - ///Returns \c false if there are nodes to be processed. - - ///Returns \c false if there are nodes to be processed - ///in the priority heap. - bool emptyQueue() const { return _heap->empty(); } - - ///Returns the number of the nodes to be processed. - - ///Returns the number of the nodes to be processed - ///in the priority heap. - int queueSize() const { return _heap->size(); } - - ///Executes the algorithm. - - ///Executes the algorithm. - /// - ///This method runs the %Dijkstra algorithm from the root node(s) - ///in order to compute the shortest path to each node. - /// - ///The algorithm computes - ///- the shortest path tree (forest), - ///- the distance of each node from the root(s). - /// - ///\pre init() must be called and at least one root node should be - ///added with addSource() before using this function. - /// - ///\note d.start() is just a shortcut of the following code. - ///\code - /// while ( !d.emptyQueue() ) { - /// d.processNextNode(); - /// } - ///\endcode - void start() - { - while ( !emptyQueue() ) processNextNode(); - } - - ///Executes the algorithm until the given target node is processed. - - ///Executes the algorithm until the given target node is processed. - /// - ///This method runs the %Dijkstra algorithm from the root node(s) - ///in order to compute the shortest path to \c t. - /// - ///The algorithm computes - ///- the shortest path to \c t, - ///- the distance of \c t from the root(s). - /// - ///\pre init() must be called and at least one root node should be - ///added with addSource() before using this function. - void start(Node t) - { - while ( !_heap->empty() && _heap->top()!=t ) processNextNode(); - if ( !_heap->empty() ) { - finalizeNodeData(_heap->top(),_heap->prio()); - _heap->pop(); - } - } - - ///Executes the algorithm until a condition is met. - - ///Executes the algorithm until a condition is met. - /// - ///This method runs the %Dijkstra algorithm from the root node(s) in - ///order to compute the shortest path to a node \c v with - /// nm[v] true, if such a node can be found. - /// - ///\param nm A \c bool (or convertible) node map. The algorithm - ///will stop when it reaches a node \c v with nm[v] true. - /// - ///\return The reached node \c v with nm[v] true or - ///\c INVALID if no such node was found. - /// - ///\pre init() must be called and at least one root node should be - ///added with addSource() before using this function. - template - Node start(const NodeBoolMap &nm) - { - while ( !_heap->empty() && !nm[_heap->top()] ) processNextNode(); - if ( _heap->empty() ) return INVALID; - finalizeNodeData(_heap->top(),_heap->prio()); - return _heap->top(); - } - - ///Runs the algorithm from the given source node. - - ///This method runs the %Dijkstra algorithm from node \c s - ///in order to compute the shortest path to each node. - /// - ///The algorithm computes - ///- the shortest path tree, - ///- the distance of each node from the root. - /// - ///\note d.run(s) is just a shortcut of the following code. - ///\code - /// d.init(); - /// d.addSource(s); - /// d.start(); - ///\endcode - void run(Node s) { - init(); - addSource(s); - start(); - } - - ///Finds the shortest path between \c s and \c t. - - ///This method runs the %Dijkstra algorithm from node \c s - ///in order to compute the shortest path to node \c t - ///(it stops searching when \c t is processed). - /// - ///\return \c true if \c t is reachable form \c s. - /// - ///\note Apart from the return value, d.run(s,t) is just a - ///shortcut of the following code. - ///\code - /// d.init(); - /// d.addSource(s); - /// d.start(t); - ///\endcode - bool run(Node s,Node t) { - init(); - addSource(s); - start(t); - return (*_heap_cross_ref)[t] == Heap::POST_HEAP; - } - - ///@} - - ///\name Query Functions - ///The results of the %Dijkstra algorithm can be obtained using these - ///functions.\n - ///Either \ref run(Node) "run()" or \ref init() should be called - ///before using them. - - ///@{ - - ///The shortest path to the given node. - - ///Returns the shortest path to the given node from the root(s). - /// - ///\warning \c t should be reached from the root(s). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - Path path(Node t) const { return Path(*G, *_pred, t); } - - ///The distance of the given node from the root(s). - - ///Returns the distance of the given node from the root(s). - /// - ///\warning If node \c v is not reached from the root(s), then - ///the return value of this function is undefined. - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - Value dist(Node v) const { return (*_dist)[v]; } - - ///\brief Returns the 'previous arc' of the shortest path tree for - ///the given node. - /// - ///This function returns the 'previous arc' of the shortest path - ///tree for the node \c v, i.e. it returns the last arc of a - ///shortest path from a root to \c v. It is \c INVALID if \c v - ///is not reached from the root(s) or if \c v is a root. - /// - ///The shortest path tree used here is equal to the shortest path - ///tree used in \ref predNode() and \ref predMap(). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - Arc predArc(Node v) const { return (*_pred)[v]; } - - ///\brief Returns the 'previous node' of the shortest path tree for - ///the given node. - /// - ///This function returns the 'previous node' of the shortest path - ///tree for the node \c v, i.e. it returns the last but one node - ///of a shortest path from a root to \c v. It is \c INVALID - ///if \c v is not reached from the root(s) or if \c v is a root. - /// - ///The shortest path tree used here is equal to the shortest path - ///tree used in \ref predArc() and \ref predMap(). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - Node predNode(Node v) const { return (*_pred)[v]==INVALID ? INVALID: - G->source((*_pred)[v]); } - - ///\brief Returns a const reference to the node map that stores the - ///distances of the nodes. - /// - ///Returns a const reference to the node map that stores the distances - ///of the nodes calculated by the algorithm. - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - const DistMap &distMap() const { return *_dist;} - - ///\brief Returns a const reference to the node map that stores the - ///predecessor arcs. - /// - ///Returns a const reference to the node map that stores the predecessor - ///arcs, which form the shortest path tree (forest). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - const PredMap &predMap() const { return *_pred;} - - ///Checks if the given node is reached from the root(s). - - ///Returns \c true if \c v is reached from the root(s). - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - bool reached(Node v) const { return (*_heap_cross_ref)[v] != - Heap::PRE_HEAP; } - - ///Checks if a node is processed. - - ///Returns \c true if \c v is processed, i.e. the shortest - ///path to \c v has already found. - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function. - bool processed(Node v) const { return (*_heap_cross_ref)[v] == - Heap::POST_HEAP; } - - ///The current distance of the given node from the root(s). - - ///Returns the current distance of the given node from the root(s). - ///It may be decreased in the following processes. - /// - ///\pre Either \ref run(Node) "run()" or \ref init() - ///must be called before using this function and - ///node \c v must be reached but not necessarily processed. - Value currentDist(Node v) const { - return processed(v) ? (*_dist)[v] : (*_heap)[v]; - } - - ///@} - }; - - - ///Default traits class of dijkstra() function. - - ///Default traits class of dijkstra() function. - ///\tparam GR The type of the digraph. - ///\tparam LEN The type of the length map. - template - struct DijkstraWizardDefaultTraits - { - ///The type of the digraph the algorithm runs on. - typedef GR Digraph; - ///The type of the map that stores the arc lengths. - - ///The type of the map that stores the arc lengths. - ///It must conform to the \ref concepts::ReadMap "ReadMap" concept. - typedef LEN LengthMap; - ///The type of the arc lengths. - typedef typename LEN::Value Value; - - /// Operation traits for Dijkstra algorithm. - - /// This class defines the operations that are used in the algorithm. - /// \see DijkstraDefaultOperationTraits - typedef DijkstraDefaultOperationTraits OperationTraits; - - /// The cross reference type used by the heap. - - /// The cross reference type used by the heap. - /// Usually it is \c Digraph::NodeMap. - typedef typename Digraph::template NodeMap HeapCrossRef; - ///Instantiates a \ref HeapCrossRef. - - ///This function instantiates a \ref HeapCrossRef. - /// \param g is the digraph, to which we would like to define the - /// HeapCrossRef. - static HeapCrossRef *createHeapCrossRef(const Digraph &g) - { - return new HeapCrossRef(g); - } - - ///The heap type used by the Dijkstra algorithm. - - ///The heap type used by the Dijkstra algorithm. - /// - ///\sa BinHeap - ///\sa Dijkstra - typedef BinHeap, - std::less > Heap; - - ///Instantiates a \ref Heap. - - ///This function instantiates a \ref Heap. - /// \param r is the HeapCrossRef which is used. - static Heap *createHeap(HeapCrossRef& r) - { - return new Heap(r); - } - - ///\brief The type of the map that stores the predecessor - ///arcs of the shortest paths. - /// - ///The type of the map that stores the predecessor - ///arcs of the shortest paths. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap PredMap; - ///Instantiates a PredMap. - - ///This function instantiates a PredMap. - ///\param g is the digraph, to which we would like to define the - ///PredMap. - static PredMap *createPredMap(const Digraph &g) - { - return new PredMap(g); - } - - ///The type of the map that indicates which nodes are processed. - - ///The type of the map that indicates which nodes are processed. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - ///By default, it is a NullMap. - typedef NullMap ProcessedMap; - ///Instantiates a ProcessedMap. - - ///This function instantiates a ProcessedMap. - ///\param g is the digraph, to which - ///we would like to define the ProcessedMap. -#ifdef DOXYGEN - static ProcessedMap *createProcessedMap(const Digraph &g) -#else - static ProcessedMap *createProcessedMap(const Digraph &) -#endif - { - return new ProcessedMap(); - } - - ///The type of the map that stores the distances of the nodes. - - ///The type of the map that stores the distances of the nodes. - ///It must conform to the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap DistMap; - ///Instantiates a DistMap. - - ///This function instantiates a DistMap. - ///\param g is the digraph, to which we would like to define - ///the DistMap - static DistMap *createDistMap(const Digraph &g) - { - return new DistMap(g); - } - - ///The type of the shortest paths. - - ///The type of the shortest paths. - ///It must conform to the \ref concepts::Path "Path" concept. - typedef lemon::Path Path; - }; - - /// Default traits class used by DijkstraWizard - - /// Default traits class used by DijkstraWizard. - /// \tparam GR The type of the digraph. - /// \tparam LEN The type of the length map. - template - class DijkstraWizardBase : public DijkstraWizardDefaultTraits - { - typedef DijkstraWizardDefaultTraits Base; - protected: - //The type of the nodes in the digraph. - typedef typename Base::Digraph::Node Node; - - //Pointer to the digraph the algorithm runs on. - void *_g; - //Pointer to the length map. - void *_length; - //Pointer to the map of processed nodes. - void *_processed; - //Pointer to the map of predecessors arcs. - void *_pred; - //Pointer to the map of distances. - void *_dist; - //Pointer to the shortest path to the target node. - void *_path; - //Pointer to the distance of the target node. - void *_di; - - public: - /// Constructor. - - /// This constructor does not require parameters, therefore it initiates - /// all of the attributes to \c 0. - DijkstraWizardBase() : _g(0), _length(0), _processed(0), _pred(0), - _dist(0), _path(0), _di(0) {} - - /// Constructor. - - /// This constructor requires two parameters, - /// others are initiated to \c 0. - /// \param g The digraph the algorithm runs on. - /// \param l The length map. - DijkstraWizardBase(const GR &g,const LEN &l) : - _g(reinterpret_cast(const_cast(&g))), - _length(reinterpret_cast(const_cast(&l))), - _processed(0), _pred(0), _dist(0), _path(0), _di(0) {} - - }; - - /// Auxiliary class for the function-type interface of Dijkstra algorithm. - - /// This auxiliary class is created to implement the - /// \ref dijkstra() "function-type interface" of \ref Dijkstra algorithm. - /// It does not have own \ref run(Node) "run()" method, it uses the - /// functions and features of the plain \ref Dijkstra. - /// - /// This class should only be used through the \ref dijkstra() function, - /// which makes it easier to use the algorithm. - /// - /// \tparam TR The traits class that defines various types used by the - /// algorithm. - template - class DijkstraWizard : public TR - { - typedef TR Base; - - typedef typename TR::Digraph Digraph; - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::OutArcIt OutArcIt; - - typedef typename TR::LengthMap LengthMap; - typedef typename LengthMap::Value Value; - typedef typename TR::PredMap PredMap; - typedef typename TR::DistMap DistMap; - typedef typename TR::ProcessedMap ProcessedMap; - typedef typename TR::Path Path; - typedef typename TR::Heap Heap; - - public: - - /// Constructor. - DijkstraWizard() : TR() {} - - /// Constructor that requires parameters. - - /// Constructor that requires parameters. - /// These parameters will be the default values for the traits class. - /// \param g The digraph the algorithm runs on. - /// \param l The length map. - DijkstraWizard(const Digraph &g, const LengthMap &l) : - TR(g,l) {} - - ///Copy constructor - DijkstraWizard(const TR &b) : TR(b) {} - - ~DijkstraWizard() {} - - ///Runs Dijkstra algorithm from the given source node. - - ///This method runs %Dijkstra algorithm from the given source node - ///in order to compute the shortest path to each node. - void run(Node s) - { - Dijkstra - dijk(*reinterpret_cast(Base::_g), - *reinterpret_cast(Base::_length)); - if (Base::_pred) - dijk.predMap(*reinterpret_cast(Base::_pred)); - if (Base::_dist) - dijk.distMap(*reinterpret_cast(Base::_dist)); - if (Base::_processed) - dijk.processedMap(*reinterpret_cast(Base::_processed)); - dijk.run(s); - } - - ///Finds the shortest path between \c s and \c t. - - ///This method runs the %Dijkstra algorithm from node \c s - ///in order to compute the shortest path to node \c t - ///(it stops searching when \c t is processed). - /// - ///\return \c true if \c t is reachable form \c s. - bool run(Node s, Node t) - { - Dijkstra - dijk(*reinterpret_cast(Base::_g), - *reinterpret_cast(Base::_length)); - if (Base::_pred) - dijk.predMap(*reinterpret_cast(Base::_pred)); - if (Base::_dist) - dijk.distMap(*reinterpret_cast(Base::_dist)); - if (Base::_processed) - dijk.processedMap(*reinterpret_cast(Base::_processed)); - dijk.run(s,t); - if (Base::_path) - *reinterpret_cast(Base::_path) = dijk.path(t); - if (Base::_di) - *reinterpret_cast(Base::_di) = dijk.dist(t); - return dijk.reached(t); - } - - template - struct SetPredMapBase : public Base { - typedef T PredMap; - static PredMap *createPredMap(const Digraph &) { return 0; }; - SetPredMapBase(const TR &b) : TR(b) {} - }; - - ///\brief \ref named-templ-param "Named parameter" for setting - ///the predecessor map. - /// - ///\ref named-templ-param "Named parameter" function for setting - ///the map that stores the predecessor arcs of the nodes. - template - DijkstraWizard > predMap(const T &t) - { - Base::_pred=reinterpret_cast(const_cast(&t)); - return DijkstraWizard >(*this); - } - - template - struct SetDistMapBase : public Base { - typedef T DistMap; - static DistMap *createDistMap(const Digraph &) { return 0; }; - SetDistMapBase(const TR &b) : TR(b) {} - }; - - ///\brief \ref named-templ-param "Named parameter" for setting - ///the distance map. - /// - ///\ref named-templ-param "Named parameter" function for setting - ///the map that stores the distances of the nodes calculated - ///by the algorithm. - template - DijkstraWizard > distMap(const T &t) - { - Base::_dist=reinterpret_cast(const_cast(&t)); - return DijkstraWizard >(*this); - } - - template - struct SetProcessedMapBase : public Base { - typedef T ProcessedMap; - static ProcessedMap *createProcessedMap(const Digraph &) { return 0; }; - SetProcessedMapBase(const TR &b) : TR(b) {} - }; - - ///\brief \ref named-func-param "Named parameter" for setting - ///the processed map. - /// - ///\ref named-templ-param "Named parameter" function for setting - ///the map that indicates which nodes are processed. - template - DijkstraWizard > processedMap(const T &t) - { - Base::_processed=reinterpret_cast(const_cast(&t)); - return DijkstraWizard >(*this); - } - - template - struct SetPathBase : public Base { - typedef T Path; - SetPathBase(const TR &b) : TR(b) {} - }; - - ///\brief \ref named-func-param "Named parameter" - ///for getting the shortest path to the target node. - /// - ///\ref named-func-param "Named parameter" - ///for getting the shortest path to the target node. - template - DijkstraWizard > path(const T &t) - { - Base::_path=reinterpret_cast(const_cast(&t)); - return DijkstraWizard >(*this); - } - - ///\brief \ref named-func-param "Named parameter" - ///for getting the distance of the target node. - /// - ///\ref named-func-param "Named parameter" - ///for getting the distance of the target node. - DijkstraWizard dist(const Value &d) - { - Base::_di=reinterpret_cast(const_cast(&d)); - return *this; - } - - }; - - ///Function-type interface for Dijkstra algorithm. - - /// \ingroup shortest_path - ///Function-type interface for Dijkstra algorithm. - /// - ///This function also has several \ref named-func-param "named parameters", - ///they are declared as the members of class \ref DijkstraWizard. - ///The following examples show how to use these parameters. - ///\code - /// // Compute shortest path from node s to each node - /// dijkstra(g,length).predMap(preds).distMap(dists).run(s); - /// - /// // Compute shortest path from s to t - /// bool reached = dijkstra(g,length).path(p).dist(d).run(s,t); - ///\endcode - ///\warning Don't forget to put the \ref DijkstraWizard::run(Node) "run()" - ///to the end of the parameter list. - ///\sa DijkstraWizard - ///\sa Dijkstra - template - DijkstraWizard > - dijkstra(const GR &digraph, const LEN &length) - { - return DijkstraWizard >(digraph,length); - } - -} //END OF NAMESPACE LEMON - -#endif diff --git a/deps/lemon/lemon/dim2.h b/deps/lemon/lemon/dim2.h deleted file mode 100644 index 0b1422106..000000000 --- a/deps/lemon/lemon/dim2.h +++ /dev/null @@ -1,726 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_DIM2_H -#define LEMON_DIM2_H - -#include -#include - -///\ingroup geomdat -///\file -///\brief A simple two dimensional vector and a bounding box implementation - -namespace lemon { - - ///Tools for handling two dimensional coordinates - - ///This namespace is a storage of several - ///tools for handling two dimensional coordinates - namespace dim2 { - - /// \addtogroup geomdat - /// @{ - - /// Two dimensional vector (plain vector) - - /// A simple two dimensional vector (plain vector) implementation - /// with the usual vector operations. - template - class Point { - - public: - - typedef T Value; - - ///First coordinate - T x; - ///Second coordinate - T y; - - ///Default constructor - Point() {} - - ///Construct an instance from coordinates - Point(T a, T b) : x(a), y(b) { } - - ///Returns the dimension of the vector (i.e. returns 2). - - ///The dimension of the vector. - ///This function always returns 2. - int size() const { return 2; } - - ///Subscripting operator - - ///\c p[0] is \c p.x and \c p[1] is \c p.y - /// - T& operator[](int idx) { return idx == 0 ? x : y; } - - ///Const subscripting operator - - ///\c p[0] is \c p.x and \c p[1] is \c p.y - /// - const T& operator[](int idx) const { return idx == 0 ? x : y; } - - ///Conversion constructor - template Point(const Point &p) : x(p.x), y(p.y) {} - - ///Give back the square of the norm of the vector - T normSquare() const { - return x*x+y*y; - } - - ///Increment the left hand side by \c u - Point& operator +=(const Point& u) { - x += u.x; - y += u.y; - return *this; - } - - ///Decrement the left hand side by \c u - Point& operator -=(const Point& u) { - x -= u.x; - y -= u.y; - return *this; - } - - ///Multiply the left hand side with a scalar - Point& operator *=(const T &u) { - x *= u; - y *= u; - return *this; - } - - ///Divide the left hand side by a scalar - Point& operator /=(const T &u) { - x /= u; - y /= u; - return *this; - } - - ///Return the scalar product of two vectors - T operator *(const Point& u) const { - return x*u.x+y*u.y; - } - - ///Return the sum of two vectors - Point operator+(const Point &u) const { - Point b=*this; - return b+=u; - } - - ///Return the negative of the vector - Point operator-() const { - Point b=*this; - b.x=-b.x; b.y=-b.y; - return b; - } - - ///Return the difference of two vectors - Point operator-(const Point &u) const { - Point b=*this; - return b-=u; - } - - ///Return a vector multiplied by a scalar - Point operator*(const T &u) const { - Point b=*this; - return b*=u; - } - - ///Return a vector divided by a scalar - Point operator/(const T &u) const { - Point b=*this; - return b/=u; - } - - ///Test equality - bool operator==(const Point &u) const { - return (x==u.x) && (y==u.y); - } - - ///Test inequality - bool operator!=(Point u) const { - return (x!=u.x) || (y!=u.y); - } - - }; - - ///Return a Point - - ///Return a Point. - ///\relates Point - template - inline Point makePoint(const T& x, const T& y) { - return Point(x, y); - } - - ///Return a vector multiplied by a scalar - - ///Return a vector multiplied by a scalar. - ///\relates Point - template Point operator*(const T &u,const Point &x) { - return x*u; - } - - ///Read a plain vector from a stream - - ///Read a plain vector from a stream. - ///\relates Point - /// - template - inline std::istream& operator>>(std::istream &is, Point &z) { - char c; - if (is >> c) { - if (c != '(') is.putback(c); - } else { - is.clear(); - } - if (!(is >> z.x)) return is; - if (is >> c) { - if (c != ',') is.putback(c); - } else { - is.clear(); - } - if (!(is >> z.y)) return is; - if (is >> c) { - if (c != ')') is.putback(c); - } else { - is.clear(); - } - return is; - } - - ///Write a plain vector to a stream - - ///Write a plain vector to a stream. - ///\relates Point - /// - template - inline std::ostream& operator<<(std::ostream &os, const Point& z) - { - os << "(" << z.x << "," << z.y << ")"; - return os; - } - - ///Rotate by 90 degrees - - ///Returns the parameter rotated by 90 degrees in positive direction. - ///\relates Point - /// - template - inline Point rot90(const Point &z) - { - return Point(-z.y,z.x); - } - - ///Rotate by 180 degrees - - ///Returns the parameter rotated by 180 degrees. - ///\relates Point - /// - template - inline Point rot180(const Point &z) - { - return Point(-z.x,-z.y); - } - - ///Rotate by 270 degrees - - ///Returns the parameter rotated by 90 degrees in negative direction. - ///\relates Point - /// - template - inline Point rot270(const Point &z) - { - return Point(z.y,-z.x); - } - - - - /// Bounding box of plain vectors (points). - - /// A class to calculate or store the bounding box of plain vectors - /// (\ref Point "points"). - template - class Box { - Point _bottom_left, _top_right; - bool _empty; - public: - - ///Default constructor: creates an empty box - Box() { _empty = true; } - - ///Construct a box from one point - Box(Point a) { - _bottom_left = _top_right = a; - _empty = false; - } - - ///Construct a box from two points - - ///Construct a box from two points. - ///\param a The bottom left corner. - ///\param b The top right corner. - ///\warning The coordinates of the bottom left corner must be no more - ///than those of the top right one. - Box(Point a,Point b) - { - _bottom_left = a; - _top_right = b; - _empty = false; - } - - ///Construct a box from four numbers - - ///Construct a box from four numbers. - ///\param l The left side of the box. - ///\param b The bottom of the box. - ///\param r The right side of the box. - ///\param t The top of the box. - ///\warning The left side must be no more than the right side and - ///bottom must be no more than the top. - Box(T l,T b,T r,T t) - { - _bottom_left=Point(l,b); - _top_right=Point(r,t); - _empty = false; - } - - ///Return \c true if the box is empty. - - ///Return \c true if the box is empty (i.e. return \c false - ///if at least one point was added to the box or the coordinates of - ///the box were set). - /// - ///The coordinates of an empty box are not defined. - bool empty() const { - return _empty; - } - - ///Make the box empty - void clear() { - _empty = true; - } - - ///Give back the bottom left corner of the box - - ///Give back the bottom left corner of the box. - ///If the box is empty, then the return value is not defined. - Point bottomLeft() const { - return _bottom_left; - } - - ///Set the bottom left corner of the box - - ///Set the bottom left corner of the box. - ///\pre The box must not be empty. - void bottomLeft(Point p) { - _bottom_left = p; - } - - ///Give back the top right corner of the box - - ///Give back the top right corner of the box. - ///If the box is empty, then the return value is not defined. - Point topRight() const { - return _top_right; - } - - ///Set the top right corner of the box - - ///Set the top right corner of the box. - ///\pre The box must not be empty. - void topRight(Point p) { - _top_right = p; - } - - ///Give back the bottom right corner of the box - - ///Give back the bottom right corner of the box. - ///If the box is empty, then the return value is not defined. - Point bottomRight() const { - return Point(_top_right.x,_bottom_left.y); - } - - ///Set the bottom right corner of the box - - ///Set the bottom right corner of the box. - ///\pre The box must not be empty. - void bottomRight(Point p) { - _top_right.x = p.x; - _bottom_left.y = p.y; - } - - ///Give back the top left corner of the box - - ///Give back the top left corner of the box. - ///If the box is empty, then the return value is not defined. - Point topLeft() const { - return Point(_bottom_left.x,_top_right.y); - } - - ///Set the top left corner of the box - - ///Set the top left corner of the box. - ///\pre The box must not be empty. - void topLeft(Point p) { - _top_right.y = p.y; - _bottom_left.x = p.x; - } - - ///Give back the bottom of the box - - ///Give back the bottom of the box. - ///If the box is empty, then the return value is not defined. - T bottom() const { - return _bottom_left.y; - } - - ///Set the bottom of the box - - ///Set the bottom of the box. - ///\pre The box must not be empty. - void bottom(T t) { - _bottom_left.y = t; - } - - ///Give back the top of the box - - ///Give back the top of the box. - ///If the box is empty, then the return value is not defined. - T top() const { - return _top_right.y; - } - - ///Set the top of the box - - ///Set the top of the box. - ///\pre The box must not be empty. - void top(T t) { - _top_right.y = t; - } - - ///Give back the left side of the box - - ///Give back the left side of the box. - ///If the box is empty, then the return value is not defined. - T left() const { - return _bottom_left.x; - } - - ///Set the left side of the box - - ///Set the left side of the box. - ///\pre The box must not be empty. - void left(T t) { - _bottom_left.x = t; - } - - /// Give back the right side of the box - - /// Give back the right side of the box. - ///If the box is empty, then the return value is not defined. - T right() const { - return _top_right.x; - } - - ///Set the right side of the box - - ///Set the right side of the box. - ///\pre The box must not be empty. - void right(T t) { - _top_right.x = t; - } - - ///Give back the height of the box - - ///Give back the height of the box. - ///If the box is empty, then the return value is not defined. - T height() const { - return _top_right.y-_bottom_left.y; - } - - ///Give back the width of the box - - ///Give back the width of the box. - ///If the box is empty, then the return value is not defined. - T width() const { - return _top_right.x-_bottom_left.x; - } - - ///Checks whether a point is inside the box - bool inside(const Point& u) const { - if (_empty) - return false; - else { - return ( (u.x-_bottom_left.x)*(_top_right.x-u.x) >= 0 && - (u.y-_bottom_left.y)*(_top_right.y-u.y) >= 0 ); - } - } - - ///Increments the box with a point - - ///Increments the box with a point. - /// - Box& add(const Point& u){ - if (_empty) { - _bottom_left = _top_right = u; - _empty = false; - } - else { - if (_bottom_left.x > u.x) _bottom_left.x = u.x; - if (_bottom_left.y > u.y) _bottom_left.y = u.y; - if (_top_right.x < u.x) _top_right.x = u.x; - if (_top_right.y < u.y) _top_right.y = u.y; - } - return *this; - } - - ///Increments the box to contain another box - - ///Increments the box to contain another box. - /// - Box& add(const Box &u){ - if ( !u.empty() ){ - add(u._bottom_left); - add(u._top_right); - } - return *this; - } - - ///Intersection of two boxes - - ///Intersection of two boxes. - /// - Box operator&(const Box& u) const { - Box b; - if (_empty || u._empty) { - b._empty = true; - } else { - b._bottom_left.x = std::max(_bottom_left.x, u._bottom_left.x); - b._bottom_left.y = std::max(_bottom_left.y, u._bottom_left.y); - b._top_right.x = std::min(_top_right.x, u._top_right.x); - b._top_right.y = std::min(_top_right.y, u._top_right.y); - b._empty = b._bottom_left.x > b._top_right.x || - b._bottom_left.y > b._top_right.y; - } - return b; - } - - };//class Box - - - ///Read a box from a stream - - ///Read a box from a stream. - ///\relates Box - template - inline std::istream& operator>>(std::istream &is, Box& b) { - char c; - Point p; - if (is >> c) { - if (c != '(') is.putback(c); - } else { - is.clear(); - } - if (!(is >> p)) return is; - b.bottomLeft(p); - if (is >> c) { - if (c != ',') is.putback(c); - } else { - is.clear(); - } - if (!(is >> p)) return is; - b.topRight(p); - if (is >> c) { - if (c != ')') is.putback(c); - } else { - is.clear(); - } - return is; - } - - ///Write a box to a stream - - ///Write a box to a stream. - ///\relates Box - template - inline std::ostream& operator<<(std::ostream &os, const Box& b) - { - os << "(" << b.bottomLeft() << "," << b.topRight() << ")"; - return os; - } - - ///Map of x-coordinates of a Point-map - - ///Map of x-coordinates of a \ref Point "Point"-map. - /// - template - class XMap - { - M& _map; - public: - - typedef typename M::Value::Value Value; - typedef typename M::Key Key; - ///\e - XMap(M& map) : _map(map) {} - Value operator[](Key k) const {return _map[k].x;} - void set(Key k,Value v) {_map.set(k,typename M::Value(v,_map[k].y));} - }; - - ///Returns an XMap class - - ///This function just returns an XMap class. - ///\relates XMap - template - inline XMap xMap(M &m) - { - return XMap(m); - } - - template - inline XMap xMap(const M &m) - { - return XMap(m); - } - - ///Constant (read only) version of XMap - - ///Constant (read only) version of XMap. - /// - template - class ConstXMap - { - const M& _map; - public: - - typedef typename M::Value::Value Value; - typedef typename M::Key Key; - ///\e - ConstXMap(const M &map) : _map(map) {} - Value operator[](Key k) const {return _map[k].x;} - }; - - ///Returns a ConstXMap class - - ///This function just returns a ConstXMap class. - ///\relates ConstXMap - template - inline ConstXMap xMap(const M &m) - { - return ConstXMap(m); - } - - ///Map of y-coordinates of a Point-map - - ///Map of y-coordinates of a \ref Point "Point"-map. - /// - template - class YMap - { - M& _map; - public: - - typedef typename M::Value::Value Value; - typedef typename M::Key Key; - ///\e - YMap(M& map) : _map(map) {} - Value operator[](Key k) const {return _map[k].y;} - void set(Key k,Value v) {_map.set(k,typename M::Value(_map[k].x,v));} - }; - - ///Returns a YMap class - - ///This function just returns a YMap class. - ///\relates YMap - template - inline YMap yMap(M &m) - { - return YMap(m); - } - - template - inline YMap yMap(const M &m) - { - return YMap(m); - } - - ///Constant (read only) version of YMap - - ///Constant (read only) version of YMap. - /// - template - class ConstYMap - { - const M& _map; - public: - - typedef typename M::Value::Value Value; - typedef typename M::Key Key; - ///\e - ConstYMap(const M &map) : _map(map) {} - Value operator[](Key k) const {return _map[k].y;} - }; - - ///Returns a ConstYMap class - - ///This function just returns a ConstYMap class. - ///\relates ConstYMap - template - inline ConstYMap yMap(const M &m) - { - return ConstYMap(m); - } - - - ///\brief Map of the normSquare() of a Point-map - /// - ///Map of the \ref Point::normSquare() "normSquare()" - ///of a \ref Point "Point"-map. - template - class NormSquareMap - { - const M& _map; - public: - - typedef typename M::Value::Value Value; - typedef typename M::Key Key; - ///\e - NormSquareMap(const M &map) : _map(map) {} - Value operator[](Key k) const {return _map[k].normSquare();} - }; - - ///Returns a NormSquareMap class - - ///This function just returns a NormSquareMap class. - ///\relates NormSquareMap - template - inline NormSquareMap normSquareMap(const M &m) - { - return NormSquareMap(m); - } - - /// @} - - } //namespce dim2 - -} //namespace lemon - -#endif //LEMON_DIM2_H diff --git a/deps/lemon/lemon/dimacs.h b/deps/lemon/lemon/dimacs.h deleted file mode 100644 index 616879ffa..000000000 --- a/deps/lemon/lemon/dimacs.h +++ /dev/null @@ -1,448 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_DIMACS_H -#define LEMON_DIMACS_H - -#include -#include -#include -#include -#include -#include -/// \ingroup dimacs_group -/// \file -/// \brief DIMACS file format reader. - -namespace lemon { - - /// \addtogroup dimacs_group - /// @{ - - /// DIMACS file type descriptor. - struct DimacsDescriptor - { - ///\brief DIMACS file type enum - /// - ///DIMACS file type enum. - enum Type { - NONE, ///< Undefined type. - MIN, ///< DIMACS file type for minimum cost flow problems. - MAX, ///< DIMACS file type for maximum flow problems. - SP, ///< DIMACS file type for shostest path problems. - MAT ///< DIMACS file type for plain graphs and matching problems. - }; - ///The file type - Type type; - ///The number of nodes in the graph - int nodeNum; - ///The number of edges in the graph - int edgeNum; - int lineShift; - ///Constructor. It sets the type to \c NONE. - DimacsDescriptor() : type(NONE) {} - }; - - ///Discover the type of a DIMACS file - - ///This function starts seeking the beginning of the given file for the - ///problem type and size info. - ///The found data is returned in a special struct that can be evaluated - ///and passed to the appropriate reader function. - DimacsDescriptor dimacsType(std::istream& is) - { - DimacsDescriptor r; - std::string problem,str; - char c; - r.lineShift=0; - while (is >> c) - switch(c) - { - case 'p': - if(is >> problem >> r.nodeNum >> r.edgeNum) - { - getline(is, str); - r.lineShift++; - if(problem=="min") r.type=DimacsDescriptor::MIN; - else if(problem=="max") r.type=DimacsDescriptor::MAX; - else if(problem=="sp") r.type=DimacsDescriptor::SP; - else if(problem=="mat") r.type=DimacsDescriptor::MAT; - else throw FormatError("Unknown problem type"); - return r; - } - else - { - throw FormatError("Missing or wrong problem type declaration."); - } - break; - case 'c': - getline(is, str); - r.lineShift++; - break; - default: - throw FormatError("Unknown DIMACS declaration."); - } - throw FormatError("Missing problem type declaration."); - } - - - /// \brief DIMACS minimum cost flow reader function. - /// - /// This function reads a minimum cost flow instance from DIMACS format, - /// i.e. from a DIMACS file having a line starting with - /// \code - /// p min - /// \endcode - /// At the beginning, \c g is cleared by \c g.clear(). The supply - /// amount of the nodes are written to the \c supply node map - /// (they are signed values). The lower bounds, capacities and costs - /// of the arcs are written to the \c lower, \c capacity and \c cost - /// arc maps. - /// - /// If the capacity of an arc is less than the lower bound, it will - /// be set to "infinite" instead. The actual value of "infinite" is - /// contolled by the \c infty parameter. If it is 0 (the default value), - /// \c std::numeric_limits::infinity() will be used if available, - /// \c std::numeric_limits::max() otherwise. If \c infty is set to - /// a non-zero value, that value will be used as "infinite". - /// - /// If the file type was previously evaluated by dimacsType(), then - /// the descriptor struct should be given by the \c dest parameter. - template - void readDimacsMin(std::istream& is, - Digraph &g, - LowerMap& lower, - CapacityMap& capacity, - CostMap& cost, - SupplyMap& supply, - typename CapacityMap::Value infty = 0, - DimacsDescriptor desc=DimacsDescriptor()) - { - g.clear(); - std::vector nodes; - typename Digraph::Arc e; - std::string problem, str; - char c; - int i, j; - if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); - if(desc.type!=DimacsDescriptor::MIN) - throw FormatError("Problem type mismatch"); - - nodes.resize(desc.nodeNum + 1); - for (int k = 1; k <= desc.nodeNum; ++k) { - nodes[k] = g.addNode(); - supply.set(nodes[k], 0); - } - - typename SupplyMap::Value sup; - typename CapacityMap::Value low; - typename CapacityMap::Value cap; - typename CostMap::Value co; - typedef typename CapacityMap::Value Capacity; - if(infty==0) - infty = std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max(); - - while (is >> c) { - switch (c) { - case 'c': // comment line - getline(is, str); - break; - case 'n': // node definition line - is >> i >> sup; - getline(is, str); - supply.set(nodes[i], sup); - break; - case 'a': // arc definition line - is >> i >> j >> low >> cap >> co; - getline(is, str); - e = g.addArc(nodes[i], nodes[j]); - lower.set(e, low); - if (cap >= low) - capacity.set(e, cap); - else - capacity.set(e, infty); - cost.set(e, co); - break; - } - } - } - - template - void _readDimacs(std::istream& is, - Digraph &g, - CapacityMap& capacity, - typename Digraph::Node &s, - typename Digraph::Node &t, - typename CapacityMap::Value infty = 0, - DimacsDescriptor desc=DimacsDescriptor()) { - g.clear(); - s=t=INVALID; - std::vector nodes; - typename Digraph::Arc e; - char c, d; - int i, j; - typename CapacityMap::Value _cap; - std::string str; - nodes.resize(desc.nodeNum + 1); - for (int k = 1; k <= desc.nodeNum; ++k) { - nodes[k] = g.addNode(); - } - typedef typename CapacityMap::Value Capacity; - - if(infty==0) - infty = std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max(); - - while (is >> c) { - switch (c) { - case 'c': // comment line - getline(is, str); - break; - case 'n': // node definition line - if (desc.type==DimacsDescriptor::SP) { // shortest path problem - is >> i; - getline(is, str); - s = nodes[i]; - } - if (desc.type==DimacsDescriptor::MAX) { // max flow problem - is >> i >> d; - getline(is, str); - if (d == 's') s = nodes[i]; - if (d == 't') t = nodes[i]; - } - break; - case 'a': // arc definition line - if (desc.type==DimacsDescriptor::SP) { - is >> i >> j >> _cap; - getline(is, str); - e = g.addArc(nodes[i], nodes[j]); - capacity.set(e, _cap); - } - else if (desc.type==DimacsDescriptor::MAX) { - is >> i >> j >> _cap; - getline(is, str); - e = g.addArc(nodes[i], nodes[j]); - if (_cap >= 0) - capacity.set(e, _cap); - else - capacity.set(e, infty); - } - else { - is >> i >> j; - getline(is, str); - g.addArc(nodes[i], nodes[j]); - } - break; - } - } - } - - /// \brief DIMACS maximum flow reader function. - /// - /// This function reads a maximum flow instance from DIMACS format, - /// i.e. from a DIMACS file having a line starting with - /// \code - /// p max - /// \endcode - /// At the beginning, \c g is cleared by \c g.clear(). The arc - /// capacities are written to the \c capacity arc map and \c s and - /// \c t are set to the source and the target nodes. - /// - /// If the capacity of an arc is negative, it will - /// be set to "infinite" instead. The actual value of "infinite" is - /// contolled by the \c infty parameter. If it is 0 (the default value), - /// \c std::numeric_limits::infinity() will be used if available, - /// \c std::numeric_limits::max() otherwise. If \c infty is set to - /// a non-zero value, that value will be used as "infinite". - /// - /// If the file type was previously evaluated by dimacsType(), then - /// the descriptor struct should be given by the \c dest parameter. - template - void readDimacsMax(std::istream& is, - Digraph &g, - CapacityMap& capacity, - typename Digraph::Node &s, - typename Digraph::Node &t, - typename CapacityMap::Value infty = 0, - DimacsDescriptor desc=DimacsDescriptor()) { - if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); - if(desc.type!=DimacsDescriptor::MAX) - throw FormatError("Problem type mismatch"); - _readDimacs(is,g,capacity,s,t,infty,desc); - } - - /// \brief DIMACS shortest path reader function. - /// - /// This function reads a shortest path instance from DIMACS format, - /// i.e. from a DIMACS file having a line starting with - /// \code - /// p sp - /// \endcode - /// At the beginning, \c g is cleared by \c g.clear(). The arc - /// lengths are written to the \c length arc map and \c s is set to the - /// source node. - /// - /// If the file type was previously evaluated by dimacsType(), then - /// the descriptor struct should be given by the \c dest parameter. - template - void readDimacsSp(std::istream& is, - Digraph &g, - LengthMap& length, - typename Digraph::Node &s, - DimacsDescriptor desc=DimacsDescriptor()) { - typename Digraph::Node t; - if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); - if(desc.type!=DimacsDescriptor::SP) - throw FormatError("Problem type mismatch"); - _readDimacs(is, g, length, s, t, 0, desc); - } - - /// \brief DIMACS capacitated digraph reader function. - /// - /// This function reads an arc capacitated digraph instance from - /// DIMACS 'max' or 'sp' format. - /// At the beginning, \c g is cleared by \c g.clear() - /// and the arc capacities/lengths are written to the \c capacity - /// arc map. - /// - /// In case of the 'max' format, if the capacity of an arc is negative, - /// it will - /// be set to "infinite" instead. The actual value of "infinite" is - /// contolled by the \c infty parameter. If it is 0 (the default value), - /// \c std::numeric_limits::infinity() will be used if available, - /// \c std::numeric_limits::max() otherwise. If \c infty is set to - /// a non-zero value, that value will be used as "infinite". - /// - /// If the file type was previously evaluated by dimacsType(), then - /// the descriptor struct should be given by the \c dest parameter. - template - void readDimacsCap(std::istream& is, - Digraph &g, - CapacityMap& capacity, - typename CapacityMap::Value infty = 0, - DimacsDescriptor desc=DimacsDescriptor()) { - typename Digraph::Node u,v; - if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); - if(desc.type!=DimacsDescriptor::MAX || desc.type!=DimacsDescriptor::SP) - throw FormatError("Problem type mismatch"); - _readDimacs(is, g, capacity, u, v, infty, desc); - } - - template - typename enable_if,void>::type - _addArcEdge(Graph &g, typename Graph::Node s, typename Graph::Node t, - dummy<0> = 0) - { - g.addEdge(s,t); - } - template - typename disable_if,void>::type - _addArcEdge(Graph &g, typename Graph::Node s, typename Graph::Node t, - dummy<1> = 1) - { - g.addArc(s,t); - } - - /// \brief DIMACS plain (di)graph reader function. - /// - /// This function reads a plain (di)graph without any designated nodes - /// and maps (e.g. a matching instance) from DIMACS format, i.e. from - /// DIMACS files having a line starting with - /// \code - /// p mat - /// \endcode - /// At the beginning, \c g is cleared by \c g.clear(). - /// - /// If the file type was previously evaluated by dimacsType(), then - /// the descriptor struct should be given by the \c dest parameter. - template - void readDimacsMat(std::istream& is, Graph &g, - DimacsDescriptor desc=DimacsDescriptor()) - { - if(desc.type==DimacsDescriptor::NONE) desc=dimacsType(is); - if(desc.type!=DimacsDescriptor::MAT) - throw FormatError("Problem type mismatch"); - - g.clear(); - std::vector nodes; - char c; - int i, j; - std::string str; - nodes.resize(desc.nodeNum + 1); - for (int k = 1; k <= desc.nodeNum; ++k) { - nodes[k] = g.addNode(); - } - - while (is >> c) { - switch (c) { - case 'c': // comment line - getline(is, str); - break; - case 'n': // node definition line - break; - case 'a': // arc definition line - is >> i >> j; - getline(is, str); - _addArcEdge(g,nodes[i], nodes[j]); - break; - } - } - } - - /// DIMACS plain digraph writer function. - /// - /// This function writes a digraph without any designated nodes and - /// maps into DIMACS format, i.e. into DIMACS file having a line - /// starting with - /// \code - /// p mat - /// \endcode - /// If \c comment is not empty, then it will be printed in the first line - /// prefixed by 'c'. - template - void writeDimacsMat(std::ostream& os, const Digraph &g, - std::string comment="") { - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::ArcIt ArcIt; - - if(!comment.empty()) - os << "c " << comment << std::endl; - os << "p mat " << g.nodeNum() << " " << g.arcNum() << std::endl; - - typename Digraph::template NodeMap nodes(g); - int i = 1; - for(NodeIt v(g); v != INVALID; ++v) { - nodes.set(v, i); - ++i; - } - for(ArcIt e(g); e != INVALID; ++e) { - os << "a " << nodes[g.source(e)] << " " << nodes[g.target(e)] - << std::endl; - } - } - - /// @} - -} //namespace lemon - -#endif //LEMON_DIMACS_H diff --git a/deps/lemon/lemon/edge_set.h b/deps/lemon/lemon/edge_set.h deleted file mode 100644 index 399b7a266..000000000 --- a/deps/lemon/lemon/edge_set.h +++ /dev/null @@ -1,1420 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_EDGE_SET_H -#define LEMON_EDGE_SET_H - -#include -#include - -/// \ingroup graphs -/// \file -/// \brief ArcSet and EdgeSet classes. -/// -/// Graphs which use another graph's node-set as own. -namespace lemon { - - template - class ListArcSetBase { - public: - - typedef typename GR::Node Node; - typedef typename GR::NodeIt NodeIt; - - protected: - - struct NodeT { - int first_out, first_in; - NodeT() : first_out(-1), first_in(-1) {} - }; - - typedef typename ItemSetTraits:: - template Map::Type NodesImplBase; - - NodesImplBase* _nodes; - - struct ArcT { - Node source, target; - int next_out, next_in; - int prev_out, prev_in; - ArcT() : prev_out(-1), prev_in(-1) {} - }; - - std::vector arcs; - - int first_arc; - int first_free_arc; - - const GR* _graph; - - void initalize(const GR& graph, NodesImplBase& nodes) { - _graph = &graph; - _nodes = &nodes; - } - - public: - - class Arc { - friend class ListArcSetBase; - protected: - Arc(int _id) : id(_id) {} - int id; - public: - Arc() {} - Arc(Invalid) : id(-1) {} - bool operator==(const Arc& arc) const { return id == arc.id; } - bool operator!=(const Arc& arc) const { return id != arc.id; } - bool operator<(const Arc& arc) const { return id < arc.id; } - }; - - ListArcSetBase() : first_arc(-1), first_free_arc(-1) {} - - Node addNode() { - LEMON_ASSERT(false, - "This graph structure does not support node insertion"); - return INVALID; // avoid warning - } - - Arc addArc(const Node& u, const Node& v) { - int n; - if (first_free_arc == -1) { - n = arcs.size(); - arcs.push_back(ArcT()); - } else { - n = first_free_arc; - first_free_arc = arcs[first_free_arc].next_in; - } - arcs[n].next_in = (*_nodes)[v].first_in; - if ((*_nodes)[v].first_in != -1) { - arcs[(*_nodes)[v].first_in].prev_in = n; - } - (*_nodes)[v].first_in = n; - arcs[n].next_out = (*_nodes)[u].first_out; - if ((*_nodes)[u].first_out != -1) { - arcs[(*_nodes)[u].first_out].prev_out = n; - } - (*_nodes)[u].first_out = n; - arcs[n].source = u; - arcs[n].target = v; - return Arc(n); - } - - void erase(const Arc& arc) { - int n = arc.id; - if (arcs[n].prev_in != -1) { - arcs[arcs[n].prev_in].next_in = arcs[n].next_in; - } else { - (*_nodes)[arcs[n].target].first_in = arcs[n].next_in; - } - if (arcs[n].next_in != -1) { - arcs[arcs[n].next_in].prev_in = arcs[n].prev_in; - } - - if (arcs[n].prev_out != -1) { - arcs[arcs[n].prev_out].next_out = arcs[n].next_out; - } else { - (*_nodes)[arcs[n].source].first_out = arcs[n].next_out; - } - if (arcs[n].next_out != -1) { - arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; - } - - } - - void clear() { - Node node; - for (first(node); node != INVALID; next(node)) { - (*_nodes)[node].first_in = -1; - (*_nodes)[node].first_out = -1; - } - arcs.clear(); - first_arc = -1; - first_free_arc = -1; - } - - void first(Node& node) const { - _graph->first(node); - } - - void next(Node& node) const { - _graph->next(node); - } - - void first(Arc& arc) const { - Node node; - first(node); - while (node != INVALID && (*_nodes)[node].first_in == -1) { - next(node); - } - arc.id = (node == INVALID) ? -1 : (*_nodes)[node].first_in; - } - - void next(Arc& arc) const { - if (arcs[arc.id].next_in != -1) { - arc.id = arcs[arc.id].next_in; - } else { - Node node = arcs[arc.id].target; - next(node); - while (node != INVALID && (*_nodes)[node].first_in == -1) { - next(node); - } - arc.id = (node == INVALID) ? -1 : (*_nodes)[node].first_in; - } - } - - void firstOut(Arc& arc, const Node& node) const { - arc.id = (*_nodes)[node].first_out; - } - - void nextOut(Arc& arc) const { - arc.id = arcs[arc.id].next_out; - } - - void firstIn(Arc& arc, const Node& node) const { - arc.id = (*_nodes)[node].first_in; - } - - void nextIn(Arc& arc) const { - arc.id = arcs[arc.id].next_in; - } - - int id(const Node& node) const { return _graph->id(node); } - int id(const Arc& arc) const { return arc.id; } - - Node nodeFromId(int ix) const { return _graph->nodeFromId(ix); } - Arc arcFromId(int ix) const { return Arc(ix); } - - int maxNodeId() const { return _graph->maxNodeId(); }; - int maxArcId() const { return arcs.size() - 1; } - - Node source(const Arc& arc) const { return arcs[arc.id].source;} - Node target(const Arc& arc) const { return arcs[arc.id].target;} - - typedef typename ItemSetTraits::ItemNotifier NodeNotifier; - - NodeNotifier& notifier(Node) const { - return _graph->notifier(Node()); - } - - template - class NodeMap : public GR::template NodeMap { - typedef typename GR::template NodeMap Parent; - - public: - - explicit NodeMap(const ListArcSetBase& arcset) - : Parent(*arcset._graph) {} - - NodeMap(const ListArcSetBase& arcset, const V& value) - : Parent(*arcset._graph, value) {} - - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - }; - - /// \ingroup graphs - /// - /// \brief Digraph using a node set of another digraph or graph and - /// an own arc set. - /// - /// This structure can be used to establish another directed graph - /// over a node set of an existing one. This class uses the same - /// Node type as the underlying graph, and each valid node of the - /// original graph is valid in this arc set, therefore the node - /// objects of the original graph can be used directly with this - /// class. The node handling functions (id handling, observing, and - /// iterators) works equivalently as in the original graph. - /// - /// This implementation is based on doubly-linked lists, from each - /// node the outgoing and the incoming arcs make up lists, therefore - /// one arc can be erased in constant time. It also makes possible, - /// that node can be removed from the underlying graph, in this case - /// all arcs incident to the given node is erased from the arc set. - /// - /// This class fully conforms to the \ref concepts::Digraph - /// "Digraph" concept. - /// It provides only linear time counting for nodes and arcs. - /// - /// \param GR The type of the graph which shares its node set with - /// this class. Its interface must conform to the - /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph" - /// concept. - template - class ListArcSet : public ArcSetExtender > { - typedef ArcSetExtender > Parent; - - public: - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - - typedef typename Parent::NodesImplBase NodesImplBase; - - void eraseNode(const Node& node) { - Arc arc; - Parent::firstOut(arc, node); - while (arc != INVALID ) { - erase(arc); - Parent::firstOut(arc, node); - } - - Parent::firstIn(arc, node); - while (arc != INVALID ) { - erase(arc); - Parent::firstIn(arc, node); - } - } - - void clearNodes() { - Parent::clear(); - } - - class NodesImpl : public NodesImplBase { - typedef NodesImplBase Parent; - - public: - NodesImpl(const GR& graph, ListArcSet& arcset) - : Parent(graph), _arcset(arcset) {} - - virtual ~NodesImpl() {} - - protected: - - virtual void erase(const Node& node) { - _arcset.eraseNode(node); - Parent::erase(node); - } - virtual void erase(const std::vector& nodes) { - for (int i = 0; i < int(nodes.size()); ++i) { - _arcset.eraseNode(nodes[i]); - } - Parent::erase(nodes); - } - virtual void clear() { - _arcset.clearNodes(); - Parent::clear(); - } - - private: - ListArcSet& _arcset; - }; - - NodesImpl _nodes; - - public: - - /// \brief Constructor of the ArcSet. - /// - /// Constructor of the ArcSet. - ListArcSet(const GR& graph) : _nodes(graph, *this) { - Parent::initalize(graph, _nodes); - } - - /// \brief Add a new arc to the digraph. - /// - /// Add a new arc to the digraph with source node \c s - /// and target node \c t. - /// \return The new arc. - Arc addArc(const Node& s, const Node& t) { - return Parent::addArc(s, t); - } - - /// \brief Erase an arc from the digraph. - /// - /// Erase an arc \c a from the digraph. - void erase(const Arc& a) { - return Parent::erase(a); - } - - }; - - template - class ListEdgeSetBase { - public: - - typedef typename GR::Node Node; - typedef typename GR::NodeIt NodeIt; - - protected: - - struct NodeT { - int first_out; - NodeT() : first_out(-1) {} - }; - - typedef typename ItemSetTraits:: - template Map::Type NodesImplBase; - - NodesImplBase* _nodes; - - struct ArcT { - Node target; - int prev_out, next_out; - ArcT() : prev_out(-1), next_out(-1) {} - }; - - std::vector arcs; - - int first_arc; - int first_free_arc; - - const GR* _graph; - - void initalize(const GR& graph, NodesImplBase& nodes) { - _graph = &graph; - _nodes = &nodes; - } - - public: - - class Edge { - friend class ListEdgeSetBase; - protected: - - int id; - explicit Edge(int _id) { id = _id;} - - public: - Edge() {} - Edge (Invalid) { id = -1; } - bool operator==(const Edge& arc) const {return id == arc.id;} - bool operator!=(const Edge& arc) const {return id != arc.id;} - bool operator<(const Edge& arc) const {return id < arc.id;} - }; - - class Arc { - friend class ListEdgeSetBase; - protected: - Arc(int _id) : id(_id) {} - int id; - public: - operator Edge() const { return edgeFromId(id / 2); } - - Arc() {} - Arc(Invalid) : id(-1) {} - bool operator==(const Arc& arc) const { return id == arc.id; } - bool operator!=(const Arc& arc) const { return id != arc.id; } - bool operator<(const Arc& arc) const { return id < arc.id; } - }; - - ListEdgeSetBase() : first_arc(-1), first_free_arc(-1) {} - - Node addNode() { - LEMON_ASSERT(false, - "This graph structure does not support node insertion"); - return INVALID; // avoid warning - } - - Edge addEdge(const Node& u, const Node& v) { - int n; - - if (first_free_arc == -1) { - n = arcs.size(); - arcs.push_back(ArcT()); - arcs.push_back(ArcT()); - } else { - n = first_free_arc; - first_free_arc = arcs[n].next_out; - } - - arcs[n].target = u; - arcs[n | 1].target = v; - - arcs[n].next_out = (*_nodes)[v].first_out; - if ((*_nodes)[v].first_out != -1) { - arcs[(*_nodes)[v].first_out].prev_out = n; - } - (*_nodes)[v].first_out = n; - arcs[n].prev_out = -1; - - if ((*_nodes)[u].first_out != -1) { - arcs[(*_nodes)[u].first_out].prev_out = (n | 1); - } - arcs[n | 1].next_out = (*_nodes)[u].first_out; - (*_nodes)[u].first_out = (n | 1); - arcs[n | 1].prev_out = -1; - - return Edge(n / 2); - } - - void erase(const Edge& arc) { - int n = arc.id * 2; - - if (arcs[n].next_out != -1) { - arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; - } - - if (arcs[n].prev_out != -1) { - arcs[arcs[n].prev_out].next_out = arcs[n].next_out; - } else { - (*_nodes)[arcs[n | 1].target].first_out = arcs[n].next_out; - } - - if (arcs[n | 1].next_out != -1) { - arcs[arcs[n | 1].next_out].prev_out = arcs[n | 1].prev_out; - } - - if (arcs[n | 1].prev_out != -1) { - arcs[arcs[n | 1].prev_out].next_out = arcs[n | 1].next_out; - } else { - (*_nodes)[arcs[n].target].first_out = arcs[n | 1].next_out; - } - - arcs[n].next_out = first_free_arc; - first_free_arc = n; - - } - - void clear() { - Node node; - for (first(node); node != INVALID; next(node)) { - (*_nodes)[node].first_out = -1; - } - arcs.clear(); - first_arc = -1; - first_free_arc = -1; - } - - void first(Node& node) const { - _graph->first(node); - } - - void next(Node& node) const { - _graph->next(node); - } - - void first(Arc& arc) const { - Node node; - first(node); - while (node != INVALID && (*_nodes)[node].first_out == -1) { - next(node); - } - arc.id = (node == INVALID) ? -1 : (*_nodes)[node].first_out; - } - - void next(Arc& arc) const { - if (arcs[arc.id].next_out != -1) { - arc.id = arcs[arc.id].next_out; - } else { - Node node = arcs[arc.id ^ 1].target; - next(node); - while(node != INVALID && (*_nodes)[node].first_out == -1) { - next(node); - } - arc.id = (node == INVALID) ? -1 : (*_nodes)[node].first_out; - } - } - - void first(Edge& edge) const { - Node node; - first(node); - while (node != INVALID) { - edge.id = (*_nodes)[node].first_out; - while ((edge.id & 1) != 1) { - edge.id = arcs[edge.id].next_out; - } - if (edge.id != -1) { - edge.id /= 2; - return; - } - next(node); - } - edge.id = -1; - } - - void next(Edge& edge) const { - Node node = arcs[edge.id * 2].target; - edge.id = arcs[(edge.id * 2) | 1].next_out; - while ((edge.id & 1) != 1) { - edge.id = arcs[edge.id].next_out; - } - if (edge.id != -1) { - edge.id /= 2; - return; - } - next(node); - while (node != INVALID) { - edge.id = (*_nodes)[node].first_out; - while ((edge.id & 1) != 1) { - edge.id = arcs[edge.id].next_out; - } - if (edge.id != -1) { - edge.id /= 2; - return; - } - next(node); - } - edge.id = -1; - } - - void firstOut(Arc& arc, const Node& node) const { - arc.id = (*_nodes)[node].first_out; - } - - void nextOut(Arc& arc) const { - arc.id = arcs[arc.id].next_out; - } - - void firstIn(Arc& arc, const Node& node) const { - arc.id = (((*_nodes)[node].first_out) ^ 1); - if (arc.id == -2) arc.id = -1; - } - - void nextIn(Arc& arc) const { - arc.id = ((arcs[arc.id ^ 1].next_out) ^ 1); - if (arc.id == -2) arc.id = -1; - } - - void firstInc(Edge &arc, bool& dir, const Node& node) const { - int de = (*_nodes)[node].first_out; - if (de != -1 ) { - arc.id = de / 2; - dir = ((de & 1) == 1); - } else { - arc.id = -1; - dir = true; - } - } - void nextInc(Edge &arc, bool& dir) const { - int de = (arcs[(arc.id * 2) | (dir ? 1 : 0)].next_out); - if (de != -1 ) { - arc.id = de / 2; - dir = ((de & 1) == 1); - } else { - arc.id = -1; - dir = true; - } - } - - static bool direction(Arc arc) { - return (arc.id & 1) == 1; - } - - static Arc direct(Edge edge, bool dir) { - return Arc(edge.id * 2 + (dir ? 1 : 0)); - } - - int id(const Node& node) const { return _graph->id(node); } - static int id(Arc e) { return e.id; } - static int id(Edge e) { return e.id; } - - Node nodeFromId(int id) const { return _graph->nodeFromId(id); } - static Arc arcFromId(int id) { return Arc(id);} - static Edge edgeFromId(int id) { return Edge(id);} - - int maxNodeId() const { return _graph->maxNodeId(); }; - int maxEdgeId() const { return arcs.size() / 2 - 1; } - int maxArcId() const { return arcs.size()-1; } - - Node source(Arc e) const { return arcs[e.id ^ 1].target; } - Node target(Arc e) const { return arcs[e.id].target; } - - Node u(Edge e) const { return arcs[2 * e.id].target; } - Node v(Edge e) const { return arcs[2 * e.id + 1].target; } - - typedef typename ItemSetTraits::ItemNotifier NodeNotifier; - - NodeNotifier& notifier(Node) const { - return _graph->notifier(Node()); - } - - template - class NodeMap : public GR::template NodeMap { - typedef typename GR::template NodeMap Parent; - - public: - - explicit NodeMap(const ListEdgeSetBase& arcset) - : Parent(*arcset._graph) {} - - NodeMap(const ListEdgeSetBase& arcset, const V& value) - : Parent(*arcset._graph, value) {} - - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - }; - - /// \ingroup graphs - /// - /// \brief Graph using a node set of another digraph or graph and an - /// own edge set. - /// - /// This structure can be used to establish another graph over a - /// node set of an existing one. This class uses the same Node type - /// as the underlying graph, and each valid node of the original - /// graph is valid in this arc set, therefore the node objects of - /// the original graph can be used directly with this class. The - /// node handling functions (id handling, observing, and iterators) - /// works equivalently as in the original graph. - /// - /// This implementation is based on doubly-linked lists, from each - /// node the incident edges make up lists, therefore one edge can be - /// erased in constant time. It also makes possible, that node can - /// be removed from the underlying graph, in this case all edges - /// incident to the given node is erased from the arc set. - /// - /// This class fully conforms to the \ref concepts::Graph "Graph" - /// concept. - /// It provides only linear time counting for nodes, edges and arcs. - /// - /// \param GR The type of the graph which shares its node set - /// with this class. Its interface must conform to the - /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph" - /// concept. - template - class ListEdgeSet : public EdgeSetExtender > { - typedef EdgeSetExtender > Parent; - - public: - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - typedef typename Parent::Edge Edge; - - typedef typename Parent::NodesImplBase NodesImplBase; - - void eraseNode(const Node& node) { - Arc arc; - Parent::firstOut(arc, node); - while (arc != INVALID ) { - erase(arc); - Parent::firstOut(arc, node); - } - - } - - void clearNodes() { - Parent::clear(); - } - - class NodesImpl : public NodesImplBase { - typedef NodesImplBase Parent; - - public: - NodesImpl(const GR& graph, ListEdgeSet& arcset) - : Parent(graph), _arcset(arcset) {} - - virtual ~NodesImpl() {} - - protected: - - virtual void erase(const Node& node) { - _arcset.eraseNode(node); - Parent::erase(node); - } - virtual void erase(const std::vector& nodes) { - for (int i = 0; i < int(nodes.size()); ++i) { - _arcset.eraseNode(nodes[i]); - } - Parent::erase(nodes); - } - virtual void clear() { - _arcset.clearNodes(); - Parent::clear(); - } - - private: - ListEdgeSet& _arcset; - }; - - NodesImpl _nodes; - - public: - - /// \brief Constructor of the EdgeSet. - /// - /// Constructor of the EdgeSet. - ListEdgeSet(const GR& graph) : _nodes(graph, *this) { - Parent::initalize(graph, _nodes); - } - - /// \brief Add a new edge to the graph. - /// - /// Add a new edge to the graph with node \c u - /// and node \c v endpoints. - /// \return The new edge. - Edge addEdge(const Node& u, const Node& v) { - return Parent::addEdge(u, v); - } - - /// \brief Erase an edge from the graph. - /// - /// Erase the edge \c e from the graph. - void erase(const Edge& e) { - return Parent::erase(e); - } - - }; - - template - class SmartArcSetBase { - public: - - typedef typename GR::Node Node; - typedef typename GR::NodeIt NodeIt; - - protected: - - struct NodeT { - int first_out, first_in; - NodeT() : first_out(-1), first_in(-1) {} - }; - - typedef typename ItemSetTraits:: - template Map::Type NodesImplBase; - - NodesImplBase* _nodes; - - struct ArcT { - Node source, target; - int next_out, next_in; - ArcT() {} - }; - - std::vector arcs; - - const GR* _graph; - - void initalize(const GR& graph, NodesImplBase& nodes) { - _graph = &graph; - _nodes = &nodes; - } - - public: - - class Arc { - friend class SmartArcSetBase; - protected: - Arc(int _id) : id(_id) {} - int id; - public: - Arc() {} - Arc(Invalid) : id(-1) {} - bool operator==(const Arc& arc) const { return id == arc.id; } - bool operator!=(const Arc& arc) const { return id != arc.id; } - bool operator<(const Arc& arc) const { return id < arc.id; } - }; - - SmartArcSetBase() {} - - Node addNode() { - LEMON_ASSERT(false, - "This graph structure does not support node insertion"); - return INVALID; // avoid warning - } - - Arc addArc(const Node& u, const Node& v) { - int n = arcs.size(); - arcs.push_back(ArcT()); - arcs[n].next_in = (*_nodes)[v].first_in; - (*_nodes)[v].first_in = n; - arcs[n].next_out = (*_nodes)[u].first_out; - (*_nodes)[u].first_out = n; - arcs[n].source = u; - arcs[n].target = v; - return Arc(n); - } - - void clear() { - Node node; - for (first(node); node != INVALID; next(node)) { - (*_nodes)[node].first_in = -1; - (*_nodes)[node].first_out = -1; - } - arcs.clear(); - } - - void first(Node& node) const { - _graph->first(node); - } - - void next(Node& node) const { - _graph->next(node); - } - - void first(Arc& arc) const { - arc.id = arcs.size() - 1; - } - - static void next(Arc& arc) { - --arc.id; - } - - void firstOut(Arc& arc, const Node& node) const { - arc.id = (*_nodes)[node].first_out; - } - - void nextOut(Arc& arc) const { - arc.id = arcs[arc.id].next_out; - } - - void firstIn(Arc& arc, const Node& node) const { - arc.id = (*_nodes)[node].first_in; - } - - void nextIn(Arc& arc) const { - arc.id = arcs[arc.id].next_in; - } - - int id(const Node& node) const { return _graph->id(node); } - int id(const Arc& arc) const { return arc.id; } - - Node nodeFromId(int ix) const { return _graph->nodeFromId(ix); } - Arc arcFromId(int ix) const { return Arc(ix); } - - int maxNodeId() const { return _graph->maxNodeId(); }; - int maxArcId() const { return arcs.size() - 1; } - - Node source(const Arc& arc) const { return arcs[arc.id].source;} - Node target(const Arc& arc) const { return arcs[arc.id].target;} - - typedef typename ItemSetTraits::ItemNotifier NodeNotifier; - - NodeNotifier& notifier(Node) const { - return _graph->notifier(Node()); - } - - template - class NodeMap : public GR::template NodeMap { - typedef typename GR::template NodeMap Parent; - - public: - - explicit NodeMap(const SmartArcSetBase& arcset) - : Parent(*arcset._graph) { } - - NodeMap(const SmartArcSetBase& arcset, const V& value) - : Parent(*arcset._graph, value) { } - - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - }; - - - /// \ingroup graphs - /// - /// \brief Digraph using a node set of another digraph or graph and - /// an own arc set. - /// - /// This structure can be used to establish another directed graph - /// over a node set of an existing one. This class uses the same - /// Node type as the underlying graph, and each valid node of the - /// original graph is valid in this arc set, therefore the node - /// objects of the original graph can be used directly with this - /// class. The node handling functions (id handling, observing, and - /// iterators) works equivalently as in the original graph. - /// - /// \param GR The type of the graph which shares its node set with - /// this class. Its interface must conform to the - /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph" - /// concept. - /// - /// This implementation is slightly faster than the \c ListArcSet, - /// because it uses continuous storage for arcs and it uses just - /// single-linked lists for enumerate outgoing and incoming - /// arcs. Therefore the arcs cannot be erased from the arc sets. - /// - /// This class fully conforms to the \ref concepts::Digraph "Digraph" - /// concept. - /// It provides only linear time counting for nodes and arcs. - /// - /// \warning If a node is erased from the underlying graph and this - /// node is the source or target of one arc in the arc set, then - /// the arc set is invalidated, and it cannot be used anymore. The - /// validity can be checked with the \c valid() member function. - template - class SmartArcSet : public ArcSetExtender > { - typedef ArcSetExtender > Parent; - - public: - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - - protected: - - typedef typename Parent::NodesImplBase NodesImplBase; - - void eraseNode(const Node& node) { - if (typename Parent::InArcIt(*this, node) == INVALID && - typename Parent::OutArcIt(*this, node) == INVALID) { - return; - } - throw typename NodesImplBase::Notifier::ImmediateDetach(); - } - - void clearNodes() { - Parent::clear(); - } - - class NodesImpl : public NodesImplBase { - typedef NodesImplBase Parent; - - public: - NodesImpl(const GR& graph, SmartArcSet& arcset) - : Parent(graph), _arcset(arcset) {} - - virtual ~NodesImpl() {} - - bool attached() const { - return Parent::attached(); - } - - protected: - - virtual void erase(const Node& node) { - try { - _arcset.eraseNode(node); - Parent::erase(node); - } catch (const typename NodesImplBase::Notifier::ImmediateDetach&) { - Parent::clear(); - throw; - } - } - virtual void erase(const std::vector& nodes) { - try { - for (int i = 0; i < int(nodes.size()); ++i) { - _arcset.eraseNode(nodes[i]); - } - Parent::erase(nodes); - } catch (const typename NodesImplBase::Notifier::ImmediateDetach&) { - Parent::clear(); - throw; - } - } - virtual void clear() { - _arcset.clearNodes(); - Parent::clear(); - } - - private: - SmartArcSet& _arcset; - }; - - NodesImpl _nodes; - - public: - - /// \brief Constructor of the ArcSet. - /// - /// Constructor of the ArcSet. - SmartArcSet(const GR& graph) : _nodes(graph, *this) { - Parent::initalize(graph, _nodes); - } - - /// \brief Add a new arc to the digraph. - /// - /// Add a new arc to the digraph with source node \c s - /// and target node \c t. - /// \return The new arc. - Arc addArc(const Node& s, const Node& t) { - return Parent::addArc(s, t); - } - - /// \brief Validity check - /// - /// This functions gives back false if the ArcSet is - /// invalidated. It occurs when a node in the underlying graph is - /// erased and it is not isolated in the ArcSet. - bool valid() const { - return _nodes.attached(); - } - - }; - - - template - class SmartEdgeSetBase { - public: - - typedef typename GR::Node Node; - typedef typename GR::NodeIt NodeIt; - - protected: - - struct NodeT { - int first_out; - NodeT() : first_out(-1) {} - }; - - typedef typename ItemSetTraits:: - template Map::Type NodesImplBase; - - NodesImplBase* _nodes; - - struct ArcT { - Node target; - int next_out; - ArcT() {} - }; - - std::vector arcs; - - const GR* _graph; - - void initalize(const GR& graph, NodesImplBase& nodes) { - _graph = &graph; - _nodes = &nodes; - } - - public: - - class Edge { - friend class SmartEdgeSetBase; - protected: - - int id; - explicit Edge(int _id) { id = _id;} - - public: - Edge() {} - Edge (Invalid) { id = -1; } - bool operator==(const Edge& arc) const {return id == arc.id;} - bool operator!=(const Edge& arc) const {return id != arc.id;} - bool operator<(const Edge& arc) const {return id < arc.id;} - }; - - class Arc { - friend class SmartEdgeSetBase; - protected: - Arc(int _id) : id(_id) {} - int id; - public: - operator Edge() const { return edgeFromId(id / 2); } - - Arc() {} - Arc(Invalid) : id(-1) {} - bool operator==(const Arc& arc) const { return id == arc.id; } - bool operator!=(const Arc& arc) const { return id != arc.id; } - bool operator<(const Arc& arc) const { return id < arc.id; } - }; - - SmartEdgeSetBase() {} - - Node addNode() { - LEMON_ASSERT(false, - "This graph structure does not support node insertion"); - return INVALID; // avoid warning - } - - Edge addEdge(const Node& u, const Node& v) { - int n = arcs.size(); - arcs.push_back(ArcT()); - arcs.push_back(ArcT()); - - arcs[n].target = u; - arcs[n | 1].target = v; - - arcs[n].next_out = (*_nodes)[v].first_out; - (*_nodes)[v].first_out = n; - - arcs[n | 1].next_out = (*_nodes)[u].first_out; - (*_nodes)[u].first_out = (n | 1); - - return Edge(n / 2); - } - - void clear() { - Node node; - for (first(node); node != INVALID; next(node)) { - (*_nodes)[node].first_out = -1; - } - arcs.clear(); - } - - void first(Node& node) const { - _graph->first(node); - } - - void next(Node& node) const { - _graph->next(node); - } - - void first(Arc& arc) const { - arc.id = arcs.size() - 1; - } - - static void next(Arc& arc) { - --arc.id; - } - - void first(Edge& arc) const { - arc.id = arcs.size() / 2 - 1; - } - - static void next(Edge& arc) { - --arc.id; - } - - void firstOut(Arc& arc, const Node& node) const { - arc.id = (*_nodes)[node].first_out; - } - - void nextOut(Arc& arc) const { - arc.id = arcs[arc.id].next_out; - } - - void firstIn(Arc& arc, const Node& node) const { - arc.id = (((*_nodes)[node].first_out) ^ 1); - if (arc.id == -2) arc.id = -1; - } - - void nextIn(Arc& arc) const { - arc.id = ((arcs[arc.id ^ 1].next_out) ^ 1); - if (arc.id == -2) arc.id = -1; - } - - void firstInc(Edge &arc, bool& dir, const Node& node) const { - int de = (*_nodes)[node].first_out; - if (de != -1 ) { - arc.id = de / 2; - dir = ((de & 1) == 1); - } else { - arc.id = -1; - dir = true; - } - } - void nextInc(Edge &arc, bool& dir) const { - int de = (arcs[(arc.id * 2) | (dir ? 1 : 0)].next_out); - if (de != -1 ) { - arc.id = de / 2; - dir = ((de & 1) == 1); - } else { - arc.id = -1; - dir = true; - } - } - - static bool direction(Arc arc) { - return (arc.id & 1) == 1; - } - - static Arc direct(Edge edge, bool dir) { - return Arc(edge.id * 2 + (dir ? 1 : 0)); - } - - int id(Node node) const { return _graph->id(node); } - static int id(Arc arc) { return arc.id; } - static int id(Edge arc) { return arc.id; } - - Node nodeFromId(int id) const { return _graph->nodeFromId(id); } - static Arc arcFromId(int id) { return Arc(id); } - static Edge edgeFromId(int id) { return Edge(id);} - - int maxNodeId() const { return _graph->maxNodeId(); }; - int maxArcId() const { return arcs.size() - 1; } - int maxEdgeId() const { return arcs.size() / 2 - 1; } - - Node source(Arc e) const { return arcs[e.id ^ 1].target; } - Node target(Arc e) const { return arcs[e.id].target; } - - Node u(Edge e) const { return arcs[2 * e.id].target; } - Node v(Edge e) const { return arcs[2 * e.id + 1].target; } - - typedef typename ItemSetTraits::ItemNotifier NodeNotifier; - - NodeNotifier& notifier(Node) const { - return _graph->notifier(Node()); - } - - template - class NodeMap : public GR::template NodeMap { - typedef typename GR::template NodeMap Parent; - - public: - - explicit NodeMap(const SmartEdgeSetBase& arcset) - : Parent(*arcset._graph) { } - - NodeMap(const SmartEdgeSetBase& arcset, const V& value) - : Parent(*arcset._graph, value) { } - - NodeMap& operator=(const NodeMap& cmap) { - return operator=(cmap); - } - - template - NodeMap& operator=(const CMap& cmap) { - Parent::operator=(cmap); - return *this; - } - }; - - }; - - /// \ingroup graphs - /// - /// \brief Graph using a node set of another digraph or graph and an - /// own edge set. - /// - /// This structure can be used to establish another graph over a - /// node set of an existing one. This class uses the same Node type - /// as the underlying graph, and each valid node of the original - /// graph is valid in this arc set, therefore the node objects of - /// the original graph can be used directly with this class. The - /// node handling functions (id handling, observing, and iterators) - /// works equivalently as in the original graph. - /// - /// \param GR The type of the graph which shares its node set - /// with this class. Its interface must conform to the - /// \ref concepts::Digraph "Digraph" or \ref concepts::Graph "Graph" - /// concept. - /// - /// This implementation is slightly faster than the \c ListEdgeSet, - /// because it uses continuous storage for edges and it uses just - /// single-linked lists for enumerate incident edges. Therefore the - /// edges cannot be erased from the edge sets. - /// - /// This class fully conforms to the \ref concepts::Graph "Graph" - /// concept. - /// It provides only linear time counting for nodes, edges and arcs. - /// - /// \warning If a node is erased from the underlying graph and this - /// node is incident to one edge in the edge set, then the edge set - /// is invalidated, and it cannot be used anymore. The validity can - /// be checked with the \c valid() member function. - template - class SmartEdgeSet : public EdgeSetExtender > { - typedef EdgeSetExtender > Parent; - - public: - - typedef typename Parent::Node Node; - typedef typename Parent::Arc Arc; - typedef typename Parent::Edge Edge; - - protected: - - typedef typename Parent::NodesImplBase NodesImplBase; - - void eraseNode(const Node& node) { - if (typename Parent::IncEdgeIt(*this, node) == INVALID) { - return; - } - throw typename NodesImplBase::Notifier::ImmediateDetach(); - } - - void clearNodes() { - Parent::clear(); - } - - class NodesImpl : public NodesImplBase { - typedef NodesImplBase Parent; - - public: - NodesImpl(const GR& graph, SmartEdgeSet& arcset) - : Parent(graph), _arcset(arcset) {} - - virtual ~NodesImpl() {} - - bool attached() const { - return Parent::attached(); - } - - protected: - - virtual void erase(const Node& node) { - try { - _arcset.eraseNode(node); - Parent::erase(node); - } catch (const typename NodesImplBase::Notifier::ImmediateDetach&) { - Parent::clear(); - throw; - } - } - virtual void erase(const std::vector& nodes) { - try { - for (int i = 0; i < int(nodes.size()); ++i) { - _arcset.eraseNode(nodes[i]); - } - Parent::erase(nodes); - } catch (const typename NodesImplBase::Notifier::ImmediateDetach&) { - Parent::clear(); - throw; - } - } - virtual void clear() { - _arcset.clearNodes(); - Parent::clear(); - } - - private: - SmartEdgeSet& _arcset; - }; - - NodesImpl _nodes; - - public: - - /// \brief Constructor of the EdgeSet. - /// - /// Constructor of the EdgeSet. - SmartEdgeSet(const GR& graph) : _nodes(graph, *this) { - Parent::initalize(graph, _nodes); - } - - /// \brief Add a new edge to the graph. - /// - /// Add a new edge to the graph with node \c u - /// and node \c v endpoints. - /// \return The new edge. - Edge addEdge(const Node& u, const Node& v) { - return Parent::addEdge(u, v); - } - - /// \brief Validity check - /// - /// This functions gives back false if the EdgeSet is - /// invalidated. It occurs when a node in the underlying graph is - /// erased and it is not isolated in the EdgeSet. - bool valid() const { - return _nodes.attached(); - } - - }; - -} - -#endif diff --git a/deps/lemon/lemon/edmonds_karp.h b/deps/lemon/lemon/edmonds_karp.h deleted file mode 100644 index 92af3cba3..000000000 --- a/deps/lemon/lemon/edmonds_karp.h +++ /dev/null @@ -1,556 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_EDMONDS_KARP_H -#define LEMON_EDMONDS_KARP_H - -/// \file -/// \ingroup max_flow -/// \brief Implementation of the Edmonds-Karp algorithm. - -#include -#include - -namespace lemon { - - /// \brief Default traits class of EdmondsKarp class. - /// - /// Default traits class of EdmondsKarp class. - /// \param GR Digraph type. - /// \param CAP Type of capacity map. - template - struct EdmondsKarpDefaultTraits { - - /// \brief The digraph type the algorithm runs on. - typedef GR Digraph; - - /// \brief The type of the map that stores the arc capacities. - /// - /// The type of the map that stores the arc capacities. - /// It must meet the \ref concepts::ReadMap "ReadMap" concept. - typedef CAP CapacityMap; - - /// \brief The type of the flow values. - typedef typename CapacityMap::Value Value; - - /// \brief The type of the map that stores the flow values. - /// - /// The type of the map that stores the flow values. - /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. -#ifdef DOXYGEN - typedef GR::ArcMap FlowMap; -#else - typedef typename Digraph::template ArcMap FlowMap; -#endif - - /// \brief Instantiates a FlowMap. - /// - /// This function instantiates a \ref FlowMap. - /// \param digraph The digraph for which we would like to define - /// the flow map. - static FlowMap* createFlowMap(const Digraph& digraph) { - return new FlowMap(digraph); - } - - /// \brief The tolerance used by the algorithm - /// - /// The tolerance used by the algorithm to handle inexact computation. - typedef lemon::Tolerance Tolerance; - - }; - - /// \ingroup max_flow - /// - /// \brief Edmonds-Karp algorithms class. - /// - /// This class provides an implementation of the \e Edmonds-Karp \e - /// algorithm producing a \ref max_flow "flow of maximum value" in a - /// digraph \cite clrs01algorithms, \cite amo93networkflows, - /// \cite edmondskarp72theoretical. - /// The Edmonds-Karp algorithm is slower than the Preflow - /// algorithm, but it has an advantage of the step-by-step execution - /// control with feasible flow solutions. The \e source node, the \e - /// target node, the \e capacity of the arcs and the \e starting \e - /// flow value of the arcs should be passed to the algorithm - /// through the constructor. - /// - /// The time complexity of the algorithm is \f$ O(nm^2) \f$ in - /// worst case. Always try the Preflow algorithm instead of this if - /// you just want to compute the optimal flow. - /// - /// \tparam GR The type of the digraph the algorithm runs on. - /// \tparam CAP The type of the capacity map. The default map - /// type is \ref concepts::Digraph::ArcMap "GR::ArcMap". - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref EdmondsKarpDefaultTraits - /// "EdmondsKarpDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. - -#ifdef DOXYGEN - template -#else - template , - typename TR = EdmondsKarpDefaultTraits > -#endif - class EdmondsKarp { - public: - - /// \brief The \ref lemon::EdmondsKarpDefaultTraits "traits class" - /// of the algorithm. - typedef TR Traits; - /// The type of the digraph the algorithm runs on. - typedef typename Traits::Digraph Digraph; - /// The type of the capacity map. - typedef typename Traits::CapacityMap CapacityMap; - /// The type of the flow values. - typedef typename Traits::Value Value; - - /// The type of the flow map. - typedef typename Traits::FlowMap FlowMap; - /// The type of the tolerance. - typedef typename Traits::Tolerance Tolerance; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - typedef typename Digraph::template NodeMap PredMap; - - const Digraph& _graph; - const CapacityMap* _capacity; - - Node _source, _target; - - FlowMap* _flow; - bool _local_flow; - - PredMap* _pred; - std::vector _queue; - - Tolerance _tolerance; - Value _flow_value; - - void createStructures() { - if (!_flow) { - _flow = Traits::createFlowMap(_graph); - _local_flow = true; - } - if (!_pred) { - _pred = new PredMap(_graph); - } - _queue.resize(countNodes(_graph)); - } - - void destroyStructures() { - if (_local_flow) { - delete _flow; - } - if (_pred) { - delete _pred; - } - } - - public: - - typedef EdmondsKarp Create; - - ///\name Named template parameters - - ///@{ - - template - struct SetFlowMapTraits : public Traits { - typedef T FlowMap; - static FlowMap *createFlowMap(const Digraph&) { - LEMON_ASSERT(false, "FlowMap is not initialized"); - return 0; - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// FlowMap type - /// - /// \ref named-templ-param "Named parameter" for setting FlowMap - /// type - template - struct SetFlowMap - : public EdmondsKarp > { - typedef EdmondsKarp > Create; - }; - - /// @} - - protected: - - EdmondsKarp() {} - - public: - - /// \brief The constructor of the class. - /// - /// The constructor of the class. - /// \param digraph The digraph the algorithm runs on. - /// \param capacity The capacity of the arcs. - /// \param source The source node. - /// \param target The target node. - EdmondsKarp(const Digraph& digraph, const CapacityMap& capacity, - Node source, Node target) - : _graph(digraph), _capacity(&capacity), _source(source), _target(target), - _flow(0), _local_flow(false), _pred(0), _tolerance(), _flow_value() - { - LEMON_ASSERT(_source != _target, - "Flow source and target are the same nodes."); - } - - /// \brief Destructor. - /// - /// Destructor. - ~EdmondsKarp() { - destroyStructures(); - } - - /// \brief Sets the capacity map. - /// - /// Sets the capacity map. - /// \return (*this) - EdmondsKarp& capacityMap(const CapacityMap& map) { - _capacity = ↦ - return *this; - } - - /// \brief Sets the flow map. - /// - /// Sets the flow map. - /// If you don't use this function before calling \ref run() or - /// \ref init(), an instance will be allocated automatically. - /// The destructor deallocates this automatically allocated map, - /// of course. - /// \return (*this) - EdmondsKarp& flowMap(FlowMap& map) { - if (_local_flow) { - delete _flow; - _local_flow = false; - } - _flow = ↦ - return *this; - } - - /// \brief Sets the source node. - /// - /// Sets the source node. - /// \return (*this) - EdmondsKarp& source(const Node& node) { - _source = node; - return *this; - } - - /// \brief Sets the target node. - /// - /// Sets the target node. - /// \return (*this) - EdmondsKarp& target(const Node& node) { - _target = node; - return *this; - } - - /// \brief Sets the tolerance used by algorithm. - /// - /// Sets the tolerance used by algorithm. - /// \return (*this) - EdmondsKarp& tolerance(const Tolerance& tolerance) { - _tolerance = tolerance; - return *this; - } - - /// \brief Returns a const reference to the tolerance. - /// - /// Returns a const reference to the tolerance object used by - /// the algorithm. - const Tolerance& tolerance() const { - return _tolerance; - } - - /// \name Execution control - /// The simplest way to execute the algorithm is to use \ref run().\n - /// If you need better control on the initial solution or the execution, - /// you have to call one of the \ref init() functions first, then - /// \ref start() or multiple times the \ref augment() function. - - ///@{ - - /// \brief Initializes the algorithm. - /// - /// Initializes the internal data structures and sets the initial - /// flow to zero on each arc. - void init() { - createStructures(); - for (ArcIt it(_graph); it != INVALID; ++it) { - _flow->set(it, 0); - } - _flow_value = 0; - } - - /// \brief Initializes the algorithm using the given flow map. - /// - /// Initializes the internal data structures and sets the initial - /// flow to the given \c flowMap. The \c flowMap should - /// contain a feasible flow, i.e. at each node excluding the source - /// and the target, the incoming flow should be equal to the - /// outgoing flow. - template - void init(const FlowMap& flowMap) { - createStructures(); - for (ArcIt e(_graph); e != INVALID; ++e) { - _flow->set(e, flowMap[e]); - } - _flow_value = 0; - for (OutArcIt jt(_graph, _source); jt != INVALID; ++jt) { - _flow_value += (*_flow)[jt]; - } - for (InArcIt jt(_graph, _source); jt != INVALID; ++jt) { - _flow_value -= (*_flow)[jt]; - } - } - - /// \brief Initializes the algorithm using the given flow map. - /// - /// Initializes the internal data structures and sets the initial - /// flow to the given \c flowMap. The \c flowMap should - /// contain a feasible flow, i.e. at each node excluding the source - /// and the target, the incoming flow should be equal to the - /// outgoing flow. - /// \return \c false when the given \c flowMap does not contain a - /// feasible flow. - template - bool checkedInit(const FlowMap& flowMap) { - createStructures(); - for (ArcIt e(_graph); e != INVALID; ++e) { - _flow->set(e, flowMap[e]); - } - for (NodeIt it(_graph); it != INVALID; ++it) { - if (it == _source || it == _target) continue; - Value outFlow = 0; - for (OutArcIt jt(_graph, it); jt != INVALID; ++jt) { - outFlow += (*_flow)[jt]; - } - Value inFlow = 0; - for (InArcIt jt(_graph, it); jt != INVALID; ++jt) { - inFlow += (*_flow)[jt]; - } - if (_tolerance.different(outFlow, inFlow)) { - return false; - } - } - for (ArcIt it(_graph); it != INVALID; ++it) { - if (_tolerance.less((*_flow)[it], 0)) return false; - if (_tolerance.less((*_capacity)[it], (*_flow)[it])) return false; - } - _flow_value = 0; - for (OutArcIt jt(_graph, _source); jt != INVALID; ++jt) { - _flow_value += (*_flow)[jt]; - } - for (InArcIt jt(_graph, _source); jt != INVALID; ++jt) { - _flow_value -= (*_flow)[jt]; - } - return true; - } - - /// \brief Augments the solution along a shortest path. - /// - /// Augments the solution along a shortest path. This function searches a - /// shortest path between the source and the target - /// in the residual digraph by the Bfs algoritm. - /// Then it increases the flow on this path with the minimal residual - /// capacity on the path. If there is no such path, it gives back - /// false. - /// \return \c false when the augmenting did not success, i.e. the - /// current flow is a feasible and optimal solution. - bool augment() { - for (NodeIt n(_graph); n != INVALID; ++n) { - _pred->set(n, INVALID); - } - - int first = 0, last = 1; - - _queue[0] = _source; - _pred->set(_source, OutArcIt(_graph, _source)); - - while (first != last && (*_pred)[_target] == INVALID) { - Node n = _queue[first++]; - - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Value rem = (*_capacity)[e] - (*_flow)[e]; - Node t = _graph.target(e); - if (_tolerance.positive(rem) && (*_pred)[t] == INVALID) { - _pred->set(t, e); - _queue[last++] = t; - } - } - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Value rem = (*_flow)[e]; - Node t = _graph.source(e); - if (_tolerance.positive(rem) && (*_pred)[t] == INVALID) { - _pred->set(t, e); - _queue[last++] = t; - } - } - } - - if ((*_pred)[_target] != INVALID) { - Node n = _target; - Arc e = (*_pred)[n]; - - Value prem = (*_capacity)[e] - (*_flow)[e]; - n = _graph.source(e); - while (n != _source) { - e = (*_pred)[n]; - if (_graph.target(e) == n) { - Value rem = (*_capacity)[e] - (*_flow)[e]; - if (rem < prem) prem = rem; - n = _graph.source(e); - } else { - Value rem = (*_flow)[e]; - if (rem < prem) prem = rem; - n = _graph.target(e); - } - } - - n = _target; - e = (*_pred)[n]; - - _flow->set(e, (*_flow)[e] + prem); - n = _graph.source(e); - while (n != _source) { - e = (*_pred)[n]; - if (_graph.target(e) == n) { - _flow->set(e, (*_flow)[e] + prem); - n = _graph.source(e); - } else { - _flow->set(e, (*_flow)[e] - prem); - n = _graph.target(e); - } - } - - _flow_value += prem; - return true; - } else { - return false; - } - } - - /// \brief Executes the algorithm - /// - /// Executes the algorithm by performing augmenting phases until the - /// optimal solution is reached. - /// \pre One of the \ref init() functions must be called before - /// using this function. - void start() { - while (augment()) {} - } - - /// \brief Runs the algorithm. - /// - /// Runs the Edmonds-Karp algorithm. - /// \note ek.run() is just a shortcut of the following code. - ///\code - /// ek.init(); - /// ek.start(); - ///\endcode - void run() { - init(); - start(); - } - - /// @} - - /// \name Query Functions - /// The result of the Edmonds-Karp algorithm can be obtained using these - /// functions.\n - /// Either \ref run() or \ref start() should be called before using them. - - ///@{ - - /// \brief Returns the value of the maximum flow. - /// - /// Returns the value of the maximum flow found by the algorithm. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - Value flowValue() const { - return _flow_value; - } - - /// \brief Returns the flow value on the given arc. - /// - /// Returns the flow value on the given arc. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - Value flow(const Arc& arc) const { - return (*_flow)[arc]; - } - - /// \brief Returns a const reference to the flow map. - /// - /// Returns a const reference to the arc map storing the found flow. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - const FlowMap& flowMap() const { - return *_flow; - } - - /// \brief Returns \c true when the node is on the source side of the - /// minimum cut. - /// - /// Returns true when the node is on the source side of the found - /// minimum cut. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - bool minCut(const Node& node) const { - return ((*_pred)[node] != INVALID) || node == _source; - } - - /// \brief Gives back a minimum value cut. - /// - /// Sets \c cutMap to the characteristic vector of a minimum value - /// cut. \c cutMap should be a \ref concepts::WriteMap "writable" - /// node map with \c bool (or convertible) value type. - /// - /// \note This function calls \ref minCut() for each node, so it runs in - /// O(n) time. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - template - void minCutMap(CutMap& cutMap) const { - for (NodeIt n(_graph); n != INVALID; ++n) { - cutMap.set(n, (*_pred)[n] != INVALID); - } - cutMap.set(_source, true); - } - - /// @} - - }; - -} - -#endif diff --git a/deps/lemon/lemon/elevator.h b/deps/lemon/lemon/elevator.h deleted file mode 100644 index e4adcd599..000000000 --- a/deps/lemon/lemon/elevator.h +++ /dev/null @@ -1,982 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_ELEVATOR_H -#define LEMON_ELEVATOR_H - -///\ingroup auxdat -///\file -///\brief Elevator class -/// -///Elevator class implements an efficient data structure -///for labeling items in push-relabel type algorithms. -/// - -#include -#include - -namespace lemon { - - ///Class for handling "labels" in push-relabel type algorithms. - - ///A class for handling "labels" in push-relabel type algorithms. - /// - ///\ingroup auxdat - ///Using this class you can assign "labels" (nonnegative integer numbers) - ///to the edges or nodes of a graph, manipulate and query them through - ///operations typically arising in "push-relabel" type algorithms. - /// - ///Each item is either \em active or not, and you can also choose a - ///highest level active item. - /// - ///\sa LinkedElevator - /// - ///\param GR Type of the underlying graph. - ///\param Item Type of the items the data is assigned to (\c GR::Node, - ///\c GR::Arc or \c GR::Edge). - template - class Elevator - { - public: - - typedef Item Key; - typedef int Value; - - private: - - typedef Item *Vit; - typedef typename ItemSetTraits::template Map::Type VitMap; - typedef typename ItemSetTraits::template Map::Type IntMap; - - const GR &_g; - int _max_level; - int _item_num; - VitMap _where; - IntMap _level; - std::vector _items; - std::vector _first; - std::vector _last_active; - - int _highest_active; - - void copy(Item i, Vit p) - { - _where[*p=i] = p; - } - void copy(Vit s, Vit p) - { - if(s!=p) - { - Item i=*s; - *p=i; - _where[i] = p; - } - } - void swap(Vit i, Vit j) - { - Item ti=*i; - Vit ct = _where[ti]; - _where[ti] = _where[*i=*j]; - _where[*j] = ct; - *j=ti; - } - - public: - - ///Constructor with given maximum level. - - ///Constructor with given maximum level. - /// - ///\param graph The underlying graph. - ///\param max_level The maximum allowed level. - ///Set the range of the possible labels to [0..max_level]. - Elevator(const GR &graph,int max_level) : - _g(graph), - _max_level(max_level), - _item_num(_max_level), - _where(graph), - _level(graph,0), - _items(_max_level), - _first(_max_level+2), - _last_active(_max_level+2), - _highest_active(-1) {} - ///Constructor. - - ///Constructor. - /// - ///\param graph The underlying graph. - ///Set the range of the possible labels to [0..max_level], - ///where \c max_level is equal to the number of labeled items in the graph. - Elevator(const GR &graph) : - _g(graph), - _max_level(countItems(graph)), - _item_num(_max_level), - _where(graph), - _level(graph,0), - _items(_max_level), - _first(_max_level+2), - _last_active(_max_level+2), - _highest_active(-1) - { - } - - ///Activate item \c i. - - ///Activate item \c i. - ///\pre Item \c i shouldn't be active before. - void activate(Item i) - { - const int l=_level[i]; - swap(_where[i],++_last_active[l]); - if(l>_highest_active) _highest_active=l; - } - - ///Deactivate item \c i. - - ///Deactivate item \c i. - ///\pre Item \c i must be active before. - void deactivate(Item i) - { - swap(_where[i],_last_active[_level[i]]--); - while(_highest_active>=0 && - _last_active[_highest_active]<_first[_highest_active]) - _highest_active--; - } - - ///Query whether item \c i is active - bool active(Item i) const { return _where[i]<=_last_active[_level[i]]; } - - ///Return the level of item \c i. - int operator[](Item i) const { return _level[i]; } - - ///Return the number of items on level \c l. - int onLevel(int l) const - { - return _first[l+1]-_first[l]; - } - ///Return true if level \c l is empty. - bool emptyLevel(int l) const - { - return _first[l+1]-_first[l]==0; - } - ///Return the number of items above level \c l. - int aboveLevel(int l) const - { - return _first[_max_level+1]-_first[l+1]; - } - ///Return the number of active items on level \c l. - int activesOnLevel(int l) const - { - return _last_active[l]-_first[l]+1; - } - ///Return true if there is no active item on level \c l. - bool activeFree(int l) const - { - return _last_active[l]<_first[l]; - } - ///Return the maximum allowed level. - int maxLevel() const - { - return _max_level; - } - - ///\name Highest Active Item - ///Functions for working with the highest level - ///active item. - - ///@{ - - ///Return a highest level active item. - - ///Return a highest level active item or INVALID if there is no active - ///item. - Item highestActive() const - { - return _highest_active>=0?*_last_active[_highest_active]:INVALID; - } - - ///Return the highest active level. - - ///Return the level of the highest active item or -1 if there is no active - ///item. - int highestActiveLevel() const - { - return _highest_active; - } - - ///Lift the highest active item by one. - - ///Lift the item returned by highestActive() by one. - /// - void liftHighestActive() - { - Item it = *_last_active[_highest_active]; - ++_level[it]; - swap(_last_active[_highest_active]--,_last_active[_highest_active+1]); - --_first[++_highest_active]; - } - - ///Lift the highest active item to the given level. - - ///Lift the item returned by highestActive() to level \c new_level. - /// - ///\warning \c new_level must be strictly higher - ///than the current level. - /// - void liftHighestActive(int new_level) - { - const Item li = *_last_active[_highest_active]; - - copy(--_first[_highest_active+1],_last_active[_highest_active]--); - for(int l=_highest_active+1;l=0 && - _last_active[_highest_active]<_first[_highest_active]) - _highest_active--; - } - - ///@} - - ///\name Active Item on Certain Level - ///Functions for working with the active items. - - ///@{ - - ///Return an active item on level \c l. - - ///Return an active item on level \c l or \ref INVALID if there is no such - ///an item. (\c l must be from the range [0...\c max_level]. - Item activeOn(int l) const - { - return _last_active[l]>=_first[l]?*_last_active[l]:INVALID; - } - - ///Lift the active item returned by \c activeOn(level) by one. - - ///Lift the active item returned by \ref activeOn() "activeOn(level)" - ///by one. - Item liftActiveOn(int level) - { - Item it =*_last_active[level]; - ++_level[it]; - swap(_last_active[level]--, --_first[level+1]); - if (level+1>_highest_active) ++_highest_active; - } - - ///Lift the active item returned by \c activeOn(level) to the given level. - - ///Lift the active item returned by \ref activeOn() "activeOn(level)" - ///to the given level. - void liftActiveOn(int level, int new_level) - { - const Item ai = *_last_active[level]; - - copy(--_first[level+1], _last_active[level]--); - for(int l=level+1;l_highest_active) _highest_active=new_level; - } - - ///Lift the active item returned by \c activeOn(level) to the top level. - - ///Lift the active item returned by \ref activeOn() "activeOn(level)" - ///to the top level and deactivate it. - void liftActiveToTop(int level) - { - const Item ai = *_last_active[level]; - - copy(--_first[level+1],_last_active[level]--); - for(int l=level+1;l<_max_level;l++) - { - copy(_last_active[l],_first[l]); - copy(--_first[l+1], _last_active[l]--); - } - copy(ai,_first[_max_level]); - --_last_active[_max_level]; - _level[ai] = _max_level; - - if (_highest_active==level) { - while(_highest_active>=0 && - _last_active[_highest_active]<_first[_highest_active]) - _highest_active--; - } - } - - ///@} - - ///Lift an active item to a higher level. - - ///Lift an active item to a higher level. - ///\param i The item to be lifted. It must be active. - ///\param new_level The new level of \c i. It must be strictly higher - ///than the current level. - /// - void lift(Item i, int new_level) - { - const int lo = _level[i]; - const Vit w = _where[i]; - - copy(_last_active[lo],w); - copy(--_first[lo+1],_last_active[lo]--); - for(int l=lo+1;l_highest_active) _highest_active=new_level; - } - - ///Move an inactive item to the top but one level (in a dirty way). - - ///This function moves an inactive item from the top level to the top - ///but one level (in a dirty way). - ///\warning It makes the underlying datastructure corrupt, so use it - ///only if you really know what it is for. - ///\pre The item is on the top level. - void dirtyTopButOne(Item i) { - _level[i] = _max_level - 1; - } - - ///Lift all items on and above the given level to the top level. - - ///This function lifts all items on and above level \c l to the top - ///level and deactivates them. - void liftToTop(int l) - { - const Vit f=_first[l]; - const Vit tl=_first[_max_level]; - for(Vit i=f;i!=tl;++i) - _level[*i] = _max_level; - for(int i=l;i<=_max_level;i++) - { - _first[i]=f; - _last_active[i]=f-1; - } - for(_highest_active=l-1; - _highest_active>=0 && - _last_active[_highest_active]<_first[_highest_active]; - _highest_active--) ; - } - - private: - int _init_lev; - Vit _init_num; - - public: - - ///\name Initialization - ///Using these functions you can initialize the levels of the items. - ///\n - ///The initialization must be started with calling \c initStart(). - ///Then the items should be listed level by level starting with the - ///lowest one (level 0) using \c initAddItem() and \c initNewLevel(). - ///Finally \c initFinish() must be called. - ///The items not listed are put on the highest level. - ///@{ - - ///Start the initialization process. - void initStart() - { - _init_lev=0; - _init_num=&_items[0]; - _first[0]=&_items[0]; - _last_active[0]=&_items[0]-1; - Vit n=&_items[0]; - for(typename ItemSetTraits::ItemIt i(_g);i!=INVALID;++i) - { - *n=i; - _where[i] = n; - _level[i] = _max_level; - ++n; - } - } - - ///Add an item to the current level. - void initAddItem(Item i) - { - swap(_where[i],_init_num); - _level[i] = _init_lev; - ++_init_num; - } - - ///Start a new level. - - ///Start a new level. - ///It shouldn't be used before the items on level 0 are listed. - void initNewLevel() - { - _init_lev++; - _first[_init_lev]=_init_num; - _last_active[_init_lev]=_init_num-1; - } - - ///Finalize the initialization process. - void initFinish() - { - for(_init_lev++;_init_lev<=_max_level;_init_lev++) - { - _first[_init_lev]=_init_num; - _last_active[_init_lev]=_init_num-1; - } - _first[_max_level+1]=&_items[0]+_item_num; - _last_active[_max_level+1]=&_items[0]+_item_num-1; - _highest_active = -1; - } - - ///@} - - }; - - ///Class for handling "labels" in push-relabel type algorithms. - - ///A class for handling "labels" in push-relabel type algorithms. - /// - ///\ingroup auxdat - ///Using this class you can assign "labels" (nonnegative integer numbers) - ///to the edges or nodes of a graph, manipulate and query them through - ///operations typically arising in "push-relabel" type algorithms. - /// - ///Each item is either \em active or not, and you can also choose a - ///highest level active item. - /// - ///\sa Elevator - /// - ///\param GR Type of the underlying graph. - ///\param Item Type of the items the data is assigned to (\c GR::Node, - ///\c GR::Arc or \c GR::Edge). - template - class LinkedElevator { - public: - - typedef Item Key; - typedef int Value; - - private: - - typedef typename ItemSetTraits:: - template Map::Type ItemMap; - typedef typename ItemSetTraits:: - template Map::Type IntMap; - typedef typename ItemSetTraits:: - template Map::Type BoolMap; - - const GR &_graph; - int _max_level; - int _item_num; - std::vector _first, _last; - ItemMap _prev, _next; - int _highest_active; - IntMap _level; - BoolMap _active; - - public: - ///Constructor with given maximum level. - - ///Constructor with given maximum level. - /// - ///\param graph The underlying graph. - ///\param max_level The maximum allowed level. - ///Set the range of the possible labels to [0..max_level]. - LinkedElevator(const GR& graph, int max_level) - : _graph(graph), _max_level(max_level), _item_num(_max_level), - _first(_max_level + 1), _last(_max_level + 1), - _prev(graph), _next(graph), - _highest_active(-1), _level(graph), _active(graph) {} - - ///Constructor. - - ///Constructor. - /// - ///\param graph The underlying graph. - ///Set the range of the possible labels to [0..max_level], - ///where \c max_level is equal to the number of labeled items in the graph. - LinkedElevator(const GR& graph) - : _graph(graph), _max_level(countItems(graph)), - _item_num(_max_level), - _first(_max_level + 1), _last(_max_level + 1), - _prev(graph, INVALID), _next(graph, INVALID), - _highest_active(-1), _level(graph), _active(graph) {} - - - ///Activate item \c i. - - ///Activate item \c i. - ///\pre Item \c i shouldn't be active before. - void activate(Item i) { - _active[i] = true; - - int level = _level[i]; - if (level > _highest_active) { - _highest_active = level; - } - - if (_prev[i] == INVALID || _active[_prev[i]]) return; - //unlace - _next[_prev[i]] = _next[i]; - if (_next[i] != INVALID) { - _prev[_next[i]] = _prev[i]; - } else { - _last[level] = _prev[i]; - } - //lace - _next[i] = _first[level]; - _prev[_first[level]] = i; - _prev[i] = INVALID; - _first[level] = i; - - } - - ///Deactivate item \c i. - - ///Deactivate item \c i. - ///\pre Item \c i must be active before. - void deactivate(Item i) { - _active[i] = false; - int level = _level[i]; - - if (_next[i] == INVALID || !_active[_next[i]]) - goto find_highest_level; - - //unlace - _prev[_next[i]] = _prev[i]; - if (_prev[i] != INVALID) { - _next[_prev[i]] = _next[i]; - } else { - _first[_level[i]] = _next[i]; - } - //lace - _prev[i] = _last[level]; - _next[_last[level]] = i; - _next[i] = INVALID; - _last[level] = i; - - find_highest_level: - if (level == _highest_active) { - while (_highest_active >= 0 && activeFree(_highest_active)) - --_highest_active; - } - } - - ///Query whether item \c i is active - bool active(Item i) const { return _active[i]; } - - ///Return the level of item \c i. - int operator[](Item i) const { return _level[i]; } - - ///Return the number of items on level \c l. - int onLevel(int l) const { - int num = 0; - Item n = _first[l]; - while (n != INVALID) { - ++num; - n = _next[n]; - } - return num; - } - - ///Return true if the level is empty. - bool emptyLevel(int l) const { - return _first[l] == INVALID; - } - - ///Return the number of items above level \c l. - int aboveLevel(int l) const { - int num = 0; - for (int level = l + 1; level < _max_level; ++level) - num += onLevel(level); - return num; - } - - ///Return the number of active items on level \c l. - int activesOnLevel(int l) const { - int num = 0; - Item n = _first[l]; - while (n != INVALID && _active[n]) { - ++num; - n = _next[n]; - } - return num; - } - - ///Return true if there is no active item on level \c l. - bool activeFree(int l) const { - return _first[l] == INVALID || !_active[_first[l]]; - } - - ///Return the maximum allowed level. - int maxLevel() const { - return _max_level; - } - - ///\name Highest Active Item - ///Functions for working with the highest level - ///active item. - - ///@{ - - ///Return a highest level active item. - - ///Return a highest level active item or INVALID if there is no active - ///item. - Item highestActive() const { - return _highest_active >= 0 ? _first[_highest_active] : INVALID; - } - - ///Return the highest active level. - - ///Return the level of the highest active item or -1 if there is no active - ///item. - int highestActiveLevel() const { - return _highest_active; - } - - ///Lift the highest active item by one. - - ///Lift the item returned by highestActive() by one. - /// - void liftHighestActive() { - Item i = _first[_highest_active]; - if (_next[i] != INVALID) { - _prev[_next[i]] = INVALID; - _first[_highest_active] = _next[i]; - } else { - _first[_highest_active] = INVALID; - _last[_highest_active] = INVALID; - } - _level[i] = ++_highest_active; - if (_first[_highest_active] == INVALID) { - _first[_highest_active] = i; - _last[_highest_active] = i; - _prev[i] = INVALID; - _next[i] = INVALID; - } else { - _prev[_first[_highest_active]] = i; - _next[i] = _first[_highest_active]; - _first[_highest_active] = i; - } - } - - ///Lift the highest active item to the given level. - - ///Lift the item returned by highestActive() to level \c new_level. - /// - ///\warning \c new_level must be strictly higher - ///than the current level. - /// - void liftHighestActive(int new_level) { - Item i = _first[_highest_active]; - if (_next[i] != INVALID) { - _prev[_next[i]] = INVALID; - _first[_highest_active] = _next[i]; - } else { - _first[_highest_active] = INVALID; - _last[_highest_active] = INVALID; - } - _level[i] = _highest_active = new_level; - if (_first[_highest_active] == INVALID) { - _first[_highest_active] = _last[_highest_active] = i; - _prev[i] = INVALID; - _next[i] = INVALID; - } else { - _prev[_first[_highest_active]] = i; - _next[i] = _first[_highest_active]; - _first[_highest_active] = i; - } - } - - ///Lift the highest active item to the top level. - - ///Lift the item returned by highestActive() to the top level and - ///deactivate it. - void liftHighestActiveToTop() { - Item i = _first[_highest_active]; - _level[i] = _max_level; - if (_next[i] != INVALID) { - _prev[_next[i]] = INVALID; - _first[_highest_active] = _next[i]; - } else { - _first[_highest_active] = INVALID; - _last[_highest_active] = INVALID; - } - while (_highest_active >= 0 && activeFree(_highest_active)) - --_highest_active; - } - - ///@} - - ///\name Active Item on Certain Level - ///Functions for working with the active items. - - ///@{ - - ///Return an active item on level \c l. - - ///Return an active item on level \c l or \ref INVALID if there is no such - ///an item. (\c l must be from the range [0...\c max_level]. - Item activeOn(int l) const - { - return _active[_first[l]] ? _first[l] : INVALID; - } - - ///Lift the active item returned by \c activeOn(l) by one. - - ///Lift the active item returned by \ref activeOn() "activeOn(l)" - ///by one. - Item liftActiveOn(int l) - { - Item i = _first[l]; - if (_next[i] != INVALID) { - _prev[_next[i]] = INVALID; - _first[l] = _next[i]; - } else { - _first[l] = INVALID; - _last[l] = INVALID; - } - _level[i] = ++l; - if (_first[l] == INVALID) { - _first[l] = _last[l] = i; - _prev[i] = INVALID; - _next[i] = INVALID; - } else { - _prev[_first[l]] = i; - _next[i] = _first[l]; - _first[l] = i; - } - if (_highest_active < l) { - _highest_active = l; - } - } - - ///Lift the active item returned by \c activeOn(l) to the given level. - - ///Lift the active item returned by \ref activeOn() "activeOn(l)" - ///to the given level. - void liftActiveOn(int l, int new_level) - { - Item i = _first[l]; - if (_next[i] != INVALID) { - _prev[_next[i]] = INVALID; - _first[l] = _next[i]; - } else { - _first[l] = INVALID; - _last[l] = INVALID; - } - _level[i] = l = new_level; - if (_first[l] == INVALID) { - _first[l] = _last[l] = i; - _prev[i] = INVALID; - _next[i] = INVALID; - } else { - _prev[_first[l]] = i; - _next[i] = _first[l]; - _first[l] = i; - } - if (_highest_active < l) { - _highest_active = l; - } - } - - ///Lift the active item returned by \c activeOn(l) to the top level. - - ///Lift the active item returned by \ref activeOn() "activeOn(l)" - ///to the top level and deactivate it. - void liftActiveToTop(int l) - { - Item i = _first[l]; - if (_next[i] != INVALID) { - _prev[_next[i]] = INVALID; - _first[l] = _next[i]; - } else { - _first[l] = INVALID; - _last[l] = INVALID; - } - _level[i] = _max_level; - if (l == _highest_active) { - while (_highest_active >= 0 && activeFree(_highest_active)) - --_highest_active; - } - } - - ///@} - - /// \brief Lift an active item to a higher level. - /// - /// Lift an active item to a higher level. - /// \param i The item to be lifted. It must be active. - /// \param new_level The new level of \c i. It must be strictly higher - /// than the current level. - /// - void lift(Item i, int new_level) { - if (_next[i] != INVALID) { - _prev[_next[i]] = _prev[i]; - } else { - _last[new_level] = _prev[i]; - } - if (_prev[i] != INVALID) { - _next[_prev[i]] = _next[i]; - } else { - _first[new_level] = _next[i]; - } - _level[i] = new_level; - if (_first[new_level] == INVALID) { - _first[new_level] = _last[new_level] = i; - _prev[i] = INVALID; - _next[i] = INVALID; - } else { - _prev[_first[new_level]] = i; - _next[i] = _first[new_level]; - _first[new_level] = i; - } - if (_highest_active < new_level) { - _highest_active = new_level; - } - } - - ///Move an inactive item to the top but one level (in a dirty way). - - ///This function moves an inactive item from the top level to the top - ///but one level (in a dirty way). - ///\warning It makes the underlying datastructure corrupt, so use it - ///only if you really know what it is for. - ///\pre The item is on the top level. - void dirtyTopButOne(Item i) { - _level[i] = _max_level - 1; - } - - ///Lift all items on and above the given level to the top level. - - ///This function lifts all items on and above level \c l to the top - ///level and deactivates them. - void liftToTop(int l) { - for (int i = l + 1; _first[i] != INVALID; ++i) { - Item n = _first[i]; - while (n != INVALID) { - _level[n] = _max_level; - n = _next[n]; - } - _first[i] = INVALID; - _last[i] = INVALID; - } - if (_highest_active > l - 1) { - _highest_active = l - 1; - while (_highest_active >= 0 && activeFree(_highest_active)) - --_highest_active; - } - } - - private: - - int _init_level; - - public: - - ///\name Initialization - ///Using these functions you can initialize the levels of the items. - ///\n - ///The initialization must be started with calling \c initStart(). - ///Then the items should be listed level by level starting with the - ///lowest one (level 0) using \c initAddItem() and \c initNewLevel(). - ///Finally \c initFinish() must be called. - ///The items not listed are put on the highest level. - ///@{ - - ///Start the initialization process. - void initStart() { - - for (int i = 0; i <= _max_level; ++i) { - _first[i] = _last[i] = INVALID; - } - _init_level = 0; - for(typename ItemSetTraits::ItemIt i(_graph); - i != INVALID; ++i) { - _level[i] = _max_level; - _active[i] = false; - } - } - - ///Add an item to the current level. - void initAddItem(Item i) { - _level[i] = _init_level; - if (_last[_init_level] == INVALID) { - _first[_init_level] = i; - _last[_init_level] = i; - _prev[i] = INVALID; - _next[i] = INVALID; - } else { - _prev[i] = _last[_init_level]; - _next[i] = INVALID; - _next[_last[_init_level]] = i; - _last[_init_level] = i; - } - } - - ///Start a new level. - - ///Start a new level. - ///It shouldn't be used before the items on level 0 are listed. - void initNewLevel() { - ++_init_level; - } - - ///Finalize the initialization process. - void initFinish() { - _highest_active = -1; - } - - ///@} - - }; - - -} //END OF NAMESPACE LEMON - -#endif - diff --git a/deps/lemon/lemon/error.h b/deps/lemon/lemon/error.h deleted file mode 100644 index f93770454..000000000 --- a/deps/lemon/lemon/error.h +++ /dev/null @@ -1,276 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_ERROR_H -#define LEMON_ERROR_H - -/// \ingroup exceptions -/// \file -/// \brief Basic exception classes and error handling. - -#include -#include -#include -#include -#include -#include - -namespace lemon { - - /// \addtogroup exceptions - /// @{ - - /// \brief Generic exception class. - /// - /// Base class for exceptions used in LEMON. - /// - class Exception : public std::exception { - public: - ///Constructor - Exception() throw() {} - ///Virtual destructor - virtual ~Exception() throw() {} - ///A short description of the exception - virtual const char* what() const throw() { - return "lemon::Exception"; - } - }; - - /// \brief Input-Output error - /// - /// This exception is thrown when a file operation cannot be - /// succeeded. - class IoError : public Exception { - protected: - std::string _message; - std::string _file; - - mutable std::string _what; - public: - - /// Copy constructor - IoError(const IoError &error) throw() : Exception() { - message(error._message); - file(error._file); - } - - /// Constructor - explicit IoError(const char *message) throw() { - IoError::message(message); - } - - /// Constructor - explicit IoError(const std::string &message) throw() { - IoError::message(message); - } - - /// Constructor - explicit IoError(const char *message, - const std::string &file) throw() { - IoError::message(message); - IoError::file(file); - } - - /// Constructor - explicit IoError(const std::string &message, - const std::string &file) throw() { - IoError::message(message); - IoError::file(file); - } - - /// Virtual destructor - virtual ~IoError() throw() {} - - /// Set the error message - void message(const char *message) throw() { - try { - _message = message; - } catch (...) {} - } - - /// Set the error message - void message(const std::string& message) throw() { - try { - _message = message; - } catch (...) {} - } - - /// Set the file name - void file(const std::string &file) throw() { - try { - _file = file; - } catch (...) {} - } - - /// Returns the error message - const std::string& message() const throw() { - return _message; - } - - /// \brief Returns the filename - /// - /// Returns the filename or an empty string if it was not specified. - const std::string& file() const throw() { - return _file; - } - - /// \brief Returns a short error message - /// - /// Returns a short error message which contains the message and the - /// file name. - virtual const char* what() const throw() { - try { - _what.clear(); - std::ostringstream oss; - oss << "lemon:IoError" << ": "; - oss << _message; - if (!_file.empty()) { - oss << " ('" << _file << "')"; - } - _what = oss.str(); - } - catch (...) {} - if (!_what.empty()) return _what.c_str(); - else return "lemon:IoError"; - } - - }; - - /// \brief Format error - /// - /// This exception is thrown when an input file has wrong - /// format or a data representation is not legal. - class FormatError : public Exception { - protected: - std::string _message; - std::string _file; - int _line; - - mutable std::string _what; - public: - - /// Copy constructor - FormatError(const FormatError &error) throw() : Exception() { - message(error._message); - file(error._file); - line(error._line); - } - - /// Constructor - explicit FormatError(const char *message) throw() { - FormatError::message(message); - _line = 0; - } - - /// Constructor - explicit FormatError(const std::string &message) throw() { - FormatError::message(message); - _line = 0; - } - - /// Constructor - explicit FormatError(const char *message, - const std::string &file, int line = 0) throw() { - FormatError::message(message); - FormatError::file(file); - FormatError::line(line); - } - - /// Constructor - explicit FormatError(const std::string &message, - const std::string &file, int line = 0) throw() { - FormatError::message(message); - FormatError::file(file); - FormatError::line(line); - } - - /// Virtual destructor - virtual ~FormatError() throw() {} - - /// Set the line number - void line(int line) throw() { _line = line; } - - /// Set the error message - void message(const char *message) throw() { - try { - _message = message; - } catch (...) {} - } - - /// Set the error message - void message(const std::string& message) throw() { - try { - _message = message; - } catch (...) {} - } - - /// Set the file name - void file(const std::string &file) throw() { - try { - _file = file; - } catch (...) {} - } - - /// \brief Returns the line number - /// - /// Returns the line number or zero if it was not specified. - int line() const throw() { return _line; } - - /// Returns the error message - const std::string& message() const throw() { - return _message; - } - - /// \brief Returns the filename - /// - /// Returns the filename or an empty string if it was not specified. - const std::string& file() const throw() { - return _file; - } - - /// \brief Returns a short error message - /// - /// Returns a short error message which contains the message, the - /// file name and the line number. - virtual const char* what() const throw() { - try { - _what.clear(); - std::ostringstream oss; - oss << "lemon:FormatError" << ": "; - oss << _message; - if (!_file.empty() || _line != 0) { - oss << " ("; - if (!_file.empty()) oss << "in file '" << _file << "'"; - if (!_file.empty() && _line != 0) oss << " "; - if (_line != 0) oss << "at line " << _line; - oss << ")"; - } - _what = oss.str(); - } - catch (...) {} - if (!_what.empty()) return _what.c_str(); - else return "lemon:FormatError"; - } - - }; - - /// @} - -} - -#endif // LEMON_ERROR_H diff --git a/deps/lemon/lemon/euler.h b/deps/lemon/lemon/euler.h deleted file mode 100644 index 3a3cbd065..000000000 --- a/deps/lemon/lemon/euler.h +++ /dev/null @@ -1,287 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_EULER_H -#define LEMON_EULER_H - -#include -#include -#include -#include - -/// \ingroup graph_properties -/// \file -/// \brief Euler tour iterators and a function for checking the \e Eulerian -/// property. -/// -///This file provides Euler tour iterators and a function to check -///if a (di)graph is \e Eulerian. - -namespace lemon { - - ///Euler tour iterator for digraphs. - - /// \ingroup graph_properties - ///This iterator provides an Euler tour (Eulerian circuit) of a \e directed - ///graph (if there exists) and it converts to the \c Arc type of the digraph. - /// - ///For example, if the given digraph has an Euler tour (i.e it has only one - ///non-trivial component and the in-degree is equal to the out-degree - ///for all nodes), then the following code will put the arcs of \c g - ///to the vector \c et according to an Euler tour of \c g. - ///\code - /// std::vector et; - /// for(DiEulerIt e(g); e!=INVALID; ++e) - /// et.push_back(e); - ///\endcode - ///If \c g has no Euler tour, then the resulted walk will not be closed - ///or not contain all arcs. - ///\sa EulerIt - template - class DiEulerIt - { - typedef typename GR::Node Node; - typedef typename GR::NodeIt NodeIt; - typedef typename GR::Arc Arc; - typedef typename GR::ArcIt ArcIt; - typedef typename GR::OutArcIt OutArcIt; - typedef typename GR::InArcIt InArcIt; - - const GR &g; - typename GR::template NodeMap narc; - std::list euler; - - public: - - ///Constructor - - ///Constructor. - ///\param gr A digraph. - ///\param start The starting point of the tour. If it is not given, - ///the tour will start from the first node that has an outgoing arc. - DiEulerIt(const GR &gr, typename GR::Node start = INVALID) - : g(gr), narc(g) - { - if (start==INVALID) { - NodeIt n(g); - while (n!=INVALID && OutArcIt(g,n)==INVALID) ++n; - start=n; - } - if (start!=INVALID) { - for (NodeIt n(g); n!=INVALID; ++n) narc[n]=OutArcIt(g,n); - while (narc[start]!=INVALID) { - euler.push_back(narc[start]); - Node next=g.target(narc[start]); - ++narc[start]; - start=next; - } - } - } - - ///Arc conversion - operator Arc() { return euler.empty()?INVALID:euler.front(); } - ///Compare with \c INVALID - bool operator==(Invalid) { return euler.empty(); } - ///Compare with \c INVALID - bool operator!=(Invalid) { return !euler.empty(); } - - ///Next arc of the tour - - ///Next arc of the tour - /// - DiEulerIt &operator++() { - Node s=g.target(euler.front()); - euler.pop_front(); - typename std::list::iterator next=euler.begin(); - while(narc[s]!=INVALID) { - euler.insert(next,narc[s]); - Node n=g.target(narc[s]); - ++narc[s]; - s=n; - } - return *this; - } - ///Postfix incrementation - - /// Postfix incrementation. - /// - ///\warning This incrementation - ///returns an \c Arc, not a \ref DiEulerIt, as one may - ///expect. - Arc operator++(int) - { - Arc e=*this; - ++(*this); - return e; - } - }; - - ///Euler tour iterator for graphs. - - /// \ingroup graph_properties - ///This iterator provides an Euler tour (Eulerian circuit) of an - ///\e undirected graph (if there exists) and it converts to the \c Arc - ///and \c Edge types of the graph. - /// - ///For example, if the given graph has an Euler tour (i.e it has only one - ///non-trivial component and the degree of each node is even), - ///the following code will print the arc IDs according to an - ///Euler tour of \c g. - ///\code - /// for(EulerIt e(g); e!=INVALID; ++e) { - /// std::cout << g.id(Edge(e)) << std::eol; - /// } - ///\endcode - ///Although this iterator is for undirected graphs, it still returns - ///arcs in order to indicate the direction of the tour. - ///(But arcs convert to edges, of course.) - /// - ///If \c g has no Euler tour, then the resulted walk will not be closed - ///or not contain all edges. - template - class EulerIt - { - typedef typename GR::Node Node; - typedef typename GR::NodeIt NodeIt; - typedef typename GR::Arc Arc; - typedef typename GR::Edge Edge; - typedef typename GR::ArcIt ArcIt; - typedef typename GR::OutArcIt OutArcIt; - typedef typename GR::InArcIt InArcIt; - - const GR &g; - typename GR::template NodeMap narc; - typename GR::template EdgeMap visited; - std::list euler; - - public: - - ///Constructor - - ///Constructor. - ///\param gr A graph. - ///\param start The starting point of the tour. If it is not given, - ///the tour will start from the first node that has an incident edge. - EulerIt(const GR &gr, typename GR::Node start = INVALID) - : g(gr), narc(g), visited(g, false) - { - if (start==INVALID) { - NodeIt n(g); - while (n!=INVALID && OutArcIt(g,n)==INVALID) ++n; - start=n; - } - if (start!=INVALID) { - for (NodeIt n(g); n!=INVALID; ++n) narc[n]=OutArcIt(g,n); - while(narc[start]!=INVALID) { - euler.push_back(narc[start]); - visited[narc[start]]=true; - Node next=g.target(narc[start]); - ++narc[start]; - start=next; - while(narc[start]!=INVALID && visited[narc[start]]) ++narc[start]; - } - } - } - - ///Arc conversion - operator Arc() const { return euler.empty()?INVALID:euler.front(); } - ///Edge conversion - operator Edge() const { return euler.empty()?INVALID:euler.front(); } - ///Compare with \c INVALID - bool operator==(Invalid) const { return euler.empty(); } - ///Compare with \c INVALID - bool operator!=(Invalid) const { return !euler.empty(); } - - ///Next arc of the tour - - ///Next arc of the tour - /// - EulerIt &operator++() { - Node s=g.target(euler.front()); - euler.pop_front(); - typename std::list::iterator next=euler.begin(); - while(narc[s]!=INVALID) { - while(narc[s]!=INVALID && visited[narc[s]]) ++narc[s]; - if(narc[s]==INVALID) break; - else { - euler.insert(next,narc[s]); - visited[narc[s]]=true; - Node n=g.target(narc[s]); - ++narc[s]; - s=n; - } - } - return *this; - } - - ///Postfix incrementation - - /// Postfix incrementation. - /// - ///\warning This incrementation returns an \c Arc (which converts to - ///an \c Edge), not an \ref EulerIt, as one may expect. - Arc operator++(int) - { - Arc e=*this; - ++(*this); - return e; - } - }; - - - ///Check if the given graph is Eulerian - - /// \ingroup graph_properties - ///This function checks if the given graph is Eulerian. - ///It works for both directed and undirected graphs. - /// - ///By definition, a digraph is called \e Eulerian if - ///and only if it is connected and the number of incoming and outgoing - ///arcs are the same for each node. - ///Similarly, an undirected graph is called \e Eulerian if - ///and only if it is connected and the number of incident edges is even - ///for each node. - /// - ///\note There are (di)graphs that are not Eulerian, but still have an - /// Euler tour, since they may contain isolated nodes. - /// - ///\sa DiEulerIt, EulerIt - template -#ifdef DOXYGEN - bool -#else - typename enable_if,bool>::type - eulerian(const GR &g) - { - for(typename GR::NodeIt n(g);n!=INVALID;++n) - if(countIncEdges(g,n)%2) return false; - return connected(g); - } - template - typename disable_if,bool>::type -#endif - eulerian(const GR &g) - { - for(typename GR::NodeIt n(g);n!=INVALID;++n) - if(countInArcs(g,n)!=countOutArcs(g,n)) return false; - return connected(undirector(g)); - } - -} - -#endif diff --git a/deps/lemon/lemon/fib_heap.h b/deps/lemon/lemon/fib_heap.h deleted file mode 100644 index 3441722a0..000000000 --- a/deps/lemon/lemon/fib_heap.h +++ /dev/null @@ -1,475 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_FIB_HEAP_H -#define LEMON_FIB_HEAP_H - -///\file -///\ingroup heaps -///\brief Fibonacci heap implementation. - -#include -#include -#include -#include - -namespace lemon { - - /// \ingroup heaps - /// - /// \brief Fibonacci heap data structure. - /// - /// This class implements the \e Fibonacci \e heap data structure. - /// It fully conforms to the \ref concepts::Heap "heap concept". - /// - /// The methods \ref increase() and \ref erase() are not efficient in a - /// Fibonacci heap. In case of many calls of these operations, it is - /// better to use other heap structure, e.g. \ref BinHeap "binary heap". - /// - /// \tparam PR Type of the priorities of the items. - /// \tparam IM A read-writable item map with \c int values, used - /// internally to handle the cross references. - /// \tparam CMP A functor class for comparing the priorities. - /// The default is \c std::less. -#ifdef DOXYGEN - template -#else - template > -#endif - class FibHeap { - public: - - /// Type of the item-int map. - typedef IM ItemIntMap; - /// Type of the priorities. - typedef PR Prio; - /// Type of the items stored in the heap. - typedef typename ItemIntMap::Key Item; - /// Type of the item-priority pairs. - typedef std::pair Pair; - /// Functor type for comparing the priorities. - typedef CMP Compare; - - private: - class Store; - - std::vector _data; - int _minimum; - ItemIntMap &_iim; - Compare _comp; - int _num; - - public: - - /// \brief Type to represent the states of the items. - /// - /// Each item has a state associated to it. It can be "in heap", - /// "pre-heap" or "post-heap". The latter two are indifferent from the - /// heap's point of view, but may be useful to the user. - /// - /// The item-int map must be initialized in such way that it assigns - /// \c PRE_HEAP (-1) to any element to be put in the heap. - enum State { - IN_HEAP = 0, ///< = 0. - PRE_HEAP = -1, ///< = -1. - POST_HEAP = -2 ///< = -2. - }; - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - explicit FibHeap(ItemIntMap &map) - : _minimum(0), _iim(map), _num() {} - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - /// \param comp The function object used for comparing the priorities. - FibHeap(ItemIntMap &map, const Compare &comp) - : _minimum(0), _iim(map), _comp(comp), _num() {} - - /// \brief The number of items stored in the heap. - /// - /// This function returns the number of items stored in the heap. - int size() const { return _num; } - - /// \brief Check if the heap is empty. - /// - /// This function returns \c true if the heap is empty. - bool empty() const { return _num==0; } - - /// \brief Make the heap empty. - /// - /// This functon makes the heap empty. - /// It does not change the cross reference map. If you want to reuse - /// a heap that is not surely empty, you should first clear it and - /// then you should set the cross reference map to \c PRE_HEAP - /// for each item. - void clear() { - _data.clear(); _minimum = 0; _num = 0; - } - - /// \brief Insert an item into the heap with the given priority. - /// - /// This function inserts the given item into the heap with the - /// given priority. - /// \param item The item to insert. - /// \param prio The priority of the item. - /// \pre \e item must not be stored in the heap. - void push (const Item& item, const Prio& prio) { - int i=_iim[item]; - if ( i < 0 ) { - int s=_data.size(); - _iim.set( item, s ); - Store st; - st.name=item; - _data.push_back(st); - i=s; - } else { - _data[i].parent=_data[i].child=-1; - _data[i].degree=0; - _data[i].in=true; - _data[i].marked=false; - } - - if ( _num ) { - _data[_data[_minimum].right_neighbor].left_neighbor=i; - _data[i].right_neighbor=_data[_minimum].right_neighbor; - _data[_minimum].right_neighbor=i; - _data[i].left_neighbor=_minimum; - if ( _comp( prio, _data[_minimum].prio) ) _minimum=i; - } else { - _data[i].right_neighbor=_data[i].left_neighbor=i; - _minimum=i; - } - _data[i].prio=prio; - ++_num; - } - - /// \brief Return the item having minimum priority. - /// - /// This function returns the item having minimum priority. - /// \pre The heap must be non-empty. - Item top() const { return _data[_minimum].name; } - - /// \brief The minimum priority. - /// - /// This function returns the minimum priority. - /// \pre The heap must be non-empty. - Prio prio() const { return _data[_minimum].prio; } - - /// \brief Remove the item having minimum priority. - /// - /// This function removes the item having minimum priority. - /// \pre The heap must be non-empty. - void pop() { - /*The first case is that there are only one root.*/ - if ( _data[_minimum].left_neighbor==_minimum ) { - _data[_minimum].in=false; - if ( _data[_minimum].degree!=0 ) { - makeRoot(_data[_minimum].child); - _minimum=_data[_minimum].child; - balance(); - } - } else { - int right=_data[_minimum].right_neighbor; - unlace(_minimum); - _data[_minimum].in=false; - if ( _data[_minimum].degree > 0 ) { - int left=_data[_minimum].left_neighbor; - int child=_data[_minimum].child; - int last_child=_data[child].left_neighbor; - - makeRoot(child); - - _data[left].right_neighbor=child; - _data[child].left_neighbor=left; - _data[right].left_neighbor=last_child; - _data[last_child].right_neighbor=right; - } - _minimum=right; - balance(); - } // the case where there are more roots - --_num; - } - - /// \brief Remove the given item from the heap. - /// - /// This function removes the given item from the heap if it is - /// already stored. - /// \param item The item to delete. - /// \pre \e item must be in the heap. - void erase (const Item& item) { - int i=_iim[item]; - - if ( i >= 0 && _data[i].in ) { - if ( _data[i].parent!=-1 ) { - int p=_data[i].parent; - cut(i,p); - cascade(p); - } - _minimum=i; //As if its prio would be -infinity - pop(); - } - } - - /// \brief The priority of the given item. - /// - /// This function returns the priority of the given item. - /// \param item The item. - /// \pre \e item must be in the heap. - Prio operator[](const Item& item) const { - return _data[_iim[item]].prio; - } - - /// \brief Set the priority of an item or insert it, if it is - /// not stored in the heap. - /// - /// This method sets the priority of the given item if it is - /// already stored in the heap. Otherwise it inserts the given - /// item into the heap with the given priority. - /// \param item The item. - /// \param prio The priority. - void set (const Item& item, const Prio& prio) { - int i=_iim[item]; - if ( i >= 0 && _data[i].in ) { - if ( _comp(prio, _data[i].prio) ) decrease(item, prio); - if ( _comp(_data[i].prio, prio) ) increase(item, prio); - } else push(item, prio); - } - - /// \brief Decrease the priority of an item to the given value. - /// - /// This function decreases the priority of an item to the given value. - /// \param item The item. - /// \param prio The priority. - /// \pre \e item must be stored in the heap with priority at least \e prio. - void decrease (const Item& item, const Prio& prio) { - int i=_iim[item]; - _data[i].prio=prio; - int p=_data[i].parent; - - if ( p!=-1 && _comp(prio, _data[p].prio) ) { - cut(i,p); - cascade(p); - } - if ( _comp(prio, _data[_minimum].prio) ) _minimum=i; - } - - /// \brief Increase the priority of an item to the given value. - /// - /// This function increases the priority of an item to the given value. - /// \param item The item. - /// \param prio The priority. - /// \pre \e item must be stored in the heap with priority at most \e prio. - void increase (const Item& item, const Prio& prio) { - erase(item); - push(item, prio); - } - - /// \brief Return the state of an item. - /// - /// This method returns \c PRE_HEAP if the given item has never - /// been in the heap, \c IN_HEAP if it is in the heap at the moment, - /// and \c POST_HEAP otherwise. - /// In the latter case it is possible that the item will get back - /// to the heap again. - /// \param item The item. - State state(const Item &item) const { - int i=_iim[item]; - if( i>=0 ) { - if ( _data[i].in ) i=0; - else i=-2; - } - return State(i); - } - - /// \brief Set the state of an item in the heap. - /// - /// This function sets the state of the given item in the heap. - /// It can be used to manually clear the heap when it is important - /// to achive better time complexity. - /// \param i The item. - /// \param st The state. It should not be \c IN_HEAP. - void state(const Item& i, State st) { - switch (st) { - case POST_HEAP: - case PRE_HEAP: - if (state(i) == IN_HEAP) { - erase(i); - } - _iim[i] = st; - break; - case IN_HEAP: - break; - } - } - - private: - - void balance() { - - int maxdeg=int( std::floor( 2.08*log(double(_data.size()))))+1; - - std::vector A(maxdeg,-1); - - /* - *Recall that now minimum does not point to the minimum prio element. - *We set minimum to this during balance(). - */ - int anchor=_data[_minimum].left_neighbor; - int next=_minimum; - bool end=false; - - do { - int active=next; - if ( anchor==active ) end=true; - int d=_data[active].degree; - next=_data[active].right_neighbor; - - while (A[d]!=-1) { - if( _comp(_data[active].prio, _data[A[d]].prio) ) { - fuse(active,A[d]); - } else { - fuse(A[d],active); - active=A[d]; - } - A[d]=-1; - ++d; - } - A[d]=active; - } while ( !end ); - - - while ( _data[_minimum].parent >=0 ) - _minimum=_data[_minimum].parent; - int s=_minimum; - int m=_minimum; - do { - if ( _comp(_data[s].prio, _data[_minimum].prio) ) _minimum=s; - s=_data[s].right_neighbor; - } while ( s != m ); - } - - void makeRoot(int c) { - int s=c; - do { - _data[s].parent=-1; - s=_data[s].right_neighbor; - } while ( s != c ); - } - - void cut(int a, int b) { - /* - *Replacing a from the children of b. - */ - --_data[b].degree; - - if ( _data[b].degree !=0 ) { - int child=_data[b].child; - if ( child==a ) - _data[b].child=_data[child].right_neighbor; - unlace(a); - } - - - /*Lacing a to the roots.*/ - int right=_data[_minimum].right_neighbor; - _data[_minimum].right_neighbor=a; - _data[a].left_neighbor=_minimum; - _data[a].right_neighbor=right; - _data[right].left_neighbor=a; - - _data[a].parent=-1; - _data[a].marked=false; - } - - void cascade(int a) { - if ( _data[a].parent!=-1 ) { - int p=_data[a].parent; - - if ( _data[a].marked==false ) _data[a].marked=true; - else { - cut(a,p); - cascade(p); - } - } - } - - void fuse(int a, int b) { - unlace(b); - - /*Lacing b under a.*/ - _data[b].parent=a; - - if (_data[a].degree==0) { - _data[b].left_neighbor=b; - _data[b].right_neighbor=b; - _data[a].child=b; - } else { - int child=_data[a].child; - int last_child=_data[child].left_neighbor; - _data[child].left_neighbor=b; - _data[b].right_neighbor=child; - _data[last_child].right_neighbor=b; - _data[b].left_neighbor=last_child; - } - - ++_data[a].degree; - - _data[b].marked=false; - } - - /* - *It is invoked only if a has siblings. - */ - void unlace(int a) { - int leftn=_data[a].left_neighbor; - int rightn=_data[a].right_neighbor; - _data[leftn].right_neighbor=rightn; - _data[rightn].left_neighbor=leftn; - } - - - class Store { - friend class FibHeap; - - Item name; - int parent; - int left_neighbor; - int right_neighbor; - int child; - int degree; - bool marked; - bool in; - Prio prio; - - Store() : parent(-1), child(-1), degree(), marked(false), in(true) {} - }; - }; - -} //namespace lemon - -#endif //LEMON_FIB_HEAP_H - diff --git a/deps/lemon/lemon/fractional_matching.h b/deps/lemon/lemon/fractional_matching.h deleted file mode 100644 index 7448f411d..000000000 --- a/deps/lemon/lemon/fractional_matching.h +++ /dev/null @@ -1,2139 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_FRACTIONAL_MATCHING_H -#define LEMON_FRACTIONAL_MATCHING_H - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -///\ingroup matching -///\file -///\brief Fractional matching algorithms in general graphs. - -namespace lemon { - - /// \brief Default traits class of MaxFractionalMatching class. - /// - /// Default traits class of MaxFractionalMatching class. - /// \tparam GR Graph type. - template - struct MaxFractionalMatchingDefaultTraits { - - /// \brief The type of the graph the algorithm runs on. - typedef GR Graph; - - /// \brief The type of the map that stores the matching. - /// - /// The type of the map that stores the matching arcs. - /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. - typedef typename Graph::template NodeMap MatchingMap; - - /// \brief Instantiates a MatchingMap. - /// - /// This function instantiates a \ref MatchingMap. - /// \param graph The graph for which we would like to define - /// the matching map. - static MatchingMap* createMatchingMap(const Graph& graph) { - return new MatchingMap(graph); - } - - /// \brief The elevator type used by MaxFractionalMatching algorithm. - /// - /// The elevator type used by MaxFractionalMatching algorithm. - /// - /// \sa Elevator - /// \sa LinkedElevator - typedef LinkedElevator Elevator; - - /// \brief Instantiates an Elevator. - /// - /// This function instantiates an \ref Elevator. - /// \param graph The graph for which we would like to define - /// the elevator. - /// \param max_level The maximum level of the elevator. - static Elevator* createElevator(const Graph& graph, int max_level) { - return new Elevator(graph, max_level); - } - }; - - /// \ingroup matching - /// - /// \brief Max cardinality fractional matching - /// - /// This class provides an implementation of fractional matching - /// algorithm based on push-relabel principle. - /// - /// The maximum cardinality fractional matching is a relaxation of the - /// maximum cardinality matching problem where the odd set constraints - /// are omitted. - /// It can be formulated with the following linear program. - /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f] - /// \f[x_e \ge 0\quad \forall e\in E\f] - /// \f[\max \sum_{e\in E}x_e\f] - /// where \f$\delta(X)\f$ is the set of edges incident to a node in - /// \f$X\f$. The result can be represented as the union of a - /// matching with one value edges and a set of odd length cycles - /// with half value edges. - /// - /// The algorithm calculates an optimal fractional matching and a - /// barrier. The number of adjacents of any node set minus the size - /// of node set is a lower bound on the uncovered nodes in the - /// graph. For maximum matching a barrier is computed which - /// maximizes this difference. - /// - /// The algorithm can be executed with the run() function. After it - /// the matching (the primal solution) and the barrier (the dual - /// solution) can be obtained using the query functions. - /// - /// The primal solution is multiplied by - /// \ref MaxFractionalMatching::primalScale "2". - /// - /// \tparam GR The undirected graph type the algorithm runs on. -#ifdef DOXYGEN - template -#else - template > -#endif - class MaxFractionalMatching { - public: - - /// \brief The \ref lemon::MaxFractionalMatchingDefaultTraits - /// "traits class" of the algorithm. - typedef TR Traits; - /// The type of the graph the algorithm runs on. - typedef typename TR::Graph Graph; - /// The type of the matching map. - typedef typename TR::MatchingMap MatchingMap; - /// The type of the elevator. - typedef typename TR::Elevator Elevator; - - /// \brief Scaling factor for primal solution - /// - /// Scaling factor for primal solution. - static const int primalScale = 2; - - private: - - const Graph &_graph; - int _node_num; - bool _allow_loops; - int _empty_level; - - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - bool _local_matching; - MatchingMap *_matching; - - bool _local_level; - Elevator *_level; - - typedef typename Graph::template NodeMap InDegMap; - InDegMap *_indeg; - - void createStructures() { - _node_num = countNodes(_graph); - - if (!_matching) { - _local_matching = true; - _matching = Traits::createMatchingMap(_graph); - } - if (!_level) { - _local_level = true; - _level = Traits::createElevator(_graph, _node_num); - } - if (!_indeg) { - _indeg = new InDegMap(_graph); - } - } - - void destroyStructures() { - if (_local_matching) { - delete _matching; - } - if (_local_level) { - delete _level; - } - if (_indeg) { - delete _indeg; - } - } - - void postprocessing() { - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_indeg)[n] != 0) continue; - _indeg->set(n, -1); - Node u = n; - while ((*_matching)[u] != INVALID) { - Node v = _graph.target((*_matching)[u]); - _indeg->set(v, -1); - Arc a = _graph.oppositeArc((*_matching)[u]); - u = _graph.target((*_matching)[v]); - _indeg->set(u, -1); - _matching->set(v, a); - } - } - - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_indeg)[n] != 1) continue; - _indeg->set(n, -1); - - int num = 1; - Node u = _graph.target((*_matching)[n]); - while (u != n) { - _indeg->set(u, -1); - u = _graph.target((*_matching)[u]); - ++num; - } - if (num % 2 == 0 && num > 2) { - Arc prev = _graph.oppositeArc((*_matching)[n]); - Node v = _graph.target((*_matching)[n]); - u = _graph.target((*_matching)[v]); - _matching->set(v, prev); - while (u != n) { - prev = _graph.oppositeArc((*_matching)[u]); - v = _graph.target((*_matching)[u]); - u = _graph.target((*_matching)[v]); - _matching->set(v, prev); - } - } - } - } - - public: - - typedef MaxFractionalMatching Create; - - ///\name Named Template Parameters - - ///@{ - - template - struct SetMatchingMapTraits : public Traits { - typedef T MatchingMap; - static MatchingMap *createMatchingMap(const Graph&) { - LEMON_ASSERT(false, "MatchingMap is not initialized"); - return 0; // ignore warnings - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// MatchingMap type - /// - /// \ref named-templ-param "Named parameter" for setting MatchingMap - /// type. - template - struct SetMatchingMap - : public MaxFractionalMatching > { - typedef MaxFractionalMatching > Create; - }; - - template - struct SetElevatorTraits : public Traits { - typedef T Elevator; - static Elevator *createElevator(const Graph&, int) { - LEMON_ASSERT(false, "Elevator is not initialized"); - return 0; // ignore warnings - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// Elevator type - /// - /// \ref named-templ-param "Named parameter" for setting Elevator - /// type. If this named parameter is used, then an external - /// elevator object must be passed to the algorithm using the - /// \ref elevator(Elevator&) "elevator()" function before calling - /// \ref run() or \ref init(). - /// \sa SetStandardElevator - template - struct SetElevator - : public MaxFractionalMatching > { - typedef MaxFractionalMatching > Create; - }; - - template - struct SetStandardElevatorTraits : public Traits { - typedef T Elevator; - static Elevator *createElevator(const Graph& graph, int max_level) { - return new Elevator(graph, max_level); - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// Elevator type with automatic allocation - /// - /// \ref named-templ-param "Named parameter" for setting Elevator - /// type with automatic allocation. - /// The Elevator should have standard constructor interface to be - /// able to automatically created by the algorithm (i.e. the - /// graph and the maximum level should be passed to it). - /// However an external elevator object could also be passed to the - /// algorithm with the \ref elevator(Elevator&) "elevator()" function - /// before calling \ref run() or \ref init(). - /// \sa SetElevator - template - struct SetStandardElevator - : public MaxFractionalMatching > { - typedef MaxFractionalMatching > Create; - }; - - /// @} - - protected: - - MaxFractionalMatching() {} - - public: - - /// \brief Constructor - /// - /// Constructor. - /// - MaxFractionalMatching(const Graph &graph, bool allow_loops = true) - : _graph(graph), _allow_loops(allow_loops), - _local_matching(false), _matching(0), - _local_level(false), _level(0), _indeg(0) - {} - - ~MaxFractionalMatching() { - destroyStructures(); - } - - /// \brief Sets the matching map. - /// - /// Sets the matching map. - /// If you don't use this function before calling \ref run() or - /// \ref init(), an instance will be allocated automatically. - /// The destructor deallocates this automatically allocated map, - /// of course. - /// \return (*this) - MaxFractionalMatching& matchingMap(MatchingMap& map) { - if (_local_matching) { - delete _matching; - _local_matching = false; - } - _matching = ↦ - return *this; - } - - /// \brief Sets the elevator used by algorithm. - /// - /// Sets the elevator used by algorithm. - /// If you don't use this function before calling \ref run() or - /// \ref init(), an instance will be allocated automatically. - /// The destructor deallocates this automatically allocated elevator, - /// of course. - /// \return (*this) - MaxFractionalMatching& elevator(Elevator& elevator) { - if (_local_level) { - delete _level; - _local_level = false; - } - _level = &elevator; - return *this; - } - - /// \brief Returns a const reference to the elevator. - /// - /// Returns a const reference to the elevator. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - const Elevator& elevator() const { - return *_level; - } - - /// \name Execution control - /// The simplest way to execute the algorithm is to use one of the - /// member functions called \c run(). \n - /// If you need more control on the execution, first - /// you must call \ref init() and then one variant of the start() - /// member. - - /// @{ - - /// \brief Initializes the internal data structures. - /// - /// Initializes the internal data structures and sets the initial - /// matching. - void init() { - createStructures(); - - _level->initStart(); - for (NodeIt n(_graph); n != INVALID; ++n) { - _indeg->set(n, 0); - _matching->set(n, INVALID); - _level->initAddItem(n); - } - _level->initFinish(); - - _empty_level = _node_num; - for (NodeIt n(_graph); n != INVALID; ++n) { - for (OutArcIt a(_graph, n); a != INVALID; ++a) { - if (_graph.target(a) == n && !_allow_loops) continue; - _matching->set(n, a); - Node v = _graph.target((*_matching)[n]); - _indeg->set(v, (*_indeg)[v] + 1); - break; - } - } - - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_indeg)[n] == 0) { - _level->activate(n); - } - } - } - - /// \brief Starts the algorithm and computes a fractional matching - /// - /// The algorithm computes a maximum fractional matching. - /// - /// \param postprocess The algorithm computes first a matching - /// which is a union of a matching with one value edges, cycles - /// with half value edges and even length paths with half value - /// edges. If the parameter is true, then after the push-relabel - /// algorithm it postprocesses the matching to contain only - /// matching edges and half value odd cycles. - void start(bool postprocess = true) { - Node n; - while ((n = _level->highestActive()) != INVALID) { - int level = _level->highestActiveLevel(); - int new_level = _level->maxLevel(); - for (InArcIt a(_graph, n); a != INVALID; ++a) { - Node u = _graph.source(a); - if (n == u && !_allow_loops) continue; - Node v = _graph.target((*_matching)[u]); - if ((*_level)[v] < level) { - _indeg->set(v, (*_indeg)[v] - 1); - if ((*_indeg)[v] == 0) { - _level->activate(v); - } - _matching->set(u, a); - _indeg->set(n, (*_indeg)[n] + 1); - _level->deactivate(n); - goto no_more_push; - } else if (new_level > (*_level)[v]) { - new_level = (*_level)[v]; - } - } - - if (new_level + 1 < _level->maxLevel()) { - _level->liftHighestActive(new_level + 1); - } else { - _level->liftHighestActiveToTop(); - } - if (_level->emptyLevel(level)) { - _level->liftToTop(level); - } - no_more_push: - ; - } - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_matching)[n] == INVALID) continue; - Node u = _graph.target((*_matching)[n]); - if ((*_indeg)[u] > 1) { - _indeg->set(u, (*_indeg)[u] - 1); - _matching->set(n, INVALID); - } - } - if (postprocess) { - postprocessing(); - } - } - - /// \brief Starts the algorithm and computes a perfect fractional - /// matching - /// - /// The algorithm computes a perfect fractional matching. If it - /// does not exists, then the algorithm returns false and the - /// matching is undefined and the barrier. - /// - /// \param postprocess The algorithm computes first a matching - /// which is a union of a matching with one value edges, cycles - /// with half value edges and even length paths with half value - /// edges. If the parameter is true, then after the push-relabel - /// algorithm it postprocesses the matching to contain only - /// matching edges and half value odd cycles. - bool startPerfect(bool postprocess = true) { - Node n; - while ((n = _level->highestActive()) != INVALID) { - int level = _level->highestActiveLevel(); - int new_level = _level->maxLevel(); - for (InArcIt a(_graph, n); a != INVALID; ++a) { - Node u = _graph.source(a); - if (n == u && !_allow_loops) continue; - Node v = _graph.target((*_matching)[u]); - if ((*_level)[v] < level) { - _indeg->set(v, (*_indeg)[v] - 1); - if ((*_indeg)[v] == 0) { - _level->activate(v); - } - _matching->set(u, a); - _indeg->set(n, (*_indeg)[n] + 1); - _level->deactivate(n); - goto no_more_push; - } else if (new_level > (*_level)[v]) { - new_level = (*_level)[v]; - } - } - - if (new_level + 1 < _level->maxLevel()) { - _level->liftHighestActive(new_level + 1); - } else { - _level->liftHighestActiveToTop(); - _empty_level = _level->maxLevel() - 1; - return false; - } - if (_level->emptyLevel(level)) { - _level->liftToTop(level); - _empty_level = level; - return false; - } - no_more_push: - ; - } - if (postprocess) { - postprocessing(); - } - return true; - } - - /// \brief Runs the algorithm - /// - /// Just a shortcut for the next code: - ///\code - /// init(); - /// start(); - ///\endcode - void run(bool postprocess = true) { - init(); - start(postprocess); - } - - /// \brief Runs the algorithm to find a perfect fractional matching - /// - /// Just a shortcut for the next code: - ///\code - /// init(); - /// startPerfect(); - ///\endcode - bool runPerfect(bool postprocess = true) { - init(); - return startPerfect(postprocess); - } - - ///@} - - /// \name Query Functions - /// The result of the %Matching algorithm can be obtained using these - /// functions.\n - /// Before the use of these functions, - /// either run() or start() must be called. - ///@{ - - - /// \brief Return the number of covered nodes in the matching. - /// - /// This function returns the number of covered nodes in the matching. - /// - /// \pre Either run() or start() must be called before using this function. - int matchingSize() const { - int num = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_matching)[n] != INVALID) { - ++num; - } - } - return num; - } - - /// \brief Returns a const reference to the matching map. - /// - /// Returns a const reference to the node map storing the found - /// fractional matching. This method can be called after - /// running the algorithm. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - const MatchingMap& matchingMap() const { - return *_matching; - } - - /// \brief Return \c true if the given edge is in the matching. - /// - /// This function returns \c true if the given edge is in the - /// found matching. The result is scaled by \ref primalScale - /// "primal scale". - /// - /// \pre Either run() or start() must be called before using this function. - int matching(const Edge& edge) const { - return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) + - (edge == (*_matching)[_graph.v(edge)] ? 1 : 0); - } - - /// \brief Return the fractional matching arc (or edge) incident - /// to the given node. - /// - /// This function returns one of the fractional matching arc (or - /// edge) incident to the given node in the found matching or \c - /// INVALID if the node is not covered by the matching or if the - /// node is on an odd length cycle then it is the successor edge - /// on the cycle. - /// - /// \pre Either run() or start() must be called before using this function. - Arc matching(const Node& node) const { - return (*_matching)[node]; - } - - /// \brief Returns true if the node is in the barrier - /// - /// The barrier is a subset of the nodes. If the nodes in the - /// barrier have less adjacent nodes than the size of the barrier, - /// then at least as much nodes cannot be covered as the - /// difference of the two subsets. - bool barrier(const Node& node) const { - return (*_level)[node] >= _empty_level; - } - - /// @} - - }; - - /// \ingroup matching - /// - /// \brief Weighted fractional matching in general graphs - /// - /// This class provides an efficient implementation of fractional - /// matching algorithm. The implementation uses priority queues and - /// provides \f$O(nm\log n)\f$ time complexity. - /// - /// The maximum weighted fractional matching is a relaxation of the - /// maximum weighted matching problem where the odd set constraints - /// are omitted. - /// It can be formulated with the following linear program. - /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f] - /// \f[x_e \ge 0\quad \forall e\in E\f] - /// \f[\max \sum_{e\in E}x_ew_e\f] - /// where \f$\delta(X)\f$ is the set of edges incident to a node in - /// \f$X\f$. The result must be the union of a matching with one - /// value edges and a set of odd length cycles with half value edges. - /// - /// The algorithm calculates an optimal fractional matching and a - /// proof of the optimality. The solution of the dual problem can be - /// used to check the result of the algorithm. The dual linear - /// problem is the following. - /// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f] - /// \f[y_u \ge 0 \quad \forall u \in V\f] - /// \f[\min \sum_{u \in V}y_u \f] - /// - /// The algorithm can be executed with the run() function. - /// After it the matching (the primal solution) and the dual solution - /// can be obtained using the query functions. - /// - /// The primal solution is multiplied by - /// \ref MaxWeightedFractionalMatching::primalScale "2". - /// If the value type is integer, then the dual - /// solution is scaled by - /// \ref MaxWeightedFractionalMatching::dualScale "4". - /// - /// \tparam GR The undirected graph type the algorithm runs on. - /// \tparam WM The type edge weight map. The default type is - /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". -#ifdef DOXYGEN - template -#else - template > -#endif - class MaxWeightedFractionalMatching { - public: - - /// The graph type of the algorithm - typedef GR Graph; - /// The type of the edge weight map - typedef WM WeightMap; - /// The value type of the edge weights - typedef typename WeightMap::Value Value; - - /// The type of the matching map - typedef typename Graph::template NodeMap - MatchingMap; - - /// \brief Scaling factor for primal solution - /// - /// Scaling factor for primal solution. - static const int primalScale = 2; - - /// \brief Scaling factor for dual solution - /// - /// Scaling factor for dual solution. It is equal to 4 or 1 - /// according to the value type. - static const int dualScale = - std::numeric_limits::is_integer ? 4 : 1; - - private: - - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - typedef typename Graph::template NodeMap NodePotential; - - const Graph& _graph; - const WeightMap& _weight; - - MatchingMap* _matching; - NodePotential* _node_potential; - - int _node_num; - bool _allow_loops; - - enum Status { - EVEN = -1, MATCHED = 0, ODD = 1 - }; - - typedef typename Graph::template NodeMap StatusMap; - StatusMap* _status; - - typedef typename Graph::template NodeMap PredMap; - PredMap* _pred; - - typedef ExtendFindEnum TreeSet; - - IntNodeMap *_tree_set_index; - TreeSet *_tree_set; - - IntNodeMap *_delta1_index; - BinHeap *_delta1; - - IntNodeMap *_delta2_index; - BinHeap *_delta2; - - IntEdgeMap *_delta3_index; - BinHeap *_delta3; - - Value _delta_sum; - - void createStructures() { - _node_num = countNodes(_graph); - - if (!_matching) { - _matching = new MatchingMap(_graph); - } - if (!_node_potential) { - _node_potential = new NodePotential(_graph); - } - if (!_status) { - _status = new StatusMap(_graph); - } - if (!_pred) { - _pred = new PredMap(_graph); - } - if (!_tree_set) { - _tree_set_index = new IntNodeMap(_graph); - _tree_set = new TreeSet(*_tree_set_index); - } - if (!_delta1) { - _delta1_index = new IntNodeMap(_graph); - _delta1 = new BinHeap(*_delta1_index); - } - if (!_delta2) { - _delta2_index = new IntNodeMap(_graph); - _delta2 = new BinHeap(*_delta2_index); - } - if (!_delta3) { - _delta3_index = new IntEdgeMap(_graph); - _delta3 = new BinHeap(*_delta3_index); - } - } - - void destroyStructures() { - if (_matching) { - delete _matching; - } - if (_node_potential) { - delete _node_potential; - } - if (_status) { - delete _status; - } - if (_pred) { - delete _pred; - } - if (_tree_set) { - delete _tree_set_index; - delete _tree_set; - } - if (_delta1) { - delete _delta1_index; - delete _delta1; - } - if (_delta2) { - delete _delta2_index; - delete _delta2; - } - if (_delta3) { - delete _delta3_index; - delete _delta3; - } - } - - void matchedToEven(Node node, int tree) { - _tree_set->insert(node, tree); - _node_potential->set(node, (*_node_potential)[node] + _delta_sum); - _delta1->push(node, (*_node_potential)[node]); - - if (_delta2->state(node) == _delta2->IN_HEAP) { - _delta2->erase(node); - } - - for (InArcIt a(_graph, node); a != INVALID; ++a) { - Node v = _graph.source(a); - Value rw = (*_node_potential)[node] + (*_node_potential)[v] - - dualScale * _weight[a]; - if (node == v) { - if (_allow_loops && _graph.direction(a)) { - _delta3->push(a, rw / 2); - } - } else if ((*_status)[v] == EVEN) { - _delta3->push(a, rw / 2); - } else if ((*_status)[v] == MATCHED) { - if (_delta2->state(v) != _delta2->IN_HEAP) { - _pred->set(v, a); - _delta2->push(v, rw); - } else if ((*_delta2)[v] > rw) { - _pred->set(v, a); - _delta2->decrease(v, rw); - } - } - } - } - - void matchedToOdd(Node node, int tree) { - _tree_set->insert(node, tree); - _node_potential->set(node, (*_node_potential)[node] - _delta_sum); - - if (_delta2->state(node) == _delta2->IN_HEAP) { - _delta2->erase(node); - } - } - - void evenToMatched(Node node, int tree) { - _delta1->erase(node); - _node_potential->set(node, (*_node_potential)[node] - _delta_sum); - Arc min = INVALID; - Value minrw = std::numeric_limits::max(); - for (InArcIt a(_graph, node); a != INVALID; ++a) { - Node v = _graph.source(a); - Value rw = (*_node_potential)[node] + (*_node_potential)[v] - - dualScale * _weight[a]; - - if (node == v) { - if (_allow_loops && _graph.direction(a)) { - _delta3->erase(a); - } - } else if ((*_status)[v] == EVEN) { - _delta3->erase(a); - if (minrw > rw) { - min = _graph.oppositeArc(a); - minrw = rw; - } - } else if ((*_status)[v] == MATCHED) { - if ((*_pred)[v] == a) { - Arc mina = INVALID; - Value minrwa = std::numeric_limits::max(); - for (OutArcIt aa(_graph, v); aa != INVALID; ++aa) { - Node va = _graph.target(aa); - if ((*_status)[va] != EVEN || - _tree_set->find(va) == tree) continue; - Value rwa = (*_node_potential)[v] + (*_node_potential)[va] - - dualScale * _weight[aa]; - if (minrwa > rwa) { - minrwa = rwa; - mina = aa; - } - } - if (mina != INVALID) { - _pred->set(v, mina); - _delta2->increase(v, minrwa); - } else { - _pred->set(v, INVALID); - _delta2->erase(v); - } - } - } - } - if (min != INVALID) { - _pred->set(node, min); - _delta2->push(node, minrw); - } else { - _pred->set(node, INVALID); - } - } - - void oddToMatched(Node node) { - _node_potential->set(node, (*_node_potential)[node] + _delta_sum); - Arc min = INVALID; - Value minrw = std::numeric_limits::max(); - for (InArcIt a(_graph, node); a != INVALID; ++a) { - Node v = _graph.source(a); - if ((*_status)[v] != EVEN) continue; - Value rw = (*_node_potential)[node] + (*_node_potential)[v] - - dualScale * _weight[a]; - - if (minrw > rw) { - min = _graph.oppositeArc(a); - minrw = rw; - } - } - if (min != INVALID) { - _pred->set(node, min); - _delta2->push(node, minrw); - } else { - _pred->set(node, INVALID); - } - } - - void alternatePath(Node even, int tree) { - Node odd; - - _status->set(even, MATCHED); - evenToMatched(even, tree); - - Arc prev = (*_matching)[even]; - while (prev != INVALID) { - odd = _graph.target(prev); - even = _graph.target((*_pred)[odd]); - _matching->set(odd, (*_pred)[odd]); - _status->set(odd, MATCHED); - oddToMatched(odd); - - prev = (*_matching)[even]; - _status->set(even, MATCHED); - _matching->set(even, _graph.oppositeArc((*_matching)[odd])); - evenToMatched(even, tree); - } - } - - void destroyTree(int tree) { - for (typename TreeSet::ItemIt n(*_tree_set, tree); n != INVALID; ++n) { - if ((*_status)[n] == EVEN) { - _status->set(n, MATCHED); - evenToMatched(n, tree); - } else if ((*_status)[n] == ODD) { - _status->set(n, MATCHED); - oddToMatched(n); - } - } - _tree_set->eraseClass(tree); - } - - - void unmatchNode(const Node& node) { - int tree = _tree_set->find(node); - - alternatePath(node, tree); - destroyTree(tree); - - _matching->set(node, INVALID); - } - - - void augmentOnEdge(const Edge& edge) { - Node left = _graph.u(edge); - int left_tree = _tree_set->find(left); - - alternatePath(left, left_tree); - destroyTree(left_tree); - _matching->set(left, _graph.direct(edge, true)); - - Node right = _graph.v(edge); - int right_tree = _tree_set->find(right); - - alternatePath(right, right_tree); - destroyTree(right_tree); - _matching->set(right, _graph.direct(edge, false)); - } - - void augmentOnArc(const Arc& arc) { - Node left = _graph.source(arc); - _status->set(left, MATCHED); - _matching->set(left, arc); - _pred->set(left, arc); - - Node right = _graph.target(arc); - int right_tree = _tree_set->find(right); - - alternatePath(right, right_tree); - destroyTree(right_tree); - _matching->set(right, _graph.oppositeArc(arc)); - } - - void extendOnArc(const Arc& arc) { - Node base = _graph.target(arc); - int tree = _tree_set->find(base); - - Node odd = _graph.source(arc); - _tree_set->insert(odd, tree); - _status->set(odd, ODD); - matchedToOdd(odd, tree); - _pred->set(odd, arc); - - Node even = _graph.target((*_matching)[odd]); - _tree_set->insert(even, tree); - _status->set(even, EVEN); - matchedToEven(even, tree); - } - - void cycleOnEdge(const Edge& edge, int tree) { - Node nca = INVALID; - std::vector left_path, right_path; - - { - std::set left_set, right_set; - Node left = _graph.u(edge); - left_path.push_back(left); - left_set.insert(left); - - Node right = _graph.v(edge); - right_path.push_back(right); - right_set.insert(right); - - while (true) { - - if (left_set.find(right) != left_set.end()) { - nca = right; - break; - } - - if ((*_matching)[left] == INVALID) break; - - left = _graph.target((*_matching)[left]); - left_path.push_back(left); - left = _graph.target((*_pred)[left]); - left_path.push_back(left); - - left_set.insert(left); - - if (right_set.find(left) != right_set.end()) { - nca = left; - break; - } - - if ((*_matching)[right] == INVALID) break; - - right = _graph.target((*_matching)[right]); - right_path.push_back(right); - right = _graph.target((*_pred)[right]); - right_path.push_back(right); - - right_set.insert(right); - - } - - if (nca == INVALID) { - if ((*_matching)[left] == INVALID) { - nca = right; - while (left_set.find(nca) == left_set.end()) { - nca = _graph.target((*_matching)[nca]); - right_path.push_back(nca); - nca = _graph.target((*_pred)[nca]); - right_path.push_back(nca); - } - } else { - nca = left; - while (right_set.find(nca) == right_set.end()) { - nca = _graph.target((*_matching)[nca]); - left_path.push_back(nca); - nca = _graph.target((*_pred)[nca]); - left_path.push_back(nca); - } - } - } - } - - alternatePath(nca, tree); - Arc prev; - - prev = _graph.direct(edge, true); - for (int i = 0; left_path[i] != nca; i += 2) { - _matching->set(left_path[i], prev); - _status->set(left_path[i], MATCHED); - evenToMatched(left_path[i], tree); - - prev = _graph.oppositeArc((*_pred)[left_path[i + 1]]); - _status->set(left_path[i + 1], MATCHED); - oddToMatched(left_path[i + 1]); - } - _matching->set(nca, prev); - - for (int i = 0; right_path[i] != nca; i += 2) { - _status->set(right_path[i], MATCHED); - evenToMatched(right_path[i], tree); - - _matching->set(right_path[i + 1], (*_pred)[right_path[i + 1]]); - _status->set(right_path[i + 1], MATCHED); - oddToMatched(right_path[i + 1]); - } - - destroyTree(tree); - } - - void extractCycle(const Arc &arc) { - Node left = _graph.source(arc); - Node odd = _graph.target((*_matching)[left]); - Arc prev; - while (odd != left) { - Node even = _graph.target((*_matching)[odd]); - prev = (*_matching)[odd]; - odd = _graph.target((*_matching)[even]); - _matching->set(even, _graph.oppositeArc(prev)); - } - _matching->set(left, arc); - - Node right = _graph.target(arc); - int right_tree = _tree_set->find(right); - alternatePath(right, right_tree); - destroyTree(right_tree); - _matching->set(right, _graph.oppositeArc(arc)); - } - - public: - - /// \brief Constructor - /// - /// Constructor. - MaxWeightedFractionalMatching(const Graph& graph, const WeightMap& weight, - bool allow_loops = true) - : _graph(graph), _weight(weight), _matching(0), - _node_potential(0), _node_num(0), _allow_loops(allow_loops), - _status(0), _pred(0), - _tree_set_index(0), _tree_set(0), - - _delta1_index(0), _delta1(0), - _delta2_index(0), _delta2(0), - _delta3_index(0), _delta3(0), - - _delta_sum() {} - - ~MaxWeightedFractionalMatching() { - destroyStructures(); - } - - /// \name Execution Control - /// The simplest way to execute the algorithm is to use the - /// \ref run() member function. - - ///@{ - - /// \brief Initialize the algorithm - /// - /// This function initializes the algorithm. - void init() { - createStructures(); - - for (NodeIt n(_graph); n != INVALID; ++n) { - (*_delta1_index)[n] = _delta1->PRE_HEAP; - (*_delta2_index)[n] = _delta2->PRE_HEAP; - } - for (EdgeIt e(_graph); e != INVALID; ++e) { - (*_delta3_index)[e] = _delta3->PRE_HEAP; - } - - _delta1->clear(); - _delta2->clear(); - _delta3->clear(); - _tree_set->clear(); - - for (NodeIt n(_graph); n != INVALID; ++n) { - Value max = 0; - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - if (_graph.target(e) == n && !_allow_loops) continue; - if ((dualScale * _weight[e]) / 2 > max) { - max = (dualScale * _weight[e]) / 2; - } - } - _node_potential->set(n, max); - _delta1->push(n, max); - - _tree_set->insert(n); - - _matching->set(n, INVALID); - _status->set(n, EVEN); - } - - for (EdgeIt e(_graph); e != INVALID; ++e) { - Node left = _graph.u(e); - Node right = _graph.v(e); - if (left == right && !_allow_loops) continue; - _delta3->push(e, ((*_node_potential)[left] + - (*_node_potential)[right] - - dualScale * _weight[e]) / 2); - } - } - - /// \brief Start the algorithm - /// - /// This function starts the algorithm. - /// - /// \pre \ref init() must be called before using this function. - void start() { - enum OpType { - D1, D2, D3 - }; - - int unmatched = _node_num; - while (unmatched > 0) { - Value d1 = !_delta1->empty() ? - _delta1->prio() : std::numeric_limits::max(); - - Value d2 = !_delta2->empty() ? - _delta2->prio() : std::numeric_limits::max(); - - Value d3 = !_delta3->empty() ? - _delta3->prio() : std::numeric_limits::max(); - - _delta_sum = d3; OpType ot = D3; - if (d1 < _delta_sum) { _delta_sum = d1; ot = D1; } - if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } - - switch (ot) { - case D1: - { - Node n = _delta1->top(); - unmatchNode(n); - --unmatched; - } - break; - case D2: - { - Node n = _delta2->top(); - Arc a = (*_pred)[n]; - if ((*_matching)[n] == INVALID) { - augmentOnArc(a); - --unmatched; - } else { - Node v = _graph.target((*_matching)[n]); - if ((*_matching)[n] != - _graph.oppositeArc((*_matching)[v])) { - extractCycle(a); - --unmatched; - } else { - extendOnArc(a); - } - } - } break; - case D3: - { - Edge e = _delta3->top(); - - Node left = _graph.u(e); - Node right = _graph.v(e); - - int left_tree = _tree_set->find(left); - int right_tree = _tree_set->find(right); - - if (left_tree == right_tree) { - cycleOnEdge(e, left_tree); - --unmatched; - } else { - augmentOnEdge(e); - unmatched -= 2; - } - } break; - } - } - } - - /// \brief Run the algorithm. - /// - /// This method runs the \c %MaxWeightedFractionalMatching algorithm. - /// - /// \note mwfm.run() is just a shortcut of the following code. - /// \code - /// mwfm.init(); - /// mwfm.start(); - /// \endcode - void run() { - init(); - start(); - } - - /// @} - - /// \name Primal Solution - /// Functions to get the primal solution, i.e. the maximum weighted - /// matching.\n - /// Either \ref run() or \ref start() function should be called before - /// using them. - - /// @{ - - /// \brief Return the weight of the matching. - /// - /// This function returns the weight of the found matching. This - /// value is scaled by \ref primalScale "primal scale". - /// - /// \pre Either run() or start() must be called before using this function. - Value matchingWeight() const { - Value sum = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_matching)[n] != INVALID) { - sum += _weight[(*_matching)[n]]; - } - } - return sum * primalScale / 2; - } - - /// \brief Return the number of covered nodes in the matching. - /// - /// This function returns the number of covered nodes in the matching. - /// - /// \pre Either run() or start() must be called before using this function. - int matchingSize() const { - int num = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_matching)[n] != INVALID) { - ++num; - } - } - return num; - } - - /// \brief Return \c true if the given edge is in the matching. - /// - /// This function returns \c true if the given edge is in the - /// found matching. The result is scaled by \ref primalScale - /// "primal scale". - /// - /// \pre Either run() or start() must be called before using this function. - int matching(const Edge& edge) const { - return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) - + (edge == (*_matching)[_graph.v(edge)] ? 1 : 0); - } - - /// \brief Return the fractional matching arc (or edge) incident - /// to the given node. - /// - /// This function returns one of the fractional matching arc (or - /// edge) incident to the given node in the found matching or \c - /// INVALID if the node is not covered by the matching or if the - /// node is on an odd length cycle then it is the successor edge - /// on the cycle. - /// - /// \pre Either run() or start() must be called before using this function. - Arc matching(const Node& node) const { - return (*_matching)[node]; - } - - /// \brief Return a const reference to the matching map. - /// - /// This function returns a const reference to a node map that stores - /// the matching arc (or edge) incident to each node. - const MatchingMap& matchingMap() const { - return *_matching; - } - - /// @} - - /// \name Dual Solution - /// Functions to get the dual solution.\n - /// Either \ref run() or \ref start() function should be called before - /// using them. - - /// @{ - - /// \brief Return the value of the dual solution. - /// - /// This function returns the value of the dual solution. - /// It should be equal to the primal value scaled by \ref dualScale - /// "dual scale". - /// - /// \pre Either run() or start() must be called before using this function. - Value dualValue() const { - Value sum = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - sum += nodeValue(n); - } - return sum; - } - - /// \brief Return the dual value (potential) of the given node. - /// - /// This function returns the dual value (potential) of the given node. - /// - /// \pre Either run() or start() must be called before using this function. - Value nodeValue(const Node& n) const { - return (*_node_potential)[n]; - } - - /// @} - - }; - - /// \ingroup matching - /// - /// \brief Weighted fractional perfect matching in general graphs - /// - /// This class provides an efficient implementation of fractional - /// matching algorithm. The implementation uses priority queues and - /// provides \f$O(nm\log n)\f$ time complexity. - /// - /// The maximum weighted fractional perfect matching is a relaxation - /// of the maximum weighted perfect matching problem where the odd - /// set constraints are omitted. - /// It can be formulated with the following linear program. - /// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f] - /// \f[x_e \ge 0\quad \forall e\in E\f] - /// \f[\max \sum_{e\in E}x_ew_e\f] - /// where \f$\delta(X)\f$ is the set of edges incident to a node in - /// \f$X\f$. The result must be the union of a matching with one - /// value edges and a set of odd length cycles with half value edges. - /// - /// The algorithm calculates an optimal fractional matching and a - /// proof of the optimality. The solution of the dual problem can be - /// used to check the result of the algorithm. The dual linear - /// problem is the following. - /// \f[ y_u + y_v \ge w_{uv} \quad \forall uv\in E\f] - /// \f[\min \sum_{u \in V}y_u \f] - /// - /// The algorithm can be executed with the run() function. - /// After it the matching (the primal solution) and the dual solution - /// can be obtained using the query functions. - /// - /// The primal solution is multiplied by - /// \ref MaxWeightedPerfectFractionalMatching::primalScale "2". - /// If the value type is integer, then the dual - /// solution is scaled by - /// \ref MaxWeightedPerfectFractionalMatching::dualScale "4". - /// - /// \tparam GR The undirected graph type the algorithm runs on. - /// \tparam WM The type edge weight map. The default type is - /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". -#ifdef DOXYGEN - template -#else - template > -#endif - class MaxWeightedPerfectFractionalMatching { - public: - - /// The graph type of the algorithm - typedef GR Graph; - /// The type of the edge weight map - typedef WM WeightMap; - /// The value type of the edge weights - typedef typename WeightMap::Value Value; - - /// The type of the matching map - typedef typename Graph::template NodeMap - MatchingMap; - - /// \brief Scaling factor for primal solution - /// - /// Scaling factor for primal solution. - static const int primalScale = 2; - - /// \brief Scaling factor for dual solution - /// - /// Scaling factor for dual solution. It is equal to 4 or 1 - /// according to the value type. - static const int dualScale = - std::numeric_limits::is_integer ? 4 : 1; - - private: - - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - typedef typename Graph::template NodeMap NodePotential; - - const Graph& _graph; - const WeightMap& _weight; - - MatchingMap* _matching; - NodePotential* _node_potential; - - int _node_num; - bool _allow_loops; - - enum Status { - EVEN = -1, MATCHED = 0, ODD = 1 - }; - - typedef typename Graph::template NodeMap StatusMap; - StatusMap* _status; - - typedef typename Graph::template NodeMap PredMap; - PredMap* _pred; - - typedef ExtendFindEnum TreeSet; - - IntNodeMap *_tree_set_index; - TreeSet *_tree_set; - - IntNodeMap *_delta2_index; - BinHeap *_delta2; - - IntEdgeMap *_delta3_index; - BinHeap *_delta3; - - Value _delta_sum; - - void createStructures() { - _node_num = countNodes(_graph); - - if (!_matching) { - _matching = new MatchingMap(_graph); - } - if (!_node_potential) { - _node_potential = new NodePotential(_graph); - } - if (!_status) { - _status = new StatusMap(_graph); - } - if (!_pred) { - _pred = new PredMap(_graph); - } - if (!_tree_set) { - _tree_set_index = new IntNodeMap(_graph); - _tree_set = new TreeSet(*_tree_set_index); - } - if (!_delta2) { - _delta2_index = new IntNodeMap(_graph); - _delta2 = new BinHeap(*_delta2_index); - } - if (!_delta3) { - _delta3_index = new IntEdgeMap(_graph); - _delta3 = new BinHeap(*_delta3_index); - } - } - - void destroyStructures() { - if (_matching) { - delete _matching; - } - if (_node_potential) { - delete _node_potential; - } - if (_status) { - delete _status; - } - if (_pred) { - delete _pred; - } - if (_tree_set) { - delete _tree_set_index; - delete _tree_set; - } - if (_delta2) { - delete _delta2_index; - delete _delta2; - } - if (_delta3) { - delete _delta3_index; - delete _delta3; - } - } - - void matchedToEven(Node node, int tree) { - _tree_set->insert(node, tree); - _node_potential->set(node, (*_node_potential)[node] + _delta_sum); - - if (_delta2->state(node) == _delta2->IN_HEAP) { - _delta2->erase(node); - } - - for (InArcIt a(_graph, node); a != INVALID; ++a) { - Node v = _graph.source(a); - Value rw = (*_node_potential)[node] + (*_node_potential)[v] - - dualScale * _weight[a]; - if (node == v) { - if (_allow_loops && _graph.direction(a)) { - _delta3->push(a, rw / 2); - } - } else if ((*_status)[v] == EVEN) { - _delta3->push(a, rw / 2); - } else if ((*_status)[v] == MATCHED) { - if (_delta2->state(v) != _delta2->IN_HEAP) { - _pred->set(v, a); - _delta2->push(v, rw); - } else if ((*_delta2)[v] > rw) { - _pred->set(v, a); - _delta2->decrease(v, rw); - } - } - } - } - - void matchedToOdd(Node node, int tree) { - _tree_set->insert(node, tree); - _node_potential->set(node, (*_node_potential)[node] - _delta_sum); - - if (_delta2->state(node) == _delta2->IN_HEAP) { - _delta2->erase(node); - } - } - - void evenToMatched(Node node, int tree) { - _node_potential->set(node, (*_node_potential)[node] - _delta_sum); - Arc min = INVALID; - Value minrw = std::numeric_limits::max(); - for (InArcIt a(_graph, node); a != INVALID; ++a) { - Node v = _graph.source(a); - Value rw = (*_node_potential)[node] + (*_node_potential)[v] - - dualScale * _weight[a]; - - if (node == v) { - if (_allow_loops && _graph.direction(a)) { - _delta3->erase(a); - } - } else if ((*_status)[v] == EVEN) { - _delta3->erase(a); - if (minrw > rw) { - min = _graph.oppositeArc(a); - minrw = rw; - } - } else if ((*_status)[v] == MATCHED) { - if ((*_pred)[v] == a) { - Arc mina = INVALID; - Value minrwa = std::numeric_limits::max(); - for (OutArcIt aa(_graph, v); aa != INVALID; ++aa) { - Node va = _graph.target(aa); - if ((*_status)[va] != EVEN || - _tree_set->find(va) == tree) continue; - Value rwa = (*_node_potential)[v] + (*_node_potential)[va] - - dualScale * _weight[aa]; - if (minrwa > rwa) { - minrwa = rwa; - mina = aa; - } - } - if (mina != INVALID) { - _pred->set(v, mina); - _delta2->increase(v, minrwa); - } else { - _pred->set(v, INVALID); - _delta2->erase(v); - } - } - } - } - if (min != INVALID) { - _pred->set(node, min); - _delta2->push(node, minrw); - } else { - _pred->set(node, INVALID); - } - } - - void oddToMatched(Node node) { - _node_potential->set(node, (*_node_potential)[node] + _delta_sum); - Arc min = INVALID; - Value minrw = std::numeric_limits::max(); - for (InArcIt a(_graph, node); a != INVALID; ++a) { - Node v = _graph.source(a); - if ((*_status)[v] != EVEN) continue; - Value rw = (*_node_potential)[node] + (*_node_potential)[v] - - dualScale * _weight[a]; - - if (minrw > rw) { - min = _graph.oppositeArc(a); - minrw = rw; - } - } - if (min != INVALID) { - _pred->set(node, min); - _delta2->push(node, minrw); - } else { - _pred->set(node, INVALID); - } - } - - void alternatePath(Node even, int tree) { - Node odd; - - _status->set(even, MATCHED); - evenToMatched(even, tree); - - Arc prev = (*_matching)[even]; - while (prev != INVALID) { - odd = _graph.target(prev); - even = _graph.target((*_pred)[odd]); - _matching->set(odd, (*_pred)[odd]); - _status->set(odd, MATCHED); - oddToMatched(odd); - - prev = (*_matching)[even]; - _status->set(even, MATCHED); - _matching->set(even, _graph.oppositeArc((*_matching)[odd])); - evenToMatched(even, tree); - } - } - - void destroyTree(int tree) { - for (typename TreeSet::ItemIt n(*_tree_set, tree); n != INVALID; ++n) { - if ((*_status)[n] == EVEN) { - _status->set(n, MATCHED); - evenToMatched(n, tree); - } else if ((*_status)[n] == ODD) { - _status->set(n, MATCHED); - oddToMatched(n); - } - } - _tree_set->eraseClass(tree); - } - - void augmentOnEdge(const Edge& edge) { - Node left = _graph.u(edge); - int left_tree = _tree_set->find(left); - - alternatePath(left, left_tree); - destroyTree(left_tree); - _matching->set(left, _graph.direct(edge, true)); - - Node right = _graph.v(edge); - int right_tree = _tree_set->find(right); - - alternatePath(right, right_tree); - destroyTree(right_tree); - _matching->set(right, _graph.direct(edge, false)); - } - - void augmentOnArc(const Arc& arc) { - Node left = _graph.source(arc); - _status->set(left, MATCHED); - _matching->set(left, arc); - _pred->set(left, arc); - - Node right = _graph.target(arc); - int right_tree = _tree_set->find(right); - - alternatePath(right, right_tree); - destroyTree(right_tree); - _matching->set(right, _graph.oppositeArc(arc)); - } - - void extendOnArc(const Arc& arc) { - Node base = _graph.target(arc); - int tree = _tree_set->find(base); - - Node odd = _graph.source(arc); - _tree_set->insert(odd, tree); - _status->set(odd, ODD); - matchedToOdd(odd, tree); - _pred->set(odd, arc); - - Node even = _graph.target((*_matching)[odd]); - _tree_set->insert(even, tree); - _status->set(even, EVEN); - matchedToEven(even, tree); - } - - void cycleOnEdge(const Edge& edge, int tree) { - Node nca = INVALID; - std::vector left_path, right_path; - - { - std::set left_set, right_set; - Node left = _graph.u(edge); - left_path.push_back(left); - left_set.insert(left); - - Node right = _graph.v(edge); - right_path.push_back(right); - right_set.insert(right); - - while (true) { - - if (left_set.find(right) != left_set.end()) { - nca = right; - break; - } - - if ((*_matching)[left] == INVALID) break; - - left = _graph.target((*_matching)[left]); - left_path.push_back(left); - left = _graph.target((*_pred)[left]); - left_path.push_back(left); - - left_set.insert(left); - - if (right_set.find(left) != right_set.end()) { - nca = left; - break; - } - - if ((*_matching)[right] == INVALID) break; - - right = _graph.target((*_matching)[right]); - right_path.push_back(right); - right = _graph.target((*_pred)[right]); - right_path.push_back(right); - - right_set.insert(right); - - } - - if (nca == INVALID) { - if ((*_matching)[left] == INVALID) { - nca = right; - while (left_set.find(nca) == left_set.end()) { - nca = _graph.target((*_matching)[nca]); - right_path.push_back(nca); - nca = _graph.target((*_pred)[nca]); - right_path.push_back(nca); - } - } else { - nca = left; - while (right_set.find(nca) == right_set.end()) { - nca = _graph.target((*_matching)[nca]); - left_path.push_back(nca); - nca = _graph.target((*_pred)[nca]); - left_path.push_back(nca); - } - } - } - } - - alternatePath(nca, tree); - Arc prev; - - prev = _graph.direct(edge, true); - for (int i = 0; left_path[i] != nca; i += 2) { - _matching->set(left_path[i], prev); - _status->set(left_path[i], MATCHED); - evenToMatched(left_path[i], tree); - - prev = _graph.oppositeArc((*_pred)[left_path[i + 1]]); - _status->set(left_path[i + 1], MATCHED); - oddToMatched(left_path[i + 1]); - } - _matching->set(nca, prev); - - for (int i = 0; right_path[i] != nca; i += 2) { - _status->set(right_path[i], MATCHED); - evenToMatched(right_path[i], tree); - - _matching->set(right_path[i + 1], (*_pred)[right_path[i + 1]]); - _status->set(right_path[i + 1], MATCHED); - oddToMatched(right_path[i + 1]); - } - - destroyTree(tree); - } - - void extractCycle(const Arc &arc) { - Node left = _graph.source(arc); - Node odd = _graph.target((*_matching)[left]); - Arc prev; - while (odd != left) { - Node even = _graph.target((*_matching)[odd]); - prev = (*_matching)[odd]; - odd = _graph.target((*_matching)[even]); - _matching->set(even, _graph.oppositeArc(prev)); - } - _matching->set(left, arc); - - Node right = _graph.target(arc); - int right_tree = _tree_set->find(right); - alternatePath(right, right_tree); - destroyTree(right_tree); - _matching->set(right, _graph.oppositeArc(arc)); - } - - public: - - /// \brief Constructor - /// - /// Constructor. - MaxWeightedPerfectFractionalMatching(const Graph& graph, - const WeightMap& weight, - bool allow_loops = true) - : _graph(graph), _weight(weight), _matching(0), - _node_potential(0), _node_num(0), _allow_loops(allow_loops), - _status(0), _pred(0), - _tree_set_index(0), _tree_set(0), - - _delta2_index(0), _delta2(0), - _delta3_index(0), _delta3(0), - - _delta_sum() {} - - ~MaxWeightedPerfectFractionalMatching() { - destroyStructures(); - } - - /// \name Execution Control - /// The simplest way to execute the algorithm is to use the - /// \ref run() member function. - - ///@{ - - /// \brief Initialize the algorithm - /// - /// This function initializes the algorithm. - void init() { - createStructures(); - - for (NodeIt n(_graph); n != INVALID; ++n) { - (*_delta2_index)[n] = _delta2->PRE_HEAP; - } - for (EdgeIt e(_graph); e != INVALID; ++e) { - (*_delta3_index)[e] = _delta3->PRE_HEAP; - } - - _delta2->clear(); - _delta3->clear(); - _tree_set->clear(); - - for (NodeIt n(_graph); n != INVALID; ++n) { - Value max = - std::numeric_limits::max(); - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - if (_graph.target(e) == n && !_allow_loops) continue; - if ((dualScale * _weight[e]) / 2 > max) { - max = (dualScale * _weight[e]) / 2; - } - } - _node_potential->set(n, max); - - _tree_set->insert(n); - - _matching->set(n, INVALID); - _status->set(n, EVEN); - } - - for (EdgeIt e(_graph); e != INVALID; ++e) { - Node left = _graph.u(e); - Node right = _graph.v(e); - if (left == right && !_allow_loops) continue; - _delta3->push(e, ((*_node_potential)[left] + - (*_node_potential)[right] - - dualScale * _weight[e]) / 2); - } - } - - /// \brief Start the algorithm - /// - /// This function starts the algorithm. - /// - /// \pre \ref init() must be called before using this function. - bool start() { - enum OpType { - D2, D3 - }; - - int unmatched = _node_num; - while (unmatched > 0) { - Value d2 = !_delta2->empty() ? - _delta2->prio() : std::numeric_limits::max(); - - Value d3 = !_delta3->empty() ? - _delta3->prio() : std::numeric_limits::max(); - - _delta_sum = d3; OpType ot = D3; - if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } - - if (_delta_sum == std::numeric_limits::max()) { - return false; - } - - switch (ot) { - case D2: - { - Node n = _delta2->top(); - Arc a = (*_pred)[n]; - if ((*_matching)[n] == INVALID) { - augmentOnArc(a); - --unmatched; - } else { - Node v = _graph.target((*_matching)[n]); - if ((*_matching)[n] != - _graph.oppositeArc((*_matching)[v])) { - extractCycle(a); - --unmatched; - } else { - extendOnArc(a); - } - } - } break; - case D3: - { - Edge e = _delta3->top(); - - Node left = _graph.u(e); - Node right = _graph.v(e); - - int left_tree = _tree_set->find(left); - int right_tree = _tree_set->find(right); - - if (left_tree == right_tree) { - cycleOnEdge(e, left_tree); - --unmatched; - } else { - augmentOnEdge(e); - unmatched -= 2; - } - } break; - } - } - return true; - } - - /// \brief Run the algorithm. - /// - /// This method runs the \c %MaxWeightedPerfectFractionalMatching - /// algorithm. - /// - /// \note mwfm.run() is just a shortcut of the following code. - /// \code - /// mwpfm.init(); - /// mwpfm.start(); - /// \endcode - bool run() { - init(); - return start(); - } - - /// @} - - /// \name Primal Solution - /// Functions to get the primal solution, i.e. the maximum weighted - /// matching.\n - /// Either \ref run() or \ref start() function should be called before - /// using them. - - /// @{ - - /// \brief Return the weight of the matching. - /// - /// This function returns the weight of the found matching. This - /// value is scaled by \ref primalScale "primal scale". - /// - /// \pre Either run() or start() must be called before using this function. - Value matchingWeight() const { - Value sum = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_matching)[n] != INVALID) { - sum += _weight[(*_matching)[n]]; - } - } - return sum * primalScale / 2; - } - - /// \brief Return the number of covered nodes in the matching. - /// - /// This function returns the number of covered nodes in the matching. - /// - /// \pre Either run() or start() must be called before using this function. - int matchingSize() const { - int num = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_matching)[n] != INVALID) { - ++num; - } - } - return num; - } - - /// \brief Return \c true if the given edge is in the matching. - /// - /// This function returns \c true if the given edge is in the - /// found matching. The result is scaled by \ref primalScale - /// "primal scale". - /// - /// \pre Either run() or start() must be called before using this function. - int matching(const Edge& edge) const { - return (edge == (*_matching)[_graph.u(edge)] ? 1 : 0) - + (edge == (*_matching)[_graph.v(edge)] ? 1 : 0); - } - - /// \brief Return the fractional matching arc (or edge) incident - /// to the given node. - /// - /// This function returns one of the fractional matching arc (or - /// edge) incident to the given node in the found matching or \c - /// INVALID if the node is not covered by the matching or if the - /// node is on an odd length cycle then it is the successor edge - /// on the cycle. - /// - /// \pre Either run() or start() must be called before using this function. - Arc matching(const Node& node) const { - return (*_matching)[node]; - } - - /// \brief Return a const reference to the matching map. - /// - /// This function returns a const reference to a node map that stores - /// the matching arc (or edge) incident to each node. - const MatchingMap& matchingMap() const { - return *_matching; - } - - /// @} - - /// \name Dual Solution - /// Functions to get the dual solution.\n - /// Either \ref run() or \ref start() function should be called before - /// using them. - - /// @{ - - /// \brief Return the value of the dual solution. - /// - /// This function returns the value of the dual solution. - /// It should be equal to the primal value scaled by \ref dualScale - /// "dual scale". - /// - /// \pre Either run() or start() must be called before using this function. - Value dualValue() const { - Value sum = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - sum += nodeValue(n); - } - return sum; - } - - /// \brief Return the dual value (potential) of the given node. - /// - /// This function returns the dual value (potential) of the given node. - /// - /// \pre Either run() or start() must be called before using this function. - Value nodeValue(const Node& n) const { - return (*_node_potential)[n]; - } - - /// @} - - }; - -} //END OF NAMESPACE LEMON - -#endif //LEMON_FRACTIONAL_MATCHING_H diff --git a/deps/lemon/lemon/full_graph.h b/deps/lemon/lemon/full_graph.h deleted file mode 100644 index b63df2e07..000000000 --- a/deps/lemon/lemon/full_graph.h +++ /dev/null @@ -1,1082 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_FULL_GRAPH_H -#define LEMON_FULL_GRAPH_H - -#include -#include - -///\ingroup graphs -///\file -///\brief FullDigraph and FullGraph classes. - -namespace lemon { - - class FullDigraphBase { - public: - - typedef FullDigraphBase Digraph; - - class Node; - class Arc; - - protected: - - int _node_num; - int _arc_num; - - FullDigraphBase() {} - - void construct(int n) { _node_num = n; _arc_num = n * n; } - - public: - - typedef True NodeNumTag; - typedef True ArcNumTag; - - Node operator()(int ix) const { return Node(ix); } - static int index(const Node& node) { return node._id; } - - Arc arc(const Node& s, const Node& t) const { - return Arc(s._id * _node_num + t._id); - } - - int nodeNum() const { return _node_num; } - int arcNum() const { return _arc_num; } - - int maxNodeId() const { return _node_num - 1; } - int maxArcId() const { return _arc_num - 1; } - - Node source(Arc arc) const { return arc._id / _node_num; } - Node target(Arc arc) const { return arc._id % _node_num; } - - static int id(Node node) { return node._id; } - static int id(Arc arc) { return arc._id; } - - static Node nodeFromId(int id) { return Node(id);} - static Arc arcFromId(int id) { return Arc(id);} - - typedef True FindArcTag; - - Arc findArc(Node s, Node t, Arc prev = INVALID) const { - return prev == INVALID ? arc(s, t) : INVALID; - } - - class Node { - friend class FullDigraphBase; - - protected: - int _id; - Node(int id) : _id(id) {} - public: - Node() {} - Node (Invalid) : _id(-1) {} - bool operator==(const Node node) const {return _id == node._id;} - bool operator!=(const Node node) const {return _id != node._id;} - bool operator<(const Node node) const {return _id < node._id;} - }; - - class Arc { - friend class FullDigraphBase; - - protected: - int _id; // _node_num * source + target; - - Arc(int id) : _id(id) {} - - public: - Arc() { } - Arc (Invalid) { _id = -1; } - bool operator==(const Arc arc) const {return _id == arc._id;} - bool operator!=(const Arc arc) const {return _id != arc._id;} - bool operator<(const Arc arc) const {return _id < arc._id;} - }; - - void first(Node& node) const { - node._id = _node_num - 1; - } - - static void next(Node& node) { - --node._id; - } - - void first(Arc& arc) const { - arc._id = _arc_num - 1; - } - - static void next(Arc& arc) { - --arc._id; - } - - void firstOut(Arc& arc, const Node& node) const { - arc._id = (node._id + 1) * _node_num - 1; - } - - void nextOut(Arc& arc) const { - if (arc._id % _node_num == 0) arc._id = 0; - --arc._id; - } - - void firstIn(Arc& arc, const Node& node) const { - arc._id = _arc_num + node._id - _node_num; - } - - void nextIn(Arc& arc) const { - arc._id -= _node_num; - if (arc._id < 0) arc._id = -1; - } - - }; - - typedef DigraphExtender ExtendedFullDigraphBase; - - /// \ingroup graphs - /// - /// \brief A directed full graph class. - /// - /// FullDigraph is a simple and fast implmenetation of directed full - /// (complete) graphs. It contains an arc from each node to each node - /// (including a loop for each node), therefore the number of arcs - /// is the square of the number of nodes. - /// This class is completely static and it needs constant memory space. - /// Thus you can neither add nor delete nodes or arcs, however - /// the structure can be resized using resize(). - /// - /// This type fully conforms to the \ref concepts::Digraph "Digraph concept". - /// Most of its member functions and nested classes are documented - /// only in the concept class. - /// - /// This class provides constant time counting for nodes and arcs. - /// - /// \note FullDigraph and FullGraph classes are very similar, - /// but there are two differences. While this class conforms only - /// to the \ref concepts::Digraph "Digraph" concept, FullGraph - /// conforms to the \ref concepts::Graph "Graph" concept, - /// moreover FullGraph does not contain a loop for each - /// node as this class does. - /// - /// \sa FullGraph - class FullDigraph : public ExtendedFullDigraphBase { - typedef ExtendedFullDigraphBase Parent; - - public: - - /// \brief Default constructor. - /// - /// Default constructor. The number of nodes and arcs will be zero. - FullDigraph() { construct(0); } - - /// \brief Constructor - /// - /// Constructor. - /// \param n The number of the nodes. - FullDigraph(int n) { construct(n); } - - /// \brief Resizes the digraph - /// - /// This function resizes the digraph. It fully destroys and - /// rebuilds the structure, therefore the maps of the digraph will be - /// reallocated automatically and the previous values will be lost. - void resize(int n) { - Parent::notifier(Arc()).clear(); - Parent::notifier(Node()).clear(); - construct(n); - Parent::notifier(Node()).build(); - Parent::notifier(Arc()).build(); - } - - /// \brief Returns the node with the given index. - /// - /// Returns the node with the given index. Since this structure is - /// completely static, the nodes can be indexed with integers from - /// the range [0..nodeNum()-1]. - /// The index of a node is the same as its ID. - /// \sa index() - Node operator()(int ix) const { return Parent::operator()(ix); } - - /// \brief Returns the index of the given node. - /// - /// Returns the index of the given node. Since this structure is - /// completely static, the nodes can be indexed with integers from - /// the range [0..nodeNum()-1]. - /// The index of a node is the same as its ID. - /// \sa operator()() - static int index(const Node& node) { return Parent::index(node); } - - /// \brief Returns the arc connecting the given nodes. - /// - /// Returns the arc connecting the given nodes. - Arc arc(Node u, Node v) const { - return Parent::arc(u, v); - } - - /// \brief Number of nodes. - int nodeNum() const { return Parent::nodeNum(); } - /// \brief Number of arcs. - int arcNum() const { return Parent::arcNum(); } - }; - - - class FullGraphBase { - public: - - typedef FullGraphBase Graph; - - class Node; - class Arc; - class Edge; - - protected: - - int _node_num; - int _edge_num; - - FullGraphBase() {} - - void construct(int n) { _node_num = n; _edge_num = n * (n - 1) / 2; } - - int _uid(int e) const { - int u = e / _node_num; - int v = e % _node_num; - return u < v ? u : _node_num - 2 - u; - } - - int _vid(int e) const { - int u = e / _node_num; - int v = e % _node_num; - return u < v ? v : _node_num - 1 - v; - } - - void _uvid(int e, int& u, int& v) const { - u = e / _node_num; - v = e % _node_num; - if (u >= v) { - u = _node_num - 2 - u; - v = _node_num - 1 - v; - } - } - - void _stid(int a, int& s, int& t) const { - if ((a & 1) == 1) { - _uvid(a >> 1, s, t); - } else { - _uvid(a >> 1, t, s); - } - } - - int _eid(int u, int v) const { - if (u < (_node_num - 1) / 2) { - return u * _node_num + v; - } else { - return (_node_num - 1 - u) * _node_num - v - 1; - } - } - - public: - - Node operator()(int ix) const { return Node(ix); } - static int index(const Node& node) { return node._id; } - - Edge edge(const Node& u, const Node& v) const { - if (u._id < v._id) { - return Edge(_eid(u._id, v._id)); - } else if (u._id != v._id) { - return Edge(_eid(v._id, u._id)); - } else { - return INVALID; - } - } - - Arc arc(const Node& s, const Node& t) const { - if (s._id < t._id) { - return Arc((_eid(s._id, t._id) << 1) | 1); - } else if (s._id != t._id) { - return Arc(_eid(t._id, s._id) << 1); - } else { - return INVALID; - } - } - - typedef True NodeNumTag; - typedef True ArcNumTag; - typedef True EdgeNumTag; - - int nodeNum() const { return _node_num; } - int arcNum() const { return 2 * _edge_num; } - int edgeNum() const { return _edge_num; } - - static int id(Node node) { return node._id; } - static int id(Arc arc) { return arc._id; } - static int id(Edge edge) { return edge._id; } - - int maxNodeId() const { return _node_num-1; } - int maxArcId() const { return 2 * _edge_num-1; } - int maxEdgeId() const { return _edge_num-1; } - - static Node nodeFromId(int id) { return Node(id);} - static Arc arcFromId(int id) { return Arc(id);} - static Edge edgeFromId(int id) { return Edge(id);} - - Node u(Edge edge) const { - return Node(_uid(edge._id)); - } - - Node v(Edge edge) const { - return Node(_vid(edge._id)); - } - - Node source(Arc arc) const { - return Node((arc._id & 1) == 1 ? - _uid(arc._id >> 1) : _vid(arc._id >> 1)); - } - - Node target(Arc arc) const { - return Node((arc._id & 1) == 1 ? - _vid(arc._id >> 1) : _uid(arc._id >> 1)); - } - - typedef True FindEdgeTag; - typedef True FindArcTag; - - Edge findEdge(Node u, Node v, Edge prev = INVALID) const { - return prev != INVALID ? INVALID : edge(u, v); - } - - Arc findArc(Node s, Node t, Arc prev = INVALID) const { - return prev != INVALID ? INVALID : arc(s, t); - } - - class Node { - friend class FullGraphBase; - - protected: - int _id; - Node(int id) : _id(id) {} - public: - Node() {} - Node (Invalid) { _id = -1; } - bool operator==(const Node node) const {return _id == node._id;} - bool operator!=(const Node node) const {return _id != node._id;} - bool operator<(const Node node) const {return _id < node._id;} - }; - - class Edge { - friend class FullGraphBase; - friend class Arc; - - protected: - int _id; - - Edge(int id) : _id(id) {} - - public: - Edge() { } - Edge (Invalid) { _id = -1; } - - bool operator==(const Edge edge) const {return _id == edge._id;} - bool operator!=(const Edge edge) const {return _id != edge._id;} - bool operator<(const Edge edge) const {return _id < edge._id;} - }; - - class Arc { - friend class FullGraphBase; - - protected: - int _id; - - Arc(int id) : _id(id) {} - - public: - Arc() { } - Arc (Invalid) { _id = -1; } - - operator Edge() const { return Edge(_id != -1 ? (_id >> 1) : -1); } - - bool operator==(const Arc arc) const {return _id == arc._id;} - bool operator!=(const Arc arc) const {return _id != arc._id;} - bool operator<(const Arc arc) const {return _id < arc._id;} - }; - - static bool direction(Arc arc) { - return (arc._id & 1) == 1; - } - - static Arc direct(Edge edge, bool dir) { - return Arc((edge._id << 1) | (dir ? 1 : 0)); - } - - void first(Node& node) const { - node._id = _node_num - 1; - } - - static void next(Node& node) { - --node._id; - } - - void first(Arc& arc) const { - arc._id = (_edge_num << 1) - 1; - } - - static void next(Arc& arc) { - --arc._id; - } - - void first(Edge& edge) const { - edge._id = _edge_num - 1; - } - - static void next(Edge& edge) { - --edge._id; - } - - void firstOut(Arc& arc, const Node& node) const { - int s = node._id, t = _node_num - 1; - if (s < t) { - arc._id = (_eid(s, t) << 1) | 1; - } else { - --t; - arc._id = (t != -1 ? (_eid(t, s) << 1) : -1); - } - } - - void nextOut(Arc& arc) const { - int s, t; - _stid(arc._id, s, t); - --t; - if (s < t) { - arc._id = (_eid(s, t) << 1) | 1; - } else { - if (s == t) --t; - arc._id = (t != -1 ? (_eid(t, s) << 1) : -1); - } - } - - void firstIn(Arc& arc, const Node& node) const { - int s = _node_num - 1, t = node._id; - if (s > t) { - arc._id = (_eid(t, s) << 1); - } else { - --s; - arc._id = (s != -1 ? (_eid(s, t) << 1) | 1 : -1); - } - } - - void nextIn(Arc& arc) const { - int s, t; - _stid(arc._id, s, t); - --s; - if (s > t) { - arc._id = (_eid(t, s) << 1); - } else { - if (s == t) --s; - arc._id = (s != -1 ? (_eid(s, t) << 1) | 1 : -1); - } - } - - void firstInc(Edge& edge, bool& dir, const Node& node) const { - int u = node._id, v = _node_num - 1; - if (u < v) { - edge._id = _eid(u, v); - dir = true; - } else { - --v; - edge._id = (v != -1 ? _eid(v, u) : -1); - dir = false; - } - } - - void nextInc(Edge& edge, bool& dir) const { - int u, v; - if (dir) { - _uvid(edge._id, u, v); - --v; - if (u < v) { - edge._id = _eid(u, v); - } else { - --v; - edge._id = (v != -1 ? _eid(v, u) : -1); - dir = false; - } - } else { - _uvid(edge._id, v, u); - --v; - edge._id = (v != -1 ? _eid(v, u) : -1); - } - } - - }; - - typedef GraphExtender ExtendedFullGraphBase; - - /// \ingroup graphs - /// - /// \brief An undirected full graph class. - /// - /// FullGraph is a simple and fast implmenetation of undirected full - /// (complete) graphs. It contains an edge between every distinct pair - /// of nodes, therefore the number of edges is n(n-1)/2. - /// This class is completely static and it needs constant memory space. - /// Thus you can neither add nor delete nodes or edges, however - /// the structure can be resized using resize(). - /// - /// This type fully conforms to the \ref concepts::Graph "Graph concept". - /// Most of its member functions and nested classes are documented - /// only in the concept class. - /// - /// This class provides constant time counting for nodes, edges and arcs. - /// - /// \note FullDigraph and FullGraph classes are very similar, - /// but there are two differences. While FullDigraph - /// conforms only to the \ref concepts::Digraph "Digraph" concept, - /// this class conforms to the \ref concepts::Graph "Graph" concept, - /// moreover this class does not contain a loop for each - /// node as FullDigraph does. - /// - /// \sa FullDigraph - class FullGraph : public ExtendedFullGraphBase { - typedef ExtendedFullGraphBase Parent; - - public: - - /// \brief Default constructor. - /// - /// Default constructor. The number of nodes and edges will be zero. - FullGraph() { construct(0); } - - /// \brief Constructor - /// - /// Constructor. - /// \param n The number of the nodes. - FullGraph(int n) { construct(n); } - - /// \brief Resizes the graph - /// - /// This function resizes the graph. It fully destroys and - /// rebuilds the structure, therefore the maps of the graph will be - /// reallocated automatically and the previous values will be lost. - void resize(int n) { - Parent::notifier(Arc()).clear(); - Parent::notifier(Edge()).clear(); - Parent::notifier(Node()).clear(); - construct(n); - Parent::notifier(Node()).build(); - Parent::notifier(Edge()).build(); - Parent::notifier(Arc()).build(); - } - - /// \brief Returns the node with the given index. - /// - /// Returns the node with the given index. Since this structure is - /// completely static, the nodes can be indexed with integers from - /// the range [0..nodeNum()-1]. - /// The index of a node is the same as its ID. - /// \sa index() - Node operator()(int ix) const { return Parent::operator()(ix); } - - /// \brief Returns the index of the given node. - /// - /// Returns the index of the given node. Since this structure is - /// completely static, the nodes can be indexed with integers from - /// the range [0..nodeNum()-1]. - /// The index of a node is the same as its ID. - /// \sa operator()() - static int index(const Node& node) { return Parent::index(node); } - - /// \brief Returns the arc connecting the given nodes. - /// - /// Returns the arc connecting the given nodes. - Arc arc(Node s, Node t) const { - return Parent::arc(s, t); - } - - /// \brief Returns the edge connecting the given nodes. - /// - /// Returns the edge connecting the given nodes. - Edge edge(Node u, Node v) const { - return Parent::edge(u, v); - } - - /// \brief Number of nodes. - int nodeNum() const { return Parent::nodeNum(); } - /// \brief Number of arcs. - int arcNum() const { return Parent::arcNum(); } - /// \brief Number of edges. - int edgeNum() const { return Parent::edgeNum(); } - - }; - - class FullBpGraphBase { - - protected: - - int _red_num, _blue_num; - int _node_num, _edge_num; - - public: - - typedef FullBpGraphBase Graph; - - class Node; - class Arc; - class Edge; - - class Node { - friend class FullBpGraphBase; - protected: - - int _id; - explicit Node(int id) { _id = id;} - - public: - Node() {} - Node (Invalid) { _id = -1; } - bool operator==(const Node& node) const {return _id == node._id;} - bool operator!=(const Node& node) const {return _id != node._id;} - bool operator<(const Node& node) const {return _id < node._id;} - }; - - class RedNode : public Node { - friend class FullBpGraphBase; - protected: - - explicit RedNode(int pid) : Node(pid) {} - - public: - RedNode() {} - RedNode(const RedNode& node) : Node(node) {} - RedNode(Invalid) : Node(INVALID){} - }; - - class BlueNode : public Node { - friend class FullBpGraphBase; - protected: - - explicit BlueNode(int pid) : Node(pid) {} - - public: - BlueNode() {} - BlueNode(const BlueNode& node) : Node(node) {} - BlueNode(Invalid) : Node(INVALID){} - }; - - class Edge { - friend class FullBpGraphBase; - protected: - - int _id; - explicit Edge(int id) { _id = id;} - - public: - Edge() {} - Edge (Invalid) { _id = -1; } - bool operator==(const Edge& arc) const {return _id == arc._id;} - bool operator!=(const Edge& arc) const {return _id != arc._id;} - bool operator<(const Edge& arc) const {return _id < arc._id;} - }; - - class Arc { - friend class FullBpGraphBase; - protected: - - int _id; - explicit Arc(int id) { _id = id;} - - public: - operator Edge() const { - return _id != -1 ? edgeFromId(_id / 2) : INVALID; - } - - Arc() {} - Arc (Invalid) { _id = -1; } - bool operator==(const Arc& arc) const {return _id == arc._id;} - bool operator!=(const Arc& arc) const {return _id != arc._id;} - bool operator<(const Arc& arc) const {return _id < arc._id;} - }; - - - protected: - - FullBpGraphBase() - : _red_num(0), _blue_num(0), _node_num(0), _edge_num(0) {} - - void construct(int redNum, int blueNum) { - _red_num = redNum; _blue_num = blueNum; - _node_num = redNum + blueNum; _edge_num = redNum * blueNum; - } - - public: - - typedef True NodeNumTag; - typedef True EdgeNumTag; - typedef True ArcNumTag; - - int nodeNum() const { return _node_num; } - int redNum() const { return _red_num; } - int blueNum() const { return _blue_num; } - int edgeNum() const { return _edge_num; } - int arcNum() const { return 2 * _edge_num; } - - int maxNodeId() const { return _node_num - 1; } - int maxRedId() const { return _red_num - 1; } - int maxBlueId() const { return _blue_num - 1; } - int maxEdgeId() const { return _edge_num - 1; } - int maxArcId() const { return 2 * _edge_num - 1; } - - bool red(Node n) const { return n._id < _red_num; } - bool blue(Node n) const { return n._id >= _red_num; } - - static RedNode asRedNodeUnsafe(Node n) { return RedNode(n._id); } - static BlueNode asBlueNodeUnsafe(Node n) { return BlueNode(n._id); } - - Node source(Arc a) const { - if (a._id & 1) { - return Node((a._id >> 1) % _red_num); - } else { - return Node((a._id >> 1) / _red_num + _red_num); - } - } - Node target(Arc a) const { - if (a._id & 1) { - return Node((a._id >> 1) / _red_num + _red_num); - } else { - return Node((a._id >> 1) % _red_num); - } - } - - RedNode redNode(Edge e) const { - return RedNode(e._id % _red_num); - } - BlueNode blueNode(Edge e) const { - return BlueNode(e._id / _red_num + _red_num); - } - - static bool direction(Arc a) { - return (a._id & 1) == 1; - } - - static Arc direct(Edge e, bool d) { - return Arc(e._id * 2 + (d ? 1 : 0)); - } - - void first(Node& node) const { - node._id = _node_num - 1; - } - - static void next(Node& node) { - --node._id; - } - - void first(RedNode& node) const { - node._id = _red_num - 1; - } - - static void next(RedNode& node) { - --node._id; - } - - void first(BlueNode& node) const { - if (_red_num == _node_num) node._id = -1; - else node._id = _node_num - 1; - } - - void next(BlueNode& node) const { - if (node._id == _red_num) node._id = -1; - else --node._id; - } - - void first(Arc& arc) const { - arc._id = 2 * _edge_num - 1; - } - - static void next(Arc& arc) { - --arc._id; - } - - void first(Edge& arc) const { - arc._id = _edge_num - 1; - } - - static void next(Edge& arc) { - --arc._id; - } - - void firstOut(Arc &a, const Node& v) const { - if (v._id < _red_num) { - a._id = 2 * (v._id + _red_num * (_blue_num - 1)) + 1; - } else { - a._id = 2 * (_red_num - 1 + _red_num * (v._id - _red_num)); - } - } - void nextOut(Arc &a) const { - if (a._id & 1) { - a._id -= 2 * _red_num; - if (a._id < 0) a._id = -1; - } else { - if (a._id % (2 * _red_num) == 0) a._id = -1; - else a._id -= 2; - } - } - - void firstIn(Arc &a, const Node& v) const { - if (v._id < _red_num) { - a._id = 2 * (v._id + _red_num * (_blue_num - 1)); - } else { - a._id = 2 * (_red_num - 1 + _red_num * (v._id - _red_num)) + 1; - } - } - void nextIn(Arc &a) const { - if (a._id & 1) { - if (a._id % (2 * _red_num) == 1) a._id = -1; - else a._id -= 2; - } else { - a._id -= 2 * _red_num; - if (a._id < 0) a._id = -1; - } - } - - void firstInc(Edge &e, bool& d, const Node& v) const { - if (v._id < _red_num) { - d = true; - e._id = v._id + _red_num * (_blue_num - 1); - } else { - d = false; - e._id = _red_num - 1 + _red_num * (v._id - _red_num); - } - } - void nextInc(Edge &e, bool& d) const { - if (d) { - e._id -= _red_num; - if (e._id < 0) e._id = -1; - } else { - if (e._id % _red_num == 0) e._id = -1; - else --e._id; - } - } - - static int id(const Node& v) { return v._id; } - int id(const RedNode& v) const { return v._id; } - int id(const BlueNode& v) const { return v._id - _red_num; } - static int id(Arc e) { return e._id; } - static int id(Edge e) { return e._id; } - - static Node nodeFromId(int id) { return Node(id);} - static Arc arcFromId(int id) { return Arc(id);} - static Edge edgeFromId(int id) { return Edge(id);} - - bool valid(Node n) const { - return n._id >= 0 && n._id < _node_num; - } - bool valid(Arc a) const { - return a._id >= 0 && a._id < 2 * _edge_num; - } - bool valid(Edge e) const { - return e._id >= 0 && e._id < _edge_num; - } - - RedNode redNode(int index) const { - return RedNode(index); - } - - int index(RedNode n) const { - return n._id; - } - - BlueNode blueNode(int index) const { - return BlueNode(index + _red_num); - } - - int index(BlueNode n) const { - return n._id - _red_num; - } - - void clear() { - _red_num = 0; _blue_num = 0; - _node_num = 0; _edge_num = 0; - } - - Edge edge(const Node& u, const Node& v) const { - if (u._id < _red_num) { - if (v._id < _red_num) { - return Edge(-1); - } else { - return Edge(u._id + _red_num * (v._id - _red_num)); - } - } else { - if (v._id < _red_num) { - return Edge(v._id + _red_num * (u._id - _red_num)); - } else { - return Edge(-1); - } - } - } - - Arc arc(const Node& u, const Node& v) const { - if (u._id < _red_num) { - if (v._id < _red_num) { - return Arc(-1); - } else { - return Arc(2 * (u._id + _red_num * (v._id - _red_num)) + 1); - } - } else { - if (v._id < _red_num) { - return Arc(2 * (v._id + _red_num * (u._id - _red_num))); - } else { - return Arc(-1); - } - } - } - - typedef True FindEdgeTag; - typedef True FindArcTag; - - Edge findEdge(Node u, Node v, Edge prev = INVALID) const { - return prev != INVALID ? INVALID : edge(u, v); - } - - Arc findArc(Node s, Node t, Arc prev = INVALID) const { - return prev != INVALID ? INVALID : arc(s, t); - } - - }; - - typedef BpGraphExtender ExtendedFullBpGraphBase; - - /// \ingroup graphs - /// - /// \brief An undirected full bipartite graph class. - /// - /// FullBpGraph is a simple and fast implmenetation of undirected - /// full bipartite graphs. It contains an edge between every - /// red-blue pairs of nodes, therefore the number of edges is - /// nr*nb. This class is completely static and it needs - /// constant memory space. Thus you can neither add nor delete - /// nodes or edges, however the structure can be resized using - /// resize(). - /// - /// This type fully conforms to the \ref concepts::BpGraph "BpGraph concept". - /// Most of its member functions and nested classes are documented - /// only in the concept class. - /// - /// This class provides constant time counting for nodes, edges and arcs. - /// - /// \sa FullGraph - class FullBpGraph : public ExtendedFullBpGraphBase { - public: - - typedef ExtendedFullBpGraphBase Parent; - - /// \brief Default constructor. - /// - /// Default constructor. The number of nodes and edges will be zero. - FullBpGraph() { construct(0, 0); } - - /// \brief Constructor - /// - /// Constructor. - /// \param redNum The number of the red nodes. - /// \param blueNum The number of the blue nodes. - FullBpGraph(int redNum, int blueNum) { construct(redNum, blueNum); } - - /// \brief Resizes the graph - /// - /// This function resizes the graph. It fully destroys and - /// rebuilds the structure, therefore the maps of the graph will be - /// reallocated automatically and the previous values will be lost. - void resize(int redNum, int blueNum) { - Parent::notifier(Arc()).clear(); - Parent::notifier(Edge()).clear(); - Parent::notifier(Node()).clear(); - Parent::notifier(BlueNode()).clear(); - Parent::notifier(RedNode()).clear(); - construct(redNum, blueNum); - Parent::notifier(RedNode()).build(); - Parent::notifier(BlueNode()).build(); - Parent::notifier(Node()).build(); - Parent::notifier(Edge()).build(); - Parent::notifier(Arc()).build(); - } - - using Parent::redNode; - using Parent::blueNode; - - /// \brief Returns the red node with the given index. - /// - /// Returns the red node with the given index. Since this - /// structure is completely static, the red nodes can be indexed - /// with integers from the range [0..redNum()-1]. - /// \sa redIndex() - RedNode redNode(int index) const { return Parent::redNode(index); } - - /// \brief Returns the index of the given red node. - /// - /// Returns the index of the given red node. Since this structure - /// is completely static, the red nodes can be indexed with - /// integers from the range [0..redNum()-1]. - /// - /// \sa operator()() - int index(RedNode node) const { return Parent::index(node); } - - /// \brief Returns the blue node with the given index. - /// - /// Returns the blue node with the given index. Since this - /// structure is completely static, the blue nodes can be indexed - /// with integers from the range [0..blueNum()-1]. - /// \sa blueIndex() - BlueNode blueNode(int index) const { return Parent::blueNode(index); } - - /// \brief Returns the index of the given blue node. - /// - /// Returns the index of the given blue node. Since this structure - /// is completely static, the blue nodes can be indexed with - /// integers from the range [0..blueNum()-1]. - /// - /// \sa operator()() - int index(BlueNode node) const { return Parent::index(node); } - - /// \brief Returns the edge which connects the given nodes. - /// - /// Returns the edge which connects the given nodes. - Edge edge(const Node& u, const Node& v) const { - return Parent::edge(u, v); - } - - /// \brief Returns the arc which connects the given nodes. - /// - /// Returns the arc which connects the given nodes. - Arc arc(const Node& u, const Node& v) const { - return Parent::arc(u, v); - } - - /// \brief Number of nodes. - int nodeNum() const { return Parent::nodeNum(); } - /// \brief Number of red nodes. - int redNum() const { return Parent::redNum(); } - /// \brief Number of blue nodes. - int blueNum() const { return Parent::blueNum(); } - /// \brief Number of arcs. - int arcNum() const { return Parent::arcNum(); } - /// \brief Number of edges. - int edgeNum() const { return Parent::edgeNum(); } - }; - - -} //namespace lemon - - -#endif //LEMON_FULL_GRAPH_H diff --git a/deps/lemon/lemon/glpk.cc b/deps/lemon/lemon/glpk.cc deleted file mode 100644 index 38d81151f..000000000 --- a/deps/lemon/lemon/glpk.cc +++ /dev/null @@ -1,1012 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\file -///\brief Implementation of the LEMON GLPK LP and MIP solver interface. - -#include -#include - -#include - -namespace lemon { - - // GlpkBase members - - GlpkBase::GlpkBase() : LpBase() { - lp = glp_create_prob(); - glp_create_index(lp); - messageLevel(MESSAGE_NOTHING); - } - - GlpkBase::GlpkBase(const GlpkBase &other) : LpBase() { - lp = glp_create_prob(); - glp_copy_prob(lp, other.lp, GLP_ON); - glp_create_index(lp); - rows = other.rows; - cols = other.cols; - messageLevel(MESSAGE_NOTHING); - } - - GlpkBase::~GlpkBase() { - glp_delete_prob(lp); - } - - int GlpkBase::_addCol() { - int i = glp_add_cols(lp, 1); - glp_set_col_bnds(lp, i, GLP_FR, 0.0, 0.0); - return i; - } - - int GlpkBase::_addRow() { - int i = glp_add_rows(lp, 1); - glp_set_row_bnds(lp, i, GLP_FR, 0.0, 0.0); - return i; - } - - int GlpkBase::_addRow(Value lo, ExprIterator b, - ExprIterator e, Value up) { - int i = glp_add_rows(lp, 1); - - if (lo == -INF) { - if (up == INF) { - glp_set_row_bnds(lp, i, GLP_FR, lo, up); - } else { - glp_set_row_bnds(lp, i, GLP_UP, lo, up); - } - } else { - if (up == INF) { - glp_set_row_bnds(lp, i, GLP_LO, lo, up); - } else if (lo != up) { - glp_set_row_bnds(lp, i, GLP_DB, lo, up); - } else { - glp_set_row_bnds(lp, i, GLP_FX, lo, up); - } - } - - std::vector indexes; - std::vector values; - - indexes.push_back(0); - values.push_back(0); - - for(ExprIterator it = b; it != e; ++it) { - indexes.push_back(it->first); - values.push_back(it->second); - } - - glp_set_mat_row(lp, i, values.size() - 1, - &indexes.front(), &values.front()); - return i; - } - - void GlpkBase::_eraseCol(int i) { - int ca[2]; - ca[1] = i; - glp_del_cols(lp, 1, ca); - } - - void GlpkBase::_eraseRow(int i) { - int ra[2]; - ra[1] = i; - glp_del_rows(lp, 1, ra); - } - - void GlpkBase::_eraseColId(int i) { - cols.eraseIndex(i); - cols.shiftIndices(i); - } - - void GlpkBase::_eraseRowId(int i) { - rows.eraseIndex(i); - rows.shiftIndices(i); - } - - void GlpkBase::_getColName(int c, std::string& name) const { - const char *str = glp_get_col_name(lp, c); - if (str) name = str; - else name.clear(); - } - - void GlpkBase::_setColName(int c, const std::string & name) { - glp_set_col_name(lp, c, const_cast(name.c_str())); - - } - - int GlpkBase::_colByName(const std::string& name) const { - int k = glp_find_col(lp, const_cast(name.c_str())); - return k > 0 ? k : -1; - } - - void GlpkBase::_getRowName(int r, std::string& name) const { - const char *str = glp_get_row_name(lp, r); - if (str) name = str; - else name.clear(); - } - - void GlpkBase::_setRowName(int r, const std::string & name) { - glp_set_row_name(lp, r, const_cast(name.c_str())); - - } - - int GlpkBase::_rowByName(const std::string& name) const { - int k = glp_find_row(lp, const_cast(name.c_str())); - return k > 0 ? k : -1; - } - - void GlpkBase::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) { - std::vector indexes; - std::vector values; - - indexes.push_back(0); - values.push_back(0); - - for(ExprIterator it = b; it != e; ++it) { - indexes.push_back(it->first); - values.push_back(it->second); - } - - glp_set_mat_row(lp, i, values.size() - 1, - &indexes.front(), &values.front()); - } - - void GlpkBase::_getRowCoeffs(int ix, InsertIterator b) const { - int length = glp_get_mat_row(lp, ix, 0, 0); - - std::vector indexes(length + 1); - std::vector values(length + 1); - - glp_get_mat_row(lp, ix, &indexes.front(), &values.front()); - - for (int i = 1; i <= length; ++i) { - *b = std::make_pair(indexes[i], values[i]); - ++b; - } - } - - void GlpkBase::_setColCoeffs(int ix, ExprIterator b, - ExprIterator e) { - - std::vector indexes; - std::vector values; - - indexes.push_back(0); - values.push_back(0); - - for(ExprIterator it = b; it != e; ++it) { - indexes.push_back(it->first); - values.push_back(it->second); - } - - glp_set_mat_col(lp, ix, values.size() - 1, - &indexes.front(), &values.front()); - } - - void GlpkBase::_getColCoeffs(int ix, InsertIterator b) const { - int length = glp_get_mat_col(lp, ix, 0, 0); - - std::vector indexes(length + 1); - std::vector values(length + 1); - - glp_get_mat_col(lp, ix, &indexes.front(), &values.front()); - - for (int i = 1; i <= length; ++i) { - *b = std::make_pair(indexes[i], values[i]); - ++b; - } - } - - void GlpkBase::_setCoeff(int ix, int jx, Value value) { - - if (glp_get_num_cols(lp) < glp_get_num_rows(lp)) { - - int length = glp_get_mat_row(lp, ix, 0, 0); - - std::vector indexes(length + 2); - std::vector values(length + 2); - - glp_get_mat_row(lp, ix, &indexes.front(), &values.front()); - - //The following code does not suppose that the elements of the - //array indexes are sorted - bool found = false; - for (int i = 1; i <= length; ++i) { - if (indexes[i] == jx) { - found = true; - values[i] = value; - break; - } - } - if (!found) { - ++length; - indexes[length] = jx; - values[length] = value; - } - - glp_set_mat_row(lp, ix, length, &indexes.front(), &values.front()); - - } else { - - int length = glp_get_mat_col(lp, jx, 0, 0); - - std::vector indexes(length + 2); - std::vector values(length + 2); - - glp_get_mat_col(lp, jx, &indexes.front(), &values.front()); - - //The following code does not suppose that the elements of the - //array indexes are sorted - bool found = false; - for (int i = 1; i <= length; ++i) { - if (indexes[i] == ix) { - found = true; - values[i] = value; - break; - } - } - if (!found) { - ++length; - indexes[length] = ix; - values[length] = value; - } - - glp_set_mat_col(lp, jx, length, &indexes.front(), &values.front()); - } - - } - - GlpkBase::Value GlpkBase::_getCoeff(int ix, int jx) const { - - int length = glp_get_mat_row(lp, ix, 0, 0); - - std::vector indexes(length + 1); - std::vector values(length + 1); - - glp_get_mat_row(lp, ix, &indexes.front(), &values.front()); - - for (int i = 1; i <= length; ++i) { - if (indexes[i] == jx) { - return values[i]; - } - } - - return 0; - } - - void GlpkBase::_setColLowerBound(int i, Value lo) { - LEMON_ASSERT(lo != INF, "Invalid bound"); - - int b = glp_get_col_type(lp, i); - double up = glp_get_col_ub(lp, i); - if (lo == -INF) { - switch (b) { - case GLP_FR: - case GLP_LO: - glp_set_col_bnds(lp, i, GLP_FR, lo, up); - break; - case GLP_UP: - break; - case GLP_DB: - case GLP_FX: - glp_set_col_bnds(lp, i, GLP_UP, lo, up); - break; - default: - break; - } - } else { - switch (b) { - case GLP_FR: - case GLP_LO: - glp_set_col_bnds(lp, i, GLP_LO, lo, up); - break; - case GLP_UP: - case GLP_DB: - case GLP_FX: - if (lo == up) - glp_set_col_bnds(lp, i, GLP_FX, lo, up); - else - glp_set_col_bnds(lp, i, GLP_DB, lo, up); - break; - default: - break; - } - } - } - - GlpkBase::Value GlpkBase::_getColLowerBound(int i) const { - int b = glp_get_col_type(lp, i); - switch (b) { - case GLP_LO: - case GLP_DB: - case GLP_FX: - return glp_get_col_lb(lp, i); - default: - return -INF; - } - } - - void GlpkBase::_setColUpperBound(int i, Value up) { - LEMON_ASSERT(up != -INF, "Invalid bound"); - - int b = glp_get_col_type(lp, i); - double lo = glp_get_col_lb(lp, i); - if (up == INF) { - switch (b) { - case GLP_FR: - case GLP_LO: - break; - case GLP_UP: - glp_set_col_bnds(lp, i, GLP_FR, lo, up); - break; - case GLP_DB: - case GLP_FX: - glp_set_col_bnds(lp, i, GLP_LO, lo, up); - break; - default: - break; - } - } else { - switch (b) { - case GLP_FR: - glp_set_col_bnds(lp, i, GLP_UP, lo, up); - break; - case GLP_UP: - glp_set_col_bnds(lp, i, GLP_UP, lo, up); - break; - case GLP_LO: - case GLP_DB: - case GLP_FX: - if (lo == up) - glp_set_col_bnds(lp, i, GLP_FX, lo, up); - else - glp_set_col_bnds(lp, i, GLP_DB, lo, up); - break; - default: - break; - } - } - - } - - GlpkBase::Value GlpkBase::_getColUpperBound(int i) const { - int b = glp_get_col_type(lp, i); - switch (b) { - case GLP_UP: - case GLP_DB: - case GLP_FX: - return glp_get_col_ub(lp, i); - default: - return INF; - } - } - - void GlpkBase::_setRowLowerBound(int i, Value lo) { - LEMON_ASSERT(lo != INF, "Invalid bound"); - - int b = glp_get_row_type(lp, i); - double up = glp_get_row_ub(lp, i); - if (lo == -INF) { - switch (b) { - case GLP_FR: - case GLP_LO: - glp_set_row_bnds(lp, i, GLP_FR, lo, up); - break; - case GLP_UP: - break; - case GLP_DB: - case GLP_FX: - glp_set_row_bnds(lp, i, GLP_UP, lo, up); - break; - default: - break; - } - } else { - switch (b) { - case GLP_FR: - case GLP_LO: - glp_set_row_bnds(lp, i, GLP_LO, lo, up); - break; - case GLP_UP: - case GLP_DB: - case GLP_FX: - if (lo == up) - glp_set_row_bnds(lp, i, GLP_FX, lo, up); - else - glp_set_row_bnds(lp, i, GLP_DB, lo, up); - break; - default: - break; - } - } - - } - - GlpkBase::Value GlpkBase::_getRowLowerBound(int i) const { - int b = glp_get_row_type(lp, i); - switch (b) { - case GLP_LO: - case GLP_DB: - case GLP_FX: - return glp_get_row_lb(lp, i); - default: - return -INF; - } - } - - void GlpkBase::_setRowUpperBound(int i, Value up) { - LEMON_ASSERT(up != -INF, "Invalid bound"); - - int b = glp_get_row_type(lp, i); - double lo = glp_get_row_lb(lp, i); - if (up == INF) { - switch (b) { - case GLP_FR: - case GLP_LO: - break; - case GLP_UP: - glp_set_row_bnds(lp, i, GLP_FR, lo, up); - break; - case GLP_DB: - case GLP_FX: - glp_set_row_bnds(lp, i, GLP_LO, lo, up); - break; - default: - break; - } - } else { - switch (b) { - case GLP_FR: - glp_set_row_bnds(lp, i, GLP_UP, lo, up); - break; - case GLP_UP: - glp_set_row_bnds(lp, i, GLP_UP, lo, up); - break; - case GLP_LO: - case GLP_DB: - case GLP_FX: - if (lo == up) - glp_set_row_bnds(lp, i, GLP_FX, lo, up); - else - glp_set_row_bnds(lp, i, GLP_DB, lo, up); - break; - default: - break; - } - } - } - - GlpkBase::Value GlpkBase::_getRowUpperBound(int i) const { - int b = glp_get_row_type(lp, i); - switch (b) { - case GLP_UP: - case GLP_DB: - case GLP_FX: - return glp_get_row_ub(lp, i); - default: - return INF; - } - } - - void GlpkBase::_setObjCoeffs(ExprIterator b, ExprIterator e) { - for (int i = 1; i <= glp_get_num_cols(lp); ++i) { - glp_set_obj_coef(lp, i, 0.0); - } - for (ExprIterator it = b; it != e; ++it) { - glp_set_obj_coef(lp, it->first, it->second); - } - } - - void GlpkBase::_getObjCoeffs(InsertIterator b) const { - for (int i = 1; i <= glp_get_num_cols(lp); ++i) { - Value val = glp_get_obj_coef(lp, i); - if (val != 0.0) { - *b = std::make_pair(i, val); - ++b; - } - } - } - - void GlpkBase::_setObjCoeff(int i, Value obj_coef) { - //i = 0 means the constant term (shift) - glp_set_obj_coef(lp, i, obj_coef); - } - - GlpkBase::Value GlpkBase::_getObjCoeff(int i) const { - //i = 0 means the constant term (shift) - return glp_get_obj_coef(lp, i); - } - - void GlpkBase::_setSense(GlpkBase::Sense sense) { - switch (sense) { - case MIN: - glp_set_obj_dir(lp, GLP_MIN); - break; - case MAX: - glp_set_obj_dir(lp, GLP_MAX); - break; - } - } - - GlpkBase::Sense GlpkBase::_getSense() const { - switch(glp_get_obj_dir(lp)) { - case GLP_MIN: - return MIN; - case GLP_MAX: - return MAX; - default: - LEMON_ASSERT(false, "Wrong sense"); - return GlpkBase::Sense(); - } - } - - void GlpkBase::_clear() { - glp_erase_prob(lp); - } - - void GlpkBase::freeEnv() { - glp_free_env(); - } - - void GlpkBase::_messageLevel(MessageLevel level) { - switch (level) { - case MESSAGE_NOTHING: - _message_level = GLP_MSG_OFF; - break; - case MESSAGE_ERROR: - _message_level = GLP_MSG_ERR; - break; - case MESSAGE_WARNING: - _message_level = GLP_MSG_ERR; - break; - case MESSAGE_NORMAL: - _message_level = GLP_MSG_ON; - break; - case MESSAGE_VERBOSE: - _message_level = GLP_MSG_ALL; - break; - } - } - - void GlpkBase::_write(std::string file, std::string format) const - { - if(format == "MPS") - glp_write_mps(lp, GLP_MPS_FILE, 0, file.c_str()); - else if(format == "LP") - glp_write_lp(lp, 0, file.c_str()); - else throw UnsupportedFormatError(format); - } - - GlpkBase::FreeEnvHelper GlpkBase::freeEnvHelper; - - // GlpkLp members - - GlpkLp::GlpkLp() - : LpBase(), LpSolver(), GlpkBase() { - presolver(false); - } - - GlpkLp::GlpkLp(const GlpkLp& other) - : LpBase(other), LpSolver(other), GlpkBase(other) { - presolver(false); - } - - GlpkLp* GlpkLp::newSolver() const { return new GlpkLp; } - GlpkLp* GlpkLp::cloneSolver() const { return new GlpkLp(*this); } - - const char* GlpkLp::_solverName() const { return "GlpkLp"; } - - void GlpkLp::_clear_temporals() { - _primal_ray.clear(); - _dual_ray.clear(); - } - - GlpkLp::SolveExitStatus GlpkLp::_solve() { - return solvePrimal(); - } - - GlpkLp::SolveExitStatus GlpkLp::solvePrimal() { - _clear_temporals(); - - glp_smcp smcp; - glp_init_smcp(&smcp); - - smcp.msg_lev = _message_level; - smcp.presolve = _presolve; - - // If the basis is not valid we get an error return value. - // In this case we can try to create a new basis. - switch (glp_simplex(lp, &smcp)) { - case 0: - break; - case GLP_EBADB: - case GLP_ESING: - case GLP_ECOND: - glp_term_out(false); - glp_adv_basis(lp, 0); - glp_term_out(true); - if (glp_simplex(lp, &smcp) != 0) return UNSOLVED; - break; - default: - return UNSOLVED; - } - - return SOLVED; - } - - GlpkLp::SolveExitStatus GlpkLp::solveDual() { - _clear_temporals(); - - glp_smcp smcp; - glp_init_smcp(&smcp); - - smcp.msg_lev = _message_level; - smcp.meth = GLP_DUAL; - smcp.presolve = _presolve; - - // If the basis is not valid we get an error return value. - // In this case we can try to create a new basis. - switch (glp_simplex(lp, &smcp)) { - case 0: - break; - case GLP_EBADB: - case GLP_ESING: - case GLP_ECOND: - glp_term_out(false); - glp_adv_basis(lp, 0); - glp_term_out(true); - if (glp_simplex(lp, &smcp) != 0) return UNSOLVED; - break; - default: - return UNSOLVED; - } - return SOLVED; - } - - GlpkLp::Value GlpkLp::_getPrimal(int i) const { - return glp_get_col_prim(lp, i); - } - - GlpkLp::Value GlpkLp::_getDual(int i) const { - return glp_get_row_dual(lp, i); - } - - GlpkLp::Value GlpkLp::_getPrimalValue() const { - return glp_get_obj_val(lp); - } - - GlpkLp::VarStatus GlpkLp::_getColStatus(int i) const { - switch (glp_get_col_stat(lp, i)) { - case GLP_BS: - return BASIC; - case GLP_UP: - return UPPER; - case GLP_LO: - return LOWER; - case GLP_NF: - return FREE; - case GLP_NS: - return FIXED; - default: - LEMON_ASSERT(false, "Wrong column status"); - return GlpkLp::VarStatus(); - } - } - - GlpkLp::VarStatus GlpkLp::_getRowStatus(int i) const { - switch (glp_get_row_stat(lp, i)) { - case GLP_BS: - return BASIC; - case GLP_UP: - return UPPER; - case GLP_LO: - return LOWER; - case GLP_NF: - return FREE; - case GLP_NS: - return FIXED; - default: - LEMON_ASSERT(false, "Wrong row status"); - return GlpkLp::VarStatus(); - } - } - - GlpkLp::Value GlpkLp::_getPrimalRay(int i) const { - if (_primal_ray.empty()) { - int row_num = glp_get_num_rows(lp); - int col_num = glp_get_num_cols(lp); - - _primal_ray.resize(col_num + 1, 0.0); - - int index = glp_get_unbnd_ray(lp); - if (index != 0) { - // The primal ray is found in primal simplex second phase - LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) : - glp_get_col_stat(lp, index - row_num)) != GLP_BS, - "Wrong primal ray"); - - bool negate = glp_get_obj_dir(lp) == GLP_MAX; - - if (index > row_num) { - _primal_ray[index - row_num] = 1.0; - if (glp_get_col_dual(lp, index - row_num) > 0) { - negate = !negate; - } - } else { - if (glp_get_row_dual(lp, index) > 0) { - negate = !negate; - } - } - - std::vector ray_indexes(row_num + 1); - std::vector ray_values(row_num + 1); - int ray_length = glp_eval_tab_col(lp, index, &ray_indexes.front(), - &ray_values.front()); - - for (int i = 1; i <= ray_length; ++i) { - if (ray_indexes[i] > row_num) { - _primal_ray[ray_indexes[i] - row_num] = ray_values[i]; - } - } - - if (negate) { - for (int i = 1; i <= col_num; ++i) { - _primal_ray[i] = - _primal_ray[i]; - } - } - } else { - for (int i = 1; i <= col_num; ++i) { - _primal_ray[i] = glp_get_col_prim(lp, i); - } - } - } - return _primal_ray[i]; - } - - GlpkLp::Value GlpkLp::_getDualRay(int i) const { - if (_dual_ray.empty()) { - int row_num = glp_get_num_rows(lp); - - _dual_ray.resize(row_num + 1, 0.0); - - int index = glp_get_unbnd_ray(lp); - if (index != 0) { - // The dual ray is found in dual simplex second phase - LEMON_ASSERT((index <= row_num ? glp_get_row_stat(lp, index) : - glp_get_col_stat(lp, index - row_num)) == GLP_BS, - - "Wrong dual ray"); - - int idx; - bool negate = false; - - if (index > row_num) { - idx = glp_get_col_bind(lp, index - row_num); - if (glp_get_col_prim(lp, index - row_num) > - glp_get_col_ub(lp, index - row_num)) { - negate = true; - } - } else { - idx = glp_get_row_bind(lp, index); - if (glp_get_row_prim(lp, index) > glp_get_row_ub(lp, index)) { - negate = true; - } - } - - _dual_ray[idx] = negate ? - 1.0 : 1.0; - - glp_btran(lp, &_dual_ray.front()); - } else { - double eps = 1e-7; - // The dual ray is found in primal simplex first phase - // We assume that the glpk minimizes the slack to get feasible solution - for (int i = 1; i <= row_num; ++i) { - int index = glp_get_bhead(lp, i); - if (index <= row_num) { - double res = glp_get_row_prim(lp, index); - if (res > glp_get_row_ub(lp, index) + eps) { - _dual_ray[i] = -1; - } else if (res < glp_get_row_lb(lp, index) - eps) { - _dual_ray[i] = 1; - } else { - _dual_ray[i] = 0; - } - _dual_ray[i] *= glp_get_rii(lp, index); - } else { - double res = glp_get_col_prim(lp, index - row_num); - if (res > glp_get_col_ub(lp, index - row_num) + eps) { - _dual_ray[i] = -1; - } else if (res < glp_get_col_lb(lp, index - row_num) - eps) { - _dual_ray[i] = 1; - } else { - _dual_ray[i] = 0; - } - _dual_ray[i] /= glp_get_sjj(lp, index - row_num); - } - } - - glp_btran(lp, &_dual_ray.front()); - - for (int i = 1; i <= row_num; ++i) { - _dual_ray[i] /= glp_get_rii(lp, i); - } - } - } - return _dual_ray[i]; - } - - GlpkLp::ProblemType GlpkLp::_getPrimalType() const { - if (glp_get_status(lp) == GLP_OPT) - return OPTIMAL; - switch (glp_get_prim_stat(lp)) { - case GLP_UNDEF: - return UNDEFINED; - case GLP_FEAS: - case GLP_INFEAS: - if (glp_get_dual_stat(lp) == GLP_NOFEAS) { - return UNBOUNDED; - } else { - return UNDEFINED; - } - case GLP_NOFEAS: - return INFEASIBLE; - default: - LEMON_ASSERT(false, "Wrong primal type"); - return GlpkLp::ProblemType(); - } - } - - GlpkLp::ProblemType GlpkLp::_getDualType() const { - if (glp_get_status(lp) == GLP_OPT) - return OPTIMAL; - switch (glp_get_dual_stat(lp)) { - case GLP_UNDEF: - return UNDEFINED; - case GLP_FEAS: - case GLP_INFEAS: - if (glp_get_prim_stat(lp) == GLP_NOFEAS) { - return UNBOUNDED; - } else { - return UNDEFINED; - } - case GLP_NOFEAS: - return INFEASIBLE; - default: - LEMON_ASSERT(false, "Wrong primal type"); - return GlpkLp::ProblemType(); - } - } - - void GlpkLp::presolver(bool presolve) { - _presolve = presolve; - } - - // GlpkMip members - - GlpkMip::GlpkMip() - : LpBase(), MipSolver(), GlpkBase() { - } - - GlpkMip::GlpkMip(const GlpkMip& other) - : LpBase(), MipSolver(), GlpkBase(other) { - } - - void GlpkMip::_setColType(int i, GlpkMip::ColTypes col_type) { - switch (col_type) { - case INTEGER: - glp_set_col_kind(lp, i, GLP_IV); - break; - case REAL: - glp_set_col_kind(lp, i, GLP_CV); - break; - } - } - - GlpkMip::ColTypes GlpkMip::_getColType(int i) const { - switch (glp_get_col_kind(lp, i)) { - case GLP_IV: - case GLP_BV: - return INTEGER; - default: - return REAL; - } - - } - - GlpkMip::SolveExitStatus GlpkMip::_solve() { - glp_smcp smcp; - glp_init_smcp(&smcp); - - smcp.msg_lev = _message_level; - smcp.meth = GLP_DUAL; - - // If the basis is not valid we get an error return value. - // In this case we can try to create a new basis. - switch (glp_simplex(lp, &smcp)) { - case 0: - break; - case GLP_EBADB: - case GLP_ESING: - case GLP_ECOND: - glp_term_out(false); - glp_adv_basis(lp, 0); - glp_term_out(true); - if (glp_simplex(lp, &smcp) != 0) return UNSOLVED; - break; - default: - return UNSOLVED; - } - - if (glp_get_status(lp) != GLP_OPT) return SOLVED; - - glp_iocp iocp; - glp_init_iocp(&iocp); - - iocp.msg_lev = _message_level; - - if (glp_intopt(lp, &iocp) != 0) return UNSOLVED; - return SOLVED; - } - - - GlpkMip::ProblemType GlpkMip::_getType() const { - switch (glp_get_status(lp)) { - case GLP_OPT: - switch (glp_mip_status(lp)) { - case GLP_UNDEF: - return UNDEFINED; - case GLP_NOFEAS: - return INFEASIBLE; - case GLP_FEAS: - return FEASIBLE; - case GLP_OPT: - return OPTIMAL; - default: - LEMON_ASSERT(false, "Wrong problem type."); - return GlpkMip::ProblemType(); - } - case GLP_NOFEAS: - return INFEASIBLE; - case GLP_INFEAS: - case GLP_FEAS: - if (glp_get_dual_stat(lp) == GLP_NOFEAS) { - return UNBOUNDED; - } else { - return UNDEFINED; - } - default: - LEMON_ASSERT(false, "Wrong problem type."); - return GlpkMip::ProblemType(); - } - } - - GlpkMip::Value GlpkMip::_getSol(int i) const { - return glp_mip_col_val(lp, i); - } - - GlpkMip::Value GlpkMip::_getSolValue() const { - return glp_mip_obj_val(lp); - } - - GlpkMip* GlpkMip::newSolver() const { return new GlpkMip; } - GlpkMip* GlpkMip::cloneSolver() const {return new GlpkMip(*this); } - - const char* GlpkMip::_solverName() const { return "GlpkMip"; } - - - -} //END OF NAMESPACE LEMON diff --git a/deps/lemon/lemon/glpk.h b/deps/lemon/lemon/glpk.h deleted file mode 100644 index ccdc54ac0..000000000 --- a/deps/lemon/lemon/glpk.h +++ /dev/null @@ -1,263 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_GLPK_H -#define LEMON_GLPK_H - -///\file -///\brief Header of the LEMON-GLPK lp solver interface. -///\ingroup lp_group - -#include - -namespace lemon { - - namespace _solver_bits { - class VoidPtr { - private: - void *_ptr; - public: - VoidPtr() : _ptr(0) {} - - template - VoidPtr(T* ptr) : _ptr(reinterpret_cast(ptr)) {} - - template - VoidPtr& operator=(T* ptr) { - _ptr = reinterpret_cast(ptr); - return *this; - } - - template - operator T*() const { return reinterpret_cast(_ptr); } - }; - } - - /// \brief Base interface for the GLPK LP and MIP solver - /// - /// This class implements the common interface of the GLPK LP and MIP solver. - /// \ingroup lp_group - class GlpkBase : virtual public LpBase { - protected: - - _solver_bits::VoidPtr lp; - - GlpkBase(); - GlpkBase(const GlpkBase&); - virtual ~GlpkBase(); - - protected: - - virtual int _addCol(); - virtual int _addRow(); - virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); - - virtual void _eraseCol(int i); - virtual void _eraseRow(int i); - - virtual void _eraseColId(int i); - virtual void _eraseRowId(int i); - - virtual void _getColName(int col, std::string& name) const; - virtual void _setColName(int col, const std::string& name); - virtual int _colByName(const std::string& name) const; - - virtual void _getRowName(int row, std::string& name) const; - virtual void _setRowName(int row, const std::string& name); - virtual int _rowByName(const std::string& name) const; - - virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); - virtual void _getRowCoeffs(int i, InsertIterator b) const; - - virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); - virtual void _getColCoeffs(int i, InsertIterator b) const; - - virtual void _setCoeff(int row, int col, Value value); - virtual Value _getCoeff(int row, int col) const; - - virtual void _setColLowerBound(int i, Value value); - virtual Value _getColLowerBound(int i) const; - - virtual void _setColUpperBound(int i, Value value); - virtual Value _getColUpperBound(int i) const; - - virtual void _setRowLowerBound(int i, Value value); - virtual Value _getRowLowerBound(int i) const; - - virtual void _setRowUpperBound(int i, Value value); - virtual Value _getRowUpperBound(int i) const; - - virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); - virtual void _getObjCoeffs(InsertIterator b) const; - - virtual void _setObjCoeff(int i, Value obj_coef); - virtual Value _getObjCoeff(int i) const; - - virtual void _setSense(Sense); - virtual Sense _getSense() const; - - virtual void _clear(); - - virtual void _messageLevel(MessageLevel level); - - virtual void _write(std::string file, std::string format) const; - - private: - - static void freeEnv(); - - struct FreeEnvHelper { - ~FreeEnvHelper() { - freeEnv(); - } - }; - - static FreeEnvHelper freeEnvHelper; - - protected: - - int _message_level; - - public: - - ///Pointer to the underlying GLPK data structure. - _solver_bits::VoidPtr lpx() {return lp;} - ///Const pointer to the underlying GLPK data structure. - _solver_bits::VoidPtr lpx() const {return lp;} - - ///Returns the constraint identifier understood by GLPK. - int lpxRow(Row r) const { return rows(id(r)); } - - ///Returns the variable identifier understood by GLPK. - int lpxCol(Col c) const { return cols(id(c)); } - -#ifdef DOXYGEN - /// Write the problem or the solution to a file in the given format - - /// This function writes the problem or the solution - /// to a file in the given format. - /// Trying to write in an unsupported format will trigger - /// \ref LpBase::UnsupportedFormatError. - /// \param file The file path - /// \param format The output file format. - /// Supportted formats are "MPS" and "LP". - void write(std::string file, std::string format = "MPS") const {} -#endif - - }; - - /// \brief Interface for the GLPK LP solver - /// - /// This class implements an interface for the GLPK LP solver. - ///\ingroup lp_group - class GlpkLp : public LpSolver, public GlpkBase { - public: - - ///\e - GlpkLp(); - ///\e - GlpkLp(const GlpkLp&); - - ///\e - virtual GlpkLp* cloneSolver() const; - ///\e - virtual GlpkLp* newSolver() const; - - private: - - mutable std::vector _primal_ray; - mutable std::vector _dual_ray; - - void _clear_temporals(); - - protected: - - virtual const char* _solverName() const; - - virtual SolveExitStatus _solve(); - virtual Value _getPrimal(int i) const; - virtual Value _getDual(int i) const; - - virtual Value _getPrimalValue() const; - - virtual VarStatus _getColStatus(int i) const; - virtual VarStatus _getRowStatus(int i) const; - - virtual Value _getPrimalRay(int i) const; - virtual Value _getDualRay(int i) const; - - virtual ProblemType _getPrimalType() const; - virtual ProblemType _getDualType() const; - - public: - - ///Solve with primal simplex - SolveExitStatus solvePrimal(); - - ///Solve with dual simplex - SolveExitStatus solveDual(); - - private: - - bool _presolve; - - public: - - ///Turns on or off the presolver - - ///Turns on (\c b is \c true) or off (\c b is \c false) the presolver - /// - ///The presolver is off by default. - void presolver(bool presolve); - - }; - - /// \brief Interface for the GLPK MIP solver - /// - /// This class implements an interface for the GLPK MIP solver. - ///\ingroup lp_group - class GlpkMip : public MipSolver, public GlpkBase { - public: - - ///\e - GlpkMip(); - ///\e - GlpkMip(const GlpkMip&); - - virtual GlpkMip* cloneSolver() const; - virtual GlpkMip* newSolver() const; - - protected: - - virtual const char* _solverName() const; - - virtual ColTypes _getColType(int col) const; - virtual void _setColType(int col, ColTypes col_type); - - virtual SolveExitStatus _solve(); - virtual ProblemType _getType() const; - virtual Value _getSol(int i) const; - virtual Value _getSolValue() const; - - }; - - -} //END OF NAMESPACE LEMON - -#endif //LEMON_GLPK_H - diff --git a/deps/lemon/lemon/gomory_hu.h b/deps/lemon/lemon/gomory_hu.h deleted file mode 100644 index c43305f88..000000000 --- a/deps/lemon/lemon/gomory_hu.h +++ /dev/null @@ -1,568 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_GOMORY_HU_TREE_H -#define LEMON_GOMORY_HU_TREE_H - -#include - -#include -#include -#include -#include - -/// \ingroup min_cut -/// \file -/// \brief Gomory-Hu cut tree in graphs. - -namespace lemon { - - /// \ingroup min_cut - /// - /// \brief Gomory-Hu cut tree algorithm - /// - /// The Gomory-Hu tree is a tree on the node set of a given graph, but it - /// may contain edges which are not in the original graph. It has the - /// property that the minimum capacity edge of the path between two nodes - /// in this tree has the same weight as the minimum cut in the graph - /// between these nodes. Moreover the components obtained by removing - /// this edge from the tree determine the corresponding minimum cut. - /// Therefore once this tree is computed, the minimum cut between any pair - /// of nodes can easily be obtained. - /// - /// The algorithm calculates \e n-1 distinct minimum cuts (currently with - /// the \ref Preflow algorithm), thus it has \f$O(n^3\sqrt{m})\f$ overall - /// time complexity. It calculates a rooted Gomory-Hu tree. - /// The structure of the tree and the edge weights can be - /// obtained using \c predNode(), \c predValue() and \c rootDist(). - /// The functions \c minCutMap() and \c minCutValue() calculate - /// the minimum cut and the minimum cut value between any two nodes - /// in the graph. You can also list (iterate on) the nodes and the - /// edges of the cuts using \c MinCutNodeIt and \c MinCutEdgeIt. - /// - /// \tparam GR The type of the undirected graph the algorithm runs on. - /// \tparam CAP The type of the edge map containing the capacities. - /// The default map type is \ref concepts::Graph::EdgeMap "GR::EdgeMap". -#ifdef DOXYGEN - template -#else - template > -#endif - class GomoryHu { - public: - - /// The graph type of the algorithm - typedef GR Graph; - /// The capacity map type of the algorithm - typedef CAP Capacity; - /// The value type of capacities - typedef typename Capacity::Value Value; - - private: - - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - const Graph& _graph; - const Capacity& _capacity; - - Node _root; - typename Graph::template NodeMap* _pred; - typename Graph::template NodeMap* _weight; - typename Graph::template NodeMap* _order; - - void createStructures() { - if (!_pred) { - _pred = new typename Graph::template NodeMap(_graph); - } - if (!_weight) { - _weight = new typename Graph::template NodeMap(_graph); - } - if (!_order) { - _order = new typename Graph::template NodeMap(_graph); - } - } - - void destroyStructures() { - if (_pred) { - delete _pred; - } - if (_weight) { - delete _weight; - } - if (_order) { - delete _order; - } - } - - public: - - /// \brief Constructor - /// - /// Constructor. - /// \param graph The undirected graph the algorithm runs on. - /// \param capacity The edge capacity map. - GomoryHu(const Graph& graph, const Capacity& capacity) - : _graph(graph), _capacity(capacity), - _pred(0), _weight(0), _order(0) - { - checkConcept, Capacity>(); - } - - - /// \brief Destructor - /// - /// Destructor. - ~GomoryHu() { - destroyStructures(); - } - - private: - - // Initialize the internal data structures - void init() { - createStructures(); - - _root = NodeIt(_graph); - for (NodeIt n(_graph); n != INVALID; ++n) { - (*_pred)[n] = _root; - (*_order)[n] = -1; - } - (*_pred)[_root] = INVALID; - (*_weight)[_root] = std::numeric_limits::max(); - } - - - // Start the algorithm - void start() { - Preflow fa(_graph, _capacity, _root, INVALID); - - for (NodeIt n(_graph); n != INVALID; ++n) { - if (n == _root) continue; - - Node pn = (*_pred)[n]; - fa.source(n); - fa.target(pn); - - fa.runMinCut(); - - (*_weight)[n] = fa.flowValue(); - - for (NodeIt nn(_graph); nn != INVALID; ++nn) { - if (nn != n && fa.minCut(nn) && (*_pred)[nn] == pn) { - (*_pred)[nn] = n; - } - } - if ((*_pred)[pn] != INVALID && fa.minCut((*_pred)[pn])) { - (*_pred)[n] = (*_pred)[pn]; - (*_pred)[pn] = n; - (*_weight)[n] = (*_weight)[pn]; - (*_weight)[pn] = fa.flowValue(); - } - } - - (*_order)[_root] = 0; - int index = 1; - - for (NodeIt n(_graph); n != INVALID; ++n) { - std::vector st; - Node nn = n; - while ((*_order)[nn] == -1) { - st.push_back(nn); - nn = (*_pred)[nn]; - } - while (!st.empty()) { - (*_order)[st.back()] = index++; - st.pop_back(); - } - } - } - - public: - - ///\name Execution Control - - ///@{ - - /// \brief Run the Gomory-Hu algorithm. - /// - /// This function runs the Gomory-Hu algorithm. - void run() { - init(); - start(); - } - - /// @} - - ///\name Query Functions - ///The results of the algorithm can be obtained using these - ///functions.\n - ///\ref run() should be called before using them.\n - ///See also \ref MinCutNodeIt and \ref MinCutEdgeIt. - - ///@{ - - /// \brief Return the predecessor node in the Gomory-Hu tree. - /// - /// This function returns the predecessor node of the given node - /// in the Gomory-Hu tree. - /// If \c node is the root of the tree, then it returns \c INVALID. - /// - /// \pre \ref run() must be called before using this function. - Node predNode(const Node& node) const { - return (*_pred)[node]; - } - - /// \brief Return the weight of the predecessor edge in the - /// Gomory-Hu tree. - /// - /// This function returns the weight of the predecessor edge of the - /// given node in the Gomory-Hu tree. - /// If \c node is the root of the tree, the result is undefined. - /// - /// \pre \ref run() must be called before using this function. - Value predValue(const Node& node) const { - return (*_weight)[node]; - } - - /// \brief Return the distance from the root node in the Gomory-Hu tree. - /// - /// This function returns the distance of the given node from the root - /// node in the Gomory-Hu tree. - /// - /// \pre \ref run() must be called before using this function. - int rootDist(const Node& node) const { - return (*_order)[node]; - } - - /// \brief Return the minimum cut value between two nodes - /// - /// This function returns the minimum cut value between the nodes - /// \c s and \c t. - /// It finds the nearest common ancestor of the given nodes in the - /// Gomory-Hu tree and calculates the minimum weight edge on the - /// paths to the ancestor. - /// - /// \pre \ref run() must be called before using this function. - Value minCutValue(const Node& s, const Node& t) const { - Node sn = s, tn = t; - Value value = std::numeric_limits::max(); - - while (sn != tn) { - if ((*_order)[sn] < (*_order)[tn]) { - if ((*_weight)[tn] <= value) value = (*_weight)[tn]; - tn = (*_pred)[tn]; - } else { - if ((*_weight)[sn] <= value) value = (*_weight)[sn]; - sn = (*_pred)[sn]; - } - } - return value; - } - - /// \brief Return the minimum cut between two nodes - /// - /// This function returns the minimum cut between the nodes \c s and \c t - /// in the \c cutMap parameter by setting the nodes in the component of - /// \c s to \c true and the other nodes to \c false. - /// - /// For higher level interfaces see MinCutNodeIt and MinCutEdgeIt. - /// - /// \param s The base node. - /// \param t The node you want to separate from node \c s. - /// \param cutMap The cut will be returned in this map. - /// It must be a \c bool (or convertible) \ref concepts::ReadWriteMap - /// "ReadWriteMap" on the graph nodes. - /// - /// \return The value of the minimum cut between \c s and \c t. - /// - /// \pre \ref run() must be called before using this function. - template - Value minCutMap(const Node& s, - const Node& t, - CutMap& cutMap - ) const { - Node sn = s, tn = t; - bool s_root=false; - Node rn = INVALID; - Value value = std::numeric_limits::max(); - - while (sn != tn) { - if ((*_order)[sn] < (*_order)[tn]) { - if ((*_weight)[tn] <= value) { - rn = tn; - s_root = false; - value = (*_weight)[tn]; - } - tn = (*_pred)[tn]; - } else { - if ((*_weight)[sn] <= value) { - rn = sn; - s_root = true; - value = (*_weight)[sn]; - } - sn = (*_pred)[sn]; - } - } - - typename Graph::template NodeMap reached(_graph, false); - reached[_root] = true; - cutMap.set(_root, !s_root); - reached[rn] = true; - cutMap.set(rn, s_root); - - std::vector st; - for (NodeIt n(_graph); n != INVALID; ++n) { - st.clear(); - Node nn = n; - while (!reached[nn]) { - st.push_back(nn); - nn = (*_pred)[nn]; - } - while (!st.empty()) { - cutMap.set(st.back(), cutMap[nn]); - st.pop_back(); - } - } - - return value; - } - - ///@} - - friend class MinCutNodeIt; - - /// Iterate on the nodes of a minimum cut - - /// This iterator class lists the nodes of a minimum cut found by - /// GomoryHu. Before using it, you must allocate a GomoryHu class - /// and call its \ref GomoryHu::run() "run()" method. - /// - /// This example counts the nodes in the minimum cut separating \c s from - /// \c t. - /// \code - /// GomoryHu gom(g, capacities); - /// gom.run(); - /// int cnt=0; - /// for(GomoryHu::MinCutNodeIt n(gom,s,t); n!=INVALID; ++n) ++cnt; - /// \endcode - class MinCutNodeIt - { - bool _side; - typename Graph::NodeIt _node_it; - typename Graph::template NodeMap _cut; - public: - /// Constructor - - /// Constructor. - /// - MinCutNodeIt(GomoryHu const &gomory, - ///< The GomoryHu class. You must call its - /// run() method - /// before initializing this iterator. - const Node& s, ///< The base node. - const Node& t, - ///< The node you want to separate from node \c s. - bool side=true - ///< If it is \c true (default) then the iterator lists - /// the nodes of the component containing \c s, - /// otherwise it lists the other component. - /// \note As the minimum cut is not always unique, - /// \code - /// MinCutNodeIt(gomory, s, t, true); - /// \endcode - /// and - /// \code - /// MinCutNodeIt(gomory, t, s, false); - /// \endcode - /// does not necessarily give the same set of nodes. - /// However, it is ensured that - /// \code - /// MinCutNodeIt(gomory, s, t, true); - /// \endcode - /// and - /// \code - /// MinCutNodeIt(gomory, s, t, false); - /// \endcode - /// together list each node exactly once. - ) - : _side(side), _cut(gomory._graph) - { - gomory.minCutMap(s,t,_cut); - for(_node_it=typename Graph::NodeIt(gomory._graph); - _node_it!=INVALID && _cut[_node_it]!=_side; - ++_node_it) {} - } - /// Conversion to \c Node - - /// Conversion to \c Node. - /// - operator typename Graph::Node() const - { - return _node_it; - } - bool operator==(Invalid) { return _node_it==INVALID; } - bool operator!=(Invalid) { return _node_it!=INVALID; } - /// Next node - - /// Next node. - /// - MinCutNodeIt &operator++() - { - for(++_node_it;_node_it!=INVALID&&_cut[_node_it]!=_side;++_node_it) {} - return *this; - } - /// Postfix incrementation - - /// Postfix incrementation. - /// - /// \warning This incrementation - /// returns a \c Node, not a \c MinCutNodeIt, as one may - /// expect. - typename Graph::Node operator++(int) - { - typename Graph::Node n=*this; - ++(*this); - return n; - } - }; - - friend class MinCutEdgeIt; - - /// Iterate on the edges of a minimum cut - - /// This iterator class lists the edges of a minimum cut found by - /// GomoryHu. Before using it, you must allocate a GomoryHu class - /// and call its \ref GomoryHu::run() "run()" method. - /// - /// This example computes the value of the minimum cut separating \c s from - /// \c t. - /// \code - /// GomoryHu gom(g, capacities); - /// gom.run(); - /// int value=0; - /// for(GomoryHu::MinCutEdgeIt e(gom,s,t); e!=INVALID; ++e) - /// value+=capacities[e]; - /// \endcode - /// The result will be the same as the value returned by - /// \ref GomoryHu::minCutValue() "gom.minCutValue(s,t)". - class MinCutEdgeIt - { - bool _side; - const Graph &_graph; - typename Graph::NodeIt _node_it; - typename Graph::OutArcIt _arc_it; - typename Graph::template NodeMap _cut; - void step() - { - ++_arc_it; - while(_node_it!=INVALID && _arc_it==INVALID) - { - for(++_node_it;_node_it!=INVALID&&!_cut[_node_it];++_node_it) {} - if(_node_it!=INVALID) - _arc_it=typename Graph::OutArcIt(_graph,_node_it); - } - } - - public: - /// Constructor - - /// Constructor. - /// - MinCutEdgeIt(GomoryHu const &gomory, - ///< The GomoryHu class. You must call its - /// run() method - /// before initializing this iterator. - const Node& s, ///< The base node. - const Node& t, - ///< The node you want to separate from node \c s. - bool side=true - ///< If it is \c true (default) then the listed arcs - /// will be oriented from the - /// nodes of the component containing \c s, - /// otherwise they will be oriented in the opposite - /// direction. - ) - : _graph(gomory._graph), _cut(_graph) - { - gomory.minCutMap(s,t,_cut); - if(!side) - for(typename Graph::NodeIt n(_graph);n!=INVALID;++n) - _cut[n]=!_cut[n]; - - for(_node_it=typename Graph::NodeIt(_graph); - _node_it!=INVALID && !_cut[_node_it]; - ++_node_it) {} - _arc_it = _node_it!=INVALID ? - typename Graph::OutArcIt(_graph,_node_it) : INVALID; - while(_node_it!=INVALID && _arc_it == INVALID) - { - for(++_node_it; _node_it!=INVALID&&!_cut[_node_it]; ++_node_it) {} - if(_node_it!=INVALID) - _arc_it= typename Graph::OutArcIt(_graph,_node_it); - } - while(_arc_it!=INVALID && _cut[_graph.target(_arc_it)]) step(); - } - /// Conversion to \c Arc - - /// Conversion to \c Arc. - /// - operator typename Graph::Arc() const - { - return _arc_it; - } - /// Conversion to \c Edge - - /// Conversion to \c Edge. - /// - operator typename Graph::Edge() const - { - return _arc_it; - } - bool operator==(Invalid) { return _node_it==INVALID; } - bool operator!=(Invalid) { return _node_it!=INVALID; } - /// Next edge - - /// Next edge. - /// - MinCutEdgeIt &operator++() - { - step(); - while(_arc_it!=INVALID && _cut[_graph.target(_arc_it)]) step(); - return *this; - } - /// Postfix incrementation - - /// Postfix incrementation. - /// - /// \warning This incrementation - /// returns an \c Arc, not a \c MinCutEdgeIt, as one may expect. - typename Graph::Arc operator++(int) - { - typename Graph::Arc e=*this; - ++(*this); - return e; - } - }; - - }; - -} - -#endif diff --git a/deps/lemon/lemon/graph_to_eps.h b/deps/lemon/lemon/graph_to_eps.h deleted file mode 100644 index 29ba83693..000000000 --- a/deps/lemon/lemon/graph_to_eps.h +++ /dev/null @@ -1,1186 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_GRAPH_TO_EPS_H -#define LEMON_GRAPH_TO_EPS_H - -#include -#include -#include -#include -#include - -#ifndef WIN32 -#include -#include -#else -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - - -///\ingroup eps_io -///\file -///\brief A well configurable tool for visualizing graphs - -namespace lemon { - - namespace _graph_to_eps_bits { - template - class _NegY { - public: - typedef typename MT::Key Key; - typedef typename MT::Value Value; - const MT ↦ - int yscale; - _NegY(const MT &m,bool b) : map(m), yscale(1-b*2) {} - Value operator[](Key n) { return Value(map[n].x,map[n].y*yscale);} - }; - } - -///Default traits class of GraphToEps - -///Default traits class of \ref GraphToEps. -/// -///\param GR is the type of the underlying graph. -template -struct DefaultGraphToEpsTraits -{ - typedef GR Graph; - typedef GR Digraph; - typedef typename Graph::Node Node; - typedef typename Graph::NodeIt NodeIt; - typedef typename Graph::Arc Arc; - typedef typename Graph::ArcIt ArcIt; - typedef typename Graph::InArcIt InArcIt; - typedef typename Graph::OutArcIt OutArcIt; - - - const Graph &g; - - std::ostream& os; - - typedef ConstMap > CoordsMapType; - CoordsMapType _coords; - ConstMap _nodeSizes; - ConstMap _nodeShapes; - - ConstMap _nodeColors; - ConstMap _arcColors; - - ConstMap _arcWidths; - - double _arcWidthScale; - - double _nodeScale; - double _xBorder, _yBorder; - double _scale; - double _nodeBorderQuotient; - - bool _drawArrows; - double _arrowLength, _arrowWidth; - - bool _showNodes, _showArcs; - - bool _enableParallel; - double _parArcDist; - - bool _showNodeText; - ConstMap _nodeTexts; - double _nodeTextSize; - - bool _showNodePsText; - ConstMap _nodePsTexts; - char *_nodePsTextsPreamble; - - bool _undirected; - - bool _pleaseRemoveOsStream; - - bool _scaleToA4; - - std::string _title; - std::string _copyright; - - enum NodeTextColorType - { DIST_COL=0, DIST_BW=1, CUST_COL=2, SAME_COL=3 } _nodeTextColorType; - ConstMap _nodeTextColors; - - bool _autoNodeScale; - bool _autoArcWidthScale; - - bool _absoluteNodeSizes; - bool _absoluteArcWidths; - - bool _negY; - - bool _preScale; - ///Constructor - - ///Constructor - ///\param gr Reference to the graph to be printed. - ///\param ost Reference to the output stream. - ///By default, it is std::cout. - ///\param pros If it is \c true, then the \c ostream referenced by \c os - ///will be explicitly deallocated by the destructor. - DefaultGraphToEpsTraits(const GR &gr, std::ostream& ost = std::cout, - bool pros = false) : - g(gr), os(ost), - _coords(dim2::Point(1,1)), _nodeSizes(1), _nodeShapes(0), - _nodeColors(WHITE), _arcColors(BLACK), - _arcWidths(1.0), _arcWidthScale(0.003), - _nodeScale(.01), _xBorder(10), _yBorder(10), _scale(1.0), - _nodeBorderQuotient(.1), - _drawArrows(false), _arrowLength(1), _arrowWidth(0.3), - _showNodes(true), _showArcs(true), - _enableParallel(false), _parArcDist(1), - _showNodeText(false), _nodeTexts(false), _nodeTextSize(1), - _showNodePsText(false), _nodePsTexts(false), _nodePsTextsPreamble(0), - _undirected(lemon::UndirectedTagIndicator::value), - _pleaseRemoveOsStream(pros), _scaleToA4(false), - _nodeTextColorType(SAME_COL), _nodeTextColors(BLACK), - _autoNodeScale(false), - _autoArcWidthScale(false), - _absoluteNodeSizes(false), - _absoluteArcWidths(false), - _negY(false), - _preScale(true) - {} -}; - -///Auxiliary class to implement the named parameters of \ref graphToEps() - -///Auxiliary class to implement the named parameters of \ref graphToEps(). -/// -///For detailed examples see the \ref graph_to_eps_demo.cc demo file. -template class GraphToEps : public T -{ - // Can't believe it is required by the C++ standard - using T::g; - using T::os; - - using T::_coords; - using T::_nodeSizes; - using T::_nodeShapes; - using T::_nodeColors; - using T::_arcColors; - using T::_arcWidths; - - using T::_arcWidthScale; - using T::_nodeScale; - using T::_xBorder; - using T::_yBorder; - using T::_scale; - using T::_nodeBorderQuotient; - - using T::_drawArrows; - using T::_arrowLength; - using T::_arrowWidth; - - using T::_showNodes; - using T::_showArcs; - - using T::_enableParallel; - using T::_parArcDist; - - using T::_showNodeText; - using T::_nodeTexts; - using T::_nodeTextSize; - - using T::_showNodePsText; - using T::_nodePsTexts; - using T::_nodePsTextsPreamble; - - using T::_undirected; - - using T::_pleaseRemoveOsStream; - - using T::_scaleToA4; - - using T::_title; - using T::_copyright; - - using T::CUST_COL; - using T::DIST_COL; - using T::DIST_BW; - using T::_nodeTextColorType; - using T::_nodeTextColors; - - using T::_autoNodeScale; - using T::_autoArcWidthScale; - - using T::_absoluteNodeSizes; - using T::_absoluteArcWidths; - - - using T::_negY; - using T::_preScale; - - // dradnats ++C eht yb deriuqer si ti eveileb t'naC - - typedef typename T::Graph Graph; - typedef typename T::Digraph Digraph; - typedef typename Graph::Node Node; - typedef typename Graph::NodeIt NodeIt; - typedef typename Graph::Arc Arc; - typedef typename Graph::ArcIt ArcIt; - typedef typename Graph::InArcIt InArcIt; - typedef typename Graph::OutArcIt OutArcIt; - - static const int INTERPOL_PREC; - static const double A4HEIGHT; - static const double A4WIDTH; - static const double A4BORDER; - - bool dontPrint; - -public: - ///Node shapes - - ///Node shapes. - /// - enum NodeShapes { - /// = 0 - ///\image html nodeshape_0.png - ///\image latex nodeshape_0.eps "CIRCLE shape (0)" width=2cm - CIRCLE=0, - /// = 1 - ///\image html nodeshape_1.png - ///\image latex nodeshape_1.eps "SQUARE shape (1)" width=2cm - SQUARE=1, - /// = 2 - ///\image html nodeshape_2.png - ///\image latex nodeshape_2.eps "DIAMOND shape (2)" width=2cm - DIAMOND=2, - /// = 3 - ///\image html nodeshape_3.png - ///\image latex nodeshape_3.eps "MALE shape (3)" width=2cm - MALE=3, - /// = 4 - ///\image html nodeshape_4.png - ///\image latex nodeshape_4.eps "FEMALE shape (4)" width=2cm - FEMALE=4 - }; - -private: - class arcLess { - const Graph &g; - public: - arcLess(const Graph &_g) : g(_g) {} - bool operator()(Arc a,Arc b) const - { - Node ai=std::min(g.source(a),g.target(a)); - Node aa=std::max(g.source(a),g.target(a)); - Node bi=std::min(g.source(b),g.target(b)); - Node ba=std::max(g.source(b),g.target(b)); - return ai - static std::string psOut(const dim2::Point &p) - { - std::ostringstream os; - os << p.x << ' ' << p.y; - return os.str(); - } - static std::string psOut(const Color &c) - { - std::ostringstream os; - os << c.red() << ' ' << c.green() << ' ' << c.blue(); - return os.str(); - } - -public: - GraphToEps(const T &t) : T(t), dontPrint(false) {}; - - template struct CoordsTraits : public T { - typedef X CoordsMapType; - const X &_coords; - CoordsTraits(const T &t,const X &x) : T(t), _coords(x) {} - }; - ///Sets the map of the node coordinates - - ///Sets the map of the node coordinates. - ///\param x must be a node map with \ref dim2::Point "dim2::Point" or - ///\ref dim2::Point "dim2::Point" values. - template GraphToEps > coords(const X &x) { - dontPrint=true; - return GraphToEps >(CoordsTraits(*this,x)); - } - template struct NodeSizesTraits : public T { - const X &_nodeSizes; - NodeSizesTraits(const T &t,const X &x) : T(t), _nodeSizes(x) {} - }; - ///Sets the map of the node sizes - - ///Sets the map of the node sizes. - ///\param x must be a node map with \c double (or convertible) values. - template GraphToEps > nodeSizes(const X &x) - { - dontPrint=true; - return GraphToEps >(NodeSizesTraits(*this,x)); - } - template struct NodeShapesTraits : public T { - const X &_nodeShapes; - NodeShapesTraits(const T &t,const X &x) : T(t), _nodeShapes(x) {} - }; - ///Sets the map of the node shapes - - ///Sets the map of the node shapes. - ///The available shape values - ///can be found in \ref NodeShapes "enum NodeShapes". - ///\param x must be a node map with \c int (or convertible) values. - ///\sa NodeShapes - template GraphToEps > nodeShapes(const X &x) - { - dontPrint=true; - return GraphToEps >(NodeShapesTraits(*this,x)); - } - template struct NodeTextsTraits : public T { - const X &_nodeTexts; - NodeTextsTraits(const T &t,const X &x) : T(t), _nodeTexts(x) {} - }; - ///Sets the text printed on the nodes - - ///Sets the text printed on the nodes. - ///\param x must be a node map with type that can be pushed to a standard - ///\c ostream. - template GraphToEps > nodeTexts(const X &x) - { - dontPrint=true; - _showNodeText=true; - return GraphToEps >(NodeTextsTraits(*this,x)); - } - template struct NodePsTextsTraits : public T { - const X &_nodePsTexts; - NodePsTextsTraits(const T &t,const X &x) : T(t), _nodePsTexts(x) {} - }; - ///Inserts a PostScript block to the nodes - - ///With this command it is possible to insert a verbatim PostScript - ///block to the nodes. - ///The PS current point will be moved to the center of the node before - ///the PostScript block inserted. - /// - ///Before and after the block a newline character is inserted so you - ///don't have to bother with the separators. - /// - ///\param x must be a node map with type that can be pushed to a standard - ///\c ostream. - /// - ///\sa nodePsTextsPreamble() - template GraphToEps > nodePsTexts(const X &x) - { - dontPrint=true; - _showNodePsText=true; - return GraphToEps >(NodePsTextsTraits(*this,x)); - } - template struct ArcWidthsTraits : public T { - const X &_arcWidths; - ArcWidthsTraits(const T &t,const X &x) : T(t), _arcWidths(x) {} - }; - ///Sets the map of the arc widths - - ///Sets the map of the arc widths. - ///\param x must be an arc map with \c double (or convertible) values. - template GraphToEps > arcWidths(const X &x) - { - dontPrint=true; - return GraphToEps >(ArcWidthsTraits(*this,x)); - } - - template struct NodeColorsTraits : public T { - const X &_nodeColors; - NodeColorsTraits(const T &t,const X &x) : T(t), _nodeColors(x) {} - }; - ///Sets the map of the node colors - - ///Sets the map of the node colors. - ///\param x must be a node map with \ref Color values. - /// - ///\sa Palette - template GraphToEps > - nodeColors(const X &x) - { - dontPrint=true; - return GraphToEps >(NodeColorsTraits(*this,x)); - } - template struct NodeTextColorsTraits : public T { - const X &_nodeTextColors; - NodeTextColorsTraits(const T &t,const X &x) : T(t), _nodeTextColors(x) {} - }; - ///Sets the map of the node text colors - - ///Sets the map of the node text colors. - ///\param x must be a node map with \ref Color values. - /// - ///\sa Palette - template GraphToEps > - nodeTextColors(const X &x) - { - dontPrint=true; - _nodeTextColorType=CUST_COL; - return GraphToEps > - (NodeTextColorsTraits(*this,x)); - } - template struct ArcColorsTraits : public T { - const X &_arcColors; - ArcColorsTraits(const T &t,const X &x) : T(t), _arcColors(x) {} - }; - ///Sets the map of the arc colors - - ///Sets the map of the arc colors. - ///\param x must be an arc map with \ref Color values. - /// - ///\sa Palette - template GraphToEps > - arcColors(const X &x) - { - dontPrint=true; - return GraphToEps >(ArcColorsTraits(*this,x)); - } - ///Sets a global scale factor for node sizes - - ///Sets a global scale factor for node sizes. - /// - /// If nodeSizes() is not given, this function simply sets the node - /// sizes to \c d. If nodeSizes() is given, but - /// autoNodeScale() is not, then the node size given by - /// nodeSizes() will be multiplied by the value \c d. - /// If both nodeSizes() and autoNodeScale() are used, then the - /// node sizes will be scaled in such a way that the greatest size will be - /// equal to \c d. - /// \sa nodeSizes() - /// \sa autoNodeScale() - GraphToEps &nodeScale(double d=.01) {_nodeScale=d;return *this;} - ///Turns on/off the automatic node size scaling. - - ///Turns on/off the automatic node size scaling. - /// - ///\sa nodeScale() - /// - GraphToEps &autoNodeScale(bool b=true) { - _autoNodeScale=b;return *this; - } - - ///Turns on/off the absolutematic node size scaling. - - ///Turns on/off the absolutematic node size scaling. - /// - ///\sa nodeScale() - /// - GraphToEps &absoluteNodeSizes(bool b=true) { - _absoluteNodeSizes=b;return *this; - } - - ///Negates the Y coordinates. - GraphToEps &negateY(bool b=true) { - _negY=b;return *this; - } - - ///Turn on/off pre-scaling - - ///By default, graphToEps() rescales the whole image in order to avoid - ///very big or very small bounding boxes. - /// - ///This (p)rescaling can be turned off with this function. - /// - GraphToEps &preScale(bool b=true) { - _preScale=b;return *this; - } - - ///Sets a global scale factor for arc widths - - /// Sets a global scale factor for arc widths. - /// - /// If arcWidths() is not given, this function simply sets the arc - /// widths to \c d. If arcWidths() is given, but - /// autoArcWidthScale() is not, then the arc withs given by - /// arcWidths() will be multiplied by the value \c d. - /// If both arcWidths() and autoArcWidthScale() are used, then the - /// arc withs will be scaled in such a way that the greatest width will be - /// equal to \c d. - GraphToEps &arcWidthScale(double d=.003) {_arcWidthScale=d;return *this;} - ///Turns on/off the automatic arc width scaling. - - ///Turns on/off the automatic arc width scaling. - /// - ///\sa arcWidthScale() - /// - GraphToEps &autoArcWidthScale(bool b=true) { - _autoArcWidthScale=b;return *this; - } - ///Turns on/off the absolutematic arc width scaling. - - ///Turns on/off the absolutematic arc width scaling. - /// - ///\sa arcWidthScale() - /// - GraphToEps &absoluteArcWidths(bool b=true) { - _absoluteArcWidths=b;return *this; - } - ///Sets a global scale factor for the whole picture - GraphToEps &scale(double d) {_scale=d;return *this;} - ///Sets the width of the border around the picture - GraphToEps &border(double b=10) {_xBorder=_yBorder=b;return *this;} - ///Sets the width of the border around the picture - GraphToEps &border(double x, double y) { - _xBorder=x;_yBorder=y;return *this; - } - ///Sets whether to draw arrows - GraphToEps &drawArrows(bool b=true) {_drawArrows=b;return *this;} - ///Sets the length of the arrowheads - GraphToEps &arrowLength(double d=1.0) {_arrowLength*=d;return *this;} - ///Sets the width of the arrowheads - GraphToEps &arrowWidth(double d=.3) {_arrowWidth*=d;return *this;} - - ///Scales the drawing to fit to A4 page - GraphToEps &scaleToA4() {_scaleToA4=true;return *this;} - - ///Enables parallel arcs - GraphToEps &enableParallel(bool b=true) {_enableParallel=b;return *this;} - - ///Sets the distance between parallel arcs - GraphToEps &parArcDist(double d) {_parArcDist*=d;return *this;} - - ///Hides the arcs - GraphToEps &hideArcs(bool b=true) {_showArcs=!b;return *this;} - ///Hides the nodes - GraphToEps &hideNodes(bool b=true) {_showNodes=!b;return *this;} - - ///Sets the size of the node texts - GraphToEps &nodeTextSize(double d) {_nodeTextSize=d;return *this;} - - ///Sets the color of the node texts to be different from the node color - - ///Sets the color of the node texts to be as different from the node color - ///as it is possible. - GraphToEps &distantColorNodeTexts() - {_nodeTextColorType=DIST_COL;return *this;} - ///Sets the color of the node texts to be black or white and always visible. - - ///Sets the color of the node texts to be black or white according to - ///which is more different from the node color. - GraphToEps &distantBWNodeTexts() - {_nodeTextColorType=DIST_BW;return *this;} - - ///Gives a preamble block for node Postscript block. - - ///Gives a preamble block for node Postscript block. - /// - ///\sa nodePsTexts() - GraphToEps & nodePsTextsPreamble(const char *str) { - _nodePsTextsPreamble=str ;return *this; - } - ///Sets whether the graph is undirected - - ///Sets whether the graph is undirected. - /// - ///This setting is the default for undirected graphs. - /// - ///\sa directed() - GraphToEps &undirected(bool b=true) {_undirected=b;return *this;} - - ///Sets whether the graph is directed - - ///Sets whether the graph is directed. - ///Use it to show the edges as a pair of directed ones. - /// - ///This setting is the default for digraphs. - /// - ///\sa undirected() - GraphToEps &directed(bool b=true) {_undirected=!b;return *this;} - - ///Sets the title. - - ///Sets the title of the generated image, - ///namely it inserts a %%Title: DSC field to the header of - ///the EPS file. - GraphToEps &title(const std::string &t) {_title=t;return *this;} - ///Sets the copyright statement. - - ///Sets the copyright statement of the generated image, - ///namely it inserts a %%Copyright: DSC field to the header of - ///the EPS file. - GraphToEps ©right(const std::string &t) {_copyright=t;return *this;} - -protected: - bool isInsideNode(dim2::Point p, double r,int t) - { - switch(t) { - case CIRCLE: - case MALE: - case FEMALE: - return p.normSquare()<=r*r; - case SQUARE: - return p.x<=r&&p.x>=-r&&p.y<=r&&p.y>=-r; - case DIAMOND: - return p.x+p.y<=r && p.x-p.y<=r && -p.x+p.y<=r && -p.x-p.y<=r; - } - return false; - } - -public: - ~GraphToEps() { } - - ///Draws the graph. - - ///Like other functions using - ///\ref named-templ-func-param "named template parameters", - ///this function calls the algorithm itself, i.e. in this case - ///it draws the graph. - void run() { - const double EPSILON=1e-9; - if(dontPrint) return; - - _graph_to_eps_bits::_NegY - mycoords(_coords,_negY); - - os << "%!PS-Adobe-2.0 EPSF-2.0\n"; - if(_title.size()>0) os << "%%Title: " << _title << '\n'; - if(_copyright.size()>0) os << "%%Copyright: " << _copyright << '\n'; - os << "%%Creator: LEMON, graphToEps()\n"; - - { - os << "%%CreationDate: "; -#ifndef WIN32 - timeval tv; - gettimeofday(&tv, 0); - - char cbuf[26]; - ctime_r(&tv.tv_sec,cbuf); - os << cbuf; -#else - os << bits::getWinFormattedDate(); - os << std::endl; -#endif - } - - if (_autoArcWidthScale) { - double max_w=0; - for(ArcIt e(g);e!=INVALID;++e) - max_w=std::max(double(_arcWidths[e]),max_w); - if(max_w>EPSILON) { - _arcWidthScale/=max_w; - } - } - - if (_autoNodeScale) { - double max_s=0; - for(NodeIt n(g);n!=INVALID;++n) - max_s=std::max(double(_nodeSizes[n]),max_s); - if(max_s>EPSILON) { - _nodeScale/=max_s; - } - } - - double diag_len = 1; - if(!(_absoluteNodeSizes&&_absoluteArcWidths)) { - dim2::Box bb; - for(NodeIt n(g);n!=INVALID;++n) bb.add(mycoords[n]); - if (bb.empty()) { - bb = dim2::Box(dim2::Point(0,0)); - } - diag_len = std::sqrt((bb.bottomLeft()-bb.topRight()).normSquare()); - if(diag_len bb; - for(NodeIt n(g);n!=INVALID;++n) { - double ns=_nodeSizes[n]*_nodeScale; - dim2::Point p(ns,ns); - switch(_nodeShapes[n]) { - case CIRCLE: - case SQUARE: - case DIAMOND: - bb.add(p+mycoords[n]); - bb.add(-p+mycoords[n]); - break; - case MALE: - bb.add(-p+mycoords[n]); - bb.add(dim2::Point(1.5*ns,1.5*std::sqrt(3.0)*ns)+mycoords[n]); - break; - case FEMALE: - bb.add(p+mycoords[n]); - bb.add(dim2::Point(-ns,-3.01*ns)+mycoords[n]); - break; - } - } - if (bb.empty()) { - bb = dim2::Box(dim2::Point(0,0)); - } - - if(_scaleToA4) - os <<"%%BoundingBox: 0 0 596 842\n%%DocumentPaperSizes: a4\n"; - else { - if(_preScale) { - //Rescale so that BoundingBox won't be neither to big nor too small. - while(bb.height()*_scale>1000||bb.width()*_scale>1000) _scale/=10; - while(bb.height()*_scale<100||bb.width()*_scale<100) _scale*=10; - } - - os << "%%BoundingBox: " - << int(floor(bb.left() * _scale - _xBorder)) << ' ' - << int(floor(bb.bottom() * _scale - _yBorder)) << ' ' - << int(ceil(bb.right() * _scale + _xBorder)) << ' ' - << int(ceil(bb.top() * _scale + _yBorder)) << '\n'; - } - - os << "%%EndComments\n"; - - //x1 y1 x2 y2 x3 y3 cr cg cb w - os << "/lb { setlinewidth setrgbcolor newpath moveto\n" - << " 4 2 roll 1 index 1 index curveto stroke } bind def\n"; - os << "/l { setlinewidth setrgbcolor newpath moveto lineto stroke }" - << " bind def\n"; - //x y r - os << "/c { newpath dup 3 index add 2 index moveto 0 360 arc closepath }" - << " bind def\n"; - //x y r - os << "/sq { newpath 2 index 1 index add 2 index 2 index add moveto\n" - << " 2 index 1 index sub 2 index 2 index add lineto\n" - << " 2 index 1 index sub 2 index 2 index sub lineto\n" - << " 2 index 1 index add 2 index 2 index sub lineto\n" - << " closepath pop pop pop} bind def\n"; - //x y r - os << "/di { newpath 2 index 1 index add 2 index moveto\n" - << " 2 index 2 index 2 index add lineto\n" - << " 2 index 1 index sub 2 index lineto\n" - << " 2 index 2 index 2 index sub lineto\n" - << " closepath pop pop pop} bind def\n"; - // x y r cr cg cb - os << "/nc { 0 0 0 setrgbcolor 5 index 5 index 5 index c fill\n" - << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n" - << " } bind def\n"; - os << "/nsq { 0 0 0 setrgbcolor 5 index 5 index 5 index sq fill\n" - << " setrgbcolor " << 1+_nodeBorderQuotient << " div sq fill\n" - << " } bind def\n"; - os << "/ndi { 0 0 0 setrgbcolor 5 index 5 index 5 index di fill\n" - << " setrgbcolor " << 1+_nodeBorderQuotient << " div di fill\n" - << " } bind def\n"; - os << "/nfemale { 0 0 0 setrgbcolor 3 index " - << _nodeBorderQuotient/(1+_nodeBorderQuotient) - << " 1.5 mul mul setlinewidth\n" - << " newpath 5 index 5 index moveto " - << "5 index 5 index 5 index 3.01 mul sub\n" - << " lineto 5 index 4 index .7 mul sub 5 index 5 index 2.2 mul sub" - << " moveto\n" - << " 5 index 4 index .7 mul add 5 index 5 index 2.2 mul sub lineto " - << "stroke\n" - << " 5 index 5 index 5 index c fill\n" - << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n" - << " } bind def\n"; - os << "/nmale {\n" - << " 0 0 0 setrgbcolor 3 index " - << _nodeBorderQuotient/(1+_nodeBorderQuotient) - <<" 1.5 mul mul setlinewidth\n" - << " newpath 5 index 5 index moveto\n" - << " 5 index 4 index 1 mul 1.5 mul add\n" - << " 5 index 5 index 3 sqrt 1.5 mul mul add\n" - << " 1 index 1 index lineto\n" - << " 1 index 1 index 7 index sub moveto\n" - << " 1 index 1 index lineto\n" - << " exch 5 index 3 sqrt .5 mul mul sub exch 5 index .5 mul sub" - << " lineto\n" - << " stroke\n" - << " 5 index 5 index 5 index c fill\n" - << " setrgbcolor " << 1+_nodeBorderQuotient << " div c fill\n" - << " } bind def\n"; - - - os << "/arrl " << _arrowLength << " def\n"; - os << "/arrw " << _arrowWidth << " def\n"; - // l dx_norm dy_norm - os << "/lrl { 2 index mul exch 2 index mul exch rlineto pop} bind def\n"; - //len w dx_norm dy_norm x1 y1 cr cg cb - os << "/arr { setrgbcolor /y1 exch def /x1 exch def /dy exch def /dx " - << "exch def\n" - << " /w exch def /len exch def\n" - //<< "0.1 setlinewidth x1 y1 moveto dx len mul dy len mul rlineto stroke" - << " newpath x1 dy w 2 div mul add y1 dx w 2 div mul sub moveto\n" - << " len w sub arrl sub dx dy lrl\n" - << " arrw dy dx neg lrl\n" - << " dx arrl w add mul dy w 2 div arrw add mul sub\n" - << " dy arrl w add mul dx w 2 div arrw add mul add rlineto\n" - << " dx arrl w add mul neg dy w 2 div arrw add mul sub\n" - << " dy arrl w add mul neg dx w 2 div arrw add mul add rlineto\n" - << " arrw dy dx neg lrl\n" - << " len w sub arrl sub neg dx dy lrl\n" - << " closepath fill } bind def\n"; - os << "/cshow { 2 index 2 index moveto dup stringwidth pop\n" - << " neg 2 div fosi .35 mul neg rmoveto show pop pop} def\n"; - - os << "\ngsave\n"; - if(_scaleToA4) - if(bb.height()>bb.width()) { - double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.height(), - (A4WIDTH-2*A4BORDER)/bb.width()); - os << ((A4WIDTH -2*A4BORDER)-sc*bb.width())/2 + A4BORDER << ' ' - << ((A4HEIGHT-2*A4BORDER)-sc*bb.height())/2 + A4BORDER - << " translate\n" - << sc << " dup scale\n" - << -bb.left() << ' ' << -bb.bottom() << " translate\n"; - } - else { - double sc= std::min((A4HEIGHT-2*A4BORDER)/bb.width(), - (A4WIDTH-2*A4BORDER)/bb.height()); - os << ((A4WIDTH -2*A4BORDER)-sc*bb.height())/2 + A4BORDER << ' ' - << ((A4HEIGHT-2*A4BORDER)-sc*bb.width())/2 + A4BORDER - << " translate\n" - << sc << " dup scale\n90 rotate\n" - << -bb.left() << ' ' << -bb.top() << " translate\n"; - } - else if(_scale!=1.0) os << _scale << " dup scale\n"; - - if(_showArcs) { - os << "%Arcs:\ngsave\n"; - if(_enableParallel) { - std::vector el; - for(ArcIt e(g);e!=INVALID;++e) - if((!_undirected||g.source(e)0 - &&g.source(e)!=g.target(e)) - el.push_back(e); - std::sort(el.begin(),el.end(),arcLess(g)); - - typename std::vector::iterator j; - for(typename std::vector::iterator i=el.begin();i!=el.end();i=j) { - for(j=i+1;j!=el.end()&&isParallel(*i,*j);++j) ; - - double sw=0; - for(typename std::vector::iterator e=i;e!=j;++e) - sw+=_arcWidths[*e]*_arcWidthScale+_parArcDist; - sw-=_parArcDist; - sw/=-2.0; - dim2::Point - dvec(mycoords[g.target(*i)]-mycoords[g.source(*i)]); - double l=std::sqrt(dvec.normSquare()); - dim2::Point d(dvec/std::max(l,EPSILON)); - dim2::Point m; -// m=dim2::Point(mycoords[g.target(*i)]+ -// mycoords[g.source(*i)])/2.0; - -// m=dim2::Point(mycoords[g.source(*i)])+ -// dvec*(double(_nodeSizes[g.source(*i)])/ -// (_nodeSizes[g.source(*i)]+_nodeSizes[g.target(*i)])); - - m=dim2::Point(mycoords[g.source(*i)])+ - d*(l+_nodeSizes[g.source(*i)]-_nodeSizes[g.target(*i)])/2.0; - - for(typename std::vector::iterator e=i;e!=j;++e) { - sw+=_arcWidths[*e]*_arcWidthScale/2.0; - dim2::Point mm=m+rot90(d)*sw/.75; - if(_drawArrows) { - int node_shape; - dim2::Point s=mycoords[g.source(*e)]; - dim2::Point t=mycoords[g.target(*e)]; - double rn=_nodeSizes[g.target(*e)]*_nodeScale; - node_shape=_nodeShapes[g.target(*e)]; - dim2::Bezier3 bez(s,mm,mm,t); - double t1=0,t2=1; - for(int ii=0;ii apoint=bez((t1+t2)/2); - rn = _arrowLength+_arcWidths[*e]*_arcWidthScale; - rn*=rn; - t2=(t1+t2)/2;t1=0; - for(int ii=0;iirn) t1=(t1+t2)/2; - else t2=(t1+t2)/2; - dim2::Point linend=bez((t1+t2)/2); - bez=bez.before((t1+t2)/2); -// rn=_nodeSizes[g.source(*e)]*_nodeScale; -// node_shape=_nodeShapes[g.source(*e)]; -// t1=0;t2=1; -// for(int i=0;i dd(rot90(linend-apoint)); - dd*=(.5*_arcWidths[*e]*_arcWidthScale+_arrowWidth)/ - std::sqrt(dd.normSquare()); - os << "newpath " << psOut(apoint) << " moveto " - << psOut(linend+dd) << " lineto " - << psOut(linend-dd) << " lineto closepath fill\n"; - } - else { - os << mycoords[g.source(*e)].x << ' ' - << mycoords[g.source(*e)].y << ' ' - << mm.x << ' ' << mm.y << ' ' - << mycoords[g.target(*e)].x << ' ' - << mycoords[g.target(*e)].y << ' ' - << _arcColors[*e].red() << ' ' - << _arcColors[*e].green() << ' ' - << _arcColors[*e].blue() << ' ' - << _arcWidths[*e]*_arcWidthScale << " lb\n"; - } - sw+=_arcWidths[*e]*_arcWidthScale/2.0+_parArcDist; - } - } - } - else for(ArcIt e(g);e!=INVALID;++e) - if((!_undirected||g.source(e)0 - &&g.source(e)!=g.target(e)) { - if(_drawArrows) { - dim2::Point d(mycoords[g.target(e)]-mycoords[g.source(e)]); - double rn=_nodeSizes[g.target(e)]*_nodeScale; - int node_shape=_nodeShapes[g.target(e)]; - double t1=0,t2=1; - for(int i=0;i GraphToEps > edgeWidths(const X &x) - { - return arcWidths(x); - } - - ///An alias for arcColors() - template GraphToEps > - edgeColors(const X &x) - { - return arcColors(x); - } - - ///An alias for arcWidthScale() - GraphToEps &edgeWidthScale(double d) {return arcWidthScale(d);} - - ///An alias for autoArcWidthScale() - GraphToEps &autoEdgeWidthScale(bool b=true) - { - return autoArcWidthScale(b); - } - - ///An alias for absoluteArcWidths() - GraphToEps &absoluteEdgeWidths(bool b=true) - { - return absoluteArcWidths(b); - } - - ///An alias for parArcDist() - GraphToEps &parEdgeDist(double d) {return parArcDist(d);} - - ///An alias for hideArcs() - GraphToEps &hideEdges(bool b=true) {return hideArcs(b);} - - ///@} -}; - -template -const int GraphToEps::INTERPOL_PREC = 20; -template -const double GraphToEps::A4HEIGHT = 841.8897637795276; -template -const double GraphToEps::A4WIDTH = 595.275590551181; -template -const double GraphToEps::A4BORDER = 15; - - -///Generates an EPS file from a graph - -///\ingroup eps_io -///Generates an EPS file from a graph. -///\param g Reference to the graph to be printed. -///\param os Reference to the output stream. -///By default, it is std::cout. -/// -///This function also has a lot of -///\ref named-templ-func-param "named parameters", -///they are declared as the members of class \ref GraphToEps. The following -///example shows how to use these parameters. -///\code -/// graphToEps(g,os).scale(10).coords(coords) -/// .nodeScale(2).nodeSizes(sizes) -/// .arcWidthScale(.4).run(); -///\endcode -/// -///For more detailed examples, see the \ref graph_to_eps_demo.cc demo file. -/// -///\warning Don't forget to put the \ref GraphToEps::run() "run()" -///to the end of the parameter list. -///\sa GraphToEps -///\sa graphToEps(GR &g, const char *file_name) -template -GraphToEps > -graphToEps(GR &g, std::ostream& os=std::cout) -{ - return - GraphToEps >(DefaultGraphToEpsTraits(g,os)); -} - -///Generates an EPS file from a graph - -///\ingroup eps_io -///This function does the same as -///\ref graphToEps(GR &g,std::ostream& os) -///but it writes its output into the file \c file_name -///instead of a stream. -///\sa graphToEps(GR &g, std::ostream& os) -template -GraphToEps > -graphToEps(GR &g,const char *file_name) -{ - std::ostream* os = new std::ofstream(file_name); - if (!(*os)) { - delete os; - throw IoError("Cannot write file", file_name); - } - return GraphToEps > - (DefaultGraphToEpsTraits(g,*os,true)); -} - -///Generates an EPS file from a graph - -///\ingroup eps_io -///This function does the same as -///\ref graphToEps(GR &g,std::ostream& os) -///but it writes its output into the file \c file_name -///instead of a stream. -///\sa graphToEps(GR &g, std::ostream& os) -template -GraphToEps > -graphToEps(GR &g,const std::string& file_name) -{ - std::ostream* os = new std::ofstream(file_name.c_str()); - if (!(*os)) { - delete os; - throw IoError("Cannot write file", file_name); - } - return GraphToEps > - (DefaultGraphToEpsTraits(g,*os,true)); -} - -} //END OF NAMESPACE LEMON - -#endif // LEMON_GRAPH_TO_EPS_H diff --git a/deps/lemon/lemon/greedy_tsp.h b/deps/lemon/lemon/greedy_tsp.h deleted file mode 100644 index 95461717a..000000000 --- a/deps/lemon/lemon/greedy_tsp.h +++ /dev/null @@ -1,251 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_GREEDY_TSP_H -#define LEMON_GREEDY_TSP_H - -/// \ingroup tsp -/// \file -/// \brief Greedy algorithm for symmetric TSP - -#include -#include -#include -#include - -namespace lemon { - - /// \ingroup tsp - /// - /// \brief Greedy algorithm for symmetric TSP. - /// - /// GreedyTsp implements the greedy heuristic for solving - /// symmetric \ref tsp "TSP". - /// - /// This algorithm is quite similar to the \ref NearestNeighborTsp - /// "nearest neighbor" heuristic, but it maintains a set of disjoint paths. - /// At each step, the shortest possible edge is added to these paths - /// as long as it does not create a cycle of less than n edges and it does - /// not increase the degree of any node above two. - /// - /// This method runs in O(n2) time. - /// It quickly finds a relatively short tour for most TSP instances, - /// but it could also yield a really bad (or even the worst) solution - /// in special cases. - /// - /// \tparam CM Type of the cost map. - template - class GreedyTsp - { - public: - - /// Type of the cost map - typedef CM CostMap; - /// Type of the edge costs - typedef typename CM::Value Cost; - - private: - - GRAPH_TYPEDEFS(FullGraph); - - const FullGraph &_gr; - const CostMap &_cost; - Cost _sum; - std::vector _path; - - private: - - // Functor class to compare edges by their costs - class EdgeComp { - private: - const CostMap &_cost; - - public: - EdgeComp(const CostMap &cost) : _cost(cost) {} - - bool operator()(const Edge &a, const Edge &b) const { - return _cost[a] < _cost[b]; - } - }; - - public: - - /// \brief Constructor - /// - /// Constructor. - /// \param gr The \ref FullGraph "full graph" the algorithm runs on. - /// \param cost The cost map. - GreedyTsp(const FullGraph &gr, const CostMap &cost) - : _gr(gr), _cost(cost) {} - - /// \name Execution Control - /// @{ - - /// \brief Runs the algorithm. - /// - /// This function runs the algorithm. - /// - /// \return The total cost of the found tour. - Cost run() { - _path.clear(); - - if (_gr.nodeNum() == 0) return _sum = 0; - else if (_gr.nodeNum() == 1) { - _path.push_back(_gr(0)); - return _sum = 0; - } - - std::vector plist; - plist.resize(_gr.nodeNum()*2, -1); - - std::vector sorted_edges; - sorted_edges.reserve(_gr.edgeNum()); - for (EdgeIt e(_gr); e != INVALID; ++e) - sorted_edges.push_back(e); - std::sort(sorted_edges.begin(), sorted_edges.end(), EdgeComp(_cost)); - - FullGraph::NodeMap item_int_map(_gr); - UnionFind > union_find(item_int_map); - for (NodeIt n(_gr); n != INVALID; ++n) - union_find.insert(n); - - FullGraph::NodeMap degree(_gr, 0); - - int nodesNum = 0, i = 0; - while (nodesNum != _gr.nodeNum()-1) { - Edge e = sorted_edges[i++]; - Node u = _gr.u(e), - v = _gr.v(e); - - if (degree[u] <= 1 && degree[v] <= 1) { - if (union_find.join(u, v)) { - const int uid = _gr.id(u), - vid = _gr.id(v); - - plist[uid*2 + degree[u]] = vid; - plist[vid*2 + degree[v]] = uid; - - ++degree[u]; - ++degree[v]; - ++nodesNum; - } - } - } - - for (int i=0, n=-1; i<_gr.nodeNum()*2; ++i) { - if (plist[i] == -1) { - if (n==-1) { - n = i; - } else { - plist[n] = i/2; - plist[i] = n/2; - break; - } - } - } - - for (int i=0, next=0, last=-1; i!=_gr.nodeNum(); ++i) { - _path.push_back(_gr.nodeFromId(next)); - if (plist[2*next] != last) { - last = next; - next = plist[2*next]; - } else { - last = next; - next = plist[2*next+1]; - } - } - - _sum = _cost[_gr.edge(_path.back(), _path.front())]; - for (int i = 0; i < int(_path.size())-1; ++i) { - _sum += _cost[_gr.edge(_path[i], _path[i+1])]; - } - - return _sum; - } - - /// @} - - /// \name Query Functions - /// @{ - - /// \brief The total cost of the found tour. - /// - /// This function returns the total cost of the found tour. - /// - /// \pre run() must be called before using this function. - Cost tourCost() const { - return _sum; - } - - /// \brief Returns a const reference to the node sequence of the - /// found tour. - /// - /// This function returns a const reference to a vector - /// that stores the node sequence of the found tour. - /// - /// \pre run() must be called before using this function. - const std::vector& tourNodes() const { - return _path; - } - - /// \brief Gives back the node sequence of the found tour. - /// - /// This function copies the node sequence of the found tour into - /// an STL container through the given output iterator. The - /// value_type of the container must be FullGraph::Node. - /// For example, - /// \code - /// std::vector nodes(countNodes(graph)); - /// tsp.tourNodes(nodes.begin()); - /// \endcode - /// or - /// \code - /// std::list nodes; - /// tsp.tourNodes(std::back_inserter(nodes)); - /// \endcode - /// - /// \pre run() must be called before using this function. - template - void tourNodes(Iterator out) const { - std::copy(_path.begin(), _path.end(), out); - } - - /// \brief Gives back the found tour as a path. - /// - /// This function copies the found tour as a list of arcs/edges into - /// the given \ref lemon::concepts::Path "path structure". - /// - /// \pre run() must be called before using this function. - template - void tour(Path &path) const { - path.clear(); - for (int i = 0; i < int(_path.size()) - 1; ++i) { - path.addBack(_gr.arc(_path[i], _path[i+1])); - } - if (int(_path.size()) >= 2) { - path.addBack(_gr.arc(_path.back(), _path.front())); - } - } - - /// @} - - }; - -}; // namespace lemon - -#endif diff --git a/deps/lemon/lemon/grid_graph.h b/deps/lemon/lemon/grid_graph.h deleted file mode 100644 index a3dff0f61..000000000 --- a/deps/lemon/lemon/grid_graph.h +++ /dev/null @@ -1,699 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef GRID_GRAPH_H -#define GRID_GRAPH_H - -#include -#include -#include -#include - -///\ingroup graphs -///\file -///\brief GridGraph class. - -namespace lemon { - - class GridGraphBase { - - public: - - typedef GridGraphBase Graph; - - class Node; - class Edge; - class Arc; - - public: - - GridGraphBase() {} - - protected: - - void construct(int width, int height) { - _width = width; _height = height; - _node_num = width * height; - _edge_num = 2 * _node_num - width - height; - _edge_limit = _node_num - _width; - } - - public: - - Node operator()(int i, int j) const { - LEMON_DEBUG(0 <= i && i < _width && - 0 <= j && j < _height, "Index out of range"); - return Node(i + j * _width); - } - - int col(Node n) const { - return n._id % _width; - } - - int row(Node n) const { - return n._id / _width; - } - - dim2::Point pos(Node n) const { - return dim2::Point(col(n), row(n)); - } - - int width() const { - return _width; - } - - int height() const { - return _height; - } - - typedef True NodeNumTag; - typedef True EdgeNumTag; - typedef True ArcNumTag; - - int nodeNum() const { return _node_num; } - int edgeNum() const { return _edge_num; } - int arcNum() const { return 2 * _edge_num; } - - Node u(Edge edge) const { - if (edge._id < _edge_limit) { - return edge._id; - } else { - return (edge._id - _edge_limit) % (_width - 1) + - (edge._id - _edge_limit) / (_width - 1) * _width; - } - } - - Node v(Edge edge) const { - if (edge._id < _edge_limit) { - return edge._id + _width; - } else { - return (edge._id - _edge_limit) % (_width - 1) + - (edge._id - _edge_limit) / (_width - 1) * _width + 1; - } - } - - Node source(Arc arc) const { - return (arc._id & 1) == 1 ? u(arc) : v(arc); - } - - Node target(Arc arc) const { - return (arc._id & 1) == 1 ? v(arc) : u(arc); - } - - static int id(Node node) { return node._id; } - static int id(Edge edge) { return edge._id; } - static int id(Arc arc) { return arc._id; } - - int maxNodeId() const { return _node_num - 1; } - int maxEdgeId() const { return _edge_num - 1; } - int maxArcId() const { return 2 * _edge_num - 1; } - - static Node nodeFromId(int id) { return Node(id);} - static Edge edgeFromId(int id) { return Edge(id);} - static Arc arcFromId(int id) { return Arc(id);} - - typedef True FindEdgeTag; - typedef True FindArcTag; - - Edge findEdge(Node u, Node v, Edge prev = INVALID) const { - if (prev != INVALID) return INVALID; - if (v._id > u._id) { - if (v._id - u._id == _width) - return Edge(u._id); - if (v._id - u._id == 1 && u._id % _width < _width - 1) { - return Edge(u._id / _width * (_width - 1) + - u._id % _width + _edge_limit); - } - } else { - if (u._id - v._id == _width) - return Edge(v._id); - if (u._id - v._id == 1 && v._id % _width < _width - 1) { - return Edge(v._id / _width * (_width - 1) + - v._id % _width + _edge_limit); - } - } - return INVALID; - } - - Arc findArc(Node u, Node v, Arc prev = INVALID) const { - if (prev != INVALID) return INVALID; - if (v._id > u._id) { - if (v._id - u._id == _width) - return Arc((u._id << 1) | 1); - if (v._id - u._id == 1 && u._id % _width < _width - 1) { - return Arc(((u._id / _width * (_width - 1) + - u._id % _width + _edge_limit) << 1) | 1); - } - } else { - if (u._id - v._id == _width) - return Arc(v._id << 1); - if (u._id - v._id == 1 && v._id % _width < _width - 1) { - return Arc((v._id / _width * (_width - 1) + - v._id % _width + _edge_limit) << 1); - } - } - return INVALID; - } - - class Node { - friend class GridGraphBase; - - protected: - int _id; - Node(int id) : _id(id) {} - public: - Node() {} - Node (Invalid) : _id(-1) {} - bool operator==(const Node node) const {return _id == node._id;} - bool operator!=(const Node node) const {return _id != node._id;} - bool operator<(const Node node) const {return _id < node._id;} - }; - - class Edge { - friend class GridGraphBase; - friend class Arc; - - protected: - int _id; - - Edge(int id) : _id(id) {} - - public: - Edge() {} - Edge (Invalid) : _id(-1) {} - bool operator==(const Edge edge) const {return _id == edge._id;} - bool operator!=(const Edge edge) const {return _id != edge._id;} - bool operator<(const Edge edge) const {return _id < edge._id;} - }; - - class Arc { - friend class GridGraphBase; - - protected: - int _id; - - Arc(int id) : _id(id) {} - - public: - Arc() {} - Arc (Invalid) : _id(-1) {} - operator Edge() const { return _id != -1 ? Edge(_id >> 1) : INVALID; } - bool operator==(const Arc arc) const {return _id == arc._id;} - bool operator!=(const Arc arc) const {return _id != arc._id;} - bool operator<(const Arc arc) const {return _id < arc._id;} - }; - - static bool direction(Arc arc) { - return (arc._id & 1) == 1; - } - - static Arc direct(Edge edge, bool dir) { - return Arc((edge._id << 1) | (dir ? 1 : 0)); - } - - void first(Node& node) const { - node._id = _node_num - 1; - } - - static void next(Node& node) { - --node._id; - } - - void first(Edge& edge) const { - edge._id = _edge_num - 1; - } - - static void next(Edge& edge) { - --edge._id; - } - - void first(Arc& arc) const { - arc._id = 2 * _edge_num - 1; - } - - static void next(Arc& arc) { - --arc._id; - } - - void firstOut(Arc& arc, const Node& node) const { - if (node._id % _width < _width - 1) { - arc._id = (_edge_limit + node._id % _width + - (node._id / _width) * (_width - 1)) << 1 | 1; - return; - } - if (node._id < _node_num - _width) { - arc._id = node._id << 1 | 1; - return; - } - if (node._id % _width > 0) { - arc._id = (_edge_limit + node._id % _width + - (node._id / _width) * (_width - 1) - 1) << 1; - return; - } - if (node._id >= _width) { - arc._id = (node._id - _width) << 1; - return; - } - arc._id = -1; - } - - void nextOut(Arc& arc) const { - int nid = arc._id >> 1; - if ((arc._id & 1) == 1) { - if (nid >= _edge_limit) { - nid = (nid - _edge_limit) % (_width - 1) + - (nid - _edge_limit) / (_width - 1) * _width; - if (nid < _node_num - _width) { - arc._id = nid << 1 | 1; - return; - } - } - if (nid % _width > 0) { - arc._id = (_edge_limit + nid % _width + - (nid / _width) * (_width - 1) - 1) << 1; - return; - } - if (nid >= _width) { - arc._id = (nid - _width) << 1; - return; - } - } else { - if (nid >= _edge_limit) { - nid = (nid - _edge_limit) % (_width - 1) + - (nid - _edge_limit) / (_width - 1) * _width + 1; - if (nid >= _width) { - arc._id = (nid - _width) << 1; - return; - } - } - } - arc._id = -1; - } - - void firstIn(Arc& arc, const Node& node) const { - if (node._id % _width < _width - 1) { - arc._id = (_edge_limit + node._id % _width + - (node._id / _width) * (_width - 1)) << 1; - return; - } - if (node._id < _node_num - _width) { - arc._id = node._id << 1; - return; - } - if (node._id % _width > 0) { - arc._id = (_edge_limit + node._id % _width + - (node._id / _width) * (_width - 1) - 1) << 1 | 1; - return; - } - if (node._id >= _width) { - arc._id = (node._id - _width) << 1 | 1; - return; - } - arc._id = -1; - } - - void nextIn(Arc& arc) const { - int nid = arc._id >> 1; - if ((arc._id & 1) == 0) { - if (nid >= _edge_limit) { - nid = (nid - _edge_limit) % (_width - 1) + - (nid - _edge_limit) / (_width - 1) * _width; - if (nid < _node_num - _width) { - arc._id = nid << 1; - return; - } - } - if (nid % _width > 0) { - arc._id = (_edge_limit + nid % _width + - (nid / _width) * (_width - 1) - 1) << 1 | 1; - return; - } - if (nid >= _width) { - arc._id = (nid - _width) << 1 | 1; - return; - } - } else { - if (nid >= _edge_limit) { - nid = (nid - _edge_limit) % (_width - 1) + - (nid - _edge_limit) / (_width - 1) * _width + 1; - if (nid >= _width) { - arc._id = (nid - _width) << 1 | 1; - return; - } - } - } - arc._id = -1; - } - - void firstInc(Edge& edge, bool& dir, const Node& node) const { - if (node._id % _width < _width - 1) { - edge._id = _edge_limit + node._id % _width + - (node._id / _width) * (_width - 1); - dir = true; - return; - } - if (node._id < _node_num - _width) { - edge._id = node._id; - dir = true; - return; - } - if (node._id % _width > 0) { - edge._id = _edge_limit + node._id % _width + - (node._id / _width) * (_width - 1) - 1; - dir = false; - return; - } - if (node._id >= _width) { - edge._id = node._id - _width; - dir = false; - return; - } - edge._id = -1; - dir = true; - } - - void nextInc(Edge& edge, bool& dir) const { - int nid = edge._id; - if (dir) { - if (nid >= _edge_limit) { - nid = (nid - _edge_limit) % (_width - 1) + - (nid - _edge_limit) / (_width - 1) * _width; - if (nid < _node_num - _width) { - edge._id = nid; - return; - } - } - if (nid % _width > 0) { - edge._id = _edge_limit + nid % _width + - (nid / _width) * (_width - 1) - 1; - dir = false; - return; - } - if (nid >= _width) { - edge._id = nid - _width; - dir = false; - return; - } - } else { - if (nid >= _edge_limit) { - nid = (nid - _edge_limit) % (_width - 1) + - (nid - _edge_limit) / (_width - 1) * _width + 1; - if (nid >= _width) { - edge._id = nid - _width; - return; - } - } - } - edge._id = -1; - dir = true; - } - - Arc right(Node n) const { - if (n._id % _width < _width - 1) { - return Arc(((_edge_limit + n._id % _width + - (n._id / _width) * (_width - 1)) << 1) | 1); - } else { - return INVALID; - } - } - - Arc left(Node n) const { - if (n._id % _width > 0) { - return Arc((_edge_limit + n._id % _width + - (n._id / _width) * (_width - 1) - 1) << 1); - } else { - return INVALID; - } - } - - Arc up(Node n) const { - if (n._id < _edge_limit) { - return Arc((n._id << 1) | 1); - } else { - return INVALID; - } - } - - Arc down(Node n) const { - if (n._id >= _width) { - return Arc((n._id - _width) << 1); - } else { - return INVALID; - } - } - - private: - int _width, _height; - int _node_num, _edge_num; - int _edge_limit; - }; - - - typedef GraphExtender ExtendedGridGraphBase; - - /// \ingroup graphs - /// - /// \brief Grid graph class - /// - /// GridGraph implements a special graph type. The nodes of the - /// graph can be indexed by two integer values \c (i,j) where \c i is - /// in the range [0..width()-1] and j is in the range - /// [0..height()-1]. Two nodes are connected in the graph if - /// the indices differ exactly on one position and the difference is - /// also exactly one. The nodes of the graph can be obtained by position - /// using the \c operator()() function and the indices of the nodes can - /// be obtained using \c pos(), \c col() and \c row() members. The outgoing - /// arcs can be retrieved with the \c right(), \c up(), \c left() - /// and \c down() functions, where the bottom-left corner is the - /// origin. - /// - /// This class is completely static and it needs constant memory space. - /// Thus you can neither add nor delete nodes or edges, however - /// the structure can be resized using resize(). - /// - /// \image html grid_graph.png - /// \image latex grid_graph.eps "Grid graph" width=\textwidth - /// - /// A short example about the basic usage: - ///\code - /// GridGraph graph(rows, cols); - /// GridGraph::NodeMap val(graph); - /// for (int i = 0; i < graph.width(); ++i) { - /// for (int j = 0; j < graph.height(); ++j) { - /// val[graph(i, j)] = i + j; - /// } - /// } - ///\endcode - /// - /// This type fully conforms to the \ref concepts::Graph "Graph concept". - /// Most of its member functions and nested classes are documented - /// only in the concept class. - /// - /// This class provides constant time counting for nodes, edges and arcs. - class GridGraph : public ExtendedGridGraphBase { - typedef ExtendedGridGraphBase Parent; - - public: - - /// \brief Map to get the indices of the nodes as \ref dim2::Point - /// "dim2::Point". - /// - /// Map to get the indices of the nodes as \ref dim2::Point - /// "dim2::Point". - class IndexMap { - public: - /// \brief The key type of the map - typedef GridGraph::Node Key; - /// \brief The value type of the map - typedef dim2::Point Value; - - /// \brief Constructor - IndexMap(const GridGraph& graph) : _graph(graph) {} - - /// \brief The subscript operator - Value operator[](Key key) const { - return _graph.pos(key); - } - - private: - const GridGraph& _graph; - }; - - /// \brief Map to get the column of the nodes. - /// - /// Map to get the column of the nodes. - class ColMap { - public: - /// \brief The key type of the map - typedef GridGraph::Node Key; - /// \brief The value type of the map - typedef int Value; - - /// \brief Constructor - ColMap(const GridGraph& graph) : _graph(graph) {} - - /// \brief The subscript operator - Value operator[](Key key) const { - return _graph.col(key); - } - - private: - const GridGraph& _graph; - }; - - /// \brief Map to get the row of the nodes. - /// - /// Map to get the row of the nodes. - class RowMap { - public: - /// \brief The key type of the map - typedef GridGraph::Node Key; - /// \brief The value type of the map - typedef int Value; - - /// \brief Constructor - RowMap(const GridGraph& graph) : _graph(graph) {} - - /// \brief The subscript operator - Value operator[](Key key) const { - return _graph.row(key); - } - - private: - const GridGraph& _graph; - }; - - /// \brief Constructor - /// - /// Construct a grid graph with the given size. - GridGraph(int width, int height) { construct(width, height); } - - /// \brief Resizes the graph - /// - /// This function resizes the graph. It fully destroys and - /// rebuilds the structure, therefore the maps of the graph will be - /// reallocated automatically and the previous values will be lost. - void resize(int width, int height) { - Parent::notifier(Arc()).clear(); - Parent::notifier(Edge()).clear(); - Parent::notifier(Node()).clear(); - construct(width, height); - Parent::notifier(Node()).build(); - Parent::notifier(Edge()).build(); - Parent::notifier(Arc()).build(); - } - - /// \brief The node on the given position. - /// - /// Gives back the node on the given position. - Node operator()(int i, int j) const { - return Parent::operator()(i, j); - } - - /// \brief The column index of the node. - /// - /// Gives back the column index of the node. - int col(Node n) const { - return Parent::col(n); - } - - /// \brief The row index of the node. - /// - /// Gives back the row index of the node. - int row(Node n) const { - return Parent::row(n); - } - - /// \brief The position of the node. - /// - /// Gives back the position of the node, ie. the (col,row) pair. - dim2::Point pos(Node n) const { - return Parent::pos(n); - } - - /// \brief The number of the columns. - /// - /// Gives back the number of the columns. - int width() const { - return Parent::width(); - } - - /// \brief The number of the rows. - /// - /// Gives back the number of the rows. - int height() const { - return Parent::height(); - } - - /// \brief The arc goes right from the node. - /// - /// Gives back the arc goes right from the node. If there is not - /// outgoing arc then it gives back INVALID. - Arc right(Node n) const { - return Parent::right(n); - } - - /// \brief The arc goes left from the node. - /// - /// Gives back the arc goes left from the node. If there is not - /// outgoing arc then it gives back INVALID. - Arc left(Node n) const { - return Parent::left(n); - } - - /// \brief The arc goes up from the node. - /// - /// Gives back the arc goes up from the node. If there is not - /// outgoing arc then it gives back INVALID. - Arc up(Node n) const { - return Parent::up(n); - } - - /// \brief The arc goes down from the node. - /// - /// Gives back the arc goes down from the node. If there is not - /// outgoing arc then it gives back INVALID. - Arc down(Node n) const { - return Parent::down(n); - } - - /// \brief Index map of the grid graph - /// - /// Just returns an IndexMap for the grid graph. - IndexMap indexMap() const { - return IndexMap(*this); - } - - /// \brief Row map of the grid graph - /// - /// Just returns a RowMap for the grid graph. - RowMap rowMap() const { - return RowMap(*this); - } - - /// \brief Column map of the grid graph - /// - /// Just returns a ColMap for the grid graph. - ColMap colMap() const { - return ColMap(*this); - } - - }; - -} -#endif diff --git a/deps/lemon/lemon/grosso_locatelli_pullan_mc.h b/deps/lemon/lemon/grosso_locatelli_pullan_mc.h deleted file mode 100644 index 669e1fa32..000000000 --- a/deps/lemon/lemon/grosso_locatelli_pullan_mc.h +++ /dev/null @@ -1,840 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_GROSSO_LOCATELLI_PULLAN_MC_H -#define LEMON_GROSSO_LOCATELLI_PULLAN_MC_H - -/// \ingroup approx_algs -/// -/// \file -/// \brief The iterated local search algorithm of Grosso, Locatelli, and Pullan -/// for the maximum clique problem - -#include -#include -#include -#include - -namespace lemon { - - /// \addtogroup approx_algs - /// @{ - - /// \brief Implementation of the iterated local search algorithm of Grosso, - /// Locatelli, and Pullan for the maximum clique problem - /// - /// \ref GrossoLocatelliPullanMc implements the iterated local search - /// algorithm of Grosso, Locatelli, and Pullan for solving the \e maximum - /// \e clique \e problem \cite grosso08maxclique. - /// It is to find the largest complete subgraph (\e clique) in an - /// undirected graph, i.e., the largest set of nodes where each - /// pair of nodes is connected. - /// - /// This class provides a simple but highly efficient and robust heuristic - /// method that quickly finds a quite large clique, but not necessarily the - /// largest one. - /// The algorithm performs a certain number of iterations to find several - /// cliques and selects the largest one among them. Various limits can be - /// specified to control the running time and the effectiveness of the - /// search process. - /// - /// \tparam GR The undirected graph type the algorithm runs on. - /// - /// \note %GrossoLocatelliPullanMc provides three different node selection - /// rules, from which the most powerful one is used by default. - /// For more information, see \ref SelectionRule. - template - class GrossoLocatelliPullanMc - { - public: - - /// \brief Constants for specifying the node selection rule. - /// - /// Enum type containing constants for specifying the node selection rule - /// for the \ref run() function. - /// - /// During the algorithm, nodes are selected for addition to the current - /// clique according to the applied rule. - /// In general, the PENALTY_BASED rule turned out to be the most powerful - /// and the most robust, thus it is the default option. - /// However, another selection rule can be specified using the \ref run() - /// function with the proper parameter. - enum SelectionRule { - - /// A node is selected randomly without any evaluation at each step. - RANDOM, - - /// A node of maximum degree is selected randomly at each step. - DEGREE_BASED, - - /// A node of minimum penalty is selected randomly at each step. - /// The node penalties are updated adaptively after each stage of the - /// search process. - PENALTY_BASED - }; - - /// \brief Constants for the causes of search termination. - /// - /// Enum type containing constants for the different causes of search - /// termination. The \ref run() function returns one of these values. - enum TerminationCause { - - /// The iteration count limit is reached. - ITERATION_LIMIT, - - /// The step count limit is reached. - STEP_LIMIT, - - /// The clique size limit is reached. - SIZE_LIMIT - }; - - private: - - TEMPLATE_GRAPH_TYPEDEFS(GR); - - typedef std::vector IntVector; - typedef std::vector BoolVector; - typedef std::vector BoolMatrix; - // Note: vector is used instead of vector for efficiency reasons - - // The underlying graph - const GR &_graph; - IntNodeMap _id; - - // Internal matrix representation of the graph - BoolMatrix _gr; - int _n; - - // Search options - bool _delta_based_restart; - int _restart_delta_limit; - - // Search limits - int _iteration_limit; - int _step_limit; - int _size_limit; - - // The current clique - BoolVector _clique; - int _size; - - // The best clique found so far - BoolVector _best_clique; - int _best_size; - - // The "distances" of the nodes from the current clique. - // _delta[u] is the number of nodes in the clique that are - // not connected with u. - IntVector _delta; - - // The current tabu set - BoolVector _tabu; - - // Random number generator - Random _rnd; - - private: - - // Implementation of the RANDOM node selection rule. - class RandomSelectionRule - { - private: - - // References to the algorithm instance - const BoolVector &_clique; - const IntVector &_delta; - const BoolVector &_tabu; - Random &_rnd; - - // Pivot rule data - int _n; - - public: - - // Constructor - RandomSelectionRule(GrossoLocatelliPullanMc &mc) : - _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu), - _rnd(mc._rnd), _n(mc._n) - {} - - // Return a node index for a feasible add move or -1 if no one exists - int nextFeasibleAddNode() const { - int start_node = _rnd[_n]; - for (int i = start_node; i != _n; i++) { - if (_delta[i] == 0 && !_tabu[i]) return i; - } - for (int i = 0; i != start_node; i++) { - if (_delta[i] == 0 && !_tabu[i]) return i; - } - return -1; - } - - // Return a node index for a feasible swap move or -1 if no one exists - int nextFeasibleSwapNode() const { - int start_node = _rnd[_n]; - for (int i = start_node; i != _n; i++) { - if (!_clique[i] && _delta[i] == 1 && !_tabu[i]) return i; - } - for (int i = 0; i != start_node; i++) { - if (!_clique[i] && _delta[i] == 1 && !_tabu[i]) return i; - } - return -1; - } - - // Return a node index for an add move or -1 if no one exists - int nextAddNode() const { - int start_node = _rnd[_n]; - for (int i = start_node; i != _n; i++) { - if (_delta[i] == 0) return i; - } - for (int i = 0; i != start_node; i++) { - if (_delta[i] == 0) return i; - } - return -1; - } - - // Update internal data structures between stages (if necessary) - void update() {} - - }; //class RandomSelectionRule - - - // Implementation of the DEGREE_BASED node selection rule. - class DegreeBasedSelectionRule - { - private: - - // References to the algorithm instance - const BoolVector &_clique; - const IntVector &_delta; - const BoolVector &_tabu; - Random &_rnd; - - // Pivot rule data - int _n; - IntVector _deg; - - public: - - // Constructor - DegreeBasedSelectionRule(GrossoLocatelliPullanMc &mc) : - _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu), - _rnd(mc._rnd), _n(mc._n), _deg(_n) - { - for (int i = 0; i != _n; i++) { - int d = 0; - BoolVector &row = mc._gr[i]; - for (int j = 0; j != _n; j++) { - if (row[j]) d++; - } - _deg[i] = d; - } - } - - // Return a node index for a feasible add move or -1 if no one exists - int nextFeasibleAddNode() const { - int start_node = _rnd[_n]; - int node = -1, max_deg = -1; - for (int i = start_node; i != _n; i++) { - if (_delta[i] == 0 && !_tabu[i] && _deg[i] > max_deg) { - node = i; - max_deg = _deg[i]; - } - } - for (int i = 0; i != start_node; i++) { - if (_delta[i] == 0 && !_tabu[i] && _deg[i] > max_deg) { - node = i; - max_deg = _deg[i]; - } - } - return node; - } - - // Return a node index for a feasible swap move or -1 if no one exists - int nextFeasibleSwapNode() const { - int start_node = _rnd[_n]; - int node = -1, max_deg = -1; - for (int i = start_node; i != _n; i++) { - if (!_clique[i] && _delta[i] == 1 && !_tabu[i] && - _deg[i] > max_deg) { - node = i; - max_deg = _deg[i]; - } - } - for (int i = 0; i != start_node; i++) { - if (!_clique[i] && _delta[i] == 1 && !_tabu[i] && - _deg[i] > max_deg) { - node = i; - max_deg = _deg[i]; - } - } - return node; - } - - // Return a node index for an add move or -1 if no one exists - int nextAddNode() const { - int start_node = _rnd[_n]; - int node = -1, max_deg = -1; - for (int i = start_node; i != _n; i++) { - if (_delta[i] == 0 && _deg[i] > max_deg) { - node = i; - max_deg = _deg[i]; - } - } - for (int i = 0; i != start_node; i++) { - if (_delta[i] == 0 && _deg[i] > max_deg) { - node = i; - max_deg = _deg[i]; - } - } - return node; - } - - // Update internal data structures between stages (if necessary) - void update() {} - - }; //class DegreeBasedSelectionRule - - - // Implementation of the PENALTY_BASED node selection rule. - class PenaltyBasedSelectionRule - { - private: - - // References to the algorithm instance - const BoolVector &_clique; - const IntVector &_delta; - const BoolVector &_tabu; - Random &_rnd; - - // Pivot rule data - int _n; - IntVector _penalty; - - public: - - // Constructor - PenaltyBasedSelectionRule(GrossoLocatelliPullanMc &mc) : - _clique(mc._clique), _delta(mc._delta), _tabu(mc._tabu), - _rnd(mc._rnd), _n(mc._n), _penalty(_n, 0) - {} - - // Return a node index for a feasible add move or -1 if no one exists - int nextFeasibleAddNode() const { - int start_node = _rnd[_n]; - int node = -1, min_p = std::numeric_limits::max(); - for (int i = start_node; i != _n; i++) { - if (_delta[i] == 0 && !_tabu[i] && _penalty[i] < min_p) { - node = i; - min_p = _penalty[i]; - } - } - for (int i = 0; i != start_node; i++) { - if (_delta[i] == 0 && !_tabu[i] && _penalty[i] < min_p) { - node = i; - min_p = _penalty[i]; - } - } - return node; - } - - // Return a node index for a feasible swap move or -1 if no one exists - int nextFeasibleSwapNode() const { - int start_node = _rnd[_n]; - int node = -1, min_p = std::numeric_limits::max(); - for (int i = start_node; i != _n; i++) { - if (!_clique[i] && _delta[i] == 1 && !_tabu[i] && - _penalty[i] < min_p) { - node = i; - min_p = _penalty[i]; - } - } - for (int i = 0; i != start_node; i++) { - if (!_clique[i] && _delta[i] == 1 && !_tabu[i] && - _penalty[i] < min_p) { - node = i; - min_p = _penalty[i]; - } - } - return node; - } - - // Return a node index for an add move or -1 if no one exists - int nextAddNode() const { - int start_node = _rnd[_n]; - int node = -1, min_p = std::numeric_limits::max(); - for (int i = start_node; i != _n; i++) { - if (_delta[i] == 0 && _penalty[i] < min_p) { - node = i; - min_p = _penalty[i]; - } - } - for (int i = 0; i != start_node; i++) { - if (_delta[i] == 0 && _penalty[i] < min_p) { - node = i; - min_p = _penalty[i]; - } - } - return node; - } - - // Update internal data structures between stages (if necessary) - void update() {} - - }; //class PenaltyBasedSelectionRule - - public: - - /// \brief Constructor. - /// - /// Constructor. - /// The global \ref rnd "random number generator instance" is used - /// during the algorithm. - /// - /// \param graph The undirected graph the algorithm runs on. - GrossoLocatelliPullanMc(const GR& graph) : - _graph(graph), _id(_graph), _rnd(rnd) - { - initOptions(); - } - - /// \brief Constructor with random seed. - /// - /// Constructor with random seed. - /// - /// \param graph The undirected graph the algorithm runs on. - /// \param seed Seed value for the internal random number generator - /// that is used during the algorithm. - GrossoLocatelliPullanMc(const GR& graph, int seed) : - _graph(graph), _id(_graph), _rnd(seed) - { - initOptions(); - } - - /// \brief Constructor with random number generator. - /// - /// Constructor with random number generator. - /// - /// \param graph The undirected graph the algorithm runs on. - /// \param random A random number generator that is used during the - /// algorithm. - GrossoLocatelliPullanMc(const GR& graph, const Random& random) : - _graph(graph), _id(_graph), _rnd(random) - { - initOptions(); - } - - /// \name Execution Control - /// The \ref run() function can be used to execute the algorithm.\n - /// The functions \ref iterationLimit(int), \ref stepLimit(int), and - /// \ref sizeLimit(int) can be used to specify various limits for the - /// search process. - - /// @{ - - /// \brief Sets the maximum number of iterations. - /// - /// This function sets the maximum number of iterations. - /// Each iteration of the algorithm finds a maximal clique (but not - /// necessarily the largest one) by performing several search steps - /// (node selections). - /// - /// This limit controls the running time and the success of the - /// algorithm. For larger values, the algorithm runs slower, but it more - /// likely finds larger cliques. For smaller values, the algorithm is - /// faster but probably gives worse results. - /// - /// The default value is \c 1000. - /// \c -1 means that number of iterations is not limited. - /// - /// \warning You should specify a reasonable limit for the number of - /// iterations and/or the number of search steps. - /// - /// \return (*this) - /// - /// \sa stepLimit(int) - /// \sa sizeLimit(int) - GrossoLocatelliPullanMc& iterationLimit(int limit) { - _iteration_limit = limit; - return *this; - } - - /// \brief Sets the maximum number of search steps. - /// - /// This function sets the maximum number of elementary search steps. - /// Each iteration of the algorithm finds a maximal clique (but not - /// necessarily the largest one) by performing several search steps - /// (node selections). - /// - /// This limit controls the running time and the success of the - /// algorithm. For larger values, the algorithm runs slower, but it more - /// likely finds larger cliques. For smaller values, the algorithm is - /// faster but probably gives worse results. - /// - /// The default value is \c -1, which means that number of steps - /// is not limited explicitly. However, the number of iterations is - /// limited and each iteration performs a finite number of search steps. - /// - /// \warning You should specify a reasonable limit for the number of - /// iterations and/or the number of search steps. - /// - /// \return (*this) - /// - /// \sa iterationLimit(int) - /// \sa sizeLimit(int) - GrossoLocatelliPullanMc& stepLimit(int limit) { - _step_limit = limit; - return *this; - } - - /// \brief Sets the desired clique size. - /// - /// This function sets the desired clique size that serves as a search - /// limit. If a clique of this size (or a larger one) is found, then the - /// algorithm terminates. - /// - /// This function is especially useful if you know an exact upper bound - /// for the size of the cliques in the graph or if any clique above - /// a certain size limit is sufficient for your application. - /// - /// The default value is \c -1, which means that the size limit is set to - /// the number of nodes in the graph. - /// - /// \return (*this) - /// - /// \sa iterationLimit(int) - /// \sa stepLimit(int) - GrossoLocatelliPullanMc& sizeLimit(int limit) { - _size_limit = limit; - return *this; - } - - /// \brief The maximum number of iterations. - /// - /// This function gives back the maximum number of iterations. - /// \c -1 means that no limit is specified. - /// - /// \sa iterationLimit(int) - int iterationLimit() const { - return _iteration_limit; - } - - /// \brief The maximum number of search steps. - /// - /// This function gives back the maximum number of search steps. - /// \c -1 means that no limit is specified. - /// - /// \sa stepLimit(int) - int stepLimit() const { - return _step_limit; - } - - /// \brief The desired clique size. - /// - /// This function gives back the desired clique size that serves as a - /// search limit. \c -1 means that this limit is set to the number of - /// nodes in the graph. - /// - /// \sa sizeLimit(int) - int sizeLimit() const { - return _size_limit; - } - - /// \brief Runs the algorithm. - /// - /// This function runs the algorithm. If one of the specified limits - /// is reached, the search process terminates. - /// - /// \param rule The node selection rule. For more information, see - /// \ref SelectionRule. - /// - /// \return The termination cause of the search. For more information, - /// see \ref TerminationCause. - TerminationCause run(SelectionRule rule = PENALTY_BASED) - { - init(); - switch (rule) { - case RANDOM: - return start(); - case DEGREE_BASED: - return start(); - default: - return start(); - } - } - - /// @} - - /// \name Query Functions - /// The results of the algorithm can be obtained using these functions.\n - /// The run() function must be called before using them. - - /// @{ - - /// \brief The size of the found clique - /// - /// This function returns the size of the found clique. - /// - /// \pre run() must be called before using this function. - int cliqueSize() const { - return _best_size; - } - - /// \brief Gives back the found clique in a \c bool node map - /// - /// This function gives back the characteristic vector of the found - /// clique in the given node map. - /// It must be a \ref concepts::WriteMap "writable" node map with - /// \c bool (or convertible) value type. - /// - /// \pre run() must be called before using this function. - template - void cliqueMap(CliqueMap &map) const { - for (NodeIt n(_graph); n != INVALID; ++n) { - map[n] = static_cast(_best_clique[_id[n]]); - } - } - - /// \brief Iterator to list the nodes of the found clique - /// - /// This iterator class lists the nodes of the found clique. - /// Before using it, you must allocate a GrossoLocatelliPullanMc instance - /// and call its \ref GrossoLocatelliPullanMc::run() "run()" method. - /// - /// The following example prints out the IDs of the nodes in the found - /// clique. - /// \code - /// GrossoLocatelliPullanMc mc(g); - /// mc.run(); - /// for (GrossoLocatelliPullanMc::CliqueNodeIt n(mc); - /// n != INVALID; ++n) - /// { - /// std::cout << g.id(n) << std::endl; - /// } - /// \endcode - class CliqueNodeIt - { - private: - NodeIt _it; - BoolNodeMap _map; - - public: - - /// Constructor - - /// Constructor. - /// \param mc The algorithm instance. - CliqueNodeIt(const GrossoLocatelliPullanMc &mc) - : _map(mc._graph) - { - mc.cliqueMap(_map); - for (_it = NodeIt(mc._graph); _it != INVALID && !_map[_it]; ++_it) ; - } - - /// Conversion to \c Node - operator Node() const { return _it; } - - bool operator==(Invalid) const { return _it == INVALID; } - bool operator!=(Invalid) const { return _it != INVALID; } - - /// Next node - CliqueNodeIt &operator++() { - for (++_it; _it != INVALID && !_map[_it]; ++_it) ; - return *this; - } - - /// Postfix incrementation - - /// Postfix incrementation. - /// - /// \warning This incrementation returns a \c Node, not a - /// \c CliqueNodeIt as one may expect. - typename GR::Node operator++(int) { - Node n=*this; - ++(*this); - return n; - } - - }; - - /// @} - - private: - - // Initialize search options and limits - void initOptions() { - // Search options - _delta_based_restart = true; - _restart_delta_limit = 4; - - // Search limits - _iteration_limit = 1000; - _step_limit = -1; // this is disabled by default - _size_limit = -1; // this is disabled by default - } - - // Adds a node to the current clique - void addCliqueNode(int u) { - if (_clique[u]) return; - _clique[u] = true; - _size++; - BoolVector &row = _gr[u]; - for (int i = 0; i != _n; i++) { - if (!row[i]) _delta[i]++; - } - } - - // Removes a node from the current clique - void delCliqueNode(int u) { - if (!_clique[u]) return; - _clique[u] = false; - _size--; - BoolVector &row = _gr[u]; - for (int i = 0; i != _n; i++) { - if (!row[i]) _delta[i]--; - } - } - - // Initialize data structures - void init() { - _n = countNodes(_graph); - int ui = 0; - for (NodeIt u(_graph); u != INVALID; ++u) { - _id[u] = ui++; - } - _gr.clear(); - _gr.resize(_n, BoolVector(_n, false)); - ui = 0; - for (NodeIt u(_graph); u != INVALID; ++u) { - for (IncEdgeIt e(_graph, u); e != INVALID; ++e) { - int vi = _id[_graph.runningNode(e)]; - _gr[ui][vi] = true; - _gr[vi][ui] = true; - } - ++ui; - } - - _clique.clear(); - _clique.resize(_n, false); - _size = 0; - _best_clique.clear(); - _best_clique.resize(_n, false); - _best_size = 0; - _delta.clear(); - _delta.resize(_n, 0); - _tabu.clear(); - _tabu.resize(_n, false); - } - - // Executes the algorithm - template - TerminationCause start() { - if (_n == 0) return SIZE_LIMIT; - if (_n == 1) { - _best_clique[0] = true; - _best_size = 1; - return SIZE_LIMIT; - } - - // Iterated local search algorithm - const int max_size = _size_limit >= 0 ? _size_limit : _n; - const int max_restart = _iteration_limit >= 0 ? - _iteration_limit : std::numeric_limits::max(); - const int max_select = _step_limit >= 0 ? - _step_limit : std::numeric_limits::max(); - - SelectionRuleImpl sel_method(*this); - int select = 0, restart = 0; - IntVector restart_nodes; - while (select < max_select && restart < max_restart) { - - // Perturbation/restart - restart++; - if (_delta_based_restart) { - restart_nodes.clear(); - for (int i = 0; i != _n; i++) { - if (_delta[i] >= _restart_delta_limit) - restart_nodes.push_back(i); - } - } - int rs_node = -1; - if (restart_nodes.size() > 0) { - rs_node = restart_nodes[_rnd[restart_nodes.size()]]; - } else { - rs_node = _rnd[_n]; - } - BoolVector &row = _gr[rs_node]; - for (int i = 0; i != _n; i++) { - if (_clique[i] && !row[i]) delCliqueNode(i); - } - addCliqueNode(rs_node); - - // Local search - _tabu.clear(); - _tabu.resize(_n, false); - bool tabu_empty = true; - int max_swap = _size; - while (select < max_select) { - select++; - int u; - if ((u = sel_method.nextFeasibleAddNode()) != -1) { - // Feasible add move - addCliqueNode(u); - if (tabu_empty) max_swap = _size; - } - else if ((u = sel_method.nextFeasibleSwapNode()) != -1) { - // Feasible swap move - int v = -1; - BoolVector &row = _gr[u]; - for (int i = 0; i != _n; i++) { - if (_clique[i] && !row[i]) { - v = i; - break; - } - } - addCliqueNode(u); - delCliqueNode(v); - _tabu[v] = true; - tabu_empty = false; - if (--max_swap <= 0) break; - } - else if ((u = sel_method.nextAddNode()) != -1) { - // Non-feasible add move - addCliqueNode(u); - } - else break; - } - if (_size > _best_size) { - _best_clique = _clique; - _best_size = _size; - if (_best_size >= max_size) return SIZE_LIMIT; - } - sel_method.update(); - } - - return (restart >= max_restart ? ITERATION_LIMIT : STEP_LIMIT); - } - - }; //class GrossoLocatelliPullanMc - - ///@} - -} //namespace lemon - -#endif //LEMON_GROSSO_LOCATELLI_PULLAN_MC_H diff --git a/deps/lemon/lemon/hao_orlin.h b/deps/lemon/lemon/hao_orlin.h deleted file mode 100644 index 0eeaff95d..000000000 --- a/deps/lemon/lemon/hao_orlin.h +++ /dev/null @@ -1,1015 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_HAO_ORLIN_H -#define LEMON_HAO_ORLIN_H - -#include -#include -#include - -#include -#include -#include - -/// \file -/// \ingroup min_cut -/// \brief Implementation of the Hao-Orlin algorithm. -/// -/// Implementation of the Hao-Orlin algorithm for finding a minimum cut -/// in a digraph. - -namespace lemon { - - /// \ingroup min_cut - /// - /// \brief Hao-Orlin algorithm for finding a minimum cut in a digraph. - /// - /// This class implements the Hao-Orlin algorithm for finding a minimum - /// value cut in a directed graph \f$D=(V,A)\f$. - /// It takes a fixed node \f$ source \in V \f$ and - /// consists of two phases: in the first phase it determines a - /// minimum cut with \f$ source \f$ on the source-side (i.e. a set - /// \f$ X\subsetneq V \f$ with \f$ source \in X \f$ and minimal outgoing - /// capacity) and in the second phase it determines a minimum cut - /// with \f$ source \f$ on the sink-side (i.e. a set - /// \f$ X\subsetneq V \f$ with \f$ source \notin X \f$ and minimal outgoing - /// capacity). Obviously, the smaller of these two cuts will be a - /// minimum cut of \f$ D \f$. The algorithm is a modified - /// preflow push-relabel algorithm. Our implementation calculates - /// the minimum cut in \f$ O(n^2\sqrt{m}) \f$ time (we use the - /// highest-label rule), or in \f$O(nm)\f$ for unit capacities. A notable - /// use of this algorithm is testing network reliability. - /// - /// For an undirected graph you can run just the first phase of the - /// algorithm or you can use the algorithm of Nagamochi and Ibaraki, - /// which solves the undirected problem in \f$ O(nm + n^2 \log n) \f$ - /// time. It is implemented in the NagamochiIbaraki algorithm class. - /// - /// \tparam GR The type of the digraph the algorithm runs on. - /// \tparam CAP The type of the arc map containing the capacities, - /// which can be any numreric type. The default map type is - /// \ref concepts::Digraph::ArcMap "GR::ArcMap". - /// \tparam TOL Tolerance class for handling inexact computations. The - /// default tolerance type is \ref Tolerance "Tolerance". -#ifdef DOXYGEN - template -#else - template , - typename TOL = Tolerance > -#endif - class HaoOrlin { - public: - - /// The digraph type of the algorithm - typedef GR Digraph; - /// The capacity map type of the algorithm - typedef CAP CapacityMap; - /// The tolerance type of the algorithm - typedef TOL Tolerance; - - private: - - typedef typename CapacityMap::Value Value; - - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - const Digraph& _graph; - const CapacityMap* _capacity; - - typedef typename Digraph::template ArcMap FlowMap; - FlowMap* _flow; - - Node _source; - - int _node_num; - - // Bucketing structure - std::vector _first, _last; - typename Digraph::template NodeMap* _next; - typename Digraph::template NodeMap* _prev; - typename Digraph::template NodeMap* _active; - typename Digraph::template NodeMap* _bucket; - - std::vector _dormant; - - std::list > _sets; - std::list::iterator _highest; - - typedef typename Digraph::template NodeMap ExcessMap; - ExcessMap* _excess; - - typedef typename Digraph::template NodeMap SourceSetMap; - SourceSetMap* _source_set; - - Value _min_cut; - - typedef typename Digraph::template NodeMap MinCutMap; - MinCutMap* _min_cut_map; - - Tolerance _tolerance; - - public: - - /// \brief Constructor - /// - /// Constructor of the algorithm class. - HaoOrlin(const Digraph& graph, const CapacityMap& capacity, - const Tolerance& tolerance = Tolerance()) : - _graph(graph), _capacity(&capacity), _flow(0), _source(), - _node_num(), _first(), _last(), _next(0), _prev(0), - _active(0), _bucket(0), _dormant(), _sets(), _highest(), - _excess(0), _source_set(0), _min_cut(), _min_cut_map(0), - _tolerance(tolerance) {} - - ~HaoOrlin() { - if (_min_cut_map) { - delete _min_cut_map; - } - if (_source_set) { - delete _source_set; - } - if (_excess) { - delete _excess; - } - if (_next) { - delete _next; - } - if (_prev) { - delete _prev; - } - if (_active) { - delete _active; - } - if (_bucket) { - delete _bucket; - } - if (_flow) { - delete _flow; - } - } - - /// \brief Set the tolerance used by the algorithm. - /// - /// This function sets the tolerance object used by the algorithm. - /// \return (*this) - HaoOrlin& tolerance(const Tolerance& tolerance) { - _tolerance = tolerance; - return *this; - } - - /// \brief Returns a const reference to the tolerance. - /// - /// This function returns a const reference to the tolerance object - /// used by the algorithm. - const Tolerance& tolerance() const { - return _tolerance; - } - - private: - - void activate(const Node& i) { - (*_active)[i] = true; - - int bucket = (*_bucket)[i]; - - if ((*_prev)[i] == INVALID || (*_active)[(*_prev)[i]]) return; - //unlace - (*_next)[(*_prev)[i]] = (*_next)[i]; - if ((*_next)[i] != INVALID) { - (*_prev)[(*_next)[i]] = (*_prev)[i]; - } else { - _last[bucket] = (*_prev)[i]; - } - //lace - (*_next)[i] = _first[bucket]; - (*_prev)[_first[bucket]] = i; - (*_prev)[i] = INVALID; - _first[bucket] = i; - } - - void deactivate(const Node& i) { - (*_active)[i] = false; - int bucket = (*_bucket)[i]; - - if ((*_next)[i] == INVALID || !(*_active)[(*_next)[i]]) return; - - //unlace - (*_prev)[(*_next)[i]] = (*_prev)[i]; - if ((*_prev)[i] != INVALID) { - (*_next)[(*_prev)[i]] = (*_next)[i]; - } else { - _first[bucket] = (*_next)[i]; - } - //lace - (*_prev)[i] = _last[bucket]; - (*_next)[_last[bucket]] = i; - (*_next)[i] = INVALID; - _last[bucket] = i; - } - - void addItem(const Node& i, int bucket) { - (*_bucket)[i] = bucket; - if (_last[bucket] != INVALID) { - (*_prev)[i] = _last[bucket]; - (*_next)[_last[bucket]] = i; - (*_next)[i] = INVALID; - _last[bucket] = i; - } else { - (*_prev)[i] = INVALID; - _first[bucket] = i; - (*_next)[i] = INVALID; - _last[bucket] = i; - } - } - - void findMinCutOut() { - - for (NodeIt n(_graph); n != INVALID; ++n) { - (*_excess)[n] = 0; - (*_source_set)[n] = false; - } - - for (ArcIt a(_graph); a != INVALID; ++a) { - (*_flow)[a] = 0; - } - - int bucket_num = 0; - std::vector queue(_node_num); - int qfirst = 0, qlast = 0, qsep = 0; - - { - typename Digraph::template NodeMap reached(_graph, false); - - reached[_source] = true; - bool first_set = true; - - for (NodeIt t(_graph); t != INVALID; ++t) { - if (reached[t]) continue; - _sets.push_front(std::list()); - - queue[qlast++] = t; - reached[t] = true; - - while (qfirst != qlast) { - if (qsep == qfirst) { - ++bucket_num; - _sets.front().push_front(bucket_num); - _dormant[bucket_num] = !first_set; - _first[bucket_num] = _last[bucket_num] = INVALID; - qsep = qlast; - } - - Node n = queue[qfirst++]; - addItem(n, bucket_num); - - for (InArcIt a(_graph, n); a != INVALID; ++a) { - Node u = _graph.source(a); - if (!reached[u] && _tolerance.positive((*_capacity)[a])) { - reached[u] = true; - queue[qlast++] = u; - } - } - } - first_set = false; - } - - ++bucket_num; - (*_bucket)[_source] = 0; - _dormant[0] = true; - } - (*_source_set)[_source] = true; - - Node target = _last[_sets.back().back()]; - { - for (OutArcIt a(_graph, _source); a != INVALID; ++a) { - if (_tolerance.positive((*_capacity)[a])) { - Node u = _graph.target(a); - (*_flow)[a] = (*_capacity)[a]; - (*_excess)[u] += (*_capacity)[a]; - if (!(*_active)[u] && u != _source) { - activate(u); - } - } - } - - if ((*_active)[target]) { - deactivate(target); - } - - _highest = _sets.back().begin(); - while (_highest != _sets.back().end() && - !(*_active)[_first[*_highest]]) { - ++_highest; - } - } - - while (true) { - while (_highest != _sets.back().end()) { - Node n = _first[*_highest]; - Value excess = (*_excess)[n]; - int next_bucket = _node_num; - - int under_bucket; - if (++std::list::iterator(_highest) == _sets.back().end()) { - under_bucket = -1; - } else { - under_bucket = *(++std::list::iterator(_highest)); - } - - for (OutArcIt a(_graph, n); a != INVALID; ++a) { - Node v = _graph.target(a); - if (_dormant[(*_bucket)[v]]) continue; - Value rem = (*_capacity)[a] - (*_flow)[a]; - if (!_tolerance.positive(rem)) continue; - if ((*_bucket)[v] == under_bucket) { - if (!(*_active)[v] && v != target) { - activate(v); - } - if (!_tolerance.less(rem, excess)) { - (*_flow)[a] += excess; - (*_excess)[v] += excess; - excess = 0; - goto no_more_push; - } else { - excess -= rem; - (*_excess)[v] += rem; - (*_flow)[a] = (*_capacity)[a]; - } - } else if (next_bucket > (*_bucket)[v]) { - next_bucket = (*_bucket)[v]; - } - } - - for (InArcIt a(_graph, n); a != INVALID; ++a) { - Node v = _graph.source(a); - if (_dormant[(*_bucket)[v]]) continue; - Value rem = (*_flow)[a]; - if (!_tolerance.positive(rem)) continue; - if ((*_bucket)[v] == under_bucket) { - if (!(*_active)[v] && v != target) { - activate(v); - } - if (!_tolerance.less(rem, excess)) { - (*_flow)[a] -= excess; - (*_excess)[v] += excess; - excess = 0; - goto no_more_push; - } else { - excess -= rem; - (*_excess)[v] += rem; - (*_flow)[a] = 0; - } - } else if (next_bucket > (*_bucket)[v]) { - next_bucket = (*_bucket)[v]; - } - } - - no_more_push: - - (*_excess)[n] = excess; - - if (excess != 0) { - if ((*_next)[n] == INVALID) { - typename std::list >::iterator new_set = - _sets.insert(--_sets.end(), std::list()); - new_set->splice(new_set->end(), _sets.back(), - _sets.back().begin(), ++_highest); - for (std::list::iterator it = new_set->begin(); - it != new_set->end(); ++it) { - _dormant[*it] = true; - } - while (_highest != _sets.back().end() && - !(*_active)[_first[*_highest]]) { - ++_highest; - } - } else if (next_bucket == _node_num) { - _first[(*_bucket)[n]] = (*_next)[n]; - (*_prev)[(*_next)[n]] = INVALID; - - std::list >::iterator new_set = - _sets.insert(--_sets.end(), std::list()); - - new_set->push_front(bucket_num); - (*_bucket)[n] = bucket_num; - _first[bucket_num] = _last[bucket_num] = n; - (*_next)[n] = INVALID; - (*_prev)[n] = INVALID; - _dormant[bucket_num] = true; - ++bucket_num; - - while (_highest != _sets.back().end() && - !(*_active)[_first[*_highest]]) { - ++_highest; - } - } else { - _first[*_highest] = (*_next)[n]; - (*_prev)[(*_next)[n]] = INVALID; - - while (next_bucket != *_highest) { - --_highest; - } - - if (_highest == _sets.back().begin()) { - _sets.back().push_front(bucket_num); - _dormant[bucket_num] = false; - _first[bucket_num] = _last[bucket_num] = INVALID; - ++bucket_num; - } - --_highest; - - (*_bucket)[n] = *_highest; - (*_next)[n] = _first[*_highest]; - if (_first[*_highest] != INVALID) { - (*_prev)[_first[*_highest]] = n; - } else { - _last[*_highest] = n; - } - _first[*_highest] = n; - } - } else { - - deactivate(n); - if (!(*_active)[_first[*_highest]]) { - ++_highest; - if (_highest != _sets.back().end() && - !(*_active)[_first[*_highest]]) { - _highest = _sets.back().end(); - } - } - } - } - - if ((*_excess)[target] < _min_cut) { - _min_cut = (*_excess)[target]; - for (NodeIt i(_graph); i != INVALID; ++i) { - (*_min_cut_map)[i] = true; - } - for (std::list::iterator it = _sets.back().begin(); - it != _sets.back().end(); ++it) { - Node n = _first[*it]; - while (n != INVALID) { - (*_min_cut_map)[n] = false; - n = (*_next)[n]; - } - } - } - - { - Node new_target; - if ((*_prev)[target] != INVALID || (*_next)[target] != INVALID) { - if ((*_next)[target] == INVALID) { - _last[(*_bucket)[target]] = (*_prev)[target]; - new_target = (*_prev)[target]; - } else { - (*_prev)[(*_next)[target]] = (*_prev)[target]; - new_target = (*_next)[target]; - } - if ((*_prev)[target] == INVALID) { - _first[(*_bucket)[target]] = (*_next)[target]; - } else { - (*_next)[(*_prev)[target]] = (*_next)[target]; - } - } else { - _sets.back().pop_back(); - if (_sets.back().empty()) { - _sets.pop_back(); - if (_sets.empty()) - break; - for (std::list::iterator it = _sets.back().begin(); - it != _sets.back().end(); ++it) { - _dormant[*it] = false; - } - } - new_target = _last[_sets.back().back()]; - } - - (*_bucket)[target] = 0; - - (*_source_set)[target] = true; - for (OutArcIt a(_graph, target); a != INVALID; ++a) { - Value rem = (*_capacity)[a] - (*_flow)[a]; - if (!_tolerance.positive(rem)) continue; - Node v = _graph.target(a); - if (!(*_active)[v] && !(*_source_set)[v]) { - activate(v); - } - (*_excess)[v] += rem; - (*_flow)[a] = (*_capacity)[a]; - } - - for (InArcIt a(_graph, target); a != INVALID; ++a) { - Value rem = (*_flow)[a]; - if (!_tolerance.positive(rem)) continue; - Node v = _graph.source(a); - if (!(*_active)[v] && !(*_source_set)[v]) { - activate(v); - } - (*_excess)[v] += rem; - (*_flow)[a] = 0; - } - - target = new_target; - if ((*_active)[target]) { - deactivate(target); - } - - _highest = _sets.back().begin(); - while (_highest != _sets.back().end() && - !(*_active)[_first[*_highest]]) { - ++_highest; - } - } - } - } - - void findMinCutIn() { - - for (NodeIt n(_graph); n != INVALID; ++n) { - (*_excess)[n] = 0; - (*_source_set)[n] = false; - } - - for (ArcIt a(_graph); a != INVALID; ++a) { - (*_flow)[a] = 0; - } - - int bucket_num = 0; - std::vector queue(_node_num); - int qfirst = 0, qlast = 0, qsep = 0; - - { - typename Digraph::template NodeMap reached(_graph, false); - - reached[_source] = true; - - bool first_set = true; - - for (NodeIt t(_graph); t != INVALID; ++t) { - if (reached[t]) continue; - _sets.push_front(std::list()); - - queue[qlast++] = t; - reached[t] = true; - - while (qfirst != qlast) { - if (qsep == qfirst) { - ++bucket_num; - _sets.front().push_front(bucket_num); - _dormant[bucket_num] = !first_set; - _first[bucket_num] = _last[bucket_num] = INVALID; - qsep = qlast; - } - - Node n = queue[qfirst++]; - addItem(n, bucket_num); - - for (OutArcIt a(_graph, n); a != INVALID; ++a) { - Node u = _graph.target(a); - if (!reached[u] && _tolerance.positive((*_capacity)[a])) { - reached[u] = true; - queue[qlast++] = u; - } - } - } - first_set = false; - } - - ++bucket_num; - (*_bucket)[_source] = 0; - _dormant[0] = true; - } - (*_source_set)[_source] = true; - - Node target = _last[_sets.back().back()]; - { - for (InArcIt a(_graph, _source); a != INVALID; ++a) { - if (_tolerance.positive((*_capacity)[a])) { - Node u = _graph.source(a); - (*_flow)[a] = (*_capacity)[a]; - (*_excess)[u] += (*_capacity)[a]; - if (!(*_active)[u] && u != _source) { - activate(u); - } - } - } - if ((*_active)[target]) { - deactivate(target); - } - - _highest = _sets.back().begin(); - while (_highest != _sets.back().end() && - !(*_active)[_first[*_highest]]) { - ++_highest; - } - } - - - while (true) { - while (_highest != _sets.back().end()) { - Node n = _first[*_highest]; - Value excess = (*_excess)[n]; - int next_bucket = _node_num; - - int under_bucket; - if (++std::list::iterator(_highest) == _sets.back().end()) { - under_bucket = -1; - } else { - under_bucket = *(++std::list::iterator(_highest)); - } - - for (InArcIt a(_graph, n); a != INVALID; ++a) { - Node v = _graph.source(a); - if (_dormant[(*_bucket)[v]]) continue; - Value rem = (*_capacity)[a] - (*_flow)[a]; - if (!_tolerance.positive(rem)) continue; - if ((*_bucket)[v] == under_bucket) { - if (!(*_active)[v] && v != target) { - activate(v); - } - if (!_tolerance.less(rem, excess)) { - (*_flow)[a] += excess; - (*_excess)[v] += excess; - excess = 0; - goto no_more_push; - } else { - excess -= rem; - (*_excess)[v] += rem; - (*_flow)[a] = (*_capacity)[a]; - } - } else if (next_bucket > (*_bucket)[v]) { - next_bucket = (*_bucket)[v]; - } - } - - for (OutArcIt a(_graph, n); a != INVALID; ++a) { - Node v = _graph.target(a); - if (_dormant[(*_bucket)[v]]) continue; - Value rem = (*_flow)[a]; - if (!_tolerance.positive(rem)) continue; - if ((*_bucket)[v] == under_bucket) { - if (!(*_active)[v] && v != target) { - activate(v); - } - if (!_tolerance.less(rem, excess)) { - (*_flow)[a] -= excess; - (*_excess)[v] += excess; - excess = 0; - goto no_more_push; - } else { - excess -= rem; - (*_excess)[v] += rem; - (*_flow)[a] = 0; - } - } else if (next_bucket > (*_bucket)[v]) { - next_bucket = (*_bucket)[v]; - } - } - - no_more_push: - - (*_excess)[n] = excess; - - if (excess != 0) { - if ((*_next)[n] == INVALID) { - typename std::list >::iterator new_set = - _sets.insert(--_sets.end(), std::list()); - new_set->splice(new_set->end(), _sets.back(), - _sets.back().begin(), ++_highest); - for (std::list::iterator it = new_set->begin(); - it != new_set->end(); ++it) { - _dormant[*it] = true; - } - while (_highest != _sets.back().end() && - !(*_active)[_first[*_highest]]) { - ++_highest; - } - } else if (next_bucket == _node_num) { - _first[(*_bucket)[n]] = (*_next)[n]; - (*_prev)[(*_next)[n]] = INVALID; - - std::list >::iterator new_set = - _sets.insert(--_sets.end(), std::list()); - - new_set->push_front(bucket_num); - (*_bucket)[n] = bucket_num; - _first[bucket_num] = _last[bucket_num] = n; - (*_next)[n] = INVALID; - (*_prev)[n] = INVALID; - _dormant[bucket_num] = true; - ++bucket_num; - - while (_highest != _sets.back().end() && - !(*_active)[_first[*_highest]]) { - ++_highest; - } - } else { - _first[*_highest] = (*_next)[n]; - (*_prev)[(*_next)[n]] = INVALID; - - while (next_bucket != *_highest) { - --_highest; - } - if (_highest == _sets.back().begin()) { - _sets.back().push_front(bucket_num); - _dormant[bucket_num] = false; - _first[bucket_num] = _last[bucket_num] = INVALID; - ++bucket_num; - } - --_highest; - - (*_bucket)[n] = *_highest; - (*_next)[n] = _first[*_highest]; - if (_first[*_highest] != INVALID) { - (*_prev)[_first[*_highest]] = n; - } else { - _last[*_highest] = n; - } - _first[*_highest] = n; - } - } else { - - deactivate(n); - if (!(*_active)[_first[*_highest]]) { - ++_highest; - if (_highest != _sets.back().end() && - !(*_active)[_first[*_highest]]) { - _highest = _sets.back().end(); - } - } - } - } - - if ((*_excess)[target] < _min_cut) { - _min_cut = (*_excess)[target]; - for (NodeIt i(_graph); i != INVALID; ++i) { - (*_min_cut_map)[i] = false; - } - for (std::list::iterator it = _sets.back().begin(); - it != _sets.back().end(); ++it) { - Node n = _first[*it]; - while (n != INVALID) { - (*_min_cut_map)[n] = true; - n = (*_next)[n]; - } - } - } - - { - Node new_target; - if ((*_prev)[target] != INVALID || (*_next)[target] != INVALID) { - if ((*_next)[target] == INVALID) { - _last[(*_bucket)[target]] = (*_prev)[target]; - new_target = (*_prev)[target]; - } else { - (*_prev)[(*_next)[target]] = (*_prev)[target]; - new_target = (*_next)[target]; - } - if ((*_prev)[target] == INVALID) { - _first[(*_bucket)[target]] = (*_next)[target]; - } else { - (*_next)[(*_prev)[target]] = (*_next)[target]; - } - } else { - _sets.back().pop_back(); - if (_sets.back().empty()) { - _sets.pop_back(); - if (_sets.empty()) - break; - for (std::list::iterator it = _sets.back().begin(); - it != _sets.back().end(); ++it) { - _dormant[*it] = false; - } - } - new_target = _last[_sets.back().back()]; - } - - (*_bucket)[target] = 0; - - (*_source_set)[target] = true; - for (InArcIt a(_graph, target); a != INVALID; ++a) { - Value rem = (*_capacity)[a] - (*_flow)[a]; - if (!_tolerance.positive(rem)) continue; - Node v = _graph.source(a); - if (!(*_active)[v] && !(*_source_set)[v]) { - activate(v); - } - (*_excess)[v] += rem; - (*_flow)[a] = (*_capacity)[a]; - } - - for (OutArcIt a(_graph, target); a != INVALID; ++a) { - Value rem = (*_flow)[a]; - if (!_tolerance.positive(rem)) continue; - Node v = _graph.target(a); - if (!(*_active)[v] && !(*_source_set)[v]) { - activate(v); - } - (*_excess)[v] += rem; - (*_flow)[a] = 0; - } - - target = new_target; - if ((*_active)[target]) { - deactivate(target); - } - - _highest = _sets.back().begin(); - while (_highest != _sets.back().end() && - !(*_active)[_first[*_highest]]) { - ++_highest; - } - } - } - } - - public: - - /// \name Execution Control - /// The simplest way to execute the algorithm is to use - /// one of the member functions called \ref run(). - /// \n - /// If you need better control on the execution, - /// you have to call one of the \ref init() functions first, then - /// \ref calculateOut() and/or \ref calculateIn(). - - /// @{ - - /// \brief Initialize the internal data structures. - /// - /// This function initializes the internal data structures. It creates - /// the maps and some bucket structures for the algorithm. - /// The first node is used as the source node for the push-relabel - /// algorithm. - void init() { - init(NodeIt(_graph)); - } - - /// \brief Initialize the internal data structures. - /// - /// This function initializes the internal data structures. It creates - /// the maps and some bucket structures for the algorithm. - /// The given node is used as the source node for the push-relabel - /// algorithm. - void init(const Node& source) { - _source = source; - - _node_num = countNodes(_graph); - - _first.resize(_node_num); - _last.resize(_node_num); - - _dormant.resize(_node_num); - - if (!_flow) { - _flow = new FlowMap(_graph); - } - if (!_next) { - _next = new typename Digraph::template NodeMap(_graph); - } - if (!_prev) { - _prev = new typename Digraph::template NodeMap(_graph); - } - if (!_active) { - _active = new typename Digraph::template NodeMap(_graph); - } - if (!_bucket) { - _bucket = new typename Digraph::template NodeMap(_graph); - } - if (!_excess) { - _excess = new ExcessMap(_graph); - } - if (!_source_set) { - _source_set = new SourceSetMap(_graph); - } - if (!_min_cut_map) { - _min_cut_map = new MinCutMap(_graph); - } - - _min_cut = std::numeric_limits::max(); - } - - - /// \brief Calculate a minimum cut with \f$ source \f$ on the - /// source-side. - /// - /// This function calculates a minimum cut with \f$ source \f$ on the - /// source-side (i.e. a set \f$ X\subsetneq V \f$ with - /// \f$ source \in X \f$ and minimal outgoing capacity). - /// It updates the stored cut if (and only if) the newly found one - /// is better. - /// - /// \pre \ref init() must be called before using this function. - void calculateOut() { - findMinCutOut(); - } - - /// \brief Calculate a minimum cut with \f$ source \f$ on the - /// sink-side. - /// - /// This function calculates a minimum cut with \f$ source \f$ on the - /// sink-side (i.e. a set \f$ X\subsetneq V \f$ with - /// \f$ source \notin X \f$ and minimal outgoing capacity). - /// It updates the stored cut if (and only if) the newly found one - /// is better. - /// - /// \pre \ref init() must be called before using this function. - void calculateIn() { - findMinCutIn(); - } - - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. It chooses source node, - /// then calls \ref init(), \ref calculateOut() - /// and \ref calculateIn(). - void run() { - init(); - calculateOut(); - calculateIn(); - } - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. It calls \ref init(), - /// \ref calculateOut() and \ref calculateIn() with the given - /// source node. - void run(const Node& s) { - init(s); - calculateOut(); - calculateIn(); - } - - /// @} - - /// \name Query Functions - /// The result of the %HaoOrlin algorithm - /// can be obtained using these functions.\n - /// \ref run(), \ref calculateOut() or \ref calculateIn() - /// should be called before using them. - - /// @{ - - /// \brief Return the value of the minimum cut. - /// - /// This function returns the value of the best cut found by the - /// previously called \ref run(), \ref calculateOut() or \ref - /// calculateIn(). - /// - /// \pre \ref run(), \ref calculateOut() or \ref calculateIn() - /// must be called before using this function. - Value minCutValue() const { - return _min_cut; - } - - - /// \brief Return a minimum cut. - /// - /// This function gives the best cut found by the - /// previously called \ref run(), \ref calculateOut() or \ref - /// calculateIn(). - /// - /// It sets \c cutMap to the characteristic vector of the found - /// minimum value cut - a non-empty set \f$ X\subsetneq V \f$ - /// of minimum outgoing capacity (i.e. \c cutMap will be \c true exactly - /// for the nodes of \f$ X \f$). - /// - /// \param cutMap A \ref concepts::WriteMap "writable" node map with - /// \c bool (or convertible) value type. - /// - /// \return The value of the minimum cut. - /// - /// \pre \ref run(), \ref calculateOut() or \ref calculateIn() - /// must be called before using this function. - template - Value minCutMap(CutMap& cutMap) const { - for (NodeIt it(_graph); it != INVALID; ++it) { - cutMap.set(it, (*_min_cut_map)[it]); - } - return _min_cut; - } - - /// @} - - }; //class HaoOrlin - -} //namespace lemon - -#endif //LEMON_HAO_ORLIN_H diff --git a/deps/lemon/lemon/hartmann_orlin_mmc.h b/deps/lemon/lemon/hartmann_orlin_mmc.h deleted file mode 100644 index 6b60a85ed..000000000 --- a/deps/lemon/lemon/hartmann_orlin_mmc.h +++ /dev/null @@ -1,654 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_HARTMANN_ORLIN_MMC_H -#define LEMON_HARTMANN_ORLIN_MMC_H - -/// \ingroup min_mean_cycle -/// -/// \file -/// \brief Hartmann-Orlin's algorithm for finding a minimum mean cycle. - -#include -#include -#include -#include -#include -#include - -namespace lemon { - - /// \brief Default traits class of HartmannOrlinMmc class. - /// - /// Default traits class of HartmannOrlinMmc class. - /// \tparam GR The type of the digraph. - /// \tparam CM The type of the cost map. - /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. -#ifdef DOXYGEN - template -#else - template ::is_integer> -#endif - struct HartmannOrlinMmcDefaultTraits - { - /// The type of the digraph - typedef GR Digraph; - /// The type of the cost map - typedef CM CostMap; - /// The type of the arc costs - typedef typename CostMap::Value Cost; - - /// \brief The large cost type used for internal computations - /// - /// The large cost type used for internal computations. - /// It is \c long \c long if the \c Cost type is integer, - /// otherwise it is \c double. - /// \c Cost must be convertible to \c LargeCost. - typedef double LargeCost; - - /// The tolerance type used for internal computations - typedef lemon::Tolerance Tolerance; - - /// \brief The path type of the found cycles - /// - /// The path type of the found cycles. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addFront() function. - typedef lemon::Path Path; - }; - - // Default traits class for integer cost types - template - struct HartmannOrlinMmcDefaultTraits - { - typedef GR Digraph; - typedef CM CostMap; - typedef typename CostMap::Value Cost; -#ifdef LEMON_HAVE_LONG_LONG - typedef long long LargeCost; -#else - typedef long LargeCost; -#endif - typedef lemon::Tolerance Tolerance; - typedef lemon::Path Path; - }; - - - /// \addtogroup min_mean_cycle - /// @{ - - /// \brief Implementation of the Hartmann-Orlin algorithm for finding - /// a minimum mean cycle. - /// - /// This class implements the Hartmann-Orlin algorithm for finding - /// a directed cycle of minimum mean cost in a digraph - /// \cite hartmann93finding, \cite dasdan98minmeancycle. - /// This method is based on \ref KarpMmc "Karp"'s original algorithm, but - /// applies an early termination scheme. It makes the algorithm - /// significantly faster for some problem instances, but slower for others. - /// The algorithm runs in time O(nm) and uses space O(n2+m). - /// - /// \tparam GR The type of the digraph the algorithm runs on. - /// \tparam CM The type of the cost map. The default - /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref HartmannOrlinMmcDefaultTraits - /// "HartmannOrlinMmcDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template < typename GR, - typename CM = typename GR::template ArcMap, - typename TR = HartmannOrlinMmcDefaultTraits > -#endif - class HartmannOrlinMmc - { - public: - - /// The type of the digraph - typedef typename TR::Digraph Digraph; - /// The type of the cost map - typedef typename TR::CostMap CostMap; - /// The type of the arc costs - typedef typename TR::Cost Cost; - - /// \brief The large cost type - /// - /// The large cost type used for internal computations. - /// By default, it is \c long \c long if the \c Cost type is integer, - /// otherwise it is \c double. - typedef typename TR::LargeCost LargeCost; - - /// The tolerance type - typedef typename TR::Tolerance Tolerance; - - /// \brief The path type of the found cycles - /// - /// The path type of the found cycles. - /// Using the \ref lemon::HartmannOrlinMmcDefaultTraits - /// "default traits class", - /// it is \ref lemon::Path "Path". - typedef typename TR::Path Path; - - /// \brief The - /// \ref lemon::HartmannOrlinMmcDefaultTraits "traits class" - /// of the algorithm - typedef TR Traits; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - // Data sturcture for path data - struct PathData - { - LargeCost dist; - Arc pred; - PathData(LargeCost d, Arc p = INVALID) : - dist(d), pred(p) {} - }; - - typedef typename Digraph::template NodeMap > - PathDataNodeMap; - - private: - - // The digraph the algorithm runs on - const Digraph &_gr; - // The cost of the arcs - const CostMap &_cost; - - // Data for storing the strongly connected components - int _comp_num; - typename Digraph::template NodeMap _comp; - std::vector > _comp_nodes; - std::vector* _nodes; - typename Digraph::template NodeMap > _out_arcs; - - // Data for the found cycles - bool _curr_found, _best_found; - LargeCost _curr_cost, _best_cost; - int _curr_size, _best_size; - Node _curr_node, _best_node; - int _curr_level, _best_level; - - Path *_cycle_path; - bool _local_path; - - // Node map for storing path data - PathDataNodeMap _data; - // The processed nodes in the last round - std::vector _process; - - Tolerance _tolerance; - - // Infinite constant - const LargeCost INF; - - public: - - /// \name Named Template Parameters - /// @{ - - template - struct SetLargeCostTraits : public Traits { - typedef T LargeCost; - typedef lemon::Tolerance Tolerance; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c LargeCost type. - /// - /// \ref named-templ-param "Named parameter" for setting \c LargeCost - /// type. It is used for internal computations in the algorithm. - template - struct SetLargeCost - : public HartmannOrlinMmc > { - typedef HartmannOrlinMmc > Create; - }; - - template - struct SetPathTraits : public Traits { - typedef T Path; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c %Path type. - /// - /// \ref named-templ-param "Named parameter" for setting the \c %Path - /// type of the found cycles. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addFront() function. - template - struct SetPath - : public HartmannOrlinMmc > { - typedef HartmannOrlinMmc > Create; - }; - - /// @} - - protected: - - HartmannOrlinMmc() {} - - public: - - /// \brief Constructor. - /// - /// The constructor of the class. - /// - /// \param digraph The digraph the algorithm runs on. - /// \param cost The costs of the arcs. - HartmannOrlinMmc( const Digraph &digraph, - const CostMap &cost ) : - _gr(digraph), _cost(cost), _comp(digraph), _out_arcs(digraph), - _best_found(false), _best_cost(0), _best_size(1), - _cycle_path(NULL), _local_path(false), _data(digraph), - INF(std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max()) - {} - - /// Destructor. - ~HartmannOrlinMmc() { - if (_local_path) delete _cycle_path; - } - - /// \brief Set the path structure for storing the found cycle. - /// - /// This function sets an external path structure for storing the - /// found cycle. - /// - /// If you don't call this function before calling \ref run() or - /// \ref findCycleMean(), a local \ref Path "path" structure - /// will be allocated. The destuctor deallocates this automatically - /// allocated object, of course. - /// - /// \note The algorithm calls only the \ref lemon::Path::addFront() - /// "addFront()" function of the given path structure. - /// - /// \return (*this) - HartmannOrlinMmc& cycle(Path &path) { - if (_local_path) { - delete _cycle_path; - _local_path = false; - } - _cycle_path = &path; - return *this; - } - - /// \brief Set the tolerance used by the algorithm. - /// - /// This function sets the tolerance object used by the algorithm. - /// - /// \return (*this) - HartmannOrlinMmc& tolerance(const Tolerance& tolerance) { - _tolerance = tolerance; - return *this; - } - - /// \brief Return a const reference to the tolerance. - /// - /// This function returns a const reference to the tolerance object - /// used by the algorithm. - const Tolerance& tolerance() const { - return _tolerance; - } - - /// \name Execution control - /// The simplest way to execute the algorithm is to call the \ref run() - /// function.\n - /// If you only need the minimum mean cost, you may call - /// \ref findCycleMean(). - - /// @{ - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. - /// It can be called more than once (e.g. if the underlying digraph - /// and/or the arc costs have been modified). - /// - /// \return \c true if a directed cycle exists in the digraph. - /// - /// \note mmc.run() is just a shortcut of the following code. - /// \code - /// return mmc.findCycleMean() && mmc.findCycle(); - /// \endcode - bool run() { - return findCycleMean() && findCycle(); - } - - /// \brief Find the minimum cycle mean. - /// - /// This function finds the minimum mean cost of the directed - /// cycles in the digraph. - /// - /// \return \c true if a directed cycle exists in the digraph. - bool findCycleMean() { - // Initialization and find strongly connected components - init(); - findComponents(); - - // Find the minimum cycle mean in the components - for (int comp = 0; comp < _comp_num; ++comp) { - if (!initComponent(comp)) continue; - processRounds(); - - // Update the best cycle (global minimum mean cycle) - if ( _curr_found && (!_best_found || - _curr_cost * _best_size < _best_cost * _curr_size) ) { - _best_found = true; - _best_cost = _curr_cost; - _best_size = _curr_size; - _best_node = _curr_node; - _best_level = _curr_level; - } - } - return _best_found; - } - - /// \brief Find a minimum mean directed cycle. - /// - /// This function finds a directed cycle of minimum mean cost - /// in the digraph using the data computed by findCycleMean(). - /// - /// \return \c true if a directed cycle exists in the digraph. - /// - /// \pre \ref findCycleMean() must be called before using this function. - bool findCycle() { - if (!_best_found) return false; - IntNodeMap reached(_gr, -1); - int r = _best_level + 1; - Node u = _best_node; - while (reached[u] < 0) { - reached[u] = --r; - u = _gr.source(_data[u][r].pred); - } - r = reached[u]; - Arc e = _data[u][r].pred; - _cycle_path->addFront(e); - _best_cost = _cost[e]; - _best_size = 1; - Node v; - while ((v = _gr.source(e)) != u) { - e = _data[v][--r].pred; - _cycle_path->addFront(e); - _best_cost += _cost[e]; - ++_best_size; - } - return true; - } - - /// @} - - /// \name Query Functions - /// The results of the algorithm can be obtained using these - /// functions.\n - /// The algorithm should be executed before using them. - - /// @{ - - /// \brief Return the total cost of the found cycle. - /// - /// This function returns the total cost of the found cycle. - /// - /// \pre \ref run() or \ref findCycleMean() must be called before - /// using this function. - Cost cycleCost() const { - return static_cast(_best_cost); - } - - /// \brief Return the number of arcs on the found cycle. - /// - /// This function returns the number of arcs on the found cycle. - /// - /// \pre \ref run() or \ref findCycleMean() must be called before - /// using this function. - int cycleSize() const { - return _best_size; - } - - /// \brief Return the mean cost of the found cycle. - /// - /// This function returns the mean cost of the found cycle. - /// - /// \note alg.cycleMean() is just a shortcut of the - /// following code. - /// \code - /// return static_cast(alg.cycleCost()) / alg.cycleSize(); - /// \endcode - /// - /// \pre \ref run() or \ref findCycleMean() must be called before - /// using this function. - double cycleMean() const { - return static_cast(_best_cost) / _best_size; - } - - /// \brief Return the found cycle. - /// - /// This function returns a const reference to the path structure - /// storing the found cycle. - /// - /// \pre \ref run() or \ref findCycle() must be called before using - /// this function. - const Path& cycle() const { - return *_cycle_path; - } - - ///@} - - private: - - // Initialization - void init() { - if (!_cycle_path) { - _local_path = true; - _cycle_path = new Path; - } - _cycle_path->clear(); - _best_found = false; - _best_cost = 0; - _best_size = 1; - _cycle_path->clear(); - for (NodeIt u(_gr); u != INVALID; ++u) - _data[u].clear(); - } - - // Find strongly connected components and initialize _comp_nodes - // and _out_arcs - void findComponents() { - _comp_num = stronglyConnectedComponents(_gr, _comp); - _comp_nodes.resize(_comp_num); - if (_comp_num == 1) { - _comp_nodes[0].clear(); - for (NodeIt n(_gr); n != INVALID; ++n) { - _comp_nodes[0].push_back(n); - _out_arcs[n].clear(); - for (OutArcIt a(_gr, n); a != INVALID; ++a) { - _out_arcs[n].push_back(a); - } - } - } else { - for (int i = 0; i < _comp_num; ++i) - _comp_nodes[i].clear(); - for (NodeIt n(_gr); n != INVALID; ++n) { - int k = _comp[n]; - _comp_nodes[k].push_back(n); - _out_arcs[n].clear(); - for (OutArcIt a(_gr, n); a != INVALID; ++a) { - if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a); - } - } - } - } - - // Initialize path data for the current component - bool initComponent(int comp) { - _nodes = &(_comp_nodes[comp]); - int n = _nodes->size(); - if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) { - return false; - } - for (int i = 0; i < n; ++i) { - _data[(*_nodes)[i]].resize(n + 1, PathData(INF)); - } - return true; - } - - // Process all rounds of computing path data for the current component. - // _data[v][k] is the cost of a shortest directed walk from the root - // node to node v containing exactly k arcs. - void processRounds() { - Node start = (*_nodes)[0]; - _data[start][0] = PathData(0); - _process.clear(); - _process.push_back(start); - - int k, n = _nodes->size(); - int next_check = 4; - bool terminate = false; - for (k = 1; k <= n && int(_process.size()) < n && !terminate; ++k) { - processNextBuildRound(k); - if (k == next_check || k == n) { - terminate = checkTermination(k); - next_check = next_check * 3 / 2; - } - } - for ( ; k <= n && !terminate; ++k) { - processNextFullRound(k); - if (k == next_check || k == n) { - terminate = checkTermination(k); - next_check = next_check * 3 / 2; - } - } - } - - // Process one round and rebuild _process - void processNextBuildRound(int k) { - std::vector next; - Node u, v; - Arc e; - LargeCost d; - for (int i = 0; i < int(_process.size()); ++i) { - u = _process[i]; - for (int j = 0; j < int(_out_arcs[u].size()); ++j) { - e = _out_arcs[u][j]; - v = _gr.target(e); - d = _data[u][k-1].dist + _cost[e]; - if (_tolerance.less(d, _data[v][k].dist)) { - if (_data[v][k].dist == INF) next.push_back(v); - _data[v][k] = PathData(d, e); - } - } - } - _process.swap(next); - } - - // Process one round using _nodes instead of _process - void processNextFullRound(int k) { - Node u, v; - Arc e; - LargeCost d; - for (int i = 0; i < int(_nodes->size()); ++i) { - u = (*_nodes)[i]; - for (int j = 0; j < int(_out_arcs[u].size()); ++j) { - e = _out_arcs[u][j]; - v = _gr.target(e); - d = _data[u][k-1].dist + _cost[e]; - if (_tolerance.less(d, _data[v][k].dist)) { - _data[v][k] = PathData(d, e); - } - } - } - } - - // Check early termination - bool checkTermination(int k) { - typedef std::pair Pair; - typename GR::template NodeMap level(_gr, Pair(-1, 0)); - typename GR::template NodeMap pi(_gr); - int n = _nodes->size(); - LargeCost cost; - int size; - Node u; - - // Search for cycles that are already found - _curr_found = false; - for (int i = 0; i < n; ++i) { - u = (*_nodes)[i]; - if (_data[u][k].dist == INF) continue; - for (int j = k; j >= 0; --j) { - if (level[u].first == i && level[u].second > 0) { - // A cycle is found - cost = _data[u][level[u].second].dist - _data[u][j].dist; - size = level[u].second - j; - if (!_curr_found || cost * _curr_size < _curr_cost * size) { - _curr_cost = cost; - _curr_size = size; - _curr_node = u; - _curr_level = level[u].second; - _curr_found = true; - } - } - level[u] = Pair(i, j); - if (j != 0) { - u = _gr.source(_data[u][j].pred); - } - } - } - - // If at least one cycle is found, check the optimality condition - LargeCost d; - if (_curr_found && k < n) { - // Find node potentials - for (int i = 0; i < n; ++i) { - u = (*_nodes)[i]; - pi[u] = INF; - for (int j = 0; j <= k; ++j) { - if (_data[u][j].dist < INF) { - d = _data[u][j].dist * _curr_size - j * _curr_cost; - if (_tolerance.less(d, pi[u])) pi[u] = d; - } - } - } - - // Check the optimality condition for all arcs - bool done = true; - for (ArcIt a(_gr); a != INVALID; ++a) { - if (_tolerance.less(_cost[a] * _curr_size - _curr_cost, - pi[_gr.target(a)] - pi[_gr.source(a)]) ) { - done = false; - break; - } - } - return done; - } - return (k == n); - } - - }; //class HartmannOrlinMmc - - ///@} - -} //namespace lemon - -#endif //LEMON_HARTMANN_ORLIN_MMC_H diff --git a/deps/lemon/lemon/howard_mmc.h b/deps/lemon/lemon/howard_mmc.h deleted file mode 100644 index 690236340..000000000 --- a/deps/lemon/lemon/howard_mmc.h +++ /dev/null @@ -1,651 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_HOWARD_MMC_H -#define LEMON_HOWARD_MMC_H - -/// \ingroup min_mean_cycle -/// -/// \file -/// \brief Howard's algorithm for finding a minimum mean cycle. - -#include -#include -#include -#include -#include -#include - -namespace lemon { - - /// \brief Default traits class of HowardMmc class. - /// - /// Default traits class of HowardMmc class. - /// \tparam GR The type of the digraph. - /// \tparam CM The type of the cost map. - /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. -#ifdef DOXYGEN - template -#else - template ::is_integer> -#endif - struct HowardMmcDefaultTraits - { - /// The type of the digraph - typedef GR Digraph; - /// The type of the cost map - typedef CM CostMap; - /// The type of the arc costs - typedef typename CostMap::Value Cost; - - /// \brief The large cost type used for internal computations - /// - /// The large cost type used for internal computations. - /// It is \c long \c long if the \c Cost type is integer, - /// otherwise it is \c double. - /// \c Cost must be convertible to \c LargeCost. - typedef double LargeCost; - - /// The tolerance type used for internal computations - typedef lemon::Tolerance Tolerance; - - /// \brief The path type of the found cycles - /// - /// The path type of the found cycles. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addBack() function. - typedef lemon::Path Path; - }; - - // Default traits class for integer cost types - template - struct HowardMmcDefaultTraits - { - typedef GR Digraph; - typedef CM CostMap; - typedef typename CostMap::Value Cost; -#ifdef LEMON_HAVE_LONG_LONG - typedef long long LargeCost; -#else - typedef long LargeCost; -#endif - typedef lemon::Tolerance Tolerance; - typedef lemon::Path Path; - }; - - - /// \addtogroup min_mean_cycle - /// @{ - - /// \brief Implementation of Howard's algorithm for finding a minimum - /// mean cycle. - /// - /// This class implements Howard's policy iteration algorithm for finding - /// a directed cycle of minimum mean cost in a digraph - /// \cite dasdan98minmeancycle, \cite dasdan04experimental. - /// This class provides the most efficient algorithm for the - /// minimum mean cycle problem, though the best known theoretical - /// bound on its running time is exponential. - /// - /// \tparam GR The type of the digraph the algorithm runs on. - /// \tparam CM The type of the cost map. The default - /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref HowardMmcDefaultTraits - /// "HowardMmcDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template < typename GR, - typename CM = typename GR::template ArcMap, - typename TR = HowardMmcDefaultTraits > -#endif - class HowardMmc - { - public: - - /// The type of the digraph - typedef typename TR::Digraph Digraph; - /// The type of the cost map - typedef typename TR::CostMap CostMap; - /// The type of the arc costs - typedef typename TR::Cost Cost; - - /// \brief The large cost type - /// - /// The large cost type used for internal computations. - /// By default, it is \c long \c long if the \c Cost type is integer, - /// otherwise it is \c double. - typedef typename TR::LargeCost LargeCost; - - /// The tolerance type - typedef typename TR::Tolerance Tolerance; - - /// \brief The path type of the found cycles - /// - /// The path type of the found cycles. - /// Using the \ref lemon::HowardMmcDefaultTraits "default traits class", - /// it is \ref lemon::Path "Path". - typedef typename TR::Path Path; - - /// The \ref lemon::HowardMmcDefaultTraits "traits class" of the algorithm - typedef TR Traits; - - /// \brief Constants for the causes of search termination. - /// - /// Enum type containing constants for the different causes of search - /// termination. The \ref findCycleMean() function returns one of - /// these values. - enum TerminationCause { - - /// No directed cycle can be found in the digraph. - NO_CYCLE = 0, - - /// Optimal solution (minimum cycle mean) is found. - OPTIMAL = 1, - - /// The iteration count limit is reached. - ITERATION_LIMIT - }; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - // The digraph the algorithm runs on - const Digraph &_gr; - // The cost of the arcs - const CostMap &_cost; - - // Data for the found cycles - bool _curr_found, _best_found; - LargeCost _curr_cost, _best_cost; - int _curr_size, _best_size; - Node _curr_node, _best_node; - - Path *_cycle_path; - bool _local_path; - - // Internal data used by the algorithm - typename Digraph::template NodeMap _policy; - typename Digraph::template NodeMap _reached; - typename Digraph::template NodeMap _level; - typename Digraph::template NodeMap _dist; - - // Data for storing the strongly connected components - int _comp_num; - typename Digraph::template NodeMap _comp; - std::vector > _comp_nodes; - std::vector* _nodes; - typename Digraph::template NodeMap > _in_arcs; - - // Queue used for BFS search - std::vector _queue; - int _qfront, _qback; - - Tolerance _tolerance; - - // Infinite constant - const LargeCost INF; - - public: - - /// \name Named Template Parameters - /// @{ - - template - struct SetLargeCostTraits : public Traits { - typedef T LargeCost; - typedef lemon::Tolerance Tolerance; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c LargeCost type. - /// - /// \ref named-templ-param "Named parameter" for setting \c LargeCost - /// type. It is used for internal computations in the algorithm. - template - struct SetLargeCost - : public HowardMmc > { - typedef HowardMmc > Create; - }; - - template - struct SetPathTraits : public Traits { - typedef T Path; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c %Path type. - /// - /// \ref named-templ-param "Named parameter" for setting the \c %Path - /// type of the found cycles. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addBack() function. - template - struct SetPath - : public HowardMmc > { - typedef HowardMmc > Create; - }; - - /// @} - - protected: - - HowardMmc() {} - - public: - - /// \brief Constructor. - /// - /// The constructor of the class. - /// - /// \param digraph The digraph the algorithm runs on. - /// \param cost The costs of the arcs. - HowardMmc( const Digraph &digraph, - const CostMap &cost ) : - _gr(digraph), _cost(cost), _best_found(false), - _best_cost(0), _best_size(1), _cycle_path(NULL), _local_path(false), - _policy(digraph), _reached(digraph), _level(digraph), _dist(digraph), - _comp(digraph), _in_arcs(digraph), - INF(std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max()) - {} - - /// Destructor. - ~HowardMmc() { - if (_local_path) delete _cycle_path; - } - - /// \brief Set the path structure for storing the found cycle. - /// - /// This function sets an external path structure for storing the - /// found cycle. - /// - /// If you don't call this function before calling \ref run() or - /// \ref findCycleMean(), a local \ref Path "path" structure - /// will be allocated. The destuctor deallocates this automatically - /// allocated object, of course. - /// - /// \note The algorithm calls only the \ref lemon::Path::addBack() - /// "addBack()" function of the given path structure. - /// - /// \return (*this) - HowardMmc& cycle(Path &path) { - if (_local_path) { - delete _cycle_path; - _local_path = false; - } - _cycle_path = &path; - return *this; - } - - /// \brief Set the tolerance used by the algorithm. - /// - /// This function sets the tolerance object used by the algorithm. - /// - /// \return (*this) - HowardMmc& tolerance(const Tolerance& tolerance) { - _tolerance = tolerance; - return *this; - } - - /// \brief Return a const reference to the tolerance. - /// - /// This function returns a const reference to the tolerance object - /// used by the algorithm. - const Tolerance& tolerance() const { - return _tolerance; - } - - /// \name Execution control - /// The simplest way to execute the algorithm is to call the \ref run() - /// function.\n - /// If you only need the minimum mean cost, you may call - /// \ref findCycleMean(). - - /// @{ - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. - /// It can be called more than once (e.g. if the underlying digraph - /// and/or the arc costs have been modified). - /// - /// \return \c true if a directed cycle exists in the digraph. - /// - /// \note mmc.run() is just a shortcut of the following code. - /// \code - /// return mmc.findCycleMean() && mmc.findCycle(); - /// \endcode - bool run() { - return findCycleMean() && findCycle(); - } - - /// \brief Find the minimum cycle mean (or an upper bound). - /// - /// This function finds the minimum mean cost of the directed - /// cycles in the digraph (or an upper bound for it). - /// - /// By default, the function finds the exact minimum cycle mean, - /// but an optional limit can also be specified for the number of - /// iterations performed during the search process. - /// The return value indicates if the optimal solution is found - /// or the iteration limit is reached. In the latter case, an - /// approximate solution is provided, which corresponds to a directed - /// cycle whose mean cost is relatively small, but not necessarily - /// minimal. - /// - /// \param limit The maximum allowed number of iterations during - /// the search process. Its default value implies that the algorithm - /// runs until it finds the exact optimal solution. - /// - /// \return The termination cause of the search process. - /// For more information, see \ref TerminationCause. - TerminationCause findCycleMean(int limit = - std::numeric_limits::max()) { - // Initialize and find strongly connected components - init(); - findComponents(); - - // Find the minimum cycle mean in the components - int iter_count = 0; - bool iter_limit_reached = false; - for (int comp = 0; comp < _comp_num; ++comp) { - // Find the minimum mean cycle in the current component - if (!buildPolicyGraph(comp)) continue; - while (true) { - if (++iter_count > limit) { - iter_limit_reached = true; - break; - } - findPolicyCycle(); - if (!computeNodeDistances()) break; - } - - // Update the best cycle (global minimum mean cycle) - if ( _curr_found && (!_best_found || - _curr_cost * _best_size < _best_cost * _curr_size) ) { - _best_found = true; - _best_cost = _curr_cost; - _best_size = _curr_size; - _best_node = _curr_node; - } - - if (iter_limit_reached) break; - } - - if (iter_limit_reached) { - return ITERATION_LIMIT; - } else { - return _best_found ? OPTIMAL : NO_CYCLE; - } - } - - /// \brief Find a minimum mean directed cycle. - /// - /// This function finds a directed cycle of minimum mean cost - /// in the digraph using the data computed by findCycleMean(). - /// - /// \return \c true if a directed cycle exists in the digraph. - /// - /// \pre \ref findCycleMean() must be called before using this function. - bool findCycle() { - if (!_best_found) return false; - _cycle_path->addBack(_policy[_best_node]); - for ( Node v = _best_node; - (v = _gr.target(_policy[v])) != _best_node; ) { - _cycle_path->addBack(_policy[v]); - } - return true; - } - - /// @} - - /// \name Query Functions - /// The results of the algorithm can be obtained using these - /// functions.\n - /// The algorithm should be executed before using them. - - /// @{ - - /// \brief Return the total cost of the found cycle. - /// - /// This function returns the total cost of the found cycle. - /// - /// \pre \ref run() or \ref findCycleMean() must be called before - /// using this function. - Cost cycleCost() const { - return static_cast(_best_cost); - } - - /// \brief Return the number of arcs on the found cycle. - /// - /// This function returns the number of arcs on the found cycle. - /// - /// \pre \ref run() or \ref findCycleMean() must be called before - /// using this function. - int cycleSize() const { - return _best_size; - } - - /// \brief Return the mean cost of the found cycle. - /// - /// This function returns the mean cost of the found cycle. - /// - /// \note alg.cycleMean() is just a shortcut of the - /// following code. - /// \code - /// return static_cast(alg.cycleCost()) / alg.cycleSize(); - /// \endcode - /// - /// \pre \ref run() or \ref findCycleMean() must be called before - /// using this function. - double cycleMean() const { - return static_cast(_best_cost) / _best_size; - } - - /// \brief Return the found cycle. - /// - /// This function returns a const reference to the path structure - /// storing the found cycle. - /// - /// \pre \ref run() or \ref findCycle() must be called before using - /// this function. - const Path& cycle() const { - return *_cycle_path; - } - - ///@} - - private: - - // Initialize - void init() { - if (!_cycle_path) { - _local_path = true; - _cycle_path = new Path; - } - _queue.resize(countNodes(_gr)); - _best_found = false; - _best_cost = 0; - _best_size = 1; - _cycle_path->clear(); - } - - // Find strongly connected components and initialize _comp_nodes - // and _in_arcs - void findComponents() { - _comp_num = stronglyConnectedComponents(_gr, _comp); - _comp_nodes.resize(_comp_num); - if (_comp_num == 1) { - _comp_nodes[0].clear(); - for (NodeIt n(_gr); n != INVALID; ++n) { - _comp_nodes[0].push_back(n); - _in_arcs[n].clear(); - for (InArcIt a(_gr, n); a != INVALID; ++a) { - _in_arcs[n].push_back(a); - } - } - } else { - for (int i = 0; i < _comp_num; ++i) - _comp_nodes[i].clear(); - for (NodeIt n(_gr); n != INVALID; ++n) { - int k = _comp[n]; - _comp_nodes[k].push_back(n); - _in_arcs[n].clear(); - for (InArcIt a(_gr, n); a != INVALID; ++a) { - if (_comp[_gr.source(a)] == k) _in_arcs[n].push_back(a); - } - } - } - } - - // Build the policy graph in the given strongly connected component - // (the out-degree of every node is 1) - bool buildPolicyGraph(int comp) { - _nodes = &(_comp_nodes[comp]); - if (_nodes->size() < 1 || - (_nodes->size() == 1 && _in_arcs[(*_nodes)[0]].size() == 0)) { - return false; - } - for (int i = 0; i < int(_nodes->size()); ++i) { - _dist[(*_nodes)[i]] = INF; - } - Node u, v; - Arc e; - for (int i = 0; i < int(_nodes->size()); ++i) { - v = (*_nodes)[i]; - for (int j = 0; j < int(_in_arcs[v].size()); ++j) { - e = _in_arcs[v][j]; - u = _gr.source(e); - if (_cost[e] < _dist[u]) { - _dist[u] = _cost[e]; - _policy[u] = e; - } - } - } - return true; - } - - // Find the minimum mean cycle in the policy graph - void findPolicyCycle() { - for (int i = 0; i < int(_nodes->size()); ++i) { - _level[(*_nodes)[i]] = -1; - } - LargeCost ccost; - int csize; - Node u, v; - _curr_found = false; - for (int i = 0; i < int(_nodes->size()); ++i) { - u = (*_nodes)[i]; - if (_level[u] >= 0) continue; - for (; _level[u] < 0; u = _gr.target(_policy[u])) { - _level[u] = i; - } - if (_level[u] == i) { - // A cycle is found - ccost = _cost[_policy[u]]; - csize = 1; - for (v = u; (v = _gr.target(_policy[v])) != u; ) { - ccost += _cost[_policy[v]]; - ++csize; - } - if ( !_curr_found || - (ccost * _curr_size < _curr_cost * csize) ) { - _curr_found = true; - _curr_cost = ccost; - _curr_size = csize; - _curr_node = u; - } - } - } - } - - // Contract the policy graph and compute node distances - bool computeNodeDistances() { - // Find the component of the main cycle and compute node distances - // using reverse BFS - for (int i = 0; i < int(_nodes->size()); ++i) { - _reached[(*_nodes)[i]] = false; - } - _qfront = _qback = 0; - _queue[0] = _curr_node; - _reached[_curr_node] = true; - _dist[_curr_node] = 0; - Node u, v; - Arc e; - while (_qfront <= _qback) { - v = _queue[_qfront++]; - for (int j = 0; j < int(_in_arcs[v].size()); ++j) { - e = _in_arcs[v][j]; - u = _gr.source(e); - if (_policy[u] == e && !_reached[u]) { - _reached[u] = true; - _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost; - _queue[++_qback] = u; - } - } - } - - // Connect all other nodes to this component and compute node - // distances using reverse BFS - _qfront = 0; - while (_qback < int(_nodes->size())-1) { - v = _queue[_qfront++]; - for (int j = 0; j < int(_in_arcs[v].size()); ++j) { - e = _in_arcs[v][j]; - u = _gr.source(e); - if (!_reached[u]) { - _reached[u] = true; - _policy[u] = e; - _dist[u] = _dist[v] + _cost[e] * _curr_size - _curr_cost; - _queue[++_qback] = u; - } - } - } - - // Improve node distances - bool improved = false; - for (int i = 0; i < int(_nodes->size()); ++i) { - v = (*_nodes)[i]; - for (int j = 0; j < int(_in_arcs[v].size()); ++j) { - e = _in_arcs[v][j]; - u = _gr.source(e); - LargeCost delta = _dist[v] + _cost[e] * _curr_size - _curr_cost; - if (_tolerance.less(delta, _dist[u])) { - _dist[u] = delta; - _policy[u] = e; - improved = true; - } - } - } - return improved; - } - - }; //class HowardMmc - - ///@} - -} //namespace lemon - -#endif //LEMON_HOWARD_MMC_H diff --git a/deps/lemon/lemon/hypercube_graph.h b/deps/lemon/lemon/hypercube_graph.h deleted file mode 100644 index 2cf37ad49..000000000 --- a/deps/lemon/lemon/hypercube_graph.h +++ /dev/null @@ -1,459 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef HYPERCUBE_GRAPH_H -#define HYPERCUBE_GRAPH_H - -#include -#include -#include -#include - -///\ingroup graphs -///\file -///\brief HypercubeGraph class. - -namespace lemon { - - class HypercubeGraphBase { - - public: - - typedef HypercubeGraphBase Graph; - - class Node; - class Edge; - class Arc; - - public: - - HypercubeGraphBase() {} - - protected: - - void construct(int dim) { - LEMON_ASSERT(dim >= 1, "The number of dimensions must be at least 1."); - _dim = dim; - _node_num = 1 << dim; - _edge_num = dim * (1 << (dim-1)); - } - - public: - - typedef True NodeNumTag; - typedef True EdgeNumTag; - typedef True ArcNumTag; - - int nodeNum() const { return _node_num; } - int edgeNum() const { return _edge_num; } - int arcNum() const { return 2 * _edge_num; } - - int maxNodeId() const { return _node_num - 1; } - int maxEdgeId() const { return _edge_num - 1; } - int maxArcId() const { return 2 * _edge_num - 1; } - - static Node nodeFromId(int id) { return Node(id); } - static Edge edgeFromId(int id) { return Edge(id); } - static Arc arcFromId(int id) { return Arc(id); } - - static int id(Node node) { return node._id; } - static int id(Edge edge) { return edge._id; } - static int id(Arc arc) { return arc._id; } - - Node u(Edge edge) const { - int base = edge._id & ((1 << (_dim-1)) - 1); - int k = edge._id >> (_dim-1); - return ((base >> k) << (k+1)) | (base & ((1 << k) - 1)); - } - - Node v(Edge edge) const { - int base = edge._id & ((1 << (_dim-1)) - 1); - int k = edge._id >> (_dim-1); - return ((base >> k) << (k+1)) | (base & ((1 << k) - 1)) | (1 << k); - } - - Node source(Arc arc) const { - return (arc._id & 1) == 1 ? u(arc) : v(arc); - } - - Node target(Arc arc) const { - return (arc._id & 1) == 1 ? v(arc) : u(arc); - } - - typedef True FindEdgeTag; - typedef True FindArcTag; - - Edge findEdge(Node u, Node v, Edge prev = INVALID) const { - if (prev != INVALID) return INVALID; - int d = u._id ^ v._id; - int k = 0; - if (d == 0) return INVALID; - for ( ; (d & 1) == 0; d >>= 1) ++k; - if (d >> 1 != 0) return INVALID; - return (k << (_dim-1)) | ((u._id >> (k+1)) << k) | - (u._id & ((1 << k) - 1)); - } - - Arc findArc(Node u, Node v, Arc prev = INVALID) const { - Edge edge = findEdge(u, v, prev); - if (edge == INVALID) return INVALID; - int k = edge._id >> (_dim-1); - return ((u._id >> k) & 1) == 1 ? edge._id << 1 : (edge._id << 1) | 1; - } - - class Node { - friend class HypercubeGraphBase; - - protected: - int _id; - Node(int id) : _id(id) {} - public: - Node() {} - Node (Invalid) : _id(-1) {} - bool operator==(const Node node) const {return _id == node._id;} - bool operator!=(const Node node) const {return _id != node._id;} - bool operator<(const Node node) const {return _id < node._id;} - }; - - class Edge { - friend class HypercubeGraphBase; - friend class Arc; - - protected: - int _id; - - Edge(int id) : _id(id) {} - - public: - Edge() {} - Edge (Invalid) : _id(-1) {} - bool operator==(const Edge edge) const {return _id == edge._id;} - bool operator!=(const Edge edge) const {return _id != edge._id;} - bool operator<(const Edge edge) const {return _id < edge._id;} - }; - - class Arc { - friend class HypercubeGraphBase; - - protected: - int _id; - - Arc(int id) : _id(id) {} - - public: - Arc() {} - Arc (Invalid) : _id(-1) {} - operator Edge() const { return _id != -1 ? Edge(_id >> 1) : INVALID; } - bool operator==(const Arc arc) const {return _id == arc._id;} - bool operator!=(const Arc arc) const {return _id != arc._id;} - bool operator<(const Arc arc) const {return _id < arc._id;} - }; - - void first(Node& node) const { - node._id = _node_num - 1; - } - - static void next(Node& node) { - --node._id; - } - - void first(Edge& edge) const { - edge._id = _edge_num - 1; - } - - static void next(Edge& edge) { - --edge._id; - } - - void first(Arc& arc) const { - arc._id = 2 * _edge_num - 1; - } - - static void next(Arc& arc) { - --arc._id; - } - - void firstInc(Edge& edge, bool& dir, const Node& node) const { - edge._id = node._id >> 1; - dir = (node._id & 1) == 0; - } - - void nextInc(Edge& edge, bool& dir) const { - Node n = dir ? u(edge) : v(edge); - int k = (edge._id >> (_dim-1)) + 1; - if (k < _dim) { - edge._id = (k << (_dim-1)) | - ((n._id >> (k+1)) << k) | (n._id & ((1 << k) - 1)); - dir = ((n._id >> k) & 1) == 0; - } else { - edge._id = -1; - dir = true; - } - } - - void firstOut(Arc& arc, const Node& node) const { - arc._id = ((node._id >> 1) << 1) | (~node._id & 1); - } - - void nextOut(Arc& arc) const { - Node n = (arc._id & 1) == 1 ? u(arc) : v(arc); - int k = (arc._id >> _dim) + 1; - if (k < _dim) { - arc._id = (k << (_dim-1)) | - ((n._id >> (k+1)) << k) | (n._id & ((1 << k) - 1)); - arc._id = (arc._id << 1) | (~(n._id >> k) & 1); - } else { - arc._id = -1; - } - } - - void firstIn(Arc& arc, const Node& node) const { - arc._id = ((node._id >> 1) << 1) | (node._id & 1); - } - - void nextIn(Arc& arc) const { - Node n = (arc._id & 1) == 1 ? v(arc) : u(arc); - int k = (arc._id >> _dim) + 1; - if (k < _dim) { - arc._id = (k << (_dim-1)) | - ((n._id >> (k+1)) << k) | (n._id & ((1 << k) - 1)); - arc._id = (arc._id << 1) | ((n._id >> k) & 1); - } else { - arc._id = -1; - } - } - - static bool direction(Arc arc) { - return (arc._id & 1) == 1; - } - - static Arc direct(Edge edge, bool dir) { - return Arc((edge._id << 1) | (dir ? 1 : 0)); - } - - int dimension() const { - return _dim; - } - - bool projection(Node node, int n) const { - return static_cast(node._id & (1 << n)); - } - - int dimension(Edge edge) const { - return edge._id >> (_dim-1); - } - - int dimension(Arc arc) const { - return arc._id >> _dim; - } - - static int index(Node node) { - return node._id; - } - - Node operator()(int ix) const { - return Node(ix); - } - - private: - int _dim; - int _node_num, _edge_num; - }; - - - typedef GraphExtender ExtendedHypercubeGraphBase; - - /// \ingroup graphs - /// - /// \brief Hypercube graph class - /// - /// HypercubeGraph implements a special graph type. The nodes of the - /// graph are indexed with integers having at most \c dim binary digits. - /// Two nodes are connected in the graph if and only if their indices - /// differ only on one position in the binary form. - /// This class is completely static and it needs constant memory space. - /// Thus you can neither add nor delete nodes or edges, however, - /// the structure can be resized using resize(). - /// - /// This type fully conforms to the \ref concepts::Graph "Graph concept". - /// Most of its member functions and nested classes are documented - /// only in the concept class. - /// - /// This class provides constant time counting for nodes, edges and arcs. - /// - /// \note The type of the indices is chosen to \c int for efficiency - /// reasons. Thus the maximum dimension of this implementation is 26 - /// (assuming that the size of \c int is 32 bit). - class HypercubeGraph : public ExtendedHypercubeGraphBase { - typedef ExtendedHypercubeGraphBase Parent; - - public: - - /// \brief Constructs a hypercube graph with \c dim dimensions. - /// - /// Constructs a hypercube graph with \c dim dimensions. - HypercubeGraph(int dim) { construct(dim); } - - /// \brief Resizes the graph - /// - /// This function resizes the graph. It fully destroys and - /// rebuilds the structure, therefore the maps of the graph will be - /// reallocated automatically and the previous values will be lost. - void resize(int dim) { - Parent::notifier(Arc()).clear(); - Parent::notifier(Edge()).clear(); - Parent::notifier(Node()).clear(); - construct(dim); - Parent::notifier(Node()).build(); - Parent::notifier(Edge()).build(); - Parent::notifier(Arc()).build(); - } - - /// \brief The number of dimensions. - /// - /// Gives back the number of dimensions. - int dimension() const { - return Parent::dimension(); - } - - /// \brief Returns \c true if the n'th bit of the node is one. - /// - /// Returns \c true if the n'th bit of the node is one. - bool projection(Node node, int n) const { - return Parent::projection(node, n); - } - - /// \brief The dimension id of an edge. - /// - /// Gives back the dimension id of the given edge. - /// It is in the range [0..dim-1]. - int dimension(Edge edge) const { - return Parent::dimension(edge); - } - - /// \brief The dimension id of an arc. - /// - /// Gives back the dimension id of the given arc. - /// It is in the range [0..dim-1]. - int dimension(Arc arc) const { - return Parent::dimension(arc); - } - - /// \brief The index of a node. - /// - /// Gives back the index of the given node. - /// The lower bits of the integer describes the node. - static int index(Node node) { - return Parent::index(node); - } - - /// \brief Gives back a node by its index. - /// - /// Gives back a node by its index. - Node operator()(int ix) const { - return Parent::operator()(ix); - } - - /// \brief Number of nodes. - int nodeNum() const { return Parent::nodeNum(); } - /// \brief Number of edges. - int edgeNum() const { return Parent::edgeNum(); } - /// \brief Number of arcs. - int arcNum() const { return Parent::arcNum(); } - - /// \brief Linear combination map. - /// - /// This map makes possible to give back a linear combination - /// for each node. It works like the \c std::accumulate function, - /// so it accumulates the \c bf binary function with the \c fv first - /// value. The map accumulates only on that positions (dimensions) - /// where the index of the node is one. The values that have to be - /// accumulated should be given by the \c begin and \c end iterators - /// and the length of this range should be equal to the dimension - /// number of the graph. - /// - ///\code - /// const int DIM = 3; - /// HypercubeGraph graph(DIM); - /// dim2::Point base[DIM]; - /// for (int k = 0; k < DIM; ++k) { - /// base[k].x = rnd(); - /// base[k].y = rnd(); - /// } - /// HypercubeGraph::HyperMap > - /// pos(graph, base, base + DIM, dim2::Point(0.0, 0.0)); - ///\endcode - /// - /// \see HypercubeGraph - template > - class HyperMap { - public: - - /// \brief The key type of the map - typedef Node Key; - /// \brief The value type of the map - typedef T Value; - - /// \brief Constructor for HyperMap. - /// - /// Construct a HyperMap for the given graph. The values that have - /// to be accumulated should be given by the \c begin and \c end - /// iterators and the length of this range should be equal to the - /// dimension number of the graph. - /// - /// This map accumulates the \c bf binary function with the \c fv - /// first value on that positions (dimensions) where the index of - /// the node is one. - template - HyperMap(const Graph& graph, It begin, It end, - T fv = 0, const BF& bf = BF()) - : _graph(graph), _values(begin, end), _first_value(fv), _bin_func(bf) - { - LEMON_ASSERT(_values.size() == graph.dimension(), - "Wrong size of range"); - } - - /// \brief The partial accumulated value. - /// - /// Gives back the partial accumulated value. - Value operator[](const Key& k) const { - Value val = _first_value; - int id = _graph.index(k); - int n = 0; - while (id != 0) { - if (id & 1) { - val = _bin_func(val, _values[n]); - } - id >>= 1; - ++n; - } - return val; - } - - private: - const Graph& _graph; - std::vector _values; - T _first_value; - BF _bin_func; - }; - - }; - -} - -#endif diff --git a/deps/lemon/lemon/insertion_tsp.h b/deps/lemon/lemon/insertion_tsp.h deleted file mode 100644 index fa16825db..000000000 --- a/deps/lemon/lemon/insertion_tsp.h +++ /dev/null @@ -1,533 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_INSERTION_TSP_H -#define LEMON_INSERTION_TSP_H - -/// \ingroup tsp -/// \file -/// \brief Insertion algorithm for symmetric TSP - -#include -#include -#include -#include -#include - -namespace lemon { - - /// \ingroup tsp - /// - /// \brief Insertion algorithm for symmetric TSP. - /// - /// InsertionTsp implements the insertion heuristic for solving - /// symmetric \ref tsp "TSP". - /// - /// This is a fast and effective tour construction method that has - /// many variants. - /// It starts with a subtour containing a few nodes of the graph and it - /// iteratively inserts the other nodes into this subtour according to a - /// certain node selection rule. - /// - /// This method is among the fastest TSP algorithms, and it typically - /// provides quite good solutions (usually much better than - /// \ref NearestNeighborTsp and \ref GreedyTsp). - /// - /// InsertionTsp implements four different node selection rules, - /// from which the most effective one (\e farthest \e node \e selection) - /// is used by default. - /// With this choice, the algorithm runs in O(n2) time. - /// For more information, see \ref SelectionRule. - /// - /// \tparam CM Type of the cost map. - template - class InsertionTsp - { - public: - - /// Type of the cost map - typedef CM CostMap; - /// Type of the edge costs - typedef typename CM::Value Cost; - - private: - - GRAPH_TYPEDEFS(FullGraph); - - const FullGraph &_gr; - const CostMap &_cost; - std::vector _notused; - std::vector _tour; - Cost _sum; - - public: - - /// \brief Constants for specifying the node selection rule. - /// - /// Enum type containing constants for specifying the node selection - /// rule for the \ref run() function. - /// - /// During the algorithm, nodes are selected for addition to the current - /// subtour according to the applied rule. - /// The FARTHEST method is one of the fastest selection rules, and - /// it is typically the most effective, thus it is the default - /// option. The RANDOM rule usually gives slightly worse results, - /// but it is more robust. - /// - /// The desired selection rule can be specified as a parameter of the - /// \ref run() function. - enum SelectionRule { - - /// An unvisited node having minimum distance from the current - /// subtour is selected at each step. - /// The algorithm runs in O(n2) time using this - /// selection rule. - NEAREST, - - /// An unvisited node having maximum distance from the current - /// subtour is selected at each step. - /// The algorithm runs in O(n2) time using this - /// selection rule. - FARTHEST, - - /// An unvisited node whose insertion results in the least - /// increase of the subtour's total cost is selected at each step. - /// The algorithm runs in O(n3) time using this - /// selection rule, but in most cases, it is almost as fast as - /// with other rules. - CHEAPEST, - - /// An unvisited node is selected randomly without any evaluation - /// at each step. - /// The global \ref rnd "random number generator instance" is used. - /// You can seed it before executing the algorithm, if you - /// would like to. - /// The algorithm runs in O(n2) time using this - /// selection rule. - RANDOM - }; - - public: - - /// \brief Constructor - /// - /// Constructor. - /// \param gr The \ref FullGraph "full graph" the algorithm runs on. - /// \param cost The cost map. - InsertionTsp(const FullGraph &gr, const CostMap &cost) - : _gr(gr), _cost(cost) {} - - /// \name Execution Control - /// @{ - - /// \brief Runs the algorithm. - /// - /// This function runs the algorithm. - /// - /// \param rule The node selection rule. For more information, see - /// \ref SelectionRule. - /// - /// \return The total cost of the found tour. - Cost run(SelectionRule rule = FARTHEST) { - _tour.clear(); - - if (_gr.nodeNum() == 0) return _sum = 0; - else if (_gr.nodeNum() == 1) { - _tour.push_back(_gr(0)); - return _sum = 0; - } - - switch (rule) { - case NEAREST: - init(true); - start >, - DefaultInsertion>(); - break; - case FARTHEST: - init(false); - start >, - DefaultInsertion>(); - break; - case CHEAPEST: - init(true); - start(); - break; - case RANDOM: - init(true); - start(); - break; - } - return _sum; - } - - /// @} - - /// \name Query Functions - /// @{ - - /// \brief The total cost of the found tour. - /// - /// This function returns the total cost of the found tour. - /// - /// \pre run() must be called before using this function. - Cost tourCost() const { - return _sum; - } - - /// \brief Returns a const reference to the node sequence of the - /// found tour. - /// - /// This function returns a const reference to a vector - /// that stores the node sequence of the found tour. - /// - /// \pre run() must be called before using this function. - const std::vector& tourNodes() const { - return _tour; - } - - /// \brief Gives back the node sequence of the found tour. - /// - /// This function copies the node sequence of the found tour into - /// an STL container through the given output iterator. The - /// value_type of the container must be FullGraph::Node. - /// For example, - /// \code - /// std::vector nodes(countNodes(graph)); - /// tsp.tourNodes(nodes.begin()); - /// \endcode - /// or - /// \code - /// std::list nodes; - /// tsp.tourNodes(std::back_inserter(nodes)); - /// \endcode - /// - /// \pre run() must be called before using this function. - template - void tourNodes(Iterator out) const { - std::copy(_tour.begin(), _tour.end(), out); - } - - /// \brief Gives back the found tour as a path. - /// - /// This function copies the found tour as a list of arcs/edges into - /// the given \ref lemon::concepts::Path "path structure". - /// - /// \pre run() must be called before using this function. - template - void tour(Path &path) const { - path.clear(); - for (int i = 0; i < int(_tour.size()) - 1; ++i) { - path.addBack(_gr.arc(_tour[i], _tour[i+1])); - } - if (int(_tour.size()) >= 2) { - path.addBack(_gr.arc(_tour.back(), _tour.front())); - } - } - - /// @} - - private: - - // Initializes the algorithm - void init(bool min) { - Edge min_edge = min ? mapMin(_gr, _cost) : mapMax(_gr, _cost); - - _tour.clear(); - _tour.push_back(_gr.u(min_edge)); - _tour.push_back(_gr.v(min_edge)); - - _notused.clear(); - for (NodeIt n(_gr); n!=INVALID; ++n) { - if (n != _gr.u(min_edge) && n != _gr.v(min_edge)) { - _notused.push_back(n); - } - } - - _sum = _cost[min_edge] * 2; - } - - // Executes the algorithm - template - void start() { - SelectionFunctor selectNode(_gr, _cost, _tour, _notused); - InsertionFunctor insertNode(_gr, _cost, _tour, _sum); - - for (int i=0; i<_gr.nodeNum()-2; ++i) { - insertNode.insert(selectNode.select()); - } - - _sum = _cost[_gr.edge(_tour.back(), _tour.front())]; - for (int i = 0; i < int(_tour.size())-1; ++i) { - _sum += _cost[_gr.edge(_tour[i], _tour[i+1])]; - } - } - - - // Implementation of the nearest and farthest selection rule - template - class ComparingSelection { - public: - ComparingSelection(const FullGraph &gr, const CostMap &cost, - std::vector &tour, std::vector ¬used) - : _gr(gr), _cost(cost), _tour(tour), _notused(notused), - _dist(gr, 0), _compare() - { - // Compute initial distances for the unused nodes - for (unsigned int i=0; i<_notused.size(); ++i) { - Node u = _notused[i]; - Cost min_dist = _cost[_gr.edge(u, _tour[0])]; - for (unsigned int j=1; j<_tour.size(); ++j) { - Cost curr = _cost[_gr.edge(u, _tour[j])]; - if (curr < min_dist) { - min_dist = curr; - } - } - _dist[u] = min_dist; - } - } - - Node select() { - - // Select an used node with minimum distance - Cost ins_dist = 0; - int ins_node = -1; - for (unsigned int i=0; i<_notused.size(); ++i) { - Cost curr = _dist[_notused[i]]; - if (_compare(curr, ins_dist) || ins_node == -1) { - ins_dist = curr; - ins_node = i; - } - } - - // Remove the selected node from the unused vector - Node sn = _notused[ins_node]; - _notused[ins_node] = _notused.back(); - _notused.pop_back(); - - // Update the distances of the remaining nodes - for (unsigned int i=0; i<_notused.size(); ++i) { - Node u = _notused[i]; - Cost nc = _cost[_gr.edge(sn, u)]; - if (nc < _dist[u]) { - _dist[u] = nc; - } - } - - return sn; - } - - private: - const FullGraph &_gr; - const CostMap &_cost; - std::vector &_tour; - std::vector &_notused; - FullGraph::NodeMap _dist; - Comparator _compare; - }; - - // Implementation of the cheapest selection rule - class CheapestSelection { - private: - Cost costDiff(Node u, Node v, Node w) const { - return - _cost[_gr.edge(u, w)] + - _cost[_gr.edge(v, w)] - - _cost[_gr.edge(u, v)]; - } - - public: - CheapestSelection(const FullGraph &gr, const CostMap &cost, - std::vector &tour, std::vector ¬used) - : _gr(gr), _cost(cost), _tour(tour), _notused(notused), - _ins_cost(gr, 0), _ins_pos(gr, -1) - { - // Compute insertion cost and position for the unused nodes - for (unsigned int i=0; i<_notused.size(); ++i) { - Node u = _notused[i]; - Cost min_cost = costDiff(_tour.back(), _tour.front(), u); - int min_pos = 0; - for (unsigned int j=1; j<_tour.size(); ++j) { - Cost curr_cost = costDiff(_tour[j-1], _tour[j], u); - if (curr_cost < min_cost) { - min_cost = curr_cost; - min_pos = j; - } - } - _ins_cost[u] = min_cost; - _ins_pos[u] = min_pos; - } - } - - Cost select() { - - // Select an used node with minimum insertion cost - Cost min_cost = 0; - int min_node = -1; - for (unsigned int i=0; i<_notused.size(); ++i) { - Cost curr_cost = _ins_cost[_notused[i]]; - if (curr_cost < min_cost || min_node == -1) { - min_cost = curr_cost; - min_node = i; - } - } - - // Remove the selected node from the unused vector - Node sn = _notused[min_node]; - _notused[min_node] = _notused.back(); - _notused.pop_back(); - - // Insert the selected node into the tour - const int ipos = _ins_pos[sn]; - _tour.insert(_tour.begin() + ipos, sn); - - // Update the insertion cost and position of the remaining nodes - for (unsigned int i=0; i<_notused.size(); ++i) { - Node u = _notused[i]; - Cost curr_cost = _ins_cost[u]; - int curr_pos = _ins_pos[u]; - - int ipos_prev = ipos == 0 ? _tour.size()-1 : ipos-1; - int ipos_next = ipos == int(_tour.size())-1 ? 0 : ipos+1; - Cost nc1 = costDiff(_tour[ipos_prev], _tour[ipos], u); - Cost nc2 = costDiff(_tour[ipos], _tour[ipos_next], u); - - if (nc1 <= curr_cost || nc2 <= curr_cost) { - // A new position is better than the old one - if (nc1 <= nc2) { - curr_cost = nc1; - curr_pos = ipos; - } else { - curr_cost = nc2; - curr_pos = ipos_next; - } - } - else { - if (curr_pos == ipos) { - // The minimum should be found again - curr_cost = costDiff(_tour.back(), _tour.front(), u); - curr_pos = 0; - for (unsigned int j=1; j<_tour.size(); ++j) { - Cost tmp_cost = costDiff(_tour[j-1], _tour[j], u); - if (tmp_cost < curr_cost) { - curr_cost = tmp_cost; - curr_pos = j; - } - } - } - else if (curr_pos > ipos) { - ++curr_pos; - } - } - - _ins_cost[u] = curr_cost; - _ins_pos[u] = curr_pos; - } - - return min_cost; - } - - private: - const FullGraph &_gr; - const CostMap &_cost; - std::vector &_tour; - std::vector &_notused; - FullGraph::NodeMap _ins_cost; - FullGraph::NodeMap _ins_pos; - }; - - // Implementation of the random selection rule - class RandomSelection { - public: - RandomSelection(const FullGraph &, const CostMap &, - std::vector &, std::vector ¬used) - : _notused(notused) {} - - Node select() const { - const int index = rnd[_notused.size()]; - Node n = _notused[index]; - _notused[index] = _notused.back(); - _notused.pop_back(); - return n; - } - - private: - std::vector &_notused; - }; - - - // Implementation of the default insertion method - class DefaultInsertion { - private: - Cost costDiff(Node u, Node v, Node w) const { - return - _cost[_gr.edge(u, w)] + - _cost[_gr.edge(v, w)] - - _cost[_gr.edge(u, v)]; - } - - public: - DefaultInsertion(const FullGraph &gr, const CostMap &cost, - std::vector &tour, Cost &total_cost) : - _gr(gr), _cost(cost), _tour(tour), _total(total_cost) {} - - void insert(Node n) const { - int min = 0; - Cost min_val = - costDiff(_tour.front(), _tour.back(), n); - - for (unsigned int i=1; i<_tour.size(); ++i) { - Cost tmp = costDiff(_tour[i-1], _tour[i], n); - if (tmp < min_val) { - min = i; - min_val = tmp; - } - } - - _tour.insert(_tour.begin()+min, n); - _total += min_val; - } - - private: - const FullGraph &_gr; - const CostMap &_cost; - std::vector &_tour; - Cost &_total; - }; - - // Implementation of a special insertion method for the cheapest - // selection rule - class CheapestInsertion { - TEMPLATE_GRAPH_TYPEDEFS(FullGraph); - public: - CheapestInsertion(const FullGraph &, const CostMap &, - std::vector &, Cost &total_cost) : - _total(total_cost) {} - - void insert(Cost diff) const { - _total += diff; - } - - private: - Cost &_total; - }; - - }; - -}; // namespace lemon - -#endif diff --git a/deps/lemon/lemon/karp_mmc.h b/deps/lemon/lemon/karp_mmc.h deleted file mode 100644 index 1f05d4369..000000000 --- a/deps/lemon/lemon/karp_mmc.h +++ /dev/null @@ -1,590 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_KARP_MMC_H -#define LEMON_KARP_MMC_H - -/// \ingroup min_mean_cycle -/// -/// \file -/// \brief Karp's algorithm for finding a minimum mean cycle. - -#include -#include -#include -#include -#include -#include - -namespace lemon { - - /// \brief Default traits class of KarpMmc class. - /// - /// Default traits class of KarpMmc class. - /// \tparam GR The type of the digraph. - /// \tparam CM The type of the cost map. - /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. -#ifdef DOXYGEN - template -#else - template ::is_integer> -#endif - struct KarpMmcDefaultTraits - { - /// The type of the digraph - typedef GR Digraph; - /// The type of the cost map - typedef CM CostMap; - /// The type of the arc costs - typedef typename CostMap::Value Cost; - - /// \brief The large cost type used for internal computations - /// - /// The large cost type used for internal computations. - /// It is \c long \c long if the \c Cost type is integer, - /// otherwise it is \c double. - /// \c Cost must be convertible to \c LargeCost. - typedef double LargeCost; - - /// The tolerance type used for internal computations - typedef lemon::Tolerance Tolerance; - - /// \brief The path type of the found cycles - /// - /// The path type of the found cycles. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addFront() function. - typedef lemon::Path Path; - }; - - // Default traits class for integer cost types - template - struct KarpMmcDefaultTraits - { - typedef GR Digraph; - typedef CM CostMap; - typedef typename CostMap::Value Cost; -#ifdef LEMON_HAVE_LONG_LONG - typedef long long LargeCost; -#else - typedef long LargeCost; -#endif - typedef lemon::Tolerance Tolerance; - typedef lemon::Path Path; - }; - - - /// \addtogroup min_mean_cycle - /// @{ - - /// \brief Implementation of Karp's algorithm for finding a minimum - /// mean cycle. - /// - /// This class implements Karp's algorithm for finding a directed - /// cycle of minimum mean cost in a digraph - /// \cite karp78characterization, \cite dasdan98minmeancycle. - /// It runs in time O(nm) and uses space O(n2+m). - /// - /// \tparam GR The type of the digraph the algorithm runs on. - /// \tparam CM The type of the cost map. The default - /// map type is \ref concepts::Digraph::ArcMap "GR::ArcMap". - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref KarpMmcDefaultTraits - /// "KarpMmcDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template < typename GR, - typename CM = typename GR::template ArcMap, - typename TR = KarpMmcDefaultTraits > -#endif - class KarpMmc - { - public: - - /// The type of the digraph - typedef typename TR::Digraph Digraph; - /// The type of the cost map - typedef typename TR::CostMap CostMap; - /// The type of the arc costs - typedef typename TR::Cost Cost; - - /// \brief The large cost type - /// - /// The large cost type used for internal computations. - /// By default, it is \c long \c long if the \c Cost type is integer, - /// otherwise it is \c double. - typedef typename TR::LargeCost LargeCost; - - /// The tolerance type - typedef typename TR::Tolerance Tolerance; - - /// \brief The path type of the found cycles - /// - /// The path type of the found cycles. - /// Using the \ref lemon::KarpMmcDefaultTraits "default traits class", - /// it is \ref lemon::Path "Path". - typedef typename TR::Path Path; - - /// The \ref lemon::KarpMmcDefaultTraits "traits class" of the algorithm - typedef TR Traits; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - // Data sturcture for path data - struct PathData - { - LargeCost dist; - Arc pred; - PathData(LargeCost d, Arc p = INVALID) : - dist(d), pred(p) {} - }; - - typedef typename Digraph::template NodeMap > - PathDataNodeMap; - - private: - - // The digraph the algorithm runs on - const Digraph &_gr; - // The cost of the arcs - const CostMap &_cost; - - // Data for storing the strongly connected components - int _comp_num; - typename Digraph::template NodeMap _comp; - std::vector > _comp_nodes; - std::vector* _nodes; - typename Digraph::template NodeMap > _out_arcs; - - // Data for the found cycle - LargeCost _cycle_cost; - int _cycle_size; - Node _cycle_node; - - Path *_cycle_path; - bool _local_path; - - // Node map for storing path data - PathDataNodeMap _data; - // The processed nodes in the last round - std::vector _process; - - Tolerance _tolerance; - - // Infinite constant - const LargeCost INF; - - public: - - /// \name Named Template Parameters - /// @{ - - template - struct SetLargeCostTraits : public Traits { - typedef T LargeCost; - typedef lemon::Tolerance Tolerance; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c LargeCost type. - /// - /// \ref named-templ-param "Named parameter" for setting \c LargeCost - /// type. It is used for internal computations in the algorithm. - template - struct SetLargeCost - : public KarpMmc > { - typedef KarpMmc > Create; - }; - - template - struct SetPathTraits : public Traits { - typedef T Path; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c %Path type. - /// - /// \ref named-templ-param "Named parameter" for setting the \c %Path - /// type of the found cycles. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addFront() function. - template - struct SetPath - : public KarpMmc > { - typedef KarpMmc > Create; - }; - - /// @} - - protected: - - KarpMmc() {} - - public: - - /// \brief Constructor. - /// - /// The constructor of the class. - /// - /// \param digraph The digraph the algorithm runs on. - /// \param cost The costs of the arcs. - KarpMmc( const Digraph &digraph, - const CostMap &cost ) : - _gr(digraph), _cost(cost), _comp(digraph), _out_arcs(digraph), - _cycle_cost(0), _cycle_size(1), _cycle_node(INVALID), - _cycle_path(NULL), _local_path(false), _data(digraph), - INF(std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : - std::numeric_limits::max()) - {} - - /// Destructor. - ~KarpMmc() { - if (_local_path) delete _cycle_path; - } - - /// \brief Set the path structure for storing the found cycle. - /// - /// This function sets an external path structure for storing the - /// found cycle. - /// - /// If you don't call this function before calling \ref run() or - /// \ref findCycleMean(), a local \ref Path "path" structure - /// will be allocated. The destuctor deallocates this automatically - /// allocated object, of course. - /// - /// \note The algorithm calls only the \ref lemon::Path::addFront() - /// "addFront()" function of the given path structure. - /// - /// \return (*this) - KarpMmc& cycle(Path &path) { - if (_local_path) { - delete _cycle_path; - _local_path = false; - } - _cycle_path = &path; - return *this; - } - - /// \brief Set the tolerance used by the algorithm. - /// - /// This function sets the tolerance object used by the algorithm. - /// - /// \return (*this) - KarpMmc& tolerance(const Tolerance& tolerance) { - _tolerance = tolerance; - return *this; - } - - /// \brief Return a const reference to the tolerance. - /// - /// This function returns a const reference to the tolerance object - /// used by the algorithm. - const Tolerance& tolerance() const { - return _tolerance; - } - - /// \name Execution control - /// The simplest way to execute the algorithm is to call the \ref run() - /// function.\n - /// If you only need the minimum mean cost, you may call - /// \ref findCycleMean(). - - /// @{ - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. - /// It can be called more than once (e.g. if the underlying digraph - /// and/or the arc costs have been modified). - /// - /// \return \c true if a directed cycle exists in the digraph. - /// - /// \note mmc.run() is just a shortcut of the following code. - /// \code - /// return mmc.findCycleMean() && mmc.findCycle(); - /// \endcode - bool run() { - return findCycleMean() && findCycle(); - } - - /// \brief Find the minimum cycle mean. - /// - /// This function finds the minimum mean cost of the directed - /// cycles in the digraph. - /// - /// \return \c true if a directed cycle exists in the digraph. - bool findCycleMean() { - // Initialization and find strongly connected components - init(); - findComponents(); - - // Find the minimum cycle mean in the components - for (int comp = 0; comp < _comp_num; ++comp) { - if (!initComponent(comp)) continue; - processRounds(); - updateMinMean(); - } - return (_cycle_node != INVALID); - } - - /// \brief Find a minimum mean directed cycle. - /// - /// This function finds a directed cycle of minimum mean cost - /// in the digraph using the data computed by findCycleMean(). - /// - /// \return \c true if a directed cycle exists in the digraph. - /// - /// \pre \ref findCycleMean() must be called before using this function. - bool findCycle() { - if (_cycle_node == INVALID) return false; - IntNodeMap reached(_gr, -1); - int r = _data[_cycle_node].size(); - Node u = _cycle_node; - while (reached[u] < 0) { - reached[u] = --r; - u = _gr.source(_data[u][r].pred); - } - r = reached[u]; - Arc e = _data[u][r].pred; - _cycle_path->addFront(e); - _cycle_cost = _cost[e]; - _cycle_size = 1; - Node v; - while ((v = _gr.source(e)) != u) { - e = _data[v][--r].pred; - _cycle_path->addFront(e); - _cycle_cost += _cost[e]; - ++_cycle_size; - } - return true; - } - - /// @} - - /// \name Query Functions - /// The results of the algorithm can be obtained using these - /// functions.\n - /// The algorithm should be executed before using them. - - /// @{ - - /// \brief Return the total cost of the found cycle. - /// - /// This function returns the total cost of the found cycle. - /// - /// \pre \ref run() or \ref findCycleMean() must be called before - /// using this function. - Cost cycleCost() const { - return static_cast(_cycle_cost); - } - - /// \brief Return the number of arcs on the found cycle. - /// - /// This function returns the number of arcs on the found cycle. - /// - /// \pre \ref run() or \ref findCycleMean() must be called before - /// using this function. - int cycleSize() const { - return _cycle_size; - } - - /// \brief Return the mean cost of the found cycle. - /// - /// This function returns the mean cost of the found cycle. - /// - /// \note alg.cycleMean() is just a shortcut of the - /// following code. - /// \code - /// return static_cast(alg.cycleCost()) / alg.cycleSize(); - /// \endcode - /// - /// \pre \ref run() or \ref findCycleMean() must be called before - /// using this function. - double cycleMean() const { - return static_cast(_cycle_cost) / _cycle_size; - } - - /// \brief Return the found cycle. - /// - /// This function returns a const reference to the path structure - /// storing the found cycle. - /// - /// \pre \ref run() or \ref findCycle() must be called before using - /// this function. - const Path& cycle() const { - return *_cycle_path; - } - - ///@} - - private: - - // Initialization - void init() { - if (!_cycle_path) { - _local_path = true; - _cycle_path = new Path; - } - _cycle_path->clear(); - _cycle_cost = 0; - _cycle_size = 1; - _cycle_node = INVALID; - for (NodeIt u(_gr); u != INVALID; ++u) - _data[u].clear(); - } - - // Find strongly connected components and initialize _comp_nodes - // and _out_arcs - void findComponents() { - _comp_num = stronglyConnectedComponents(_gr, _comp); - _comp_nodes.resize(_comp_num); - if (_comp_num == 1) { - _comp_nodes[0].clear(); - for (NodeIt n(_gr); n != INVALID; ++n) { - _comp_nodes[0].push_back(n); - _out_arcs[n].clear(); - for (OutArcIt a(_gr, n); a != INVALID; ++a) { - _out_arcs[n].push_back(a); - } - } - } else { - for (int i = 0; i < _comp_num; ++i) - _comp_nodes[i].clear(); - for (NodeIt n(_gr); n != INVALID; ++n) { - int k = _comp[n]; - _comp_nodes[k].push_back(n); - _out_arcs[n].clear(); - for (OutArcIt a(_gr, n); a != INVALID; ++a) { - if (_comp[_gr.target(a)] == k) _out_arcs[n].push_back(a); - } - } - } - } - - // Initialize path data for the current component - bool initComponent(int comp) { - _nodes = &(_comp_nodes[comp]); - int n = _nodes->size(); - if (n < 1 || (n == 1 && _out_arcs[(*_nodes)[0]].size() == 0)) { - return false; - } - for (int i = 0; i < n; ++i) { - _data[(*_nodes)[i]].resize(n + 1, PathData(INF)); - } - return true; - } - - // Process all rounds of computing path data for the current component. - // _data[v][k] is the cost of a shortest directed walk from the root - // node to node v containing exactly k arcs. - void processRounds() { - Node start = (*_nodes)[0]; - _data[start][0] = PathData(0); - _process.clear(); - _process.push_back(start); - - int k, n = _nodes->size(); - for (k = 1; k <= n && int(_process.size()) < n; ++k) { - processNextBuildRound(k); - } - for ( ; k <= n; ++k) { - processNextFullRound(k); - } - } - - // Process one round and rebuild _process - void processNextBuildRound(int k) { - std::vector next; - Node u, v; - Arc e; - LargeCost d; - for (int i = 0; i < int(_process.size()); ++i) { - u = _process[i]; - for (int j = 0; j < int(_out_arcs[u].size()); ++j) { - e = _out_arcs[u][j]; - v = _gr.target(e); - d = _data[u][k-1].dist + _cost[e]; - if (_tolerance.less(d, _data[v][k].dist)) { - if (_data[v][k].dist == INF) next.push_back(v); - _data[v][k] = PathData(d, e); - } - } - } - _process.swap(next); - } - - // Process one round using _nodes instead of _process - void processNextFullRound(int k) { - Node u, v; - Arc e; - LargeCost d; - for (int i = 0; i < int(_nodes->size()); ++i) { - u = (*_nodes)[i]; - for (int j = 0; j < int(_out_arcs[u].size()); ++j) { - e = _out_arcs[u][j]; - v = _gr.target(e); - d = _data[u][k-1].dist + _cost[e]; - if (_tolerance.less(d, _data[v][k].dist)) { - _data[v][k] = PathData(d, e); - } - } - } - } - - // Update the minimum cycle mean - void updateMinMean() { - int n = _nodes->size(); - for (int i = 0; i < n; ++i) { - Node u = (*_nodes)[i]; - if (_data[u][n].dist == INF) continue; - LargeCost cost, max_cost = 0; - int size, max_size = 1; - bool found_curr = false; - for (int k = 0; k < n; ++k) { - if (_data[u][k].dist == INF) continue; - cost = _data[u][n].dist - _data[u][k].dist; - size = n - k; - if (!found_curr || cost * max_size > max_cost * size) { - found_curr = true; - max_cost = cost; - max_size = size; - } - } - if ( found_curr && (_cycle_node == INVALID || - max_cost * _cycle_size < _cycle_cost * max_size) ) { - _cycle_cost = max_cost; - _cycle_size = max_size; - _cycle_node = u; - } - } - } - - }; //class KarpMmc - - ///@} - -} //namespace lemon - -#endif //LEMON_KARP_MMC_H diff --git a/deps/lemon/lemon/kruskal.h b/deps/lemon/lemon/kruskal.h deleted file mode 100644 index 04c2ddb93..000000000 --- a/deps/lemon/lemon/kruskal.h +++ /dev/null @@ -1,324 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_KRUSKAL_H -#define LEMON_KRUSKAL_H - -#include -#include -#include -#include - -#include -#include - -///\ingroup spantree -///\file -///\brief Kruskal's algorithm to compute a minimum cost spanning tree - -namespace lemon { - - namespace _kruskal_bits { - - // Kruskal for directed graphs. - - template - typename disable_if, - typename In::value_type::second_type >::type - kruskal(const Digraph& digraph, const In& in, Out& out,dummy<0> = 0) { - typedef typename In::value_type::second_type Value; - typedef typename Digraph::template NodeMap IndexMap; - typedef typename Digraph::Node Node; - - IndexMap index(digraph); - UnionFind uf(index); - for (typename Digraph::NodeIt it(digraph); it != INVALID; ++it) { - uf.insert(it); - } - - Value tree_value = 0; - for (typename In::const_iterator it = in.begin(); it != in.end(); ++it) { - if (uf.join(digraph.target(it->first),digraph.source(it->first))) { - out.set(it->first, true); - tree_value += it->second; - } - else { - out.set(it->first, false); - } - } - return tree_value; - } - - // Kruskal for undirected graphs. - - template - typename enable_if, - typename In::value_type::second_type >::type - kruskal(const Graph& graph, const In& in, Out& out,dummy<1> = 1) { - typedef typename In::value_type::second_type Value; - typedef typename Graph::template NodeMap IndexMap; - typedef typename Graph::Node Node; - - IndexMap index(graph); - UnionFind uf(index); - for (typename Graph::NodeIt it(graph); it != INVALID; ++it) { - uf.insert(it); - } - - Value tree_value = 0; - for (typename In::const_iterator it = in.begin(); it != in.end(); ++it) { - if (uf.join(graph.u(it->first),graph.v(it->first))) { - out.set(it->first, true); - tree_value += it->second; - } - else { - out.set(it->first, false); - } - } - return tree_value; - } - - - template - struct PairComp { - typedef typename Sequence::value_type Value; - bool operator()(const Value& left, const Value& right) { - return left.second < right.second; - } - }; - - template - struct SequenceInputIndicator { - static const bool value = false; - }; - - template - struct SequenceInputIndicator::type> { - static const bool value = true; - }; - - template - struct MapInputIndicator { - static const bool value = false; - }; - - template - struct MapInputIndicator::type> { - static const bool value = true; - }; - - template - struct SequenceOutputIndicator { - static const bool value = false; - }; - - template - struct SequenceOutputIndicator::type> { - static const bool value = true; - }; - - template - struct MapOutputIndicator { - static const bool value = false; - }; - - template - struct MapOutputIndicator::type> { - static const bool value = true; - }; - - template - struct KruskalValueSelector {}; - - template - struct KruskalValueSelector, void>::type> - { - typedef typename In::value_type::second_type Value; - }; - - template - struct KruskalValueSelector, void>::type> - { - typedef typename In::Value Value; - }; - - template - struct KruskalInputSelector {}; - - template - struct KruskalOutputSelector {}; - - template - struct KruskalInputSelector, void>::type > - { - typedef typename In::value_type::second_type Value; - - static Value kruskal(const Graph& graph, const In& in, Out& out) { - return KruskalOutputSelector:: - kruskal(graph, in, out); - } - - }; - - template - struct KruskalInputSelector, void>::type > - { - typedef typename In::Value Value; - static Value kruskal(const Graph& graph, const In& in, Out& out) { - typedef typename In::Key MapArc; - typedef typename In::Value Value; - typedef typename ItemSetTraits::ItemIt MapArcIt; - typedef std::vector > Sequence; - Sequence seq; - - for (MapArcIt it(graph); it != INVALID; ++it) { - seq.push_back(std::make_pair(it, in[it])); - } - - std::sort(seq.begin(), seq.end(), PairComp()); - return KruskalOutputSelector:: - kruskal(graph, seq, out); - } - }; - - template - struct RemoveConst { - typedef T type; - }; - - template - struct RemoveConst { - typedef T type; - }; - - template - struct KruskalOutputSelector, void>::type > - { - typedef typename In::value_type::second_type Value; - - static Value kruskal(const Graph& graph, const In& in, Out& out) { - typedef LoggerBoolMap::type> Map; - Map map(out); - return _kruskal_bits::kruskal(graph, in, map); - } - - }; - - template - struct KruskalOutputSelector, void>::type > - { - typedef typename In::value_type::second_type Value; - - static Value kruskal(const Graph& graph, const In& in, Out& out) { - return _kruskal_bits::kruskal(graph, in, out); - } - }; - - } - - /// \ingroup spantree - /// - /// \brief Kruskal's algorithm for finding a minimum cost spanning tree of - /// a graph. - /// - /// This function runs Kruskal's algorithm to find a minimum cost - /// spanning tree of a graph. - /// Due to some C++ hacking, it accepts various input and output types. - /// - /// \param g The graph the algorithm runs on. - /// It can be either \ref concepts::Digraph "directed" or - /// \ref concepts::Graph "undirected". - /// If the graph is directed, the algorithm consider it to be - /// undirected by disregarding the direction of the arcs. - /// - /// \param in This object is used to describe the arc/edge costs. - /// It can be one of the following choices. - /// - An STL compatible 'Forward Container' with - /// std::pair or - /// std::pair as its value_type, where - /// \c C is the type of the costs. The pairs indicates the arcs/edges - /// along with the assigned cost. They must be in a - /// cost-ascending order. - /// - Any readable arc/edge map. The values of the map indicate the - /// arc/edge costs. - /// - /// \retval out Here we also have a choice. - /// - It can be a writable arc/edge map with \c bool value type. After - /// running the algorithm it will contain the found minimum cost spanning - /// tree: the value of an arc/edge will be set to \c true if it belongs - /// to the tree, otherwise it will be set to \c false. The value of - /// each arc/edge will be set exactly once. - /// - It can also be an iteraror of an STL Container with - /// GR::Arc or GR::Edge as its - /// value_type. The algorithm copies the elements of the - /// found tree into this sequence. For example, if we know that the - /// spanning tree of the graph \c g has say 53 arcs, then we can - /// put its arcs into an STL vector \c tree with a code like this. - ///\code - /// std::vector tree(53); - /// kruskal(g,cost,tree.begin()); - ///\endcode - /// Or if we don't know in advance the size of the tree, we can - /// write this. - ///\code - /// std::vector tree; - /// kruskal(g,cost,std::back_inserter(tree)); - ///\endcode - /// - /// \return The total cost of the found spanning tree. - /// - /// \note If the input graph is not (weakly) connected, a spanning - /// forest is calculated instead of a spanning tree. - -#ifdef DOXYGEN - template - Value kruskal(const Graph& g, const In& in, Out& out) -#else - template - inline typename _kruskal_bits::KruskalValueSelector::Value - kruskal(const Graph& graph, const In& in, Out& out) -#endif - { - return _kruskal_bits::KruskalInputSelector:: - kruskal(graph, in, out); - } - - - template - inline typename _kruskal_bits::KruskalValueSelector::Value - kruskal(const Graph& graph, const In& in, const Out& out) - { - return _kruskal_bits::KruskalInputSelector:: - kruskal(graph, in, out); - } - -} //namespace lemon - -#endif //LEMON_KRUSKAL_H diff --git a/deps/lemon/lemon/lemon.pc.in b/deps/lemon/lemon/lemon.pc.in deleted file mode 100644 index e85bf7652..000000000 --- a/deps/lemon/lemon/lemon.pc.in +++ /dev/null @@ -1,10 +0,0 @@ -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=@CMAKE_INSTALL_PREFIX@/bin -libdir=@CMAKE_INSTALL_PREFIX@/lib -includedir=@CMAKE_INSTALL_PREFIX@/include - -Name: @PROJECT_NAME@ -Description: Library for Efficient Modeling and Optimization in Networks -Version: @PROJECT_VERSION@ -Libs: -L${libdir} -lemon @GLPK_LIBS@ @CPLEX_LIBS@ @SOPLEX_LIBS@ @CLP_LIBS@ @CBC_LIBS@ -Cflags: -I${includedir} diff --git a/deps/lemon/lemon/lgf_reader.h b/deps/lemon/lemon/lgf_reader.h deleted file mode 100644 index 2f49fa25f..000000000 --- a/deps/lemon/lemon/lgf_reader.h +++ /dev/null @@ -1,3854 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\ingroup lemon_io -///\file -///\brief \ref lgf-format "LEMON Graph Format" reader. - - -#ifndef LEMON_LGF_READER_H -#define LEMON_LGF_READER_H - -#include -#include -#include - -#include -#include - -#include - -#include - -#include -#include - -namespace lemon { - - namespace _reader_bits { - - template - struct DefaultConverter { - Value operator()(const std::string& str) { - std::istringstream is(str); - Value value; - if (!(is >> value)) { - throw FormatError("Cannot read token"); - } - - char c; - if (is >> std::ws >> c) { - throw FormatError("Remaining characters in token"); - } - return value; - } - }; - - template <> - struct DefaultConverter { - std::string operator()(const std::string& str) { - return str; - } - }; - - template - class MapStorageBase { - public: - typedef _Item Item; - - public: - MapStorageBase() {} - virtual ~MapStorageBase() {} - - virtual void set(const Item& item, const std::string& value) = 0; - - }; - - template > - class MapStorage : public MapStorageBase<_Item> { - public: - typedef _Map Map; - typedef _Converter Converter; - typedef _Item Item; - - private: - Map& _map; - Converter _converter; - - public: - MapStorage(Map& map, const Converter& converter = Converter()) - : _map(map), _converter(converter) {} - virtual ~MapStorage() {} - - virtual void set(const Item& item ,const std::string& value) { - _map.set(item, _converter(value)); - } - }; - - template > - class GraphArcMapStorage : public MapStorageBase { - public: - typedef _Map Map; - typedef _Converter Converter; - typedef _GR GR; - typedef typename GR::Edge Item; - static const bool dir = _dir; - - private: - const GR& _graph; - Map& _map; - Converter _converter; - - public: - GraphArcMapStorage(const GR& graph, Map& map, - const Converter& converter = Converter()) - : _graph(graph), _map(map), _converter(converter) {} - virtual ~GraphArcMapStorage() {} - - virtual void set(const Item& item ,const std::string& value) { - _map.set(_graph.direct(item, dir), _converter(value)); - } - }; - - class ValueStorageBase { - public: - ValueStorageBase() {} - virtual ~ValueStorageBase() {} - - virtual void set(const std::string&) = 0; - }; - - template > - class ValueStorage : public ValueStorageBase { - public: - typedef _Value Value; - typedef _Converter Converter; - - private: - Value& _value; - Converter _converter; - - public: - ValueStorage(Value& value, const Converter& converter = Converter()) - : _value(value), _converter(converter) {} - - virtual void set(const std::string& value) { - _value = _converter(value); - } - }; - - template > - struct MapLookUpConverter { - const Map& _map; - - MapLookUpConverter(const Map& map) - : _map(map) {} - - Value operator()(const std::string& str) { - typename Map::const_iterator it = _map.find(str); - if (it == _map.end()) { - std::ostringstream msg; - msg << "Item not found: " << str; - throw FormatError(msg.str()); - } - return it->second; - } - }; - - template , - typename Map2 = std::map > - struct DoubleMapLookUpConverter { - const Map1& _map1; - const Map2& _map2; - - DoubleMapLookUpConverter(const Map1& map1, const Map2& map2) - : _map1(map1), _map2(map2) {} - - Value operator()(const std::string& str) { - typename Map1::const_iterator it1 = _map1.find(str); - typename Map2::const_iterator it2 = _map2.find(str); - if (it1 == _map1.end()) { - if (it2 == _map2.end()) { - std::ostringstream msg; - msg << "Item not found: " << str; - throw FormatError(msg.str()); - } else { - return it2->second; - } - } else { - if (it2 == _map2.end()) { - return it1->second; - } else { - std::ostringstream msg; - msg << "Item is ambigous: " << str; - throw FormatError(msg.str()); - } - } - } - }; - - template - struct GraphArcLookUpConverter { - const GR& _graph; - const std::map& _map; - - GraphArcLookUpConverter(const GR& graph, - const std::map& map) - : _graph(graph), _map(map) {} - - typename GR::Arc operator()(const std::string& str) { - if (str.empty() || (str[0] != '+' && str[0] != '-')) { - throw FormatError("Item must start with '+' or '-'"); - } - typename std::map - ::const_iterator it = _map.find(str.substr(1)); - if (it == _map.end()) { - throw FormatError("Item not found"); - } - return _graph.direct(it->second, str[0] == '+'); - } - }; - - inline bool isWhiteSpace(char c) { - return c == ' ' || c == '\t' || c == '\v' || - c == '\n' || c == '\r' || c == '\f'; - } - - inline bool isOct(char c) { - return '0' <= c && c <='7'; - } - - inline int valueOct(char c) { - LEMON_ASSERT(isOct(c), "The character is not octal."); - return c - '0'; - } - - inline bool isHex(char c) { - return ('0' <= c && c <= '9') || - ('a' <= c && c <= 'z') || - ('A' <= c && c <= 'Z'); - } - - inline int valueHex(char c) { - LEMON_ASSERT(isHex(c), "The character is not hexadecimal."); - if ('0' <= c && c <= '9') return c - '0'; - if ('a' <= c && c <= 'z') return c - 'a' + 10; - return c - 'A' + 10; - } - - inline bool isIdentifierFirstChar(char c) { - return ('a' <= c && c <= 'z') || - ('A' <= c && c <= 'Z') || c == '_'; - } - - inline bool isIdentifierChar(char c) { - return isIdentifierFirstChar(c) || - ('0' <= c && c <= '9'); - } - - inline char readEscape(std::istream& is) { - char c; - if (!is.get(c)) - throw FormatError("Escape format error"); - - switch (c) { - case '\\': - return '\\'; - case '\"': - return '\"'; - case '\'': - return '\''; - case '\?': - return '\?'; - case 'a': - return '\a'; - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; - case 'v': - return '\v'; - case 'x': - { - int code; - if (!is.get(c) || !isHex(c)) - throw FormatError("Escape format error"); - else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c); - else code = code * 16 + valueHex(c); - return code; - } - default: - { - int code; - if (!isOct(c)) - throw FormatError("Escape format error"); - else if (code = valueOct(c), !is.get(c) || !isOct(c)) - is.putback(c); - else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) - is.putback(c); - else code = code * 8 + valueOct(c); - return code; - } - } - } - - inline std::istream& readToken(std::istream& is, std::string& str) { - std::ostringstream os; - - char c; - is >> std::ws; - - if (!is.get(c)) - return is; - - if (c == '\"') { - while (is.get(c) && c != '\"') { - if (c == '\\') - c = readEscape(is); - os << c; - } - if (!is) - throw FormatError("Quoted format error"); - } else { - is.putback(c); - while (is.get(c) && !isWhiteSpace(c)) { - if (c == '\\') - c = readEscape(is); - os << c; - } - if (!is) { - is.clear(); - } else { - is.putback(c); - } - } - str = os.str(); - return is; - } - - class Section { - public: - virtual ~Section() {} - virtual void process(std::istream& is, int& line_num) = 0; - }; - - template - class LineSection : public Section { - private: - - Functor _functor; - - public: - - LineSection(const Functor& functor) : _functor(functor) {} - virtual ~LineSection() {} - - virtual void process(std::istream& is, int& line_num) { - char c; - std::string line; - while (is.get(c) && c != '@') { - if (c == '\n') { - ++line_num; - } else if (c == '#') { - getline(is, line); - ++line_num; - } else if (!isWhiteSpace(c)) { - is.putback(c); - getline(is, line); - _functor(line); - ++line_num; - } - } - if (is) is.putback(c); - else if (is.eof()) is.clear(); - } - }; - - template - class StreamSection : public Section { - private: - - Functor _functor; - - public: - - StreamSection(const Functor& functor) : _functor(functor) {} - virtual ~StreamSection() {} - - virtual void process(std::istream& is, int& line_num) { - _functor(is, line_num); - char c; - std::string line; - while (is.get(c) && c != '@') { - if (c == '\n') { - ++line_num; - } else if (!isWhiteSpace(c)) { - getline(is, line); - ++line_num; - } - } - if (is) is.putback(c); - else if (is.eof()) is.clear(); - } - }; - - } - - template - class DigraphReader; - - template - DigraphReader digraphReader(TDGR& digraph, std::istream& is = std::cin); - template - DigraphReader digraphReader(TDGR& digraph, const std::string& fn); - template - DigraphReader digraphReader(TDGR& digraph, const char *fn); - - /// \ingroup lemon_io - /// - /// \brief \ref lgf-format "LGF" reader for directed graphs - /// - /// This utility reads an \ref lgf-format "LGF" file. - /// - /// The reading method does a batch processing. The user creates a - /// reader object, then various reading rules can be added to the - /// reader, and eventually the reading is executed with the \c run() - /// member function. A map reading rule can be added to the reader - /// with the \c nodeMap() or \c arcMap() members. An optional - /// converter parameter can also be added as a standard functor - /// converting from \c std::string to the value type of the map. If it - /// is set, it will determine how the tokens in the file should be - /// converted to the value type of the map. If the functor is not set, - /// then a default conversion will be used. One map can be read into - /// multiple map objects at the same time. The \c attribute(), \c - /// node() and \c arc() functions are used to add attribute reading - /// rules. - /// - ///\code - /// DigraphReader(digraph, std::cin). - /// nodeMap("coordinates", coord_map). - /// arcMap("capacity", cap_map). - /// node("source", src). - /// node("target", trg). - /// attribute("caption", caption). - /// run(); - ///\endcode - /// - /// By default, the reader uses the first section in the file of the - /// proper type. If a section has an optional name, then it can be - /// selected for reading by giving an optional name parameter to the - /// \c nodes(), \c arcs() or \c attributes() functions. - /// - /// The \c useNodes() and \c useArcs() functions are used to tell the reader - /// that the nodes or arcs should not be constructed (added to the - /// graph) during the reading, but instead the label map of the items - /// are given as a parameter of these functions. An - /// application of these functions is multipass reading, which is - /// important if two \c \@arcs sections must be read from the - /// file. In this case the first phase would read the node set and one - /// of the arc sets, while the second phase would read the second arc - /// set into an \e ArcSet class (\c SmartArcSet or \c ListArcSet). - /// The previously read label node map should be passed to the \c - /// useNodes() functions. Another application of multipass reading when - /// paths are given as a node map or an arc map. - /// It is impossible to read this in - /// a single pass, because the arcs are not constructed when the node - /// maps are read. - template - class DigraphReader { - public: - - typedef DGR Digraph; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(DGR); - - std::istream* _is; - bool local_is; - std::string _filename; - - DGR& _digraph; - - std::string _nodes_caption; - std::string _arcs_caption; - std::string _attributes_caption; - - typedef std::map NodeIndex; - NodeIndex _node_index; - typedef std::map ArcIndex; - ArcIndex _arc_index; - - typedef std::vector*> > NodeMaps; - NodeMaps _node_maps; - - typedef std::vector*> >ArcMaps; - ArcMaps _arc_maps; - - typedef std::multimap - Attributes; - Attributes _attributes; - - bool _use_nodes; - bool _use_arcs; - - bool _skip_nodes; - bool _skip_arcs; - - int line_num; - std::istringstream line; - - public: - - /// \brief Constructor - /// - /// Construct a directed graph reader, which reads from the given - /// input stream. - DigraphReader(DGR& digraph, std::istream& is = std::cin) - : _is(&is), local_is(false), _digraph(digraph), - _use_nodes(false), _use_arcs(false), - _skip_nodes(false), _skip_arcs(false) {} - - /// \brief Constructor - /// - /// Construct a directed graph reader, which reads from the given - /// file. - DigraphReader(DGR& digraph, const std::string& fn) - : _is(new std::ifstream(fn.c_str())), local_is(true), - _filename(fn), _digraph(digraph), - _use_nodes(false), _use_arcs(false), - _skip_nodes(false), _skip_arcs(false) { - if (!(*_is)) { - delete _is; - throw IoError("Cannot open file", fn); - } - } - - /// \brief Constructor - /// - /// Construct a directed graph reader, which reads from the given - /// file. - DigraphReader(DGR& digraph, const char* fn) - : _is(new std::ifstream(fn)), local_is(true), - _filename(fn), _digraph(digraph), - _use_nodes(false), _use_arcs(false), - _skip_nodes(false), _skip_arcs(false) { - if (!(*_is)) { - delete _is; - throw IoError("Cannot open file", fn); - } - } - - /// \brief Destructor - ~DigraphReader() { - for (typename NodeMaps::iterator it = _node_maps.begin(); - it != _node_maps.end(); ++it) { - delete it->second; - } - - for (typename ArcMaps::iterator it = _arc_maps.begin(); - it != _arc_maps.end(); ++it) { - delete it->second; - } - - for (typename Attributes::iterator it = _attributes.begin(); - it != _attributes.end(); ++it) { - delete it->second; - } - - if (local_is) { - delete _is; - } - - } - - private: - - template - friend DigraphReader digraphReader(TDGR& digraph, std::istream& is); - template - friend DigraphReader digraphReader(TDGR& digraph, - const std::string& fn); - template - friend DigraphReader digraphReader(TDGR& digraph, const char *fn); - - DigraphReader(DigraphReader& other) - : _is(other._is), local_is(other.local_is), _digraph(other._digraph), - _use_nodes(other._use_nodes), _use_arcs(other._use_arcs), - _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) { - - other._is = 0; - other.local_is = false; - - _node_index.swap(other._node_index); - _arc_index.swap(other._arc_index); - - _node_maps.swap(other._node_maps); - _arc_maps.swap(other._arc_maps); - _attributes.swap(other._attributes); - - _nodes_caption = other._nodes_caption; - _arcs_caption = other._arcs_caption; - _attributes_caption = other._attributes_caption; - - } - - DigraphReader& operator=(const DigraphReader&); - - public: - - /// \name Reading Rules - /// @{ - - /// \brief Node map reading rule - /// - /// Add a node map reading rule to the reader. - template - DigraphReader& nodeMap(const std::string& caption, Map& map) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map); - _node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Node map reading rule - /// - /// Add a node map reading rule with specialized converter to the - /// reader. - template - DigraphReader& nodeMap(const std::string& caption, Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map, converter); - _node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc map reading rule - /// - /// Add an arc map reading rule to the reader. - template - DigraphReader& arcMap(const std::string& caption, Map& map) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map); - _arc_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc map reading rule - /// - /// Add an arc map reading rule with specialized converter to the - /// reader. - template - DigraphReader& arcMap(const std::string& caption, Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map, converter); - _arc_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Attribute reading rule - /// - /// Add an attribute reading rule to the reader. - template - DigraphReader& attribute(const std::string& caption, Value& value) { - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(value); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Attribute reading rule - /// - /// Add an attribute reading rule with specialized converter to the - /// reader. - template - DigraphReader& attribute(const std::string& caption, Value& value, - const Converter& converter = Converter()) { - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(value, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Node reading rule - /// - /// Add a node reading rule to reader. - DigraphReader& node(const std::string& caption, Node& node) { - typedef _reader_bits::MapLookUpConverter Converter; - Converter converter(_node_index); - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(node, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc reading rule - /// - /// Add an arc reading rule to reader. - DigraphReader& arc(const std::string& caption, Arc& arc) { - typedef _reader_bits::MapLookUpConverter Converter; - Converter converter(_arc_index); - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(arc, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// @} - - /// \name Select Section by Name - /// @{ - - /// \brief Set \c \@nodes section to be read - /// - /// Set \c \@nodes section to be read - DigraphReader& nodes(const std::string& caption) { - _nodes_caption = caption; - return *this; - } - - /// \brief Set \c \@arcs section to be read - /// - /// Set \c \@arcs section to be read - DigraphReader& arcs(const std::string& caption) { - _arcs_caption = caption; - return *this; - } - - /// \brief Set \c \@attributes section to be read - /// - /// Set \c \@attributes section to be read - DigraphReader& attributes(const std::string& caption) { - _attributes_caption = caption; - return *this; - } - - /// @} - - /// \name Using Previously Constructed Node or Arc Set - /// @{ - - /// \brief Use previously constructed node set - /// - /// Use previously constructed node set, and specify the node - /// label map. - template - DigraphReader& useNodes(const Map& map) { - checkConcept, Map>(); - LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); - _use_nodes = true; - _writer_bits::DefaultConverter converter; - for (NodeIt n(_digraph); n != INVALID; ++n) { - _node_index.insert(std::make_pair(converter(map[n]), n)); - } - return *this; - } - - /// \brief Use previously constructed node set - /// - /// Use previously constructed node set, and specify the node - /// label map and a functor which converts the label map values to - /// \c std::string. - template - DigraphReader& useNodes(const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); - _use_nodes = true; - for (NodeIt n(_digraph); n != INVALID; ++n) { - _node_index.insert(std::make_pair(converter(map[n]), n)); - } - return *this; - } - - /// \brief Use previously constructed arc set - /// - /// Use previously constructed arc set, and specify the arc - /// label map. - template - DigraphReader& useArcs(const Map& map) { - checkConcept, Map>(); - LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member"); - _use_arcs = true; - _writer_bits::DefaultConverter converter; - for (ArcIt a(_digraph); a != INVALID; ++a) { - _arc_index.insert(std::make_pair(converter(map[a]), a)); - } - return *this; - } - - /// \brief Use previously constructed arc set - /// - /// Use previously constructed arc set, and specify the arc - /// label map and a functor which converts the label map values to - /// \c std::string. - template - DigraphReader& useArcs(const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member"); - _use_arcs = true; - for (ArcIt a(_digraph); a != INVALID; ++a) { - _arc_index.insert(std::make_pair(converter(map[a]), a)); - } - return *this; - } - - /// \brief Skips the reading of node section - /// - /// Omit the reading of the node section. This implies that each node - /// map reading rule will be abandoned, and the nodes of the graph - /// will not be constructed, which usually cause that the arc set - /// could not be read due to lack of node name resolving. - /// Therefore \c skipArcs() function should also be used, or - /// \c useNodes() should be used to specify the label of the nodes. - DigraphReader& skipNodes() { - LEMON_ASSERT(!_skip_nodes, "Skip nodes already set"); - _skip_nodes = true; - return *this; - } - - /// \brief Skips the reading of arc section - /// - /// Omit the reading of the arc section. This implies that each arc - /// map reading rule will be abandoned, and the arcs of the graph - /// will not be constructed. - DigraphReader& skipArcs() { - LEMON_ASSERT(!_skip_arcs, "Skip arcs already set"); - _skip_arcs = true; - return *this; - } - - /// @} - - private: - - bool readLine() { - std::string str; - while(++line_num, std::getline(*_is, str)) { - line.clear(); line.str(str); - char c; - if (line >> std::ws >> c && c != '#') { - line.putback(c); - return true; - } - } - return false; - } - - bool readSuccess() { - return static_cast(*_is); - } - - void skipSection() { - char c; - while (readSuccess() && line >> c && c != '@') { - readLine(); - } - if (readSuccess()) { - line.putback(c); - } - } - - void readNodes() { - - std::vector map_index(_node_maps.size()); - int map_num, label_index; - - char c; - if (!readLine() || !(line >> c) || c == '@') { - if (readSuccess() && line) line.putback(c); - if (!_node_maps.empty()) - throw FormatError("Cannot find map names"); - return; - } - line.putback(c); - - { - std::map maps; - - std::string map; - int index = 0; - while (_reader_bits::readToken(line, map)) { - if (maps.find(map) != maps.end()) { - std::ostringstream msg; - msg << "Multiple occurence of node map: " << map; - throw FormatError(msg.str()); - } - maps.insert(std::make_pair(map, index)); - ++index; - } - - for (int i = 0; i < static_cast(_node_maps.size()); ++i) { - std::map::iterator jt = - maps.find(_node_maps[i].first); - if (jt == maps.end()) { - std::ostringstream msg; - msg << "Map not found: " << _node_maps[i].first; - throw FormatError(msg.str()); - } - map_index[i] = jt->second; - } - - { - std::map::iterator jt = maps.find("label"); - if (jt != maps.end()) { - label_index = jt->second; - } else { - label_index = -1; - } - } - map_num = maps.size(); - } - - while (readLine() && line >> c && c != '@') { - line.putback(c); - - std::vector tokens(map_num); - for (int i = 0; i < map_num; ++i) { - if (!_reader_bits::readToken(line, tokens[i])) { - std::ostringstream msg; - msg << "Column not found (" << i + 1 << ")"; - throw FormatError(msg.str()); - } - } - if (line >> std::ws >> c) - throw FormatError("Extra character at the end of line"); - - Node n; - if (!_use_nodes) { - n = _digraph.addNode(); - if (label_index != -1) - _node_index.insert(std::make_pair(tokens[label_index], n)); - } else { - if (label_index == -1) - throw FormatError("Label map not found"); - typename std::map::iterator it = - _node_index.find(tokens[label_index]); - if (it == _node_index.end()) { - std::ostringstream msg; - msg << "Node with label not found: " << tokens[label_index]; - throw FormatError(msg.str()); - } - n = it->second; - } - - for (int i = 0; i < static_cast(_node_maps.size()); ++i) { - _node_maps[i].second->set(n, tokens[map_index[i]]); - } - - } - if (readSuccess()) { - line.putback(c); - } - } - - void readArcs() { - - std::vector map_index(_arc_maps.size()); - int map_num, label_index; - - char c; - if (!readLine() || !(line >> c) || c == '@') { - if (readSuccess() && line) line.putback(c); - if (!_arc_maps.empty()) - throw FormatError("Cannot find map names"); - return; - } - line.putback(c); - - { - std::map maps; - - std::string map; - int index = 0; - while (_reader_bits::readToken(line, map)) { - if(map == "-") { - if(index!=0) - throw FormatError("'-' is not allowed as a map name"); - else if (line >> std::ws >> c) - throw FormatError("Extra character at the end of line"); - else break; - } - if (maps.find(map) != maps.end()) { - std::ostringstream msg; - msg << "Multiple occurence of arc map: " << map; - throw FormatError(msg.str()); - } - maps.insert(std::make_pair(map, index)); - ++index; - } - - for (int i = 0; i < static_cast(_arc_maps.size()); ++i) { - std::map::iterator jt = - maps.find(_arc_maps[i].first); - if (jt == maps.end()) { - std::ostringstream msg; - msg << "Map not found: " << _arc_maps[i].first; - throw FormatError(msg.str()); - } - map_index[i] = jt->second; - } - - { - std::map::iterator jt = maps.find("label"); - if (jt != maps.end()) { - label_index = jt->second; - } else { - label_index = -1; - } - } - map_num = maps.size(); - } - - while (readLine() && line >> c && c != '@') { - line.putback(c); - - std::string source_token; - std::string target_token; - - if (!_reader_bits::readToken(line, source_token)) - throw FormatError("Source not found"); - - if (!_reader_bits::readToken(line, target_token)) - throw FormatError("Target not found"); - - std::vector tokens(map_num); - for (int i = 0; i < map_num; ++i) { - if (!_reader_bits::readToken(line, tokens[i])) { - std::ostringstream msg; - msg << "Column not found (" << i + 1 << ")"; - throw FormatError(msg.str()); - } - } - if (line >> std::ws >> c) - throw FormatError("Extra character at the end of line"); - - Arc a; - if (!_use_arcs) { - - typename NodeIndex::iterator it; - - it = _node_index.find(source_token); - if (it == _node_index.end()) { - std::ostringstream msg; - msg << "Item not found: " << source_token; - throw FormatError(msg.str()); - } - Node source = it->second; - - it = _node_index.find(target_token); - if (it == _node_index.end()) { - std::ostringstream msg; - msg << "Item not found: " << target_token; - throw FormatError(msg.str()); - } - Node target = it->second; - - a = _digraph.addArc(source, target); - if (label_index != -1) - _arc_index.insert(std::make_pair(tokens[label_index], a)); - } else { - if (label_index == -1) - throw FormatError("Label map not found"); - typename std::map::iterator it = - _arc_index.find(tokens[label_index]); - if (it == _arc_index.end()) { - std::ostringstream msg; - msg << "Arc with label not found: " << tokens[label_index]; - throw FormatError(msg.str()); - } - a = it->second; - } - - for (int i = 0; i < static_cast(_arc_maps.size()); ++i) { - _arc_maps[i].second->set(a, tokens[map_index[i]]); - } - - } - if (readSuccess()) { - line.putback(c); - } - } - - void readAttributes() { - - std::set read_attr; - - char c; - while (readLine() && line >> c && c != '@') { - line.putback(c); - - std::string attr, token; - if (!_reader_bits::readToken(line, attr)) - throw FormatError("Attribute name not found"); - if (!_reader_bits::readToken(line, token)) - throw FormatError("Attribute value not found"); - if (line >> c) - throw FormatError("Extra character at the end of line"); - - { - std::set::iterator it = read_attr.find(attr); - if (it != read_attr.end()) { - std::ostringstream msg; - msg << "Multiple occurence of attribute: " << attr; - throw FormatError(msg.str()); - } - read_attr.insert(attr); - } - - { - typename Attributes::iterator it = _attributes.lower_bound(attr); - while (it != _attributes.end() && it->first == attr) { - it->second->set(token); - ++it; - } - } - - } - if (readSuccess()) { - line.putback(c); - } - for (typename Attributes::iterator it = _attributes.begin(); - it != _attributes.end(); ++it) { - if (read_attr.find(it->first) == read_attr.end()) { - std::ostringstream msg; - msg << "Attribute not found: " << it->first; - throw FormatError(msg.str()); - } - } - } - - public: - - /// \name Execution of the Reader - /// @{ - - /// \brief Start the batch processing - /// - /// This function starts the batch processing - void run() { - LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); - - bool nodes_done = _skip_nodes; - bool arcs_done = _skip_arcs; - bool attributes_done = false; - - line_num = 0; - readLine(); - skipSection(); - - while (readSuccess()) { - try { - char c; - std::string section, caption; - line >> c; - _reader_bits::readToken(line, section); - _reader_bits::readToken(line, caption); - - if (line >> c) - throw FormatError("Extra character at the end of line"); - - if (section == "nodes" && !nodes_done) { - if (_nodes_caption.empty() || _nodes_caption == caption) { - readNodes(); - nodes_done = true; - } - } else if ((section == "arcs" || section == "edges") && - !arcs_done) { - if (_arcs_caption.empty() || _arcs_caption == caption) { - readArcs(); - arcs_done = true; - } - } else if (section == "attributes" && !attributes_done) { - if (_attributes_caption.empty() || _attributes_caption == caption) { - readAttributes(); - attributes_done = true; - } - } else { - readLine(); - skipSection(); - } - } catch (FormatError& error) { - error.line(line_num); - error.file(_filename); - throw; - } - } - - if (!nodes_done) { - throw FormatError("Section @nodes not found"); - } - - if (!arcs_done) { - throw FormatError("Section @arcs not found"); - } - - if (!attributes_done && !_attributes.empty()) { - throw FormatError("Section @attributes not found"); - } - - } - - /// @} - - }; - - /// \ingroup lemon_io - /// - /// \brief Return a \ref lemon::DigraphReader "DigraphReader" class - /// - /// This function just returns a \ref lemon::DigraphReader - /// "DigraphReader" class. - /// - /// With this function a digraph can be read from an - /// \ref lgf-format "LGF" file or input stream with several maps and - /// attributes. For example, there is network flow problem on a - /// digraph, i.e. a digraph with a \e capacity map on the arcs and - /// \e source and \e target nodes. This digraph can be read with the - /// following code: - /// - ///\code - ///ListDigraph digraph; - ///ListDigraph::ArcMap cm(digraph); - ///ListDigraph::Node src, trg; - ///digraphReader(digraph, std::cin). - /// arcMap("capacity", cap). - /// node("source", src). - /// node("target", trg). - /// run(); - ///\endcode - /// - /// For a complete documentation, please see the - /// \ref lemon::DigraphReader "DigraphReader" - /// class documentation. - /// \warning Don't forget to put the \ref lemon::DigraphReader::run() "run()" - /// to the end of the parameter list. - /// \relates DigraphReader - /// \sa digraphReader(TDGR& digraph, const std::string& fn) - /// \sa digraphReader(TDGR& digraph, const char* fn) - template - DigraphReader digraphReader(TDGR& digraph, std::istream& is) { - DigraphReader tmp(digraph, is); - return tmp; - } - - /// \brief Return a \ref DigraphReader class - /// - /// This function just returns a \ref DigraphReader class. - /// \relates DigraphReader - /// \sa digraphReader(TDGR& digraph, std::istream& is) - template - DigraphReader digraphReader(TDGR& digraph, const std::string& fn) { - DigraphReader tmp(digraph, fn); - return tmp; - } - - /// \brief Return a \ref DigraphReader class - /// - /// This function just returns a \ref DigraphReader class. - /// \relates DigraphReader - /// \sa digraphReader(TDGR& digraph, std::istream& is) - template - DigraphReader digraphReader(TDGR& digraph, const char* fn) { - DigraphReader tmp(digraph, fn); - return tmp; - } - - template - class GraphReader; - - template - GraphReader graphReader(TGR& graph, std::istream& is = std::cin); - template - GraphReader graphReader(TGR& graph, const std::string& fn); - template - GraphReader graphReader(TGR& graph, const char *fn); - - /// \ingroup lemon_io - /// - /// \brief \ref lgf-format "LGF" reader for undirected graphs - /// - /// This utility reads an \ref lgf-format "LGF" file. - /// - /// It can be used almost the same way as \c DigraphReader. - /// The only difference is that this class can handle edges and - /// edge maps as well as arcs and arc maps. - /// - /// The columns in the \c \@edges (or \c \@arcs) section are the - /// edge maps. However, if there are two maps with the same name - /// prefixed with \c '+' and \c '-', then these can be read into an - /// arc map. Similarly, an attribute can be read into an arc, if - /// it's value is an edge label prefixed with \c '+' or \c '-'. - template - class GraphReader { - public: - - typedef GR Graph; - - private: - - TEMPLATE_GRAPH_TYPEDEFS(GR); - - std::istream* _is; - bool local_is; - std::string _filename; - - GR& _graph; - - std::string _nodes_caption; - std::string _edges_caption; - std::string _attributes_caption; - - typedef std::map NodeIndex; - NodeIndex _node_index; - typedef std::map EdgeIndex; - EdgeIndex _edge_index; - - typedef std::vector*> > NodeMaps; - NodeMaps _node_maps; - - typedef std::vector*> > EdgeMaps; - EdgeMaps _edge_maps; - - typedef std::multimap - Attributes; - Attributes _attributes; - - bool _use_nodes; - bool _use_edges; - - bool _skip_nodes; - bool _skip_edges; - - int line_num; - std::istringstream line; - - public: - - /// \brief Constructor - /// - /// Construct an undirected graph reader, which reads from the given - /// input stream. - GraphReader(GR& graph, std::istream& is = std::cin) - : _is(&is), local_is(false), _graph(graph), - _use_nodes(false), _use_edges(false), - _skip_nodes(false), _skip_edges(false) {} - - /// \brief Constructor - /// - /// Construct an undirected graph reader, which reads from the given - /// file. - GraphReader(GR& graph, const std::string& fn) - : _is(new std::ifstream(fn.c_str())), local_is(true), - _filename(fn), _graph(graph), - _use_nodes(false), _use_edges(false), - _skip_nodes(false), _skip_edges(false) { - if (!(*_is)) { - delete _is; - throw IoError("Cannot open file", fn); - } - } - - /// \brief Constructor - /// - /// Construct an undirected graph reader, which reads from the given - /// file. - GraphReader(GR& graph, const char* fn) - : _is(new std::ifstream(fn)), local_is(true), - _filename(fn), _graph(graph), - _use_nodes(false), _use_edges(false), - _skip_nodes(false), _skip_edges(false) { - if (!(*_is)) { - delete _is; - throw IoError("Cannot open file", fn); - } - } - - /// \brief Destructor - ~GraphReader() { - for (typename NodeMaps::iterator it = _node_maps.begin(); - it != _node_maps.end(); ++it) { - delete it->second; - } - - for (typename EdgeMaps::iterator it = _edge_maps.begin(); - it != _edge_maps.end(); ++it) { - delete it->second; - } - - for (typename Attributes::iterator it = _attributes.begin(); - it != _attributes.end(); ++it) { - delete it->second; - } - - if (local_is) { - delete _is; - } - - } - - private: - template - friend GraphReader graphReader(TGR& graph, std::istream& is); - template - friend GraphReader graphReader(TGR& graph, const std::string& fn); - template - friend GraphReader graphReader(TGR& graph, const char *fn); - - GraphReader(GraphReader& other) - : _is(other._is), local_is(other.local_is), _graph(other._graph), - _use_nodes(other._use_nodes), _use_edges(other._use_edges), - _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { - - other._is = 0; - other.local_is = false; - - _node_index.swap(other._node_index); - _edge_index.swap(other._edge_index); - - _node_maps.swap(other._node_maps); - _edge_maps.swap(other._edge_maps); - _attributes.swap(other._attributes); - - _nodes_caption = other._nodes_caption; - _edges_caption = other._edges_caption; - _attributes_caption = other._attributes_caption; - - } - - GraphReader& operator=(const GraphReader&); - - public: - - /// \name Reading Rules - /// @{ - - /// \brief Node map reading rule - /// - /// Add a node map reading rule to the reader. - template - GraphReader& nodeMap(const std::string& caption, Map& map) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map); - _node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Node map reading rule - /// - /// Add a node map reading rule with specialized converter to the - /// reader. - template - GraphReader& nodeMap(const std::string& caption, Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map, converter); - _node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Edge map reading rule - /// - /// Add an edge map reading rule to the reader. - template - GraphReader& edgeMap(const std::string& caption, Map& map) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map); - _edge_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Edge map reading rule - /// - /// Add an edge map reading rule with specialized converter to the - /// reader. - template - GraphReader& edgeMap(const std::string& caption, Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map, converter); - _edge_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc map reading rule - /// - /// Add an arc map reading rule to the reader. - template - GraphReader& arcMap(const std::string& caption, Map& map) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* forward_storage = - new _reader_bits::GraphArcMapStorage(_graph, map); - _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); - _reader_bits::MapStorageBase* backward_storage = - new _reader_bits::GraphArcMapStorage(_graph, map); - _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); - return *this; - } - - /// \brief Arc map reading rule - /// - /// Add an arc map reading rule with specialized converter to the - /// reader. - template - GraphReader& arcMap(const std::string& caption, Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* forward_storage = - new _reader_bits::GraphArcMapStorage - (_graph, map, converter); - _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); - _reader_bits::MapStorageBase* backward_storage = - new _reader_bits::GraphArcMapStorage - (_graph, map, converter); - _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); - return *this; - } - - /// \brief Attribute reading rule - /// - /// Add an attribute reading rule to the reader. - template - GraphReader& attribute(const std::string& caption, Value& value) { - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(value); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Attribute reading rule - /// - /// Add an attribute reading rule with specialized converter to the - /// reader. - template - GraphReader& attribute(const std::string& caption, Value& value, - const Converter& converter = Converter()) { - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(value, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Node reading rule - /// - /// Add a node reading rule to reader. - GraphReader& node(const std::string& caption, Node& node) { - typedef _reader_bits::MapLookUpConverter Converter; - Converter converter(_node_index); - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(node, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Edge reading rule - /// - /// Add an edge reading rule to reader. - GraphReader& edge(const std::string& caption, Edge& edge) { - typedef _reader_bits::MapLookUpConverter Converter; - Converter converter(_edge_index); - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(edge, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc reading rule - /// - /// Add an arc reading rule to reader. - GraphReader& arc(const std::string& caption, Arc& arc) { - typedef _reader_bits::GraphArcLookUpConverter Converter; - Converter converter(_graph, _edge_index); - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(arc, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// @} - - /// \name Select Section by Name - /// @{ - - /// \brief Set \c \@nodes section to be read - /// - /// Set \c \@nodes section to be read. - GraphReader& nodes(const std::string& caption) { - _nodes_caption = caption; - return *this; - } - - /// \brief Set \c \@edges section to be read - /// - /// Set \c \@edges section to be read. - GraphReader& edges(const std::string& caption) { - _edges_caption = caption; - return *this; - } - - /// \brief Set \c \@attributes section to be read - /// - /// Set \c \@attributes section to be read. - GraphReader& attributes(const std::string& caption) { - _attributes_caption = caption; - return *this; - } - - /// @} - - /// \name Using Previously Constructed Node or Edge Set - /// @{ - - /// \brief Use previously constructed node set - /// - /// Use previously constructed node set, and specify the node - /// label map. - template - GraphReader& useNodes(const Map& map) { - checkConcept, Map>(); - LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); - _use_nodes = true; - _writer_bits::DefaultConverter converter; - for (NodeIt n(_graph); n != INVALID; ++n) { - _node_index.insert(std::make_pair(converter(map[n]), n)); - } - return *this; - } - - /// \brief Use previously constructed node set - /// - /// Use previously constructed node set, and specify the node - /// label map and a functor which converts the label map values to - /// \c std::string. - template - GraphReader& useNodes(const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); - _use_nodes = true; - for (NodeIt n(_graph); n != INVALID; ++n) { - _node_index.insert(std::make_pair(converter(map[n]), n)); - } - return *this; - } - - /// \brief Use previously constructed edge set - /// - /// Use previously constructed edge set, and specify the edge - /// label map. - template - GraphReader& useEdges(const Map& map) { - checkConcept, Map>(); - LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member"); - _use_edges = true; - _writer_bits::DefaultConverter converter; - for (EdgeIt a(_graph); a != INVALID; ++a) { - _edge_index.insert(std::make_pair(converter(map[a]), a)); - } - return *this; - } - - /// \brief Use previously constructed edge set - /// - /// Use previously constructed edge set, and specify the edge - /// label map and a functor which converts the label map values to - /// \c std::string. - template - GraphReader& useEdges(const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member"); - _use_edges = true; - for (EdgeIt a(_graph); a != INVALID; ++a) { - _edge_index.insert(std::make_pair(converter(map[a]), a)); - } - return *this; - } - - /// \brief Skip the reading of node section - /// - /// Omit the reading of the node section. This implies that each node - /// map reading rule will be abandoned, and the nodes of the graph - /// will not be constructed, which usually cause that the edge set - /// could not be read due to lack of node name - /// could not be read due to lack of node name resolving. - /// Therefore \c skipEdges() function should also be used, or - /// \c useNodes() should be used to specify the label of the nodes. - GraphReader& skipNodes() { - LEMON_ASSERT(!_skip_nodes, "Skip nodes already set"); - _skip_nodes = true; - return *this; - } - - /// \brief Skip the reading of edge section - /// - /// Omit the reading of the edge section. This implies that each edge - /// map reading rule will be abandoned, and the edges of the graph - /// will not be constructed. - GraphReader& skipEdges() { - LEMON_ASSERT(!_skip_edges, "Skip edges already set"); - _skip_edges = true; - return *this; - } - - /// @} - - private: - - bool readLine() { - std::string str; - while(++line_num, std::getline(*_is, str)) { - line.clear(); line.str(str); - char c; - if (line >> std::ws >> c && c != '#') { - line.putback(c); - return true; - } - } - return false; - } - - bool readSuccess() { - return static_cast(*_is); - } - - void skipSection() { - char c; - while (readSuccess() && line >> c && c != '@') { - readLine(); - } - if (readSuccess()) { - line.putback(c); - } - } - - void readNodes() { - - std::vector map_index(_node_maps.size()); - int map_num, label_index; - - char c; - if (!readLine() || !(line >> c) || c == '@') { - if (readSuccess() && line) line.putback(c); - if (!_node_maps.empty()) - throw FormatError("Cannot find map names"); - return; - } - line.putback(c); - - { - std::map maps; - - std::string map; - int index = 0; - while (_reader_bits::readToken(line, map)) { - if (maps.find(map) != maps.end()) { - std::ostringstream msg; - msg << "Multiple occurence of node map: " << map; - throw FormatError(msg.str()); - } - maps.insert(std::make_pair(map, index)); - ++index; - } - - for (int i = 0; i < static_cast(_node_maps.size()); ++i) { - std::map::iterator jt = - maps.find(_node_maps[i].first); - if (jt == maps.end()) { - std::ostringstream msg; - msg << "Map not found: " << _node_maps[i].first; - throw FormatError(msg.str()); - } - map_index[i] = jt->second; - } - - { - std::map::iterator jt = maps.find("label"); - if (jt != maps.end()) { - label_index = jt->second; - } else { - label_index = -1; - } - } - map_num = maps.size(); - } - - while (readLine() && line >> c && c != '@') { - line.putback(c); - - std::vector tokens(map_num); - for (int i = 0; i < map_num; ++i) { - if (!_reader_bits::readToken(line, tokens[i])) { - std::ostringstream msg; - msg << "Column not found (" << i + 1 << ")"; - throw FormatError(msg.str()); - } - } - if (line >> std::ws >> c) - throw FormatError("Extra character at the end of line"); - - Node n; - if (!_use_nodes) { - n = _graph.addNode(); - if (label_index != -1) - _node_index.insert(std::make_pair(tokens[label_index], n)); - } else { - if (label_index == -1) - throw FormatError("Label map not found"); - typename std::map::iterator it = - _node_index.find(tokens[label_index]); - if (it == _node_index.end()) { - std::ostringstream msg; - msg << "Node with label not found: " << tokens[label_index]; - throw FormatError(msg.str()); - } - n = it->second; - } - - for (int i = 0; i < static_cast(_node_maps.size()); ++i) { - _node_maps[i].second->set(n, tokens[map_index[i]]); - } - - } - if (readSuccess()) { - line.putback(c); - } - } - - void readEdges() { - - std::vector map_index(_edge_maps.size()); - int map_num, label_index; - - char c; - if (!readLine() || !(line >> c) || c == '@') { - if (readSuccess() && line) line.putback(c); - if (!_edge_maps.empty()) - throw FormatError("Cannot find map names"); - return; - } - line.putback(c); - - { - std::map maps; - - std::string map; - int index = 0; - while (_reader_bits::readToken(line, map)) { - if(map == "-") { - if(index!=0) - throw FormatError("'-' is not allowed as a map name"); - else if (line >> std::ws >> c) - throw FormatError("Extra character at the end of line"); - else break; - } - if (maps.find(map) != maps.end()) { - std::ostringstream msg; - msg << "Multiple occurence of edge map: " << map; - throw FormatError(msg.str()); - } - maps.insert(std::make_pair(map, index)); - ++index; - } - - for (int i = 0; i < static_cast(_edge_maps.size()); ++i) { - std::map::iterator jt = - maps.find(_edge_maps[i].first); - if (jt == maps.end()) { - std::ostringstream msg; - msg << "Map not found: " << _edge_maps[i].first; - throw FormatError(msg.str()); - } - map_index[i] = jt->second; - } - - { - std::map::iterator jt = maps.find("label"); - if (jt != maps.end()) { - label_index = jt->second; - } else { - label_index = -1; - } - } - map_num = maps.size(); - } - - while (readLine() && line >> c && c != '@') { - line.putback(c); - - std::string source_token; - std::string target_token; - - if (!_reader_bits::readToken(line, source_token)) - throw FormatError("Node u not found"); - - if (!_reader_bits::readToken(line, target_token)) - throw FormatError("Node v not found"); - - std::vector tokens(map_num); - for (int i = 0; i < map_num; ++i) { - if (!_reader_bits::readToken(line, tokens[i])) { - std::ostringstream msg; - msg << "Column not found (" << i + 1 << ")"; - throw FormatError(msg.str()); - } - } - if (line >> std::ws >> c) - throw FormatError("Extra character at the end of line"); - - Edge e; - if (!_use_edges) { - - typename NodeIndex::iterator it; - - it = _node_index.find(source_token); - if (it == _node_index.end()) { - std::ostringstream msg; - msg << "Item not found: " << source_token; - throw FormatError(msg.str()); - } - Node source = it->second; - - it = _node_index.find(target_token); - if (it == _node_index.end()) { - std::ostringstream msg; - msg << "Item not found: " << target_token; - throw FormatError(msg.str()); - } - Node target = it->second; - - e = _graph.addEdge(source, target); - if (label_index != -1) - _edge_index.insert(std::make_pair(tokens[label_index], e)); - } else { - if (label_index == -1) - throw FormatError("Label map not found"); - typename std::map::iterator it = - _edge_index.find(tokens[label_index]); - if (it == _edge_index.end()) { - std::ostringstream msg; - msg << "Edge with label not found: " << tokens[label_index]; - throw FormatError(msg.str()); - } - e = it->second; - } - - for (int i = 0; i < static_cast(_edge_maps.size()); ++i) { - _edge_maps[i].second->set(e, tokens[map_index[i]]); - } - - } - if (readSuccess()) { - line.putback(c); - } - } - - void readAttributes() { - - std::set read_attr; - - char c; - while (readLine() && line >> c && c != '@') { - line.putback(c); - - std::string attr, token; - if (!_reader_bits::readToken(line, attr)) - throw FormatError("Attribute name not found"); - if (!_reader_bits::readToken(line, token)) - throw FormatError("Attribute value not found"); - if (line >> c) - throw FormatError("Extra character at the end of line"); - - { - std::set::iterator it = read_attr.find(attr); - if (it != read_attr.end()) { - std::ostringstream msg; - msg << "Multiple occurence of attribute: " << attr; - throw FormatError(msg.str()); - } - read_attr.insert(attr); - } - - { - typename Attributes::iterator it = _attributes.lower_bound(attr); - while (it != _attributes.end() && it->first == attr) { - it->second->set(token); - ++it; - } - } - - } - if (readSuccess()) { - line.putback(c); - } - for (typename Attributes::iterator it = _attributes.begin(); - it != _attributes.end(); ++it) { - if (read_attr.find(it->first) == read_attr.end()) { - std::ostringstream msg; - msg << "Attribute not found: " << it->first; - throw FormatError(msg.str()); - } - } - } - - public: - - /// \name Execution of the Reader - /// @{ - - /// \brief Start the batch processing - /// - /// This function starts the batch processing - void run() { - - LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); - - bool nodes_done = _skip_nodes; - bool edges_done = _skip_edges; - bool attributes_done = false; - - line_num = 0; - readLine(); - skipSection(); - - while (readSuccess()) { - try { - char c; - std::string section, caption; - line >> c; - _reader_bits::readToken(line, section); - _reader_bits::readToken(line, caption); - - if (line >> c) - throw FormatError("Extra character at the end of line"); - - if (section == "nodes" && !nodes_done) { - if (_nodes_caption.empty() || _nodes_caption == caption) { - readNodes(); - nodes_done = true; - } - } else if ((section == "edges" || section == "arcs") && - !edges_done) { - if (_edges_caption.empty() || _edges_caption == caption) { - readEdges(); - edges_done = true; - } - } else if (section == "attributes" && !attributes_done) { - if (_attributes_caption.empty() || _attributes_caption == caption) { - readAttributes(); - attributes_done = true; - } - } else { - readLine(); - skipSection(); - } - } catch (FormatError& error) { - error.line(line_num); - error.file(_filename); - throw; - } - } - - if (!nodes_done) { - throw FormatError("Section @nodes not found"); - } - - if (!edges_done) { - throw FormatError("Section @edges not found"); - } - - if (!attributes_done && !_attributes.empty()) { - throw FormatError("Section @attributes not found"); - } - - } - - /// @} - - }; - - /// \ingroup lemon_io - /// - /// \brief Return a \ref lemon::GraphReader "GraphReader" class - /// - /// This function just returns a \ref lemon::GraphReader "GraphReader" class. - /// - /// With this function a graph can be read from an - /// \ref lgf-format "LGF" file or input stream with several maps and - /// attributes. For example, there is weighted matching problem on a - /// graph, i.e. a graph with a \e weight map on the edges. This - /// graph can be read with the following code: - /// - ///\code - ///ListGraph graph; - ///ListGraph::EdgeMap weight(graph); - ///graphReader(graph, std::cin). - /// edgeMap("weight", weight). - /// run(); - ///\endcode - /// - /// For a complete documentation, please see the - /// \ref lemon::GraphReader "GraphReader" - /// class documentation. - /// \warning Don't forget to put the \ref lemon::GraphReader::run() "run()" - /// to the end of the parameter list. - /// \relates GraphReader - /// \sa graphReader(TGR& graph, const std::string& fn) - /// \sa graphReader(TGR& graph, const char* fn) - template - GraphReader graphReader(TGR& graph, std::istream& is) { - GraphReader tmp(graph, is); - return tmp; - } - - /// \brief Return a \ref GraphReader class - /// - /// This function just returns a \ref GraphReader class. - /// \relates GraphReader - /// \sa graphReader(TGR& graph, std::istream& is) - template - GraphReader graphReader(TGR& graph, const std::string& fn) { - GraphReader tmp(graph, fn); - return tmp; - } - - /// \brief Return a \ref GraphReader class - /// - /// This function just returns a \ref GraphReader class. - /// \relates GraphReader - /// \sa graphReader(TGR& graph, std::istream& is) - template - GraphReader graphReader(TGR& graph, const char* fn) { - GraphReader tmp(graph, fn); - return tmp; - } - - template - class BpGraphReader; - - template - BpGraphReader bpGraphReader(TBGR& graph, std::istream& is = std::cin); - template - BpGraphReader bpGraphReader(TBGR& graph, const std::string& fn); - template - BpGraphReader bpGraphReader(TBGR& graph, const char *fn); - - /// \ingroup lemon_io - /// - /// \brief \ref lgf-format "LGF" reader for bipartite graphs - /// - /// This utility reads an \ref lgf-format "LGF" file. - /// - /// It can be used almost the same way as \c GraphReader, but it - /// reads the red and blue nodes from separate sections, and these - /// sections can contain different set of maps. - /// - /// The red and blue node maps are read from the corresponding - /// sections. If a map is defined with the same name in both of - /// these sections, then it can be read as a node map. - template - class BpGraphReader { - public: - - typedef BGR Graph; - - private: - - TEMPLATE_BPGRAPH_TYPEDEFS(BGR); - - std::istream* _is; - bool local_is; - std::string _filename; - - BGR& _graph; - - std::string _nodes_caption; - std::string _edges_caption; - std::string _attributes_caption; - - typedef std::map RedNodeIndex; - RedNodeIndex _red_node_index; - typedef std::map BlueNodeIndex; - BlueNodeIndex _blue_node_index; - typedef std::map EdgeIndex; - EdgeIndex _edge_index; - - typedef std::vector*> > RedNodeMaps; - RedNodeMaps _red_node_maps; - typedef std::vector*> > BlueNodeMaps; - BlueNodeMaps _blue_node_maps; - - typedef std::vector*> > EdgeMaps; - EdgeMaps _edge_maps; - - typedef std::multimap - Attributes; - Attributes _attributes; - - bool _use_nodes; - bool _use_edges; - - bool _skip_nodes; - bool _skip_edges; - - int line_num; - std::istringstream line; - - public: - - /// \brief Constructor - /// - /// Construct an undirected graph reader, which reads from the given - /// input stream. - BpGraphReader(BGR& graph, std::istream& is = std::cin) - : _is(&is), local_is(false), _graph(graph), - _use_nodes(false), _use_edges(false), - _skip_nodes(false), _skip_edges(false) {} - - /// \brief Constructor - /// - /// Construct an undirected graph reader, which reads from the given - /// file. - BpGraphReader(BGR& graph, const std::string& fn) - : _is(new std::ifstream(fn.c_str())), local_is(true), - _filename(fn), _graph(graph), - _use_nodes(false), _use_edges(false), - _skip_nodes(false), _skip_edges(false) { - if (!(*_is)) { - delete _is; - throw IoError("Cannot open file", fn); - } - } - - /// \brief Constructor - /// - /// Construct an undirected graph reader, which reads from the given - /// file. - BpGraphReader(BGR& graph, const char* fn) - : _is(new std::ifstream(fn)), local_is(true), - _filename(fn), _graph(graph), - _use_nodes(false), _use_edges(false), - _skip_nodes(false), _skip_edges(false) { - if (!(*_is)) { - delete _is; - throw IoError("Cannot open file", fn); - } - } - - /// \brief Destructor - ~BpGraphReader() { - for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); - it != _red_node_maps.end(); ++it) { - delete it->second; - } - - for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); - it != _blue_node_maps.end(); ++it) { - delete it->second; - } - - for (typename EdgeMaps::iterator it = _edge_maps.begin(); - it != _edge_maps.end(); ++it) { - delete it->second; - } - - for (typename Attributes::iterator it = _attributes.begin(); - it != _attributes.end(); ++it) { - delete it->second; - } - - if (local_is) { - delete _is; - } - - } - - private: - template - friend BpGraphReader bpGraphReader(TBGR& graph, std::istream& is); - template - friend BpGraphReader bpGraphReader(TBGR& graph, - const std::string& fn); - template - friend BpGraphReader bpGraphReader(TBGR& graph, const char *fn); - - BpGraphReader(BpGraphReader& other) - : _is(other._is), local_is(other.local_is), _graph(other._graph), - _use_nodes(other._use_nodes), _use_edges(other._use_edges), - _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { - - other._is = 0; - other.local_is = false; - - _red_node_index.swap(other._red_node_index); - _blue_node_index.swap(other._blue_node_index); - _edge_index.swap(other._edge_index); - - _red_node_maps.swap(other._red_node_maps); - _blue_node_maps.swap(other._blue_node_maps); - _edge_maps.swap(other._edge_maps); - _attributes.swap(other._attributes); - - _nodes_caption = other._nodes_caption; - _edges_caption = other._edges_caption; - _attributes_caption = other._attributes_caption; - - } - - BpGraphReader& operator=(const BpGraphReader&); - - public: - - /// \name Reading Rules - /// @{ - - /// \brief Node map reading rule - /// - /// Add a node map reading rule to the reader. - template - BpGraphReader& nodeMap(const std::string& caption, Map& map) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* red_storage = - new _reader_bits::MapStorage(map); - _red_node_maps.push_back(std::make_pair(caption, red_storage)); - _reader_bits::MapStorageBase* blue_storage = - new _reader_bits::MapStorage(map); - _blue_node_maps.push_back(std::make_pair(caption, blue_storage)); - return *this; - } - - /// \brief Node map reading rule - /// - /// Add a node map reading rule with specialized converter to the - /// reader. - template - BpGraphReader& nodeMap(const std::string& caption, Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* red_storage = - new _reader_bits::MapStorage(map, converter); - _red_node_maps.push_back(std::make_pair(caption, red_storage)); - _reader_bits::MapStorageBase* blue_storage = - new _reader_bits::MapStorage(map, converter); - _blue_node_maps.push_back(std::make_pair(caption, blue_storage)); - return *this; - } - - /// Add a red node map reading rule to the reader. - template - BpGraphReader& redNodeMap(const std::string& caption, Map& map) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map); - _red_node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Red node map reading rule - /// - /// Add a red node map node reading rule with specialized converter to - /// the reader. - template - BpGraphReader& redNodeMap(const std::string& caption, Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map, converter); - _red_node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// Add a blue node map reading rule to the reader. - template - BpGraphReader& blueNodeMap(const std::string& caption, Map& map) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map); - _blue_node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Blue node map reading rule - /// - /// Add a blue node map reading rule with specialized converter to - /// the reader. - template - BpGraphReader& blueNodeMap(const std::string& caption, Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map, converter); - _blue_node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Edge map reading rule - /// - /// Add an edge map reading rule to the reader. - template - BpGraphReader& edgeMap(const std::string& caption, Map& map) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map); - _edge_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Edge map reading rule - /// - /// Add an edge map reading rule with specialized converter to the - /// reader. - template - BpGraphReader& edgeMap(const std::string& caption, Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* storage = - new _reader_bits::MapStorage(map, converter); - _edge_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc map reading rule - /// - /// Add an arc map reading rule to the reader. - template - BpGraphReader& arcMap(const std::string& caption, Map& map) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* forward_storage = - new _reader_bits::GraphArcMapStorage(_graph, map); - _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); - _reader_bits::MapStorageBase* backward_storage = - new _reader_bits::GraphArcMapStorage(_graph, map); - _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); - return *this; - } - - /// \brief Arc map reading rule - /// - /// Add an arc map reading rule with specialized converter to the - /// reader. - template - BpGraphReader& arcMap(const std::string& caption, Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _reader_bits::MapStorageBase* forward_storage = - new _reader_bits::GraphArcMapStorage - (_graph, map, converter); - _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); - _reader_bits::MapStorageBase* backward_storage = - new _reader_bits::GraphArcMapStorage - (_graph, map, converter); - _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); - return *this; - } - - /// \brief Attribute reading rule - /// - /// Add an attribute reading rule to the reader. - template - BpGraphReader& attribute(const std::string& caption, Value& value) { - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(value); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Attribute reading rule - /// - /// Add an attribute reading rule with specialized converter to the - /// reader. - template - BpGraphReader& attribute(const std::string& caption, Value& value, - const Converter& converter = Converter()) { - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(value, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Node reading rule - /// - /// Add a node reading rule to reader. - BpGraphReader& node(const std::string& caption, Node& node) { - typedef _reader_bits::DoubleMapLookUpConverter< - Node, RedNodeIndex, BlueNodeIndex> Converter; - Converter converter(_red_node_index, _blue_node_index); - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(node, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Red node reading rule - /// - /// Add a red node reading rule to reader. - BpGraphReader& redNode(const std::string& caption, RedNode& node) { - typedef _reader_bits::MapLookUpConverter Converter; - Converter converter(_red_node_index); - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(node, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Blue node reading rule - /// - /// Add a blue node reading rule to reader. - BpGraphReader& blueNode(const std::string& caption, BlueNode& node) { - typedef _reader_bits::MapLookUpConverter Converter; - Converter converter(_blue_node_index); - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(node, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Edge reading rule - /// - /// Add an edge reading rule to reader. - BpGraphReader& edge(const std::string& caption, Edge& edge) { - typedef _reader_bits::MapLookUpConverter Converter; - Converter converter(_edge_index); - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(edge, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc reading rule - /// - /// Add an arc reading rule to reader. - BpGraphReader& arc(const std::string& caption, Arc& arc) { - typedef _reader_bits::GraphArcLookUpConverter Converter; - Converter converter(_graph, _edge_index); - _reader_bits::ValueStorageBase* storage = - new _reader_bits::ValueStorage(arc, converter); - _attributes.insert(std::make_pair(caption, storage)); - return *this; - } - - /// @} - - /// \name Select Section by Name - /// @{ - - /// \brief Set \c \@nodes section to be read - /// - /// Set \c \@nodes section to be read. - BpGraphReader& nodes(const std::string& caption) { - _nodes_caption = caption; - return *this; - } - - /// \brief Set \c \@edges section to be read - /// - /// Set \c \@edges section to be read. - BpGraphReader& edges(const std::string& caption) { - _edges_caption = caption; - return *this; - } - - /// \brief Set \c \@attributes section to be read - /// - /// Set \c \@attributes section to be read. - BpGraphReader& attributes(const std::string& caption) { - _attributes_caption = caption; - return *this; - } - - /// @} - - /// \name Using Previously Constructed Node or Edge Set - /// @{ - - /// \brief Use previously constructed node set - /// - /// Use previously constructed node set, and specify the node - /// label map. - template - BpGraphReader& useNodes(const Map& map) { - checkConcept, Map>(); - LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); - _use_nodes = true; - _writer_bits::DefaultConverter converter; - for (RedNodeIt n(_graph); n != INVALID; ++n) { - _red_node_index.insert(std::make_pair(converter(map[n]), n)); - } - for (BlueNodeIt n(_graph); n != INVALID; ++n) { - _blue_node_index.insert(std::make_pair(converter(map[n]), n)); - } - return *this; - } - - /// \brief Use previously constructed node set - /// - /// Use previously constructed node set, and specify the node - /// label map and a functor which converts the label map values to - /// \c std::string. - template - BpGraphReader& useNodes(const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); - _use_nodes = true; - for (RedNodeIt n(_graph); n != INVALID; ++n) { - _red_node_index.insert(std::make_pair(converter(map[n]), n)); - } - for (BlueNodeIt n(_graph); n != INVALID; ++n) { - _blue_node_index.insert(std::make_pair(converter(map[n]), n)); - } - return *this; - } - - /// \brief Use previously constructed edge set - /// - /// Use previously constructed edge set, and specify the edge - /// label map. - template - BpGraphReader& useEdges(const Map& map) { - checkConcept, Map>(); - LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member"); - _use_edges = true; - _writer_bits::DefaultConverter converter; - for (EdgeIt a(_graph); a != INVALID; ++a) { - _edge_index.insert(std::make_pair(converter(map[a]), a)); - } - return *this; - } - - /// \brief Use previously constructed edge set - /// - /// Use previously constructed edge set, and specify the edge - /// label map and a functor which converts the label map values to - /// \c std::string. - template - BpGraphReader& useEdges(const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member"); - _use_edges = true; - for (EdgeIt a(_graph); a != INVALID; ++a) { - _edge_index.insert(std::make_pair(converter(map[a]), a)); - } - return *this; - } - - /// \brief Skip the reading of node section - /// - /// Omit the reading of the node section. This implies that each node - /// map reading rule will be abandoned, and the nodes of the graph - /// will not be constructed, which usually cause that the edge set - /// could not be read due to lack of node name - /// could not be read due to lack of node name resolving. - /// Therefore \c skipEdges() function should also be used, or - /// \c useNodes() should be used to specify the label of the nodes. - BpGraphReader& skipNodes() { - LEMON_ASSERT(!_skip_nodes, "Skip nodes already set"); - _skip_nodes = true; - return *this; - } - - /// \brief Skip the reading of edge section - /// - /// Omit the reading of the edge section. This implies that each edge - /// map reading rule will be abandoned, and the edges of the graph - /// will not be constructed. - BpGraphReader& skipEdges() { - LEMON_ASSERT(!_skip_edges, "Skip edges already set"); - _skip_edges = true; - return *this; - } - - /// @} - - private: - - bool readLine() { - std::string str; - while(++line_num, std::getline(*_is, str)) { - line.clear(); line.str(str); - char c; - if (line >> std::ws >> c && c != '#') { - line.putback(c); - return true; - } - } - return false; - } - - bool readSuccess() { - return static_cast(*_is); - } - - void skipSection() { - char c; - while (readSuccess() && line >> c && c != '@') { - readLine(); - } - if (readSuccess()) { - line.putback(c); - } - } - - void readRedNodes() { - - std::vector map_index(_red_node_maps.size()); - int map_num, label_index; - - char c; - if (!readLine() || !(line >> c) || c == '@') { - if (readSuccess() && line) line.putback(c); - if (!_red_node_maps.empty()) - throw FormatError("Cannot find map names"); - return; - } - line.putback(c); - - { - std::map maps; - - std::string map; - int index = 0; - while (_reader_bits::readToken(line, map)) { - if (maps.find(map) != maps.end()) { - std::ostringstream msg; - msg << "Multiple occurence of red node map: " << map; - throw FormatError(msg.str()); - } - maps.insert(std::make_pair(map, index)); - ++index; - } - - for (int i = 0; i < static_cast(_red_node_maps.size()); ++i) { - std::map::iterator jt = - maps.find(_red_node_maps[i].first); - if (jt == maps.end()) { - std::ostringstream msg; - msg << "Map not found: " << _red_node_maps[i].first; - throw FormatError(msg.str()); - } - map_index[i] = jt->second; - } - - { - std::map::iterator jt = maps.find("label"); - if (jt != maps.end()) { - label_index = jt->second; - } else { - label_index = -1; - } - } - map_num = maps.size(); - } - - while (readLine() && line >> c && c != '@') { - line.putback(c); - - std::vector tokens(map_num); - for (int i = 0; i < map_num; ++i) { - if (!_reader_bits::readToken(line, tokens[i])) { - std::ostringstream msg; - msg << "Column not found (" << i + 1 << ")"; - throw FormatError(msg.str()); - } - } - if (line >> std::ws >> c) - throw FormatError("Extra character at the end of line"); - - RedNode n; - if (!_use_nodes) { - n = _graph.addRedNode(); - if (label_index != -1) - _red_node_index.insert(std::make_pair(tokens[label_index], n)); - } else { - if (label_index == -1) - throw FormatError("Label map not found"); - typename std::map::iterator it = - _red_node_index.find(tokens[label_index]); - if (it == _red_node_index.end()) { - std::ostringstream msg; - msg << "Node with label not found: " << tokens[label_index]; - throw FormatError(msg.str()); - } - n = it->second; - } - - for (int i = 0; i < static_cast(_red_node_maps.size()); ++i) { - _red_node_maps[i].second->set(n, tokens[map_index[i]]); - } - - } - if (readSuccess()) { - line.putback(c); - } - } - - void readBlueNodes() { - - std::vector map_index(_blue_node_maps.size()); - int map_num, label_index; - - char c; - if (!readLine() || !(line >> c) || c == '@') { - if (readSuccess() && line) line.putback(c); - if (!_blue_node_maps.empty()) - throw FormatError("Cannot find map names"); - return; - } - line.putback(c); - - { - std::map maps; - - std::string map; - int index = 0; - while (_reader_bits::readToken(line, map)) { - if (maps.find(map) != maps.end()) { - std::ostringstream msg; - msg << "Multiple occurence of blue node map: " << map; - throw FormatError(msg.str()); - } - maps.insert(std::make_pair(map, index)); - ++index; - } - - for (int i = 0; i < static_cast(_blue_node_maps.size()); ++i) { - std::map::iterator jt = - maps.find(_blue_node_maps[i].first); - if (jt == maps.end()) { - std::ostringstream msg; - msg << "Map not found: " << _blue_node_maps[i].first; - throw FormatError(msg.str()); - } - map_index[i] = jt->second; - } - - { - std::map::iterator jt = maps.find("label"); - if (jt != maps.end()) { - label_index = jt->second; - } else { - label_index = -1; - } - } - map_num = maps.size(); - } - - while (readLine() && line >> c && c != '@') { - line.putback(c); - - std::vector tokens(map_num); - for (int i = 0; i < map_num; ++i) { - if (!_reader_bits::readToken(line, tokens[i])) { - std::ostringstream msg; - msg << "Column not found (" << i + 1 << ")"; - throw FormatError(msg.str()); - } - } - if (line >> std::ws >> c) - throw FormatError("Extra character at the end of line"); - - BlueNode n; - if (!_use_nodes) { - n = _graph.addBlueNode(); - if (label_index != -1) - _blue_node_index.insert(std::make_pair(tokens[label_index], n)); - } else { - if (label_index == -1) - throw FormatError("Label map not found"); - typename std::map::iterator it = - _blue_node_index.find(tokens[label_index]); - if (it == _blue_node_index.end()) { - std::ostringstream msg; - msg << "Node with label not found: " << tokens[label_index]; - throw FormatError(msg.str()); - } - n = it->second; - } - - for (int i = 0; i < static_cast(_blue_node_maps.size()); ++i) { - _blue_node_maps[i].second->set(n, tokens[map_index[i]]); - } - - } - if (readSuccess()) { - line.putback(c); - } - } - - void readEdges() { - - std::vector map_index(_edge_maps.size()); - int map_num, label_index; - - char c; - if (!readLine() || !(line >> c) || c == '@') { - if (readSuccess() && line) line.putback(c); - if (!_edge_maps.empty()) - throw FormatError("Cannot find map names"); - return; - } - line.putback(c); - - { - std::map maps; - - std::string map; - int index = 0; - while (_reader_bits::readToken(line, map)) { - if (maps.find(map) != maps.end()) { - std::ostringstream msg; - msg << "Multiple occurence of edge map: " << map; - throw FormatError(msg.str()); - } - maps.insert(std::make_pair(map, index)); - ++index; - } - - for (int i = 0; i < static_cast(_edge_maps.size()); ++i) { - std::map::iterator jt = - maps.find(_edge_maps[i].first); - if (jt == maps.end()) { - std::ostringstream msg; - msg << "Map not found: " << _edge_maps[i].first; - throw FormatError(msg.str()); - } - map_index[i] = jt->second; - } - - { - std::map::iterator jt = maps.find("label"); - if (jt != maps.end()) { - label_index = jt->second; - } else { - label_index = -1; - } - } - map_num = maps.size(); - } - - while (readLine() && line >> c && c != '@') { - line.putback(c); - - std::string source_token; - std::string target_token; - - if (!_reader_bits::readToken(line, source_token)) - throw FormatError("Red node not found"); - - if (!_reader_bits::readToken(line, target_token)) - throw FormatError("Blue node not found"); - - std::vector tokens(map_num); - for (int i = 0; i < map_num; ++i) { - if (!_reader_bits::readToken(line, tokens[i])) { - std::ostringstream msg; - msg << "Column not found (" << i + 1 << ")"; - throw FormatError(msg.str()); - } - } - if (line >> std::ws >> c) - throw FormatError("Extra character at the end of line"); - - Edge e; - if (!_use_edges) { - typename RedNodeIndex::iterator rit = - _red_node_index.find(source_token); - if (rit == _red_node_index.end()) { - std::ostringstream msg; - msg << "Item not found: " << source_token; - throw FormatError(msg.str()); - } - RedNode source = rit->second; - typename BlueNodeIndex::iterator it = - _blue_node_index.find(target_token); - if (it == _blue_node_index.end()) { - std::ostringstream msg; - msg << "Item not found: " << target_token; - throw FormatError(msg.str()); - } - BlueNode target = it->second; - - // It is checked that source is red and - // target is blue, so this should be safe: - e = _graph.addEdge(source, target); - if (label_index != -1) - _edge_index.insert(std::make_pair(tokens[label_index], e)); - } else { - if (label_index == -1) - throw FormatError("Label map not found"); - typename std::map::iterator it = - _edge_index.find(tokens[label_index]); - if (it == _edge_index.end()) { - std::ostringstream msg; - msg << "Edge with label not found: " << tokens[label_index]; - throw FormatError(msg.str()); - } - e = it->second; - } - - for (int i = 0; i < static_cast(_edge_maps.size()); ++i) { - _edge_maps[i].second->set(e, tokens[map_index[i]]); - } - - } - if (readSuccess()) { - line.putback(c); - } - } - - void readAttributes() { - - std::set read_attr; - - char c; - while (readLine() && line >> c && c != '@') { - line.putback(c); - - std::string attr, token; - if (!_reader_bits::readToken(line, attr)) - throw FormatError("Attribute name not found"); - if (!_reader_bits::readToken(line, token)) - throw FormatError("Attribute value not found"); - if (line >> c) - throw FormatError("Extra character at the end of line"); - - { - std::set::iterator it = read_attr.find(attr); - if (it != read_attr.end()) { - std::ostringstream msg; - msg << "Multiple occurence of attribute: " << attr; - throw FormatError(msg.str()); - } - read_attr.insert(attr); - } - - { - typename Attributes::iterator it = _attributes.lower_bound(attr); - while (it != _attributes.end() && it->first == attr) { - it->second->set(token); - ++it; - } - } - - } - if (readSuccess()) { - line.putback(c); - } - for (typename Attributes::iterator it = _attributes.begin(); - it != _attributes.end(); ++it) { - if (read_attr.find(it->first) == read_attr.end()) { - std::ostringstream msg; - msg << "Attribute not found: " << it->first; - throw FormatError(msg.str()); - } - } - } - - public: - - /// \name Execution of the Reader - /// @{ - - /// \brief Start the batch processing - /// - /// This function starts the batch processing - void run() { - - LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); - - bool red_nodes_done = _skip_nodes; - bool blue_nodes_done = _skip_nodes; - bool edges_done = _skip_edges; - bool attributes_done = false; - - line_num = 0; - readLine(); - skipSection(); - - while (readSuccess()) { - try { - char c; - std::string section, caption; - line >> c; - _reader_bits::readToken(line, section); - _reader_bits::readToken(line, caption); - - if (line >> c) - throw FormatError("Extra character at the end of line"); - - if (section == "red_nodes" && !red_nodes_done) { - if (_nodes_caption.empty() || _nodes_caption == caption) { - readRedNodes(); - red_nodes_done = true; - } - } else if (section == "blue_nodes" && !blue_nodes_done) { - if (_nodes_caption.empty() || _nodes_caption == caption) { - readBlueNodes(); - blue_nodes_done = true; - } - } else if ((section == "edges" || section == "arcs") && - !edges_done) { - if (_edges_caption.empty() || _edges_caption == caption) { - readEdges(); - edges_done = true; - } - } else if (section == "attributes" && !attributes_done) { - if (_attributes_caption.empty() || _attributes_caption == caption) { - readAttributes(); - attributes_done = true; - } - } else { - readLine(); - skipSection(); - } - } catch (FormatError& error) { - error.line(line_num); - error.file(_filename); - throw; - } - } - - if (!red_nodes_done) { - throw FormatError("Section @red_nodes not found"); - } - - if (!blue_nodes_done) { - throw FormatError("Section @blue_nodes not found"); - } - - if (!edges_done) { - throw FormatError("Section @edges not found"); - } - - if (!attributes_done && !_attributes.empty()) { - throw FormatError("Section @attributes not found"); - } - - } - - /// @} - - }; - - /// \ingroup lemon_io - /// - /// \brief Return a \ref lemon::BpGraphReader "BpGraphReader" class - /// - /// This function just returns a \ref lemon::BpGraphReader - /// "BpGraphReader" class. - /// - /// With this function a graph can be read from an - /// \ref lgf-format "LGF" file or input stream with several maps and - /// attributes. For example, there is bipartite weighted matching problem - /// on a graph, i.e. a graph with a \e weight map on the edges. This - /// graph can be read with the following code: - /// - ///\code - ///ListBpGraph graph; - ///ListBpGraph::EdgeMap weight(graph); - ///bpGraphReader(graph, std::cin). - /// edgeMap("weight", weight). - /// run(); - ///\endcode - /// - /// For a complete documentation, please see the - /// \ref lemon::BpGraphReader "BpGraphReader" - /// class documentation. - /// \warning Don't forget to put the \ref lemon::BpGraphReader::run() "run()" - /// to the end of the parameter list. - /// \relates BpGraphReader - /// \sa bpGraphReader(TBGR& graph, const std::string& fn) - /// \sa bpGraphReader(TBGR& graph, const char* fn) - template - BpGraphReader bpGraphReader(TBGR& graph, std::istream& is) { - BpGraphReader tmp(graph, is); - return tmp; - } - - /// \brief Return a \ref BpGraphReader class - /// - /// This function just returns a \ref BpGraphReader class. - /// \relates BpGraphReader - /// \sa bpGraphReader(TBGR& graph, std::istream& is) - template - BpGraphReader bpGraphReader(TBGR& graph, const std::string& fn) { - BpGraphReader tmp(graph, fn); - return tmp; - } - - /// \brief Return a \ref BpGraphReader class - /// - /// This function just returns a \ref BpGraphReader class. - /// \relates BpGraphReader - /// \sa bpGraphReader(TBGR& graph, std::istream& is) - template - BpGraphReader bpGraphReader(TBGR& graph, const char* fn) { - BpGraphReader tmp(graph, fn); - return tmp; - } - - class SectionReader; - - SectionReader sectionReader(std::istream& is); - SectionReader sectionReader(const std::string& fn); - SectionReader sectionReader(const char* fn); - - /// \ingroup lemon_io - /// - /// \brief Section reader class - /// - /// In the \ref lgf-format "LGF" file extra sections can be placed, - /// which contain any data in arbitrary format. Such sections can be - /// read with this class. A reading rule can be added to the class - /// with two different functions. With the \c sectionLines() function a - /// functor can process the section line-by-line, while with the \c - /// sectionStream() member the section can be read from an input - /// stream. - class SectionReader { - private: - - std::istream* _is; - bool local_is; - std::string _filename; - - typedef std::map Sections; - Sections _sections; - - int line_num; - std::istringstream line; - - public: - - /// \brief Constructor - /// - /// Construct a section reader, which reads from the given input - /// stream. - SectionReader(std::istream& is) - : _is(&is), local_is(false) {} - - /// \brief Constructor - /// - /// Construct a section reader, which reads from the given file. - SectionReader(const std::string& fn) - : _is(new std::ifstream(fn.c_str())), local_is(true), - _filename(fn) { - if (!(*_is)) { - delete _is; - throw IoError("Cannot open file", fn); - } - } - - /// \brief Constructor - /// - /// Construct a section reader, which reads from the given file. - SectionReader(const char* fn) - : _is(new std::ifstream(fn)), local_is(true), - _filename(fn) { - if (!(*_is)) { - delete _is; - throw IoError("Cannot open file", fn); - } - } - - /// \brief Destructor - ~SectionReader() { - for (Sections::iterator it = _sections.begin(); - it != _sections.end(); ++it) { - delete it->second; - } - - if (local_is) { - delete _is; - } - - } - - private: - - friend SectionReader sectionReader(std::istream& is); - friend SectionReader sectionReader(const std::string& fn); - friend SectionReader sectionReader(const char* fn); - - SectionReader(SectionReader& other) - : _is(other._is), local_is(other.local_is) { - - other._is = 0; - other.local_is = false; - - _sections.swap(other._sections); - } - - SectionReader& operator=(const SectionReader&); - - public: - - /// \name Section Readers - /// @{ - - /// \brief Add a section processor with line oriented reading - /// - /// The first parameter is the type descriptor of the section, the - /// second is a functor, which takes just one \c std::string - /// parameter. At the reading process, each line of the section - /// will be given to the functor object. However, the empty lines - /// and the comment lines are filtered out, and the leading - /// whitespaces are trimmed from each processed string. - /// - /// For example, let's see a section, which contain several - /// integers, which should be inserted into a vector. - ///\code - /// @numbers - /// 12 45 23 - /// 4 - /// 23 6 - ///\endcode - /// - /// The functor is implemented as a struct: - ///\code - /// struct NumberSection { - /// std::vector& _data; - /// NumberSection(std::vector& data) : _data(data) {} - /// void operator()(const std::string& line) { - /// std::istringstream ls(line); - /// int value; - /// while (ls >> value) _data.push_back(value); - /// } - /// }; - /// - /// // ... - /// - /// reader.sectionLines("numbers", NumberSection(vec)); - ///\endcode - template - SectionReader& sectionLines(const std::string& type, Functor functor) { - LEMON_ASSERT(!type.empty(), "Type is empty."); - LEMON_ASSERT(_sections.find(type) == _sections.end(), - "Multiple reading of section."); - _sections.insert(std::make_pair(type, - new _reader_bits::LineSection(functor))); - return *this; - } - - - /// \brief Add a section processor with stream oriented reading - /// - /// The first parameter is the type of the section, the second is - /// a functor, which takes an \c std::istream& and an \c int& - /// parameter, the latter regard to the line number of stream. The - /// functor can read the input while the section go on, and the - /// line number should be modified accordingly. - template - SectionReader& sectionStream(const std::string& type, Functor functor) { - LEMON_ASSERT(!type.empty(), "Type is empty."); - LEMON_ASSERT(_sections.find(type) == _sections.end(), - "Multiple reading of section."); - _sections.insert(std::make_pair(type, - new _reader_bits::StreamSection(functor))); - return *this; - } - - /// @} - - private: - - bool readLine() { - std::string str; - while(++line_num, std::getline(*_is, str)) { - line.clear(); line.str(str); - char c; - if (line >> std::ws >> c && c != '#') { - line.putback(c); - return true; - } - } - return false; - } - - bool readSuccess() { - return static_cast(*_is); - } - - void skipSection() { - char c; - while (readSuccess() && line >> c && c != '@') { - readLine(); - } - if (readSuccess()) { - line.putback(c); - } - } - - public: - - - /// \name Execution of the Reader - /// @{ - - /// \brief Start the batch processing - /// - /// This function starts the batch processing. - void run() { - - LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); - - std::set extra_sections; - - line_num = 0; - readLine(); - skipSection(); - - while (readSuccess()) { - try { - char c; - std::string section, caption; - line >> c; - _reader_bits::readToken(line, section); - _reader_bits::readToken(line, caption); - - if (line >> c) - throw FormatError("Extra character at the end of line"); - - if (extra_sections.find(section) != extra_sections.end()) { - std::ostringstream msg; - msg << "Multiple occurence of section: " << section; - throw FormatError(msg.str()); - } - Sections::iterator it = _sections.find(section); - if (it != _sections.end()) { - extra_sections.insert(section); - it->second->process(*_is, line_num); - } - readLine(); - skipSection(); - } catch (FormatError& error) { - error.line(line_num); - error.file(_filename); - throw; - } - } - for (Sections::iterator it = _sections.begin(); - it != _sections.end(); ++it) { - if (extra_sections.find(it->first) == extra_sections.end()) { - std::ostringstream os; - os << "Cannot find section: " << it->first; - throw FormatError(os.str()); - } - } - } - - /// @} - - }; - - /// \ingroup lemon_io - /// - /// \brief Return a \ref SectionReader class - /// - /// This function just returns a \ref SectionReader class. - /// - /// Please see SectionReader documentation about the custom section - /// input. - /// - /// \relates SectionReader - /// \sa sectionReader(const std::string& fn) - /// \sa sectionReader(const char *fn) - inline SectionReader sectionReader(std::istream& is) { - SectionReader tmp(is); - return tmp; - } - - /// \brief Return a \ref SectionReader class - /// - /// This function just returns a \ref SectionReader class. - /// \relates SectionReader - /// \sa sectionReader(std::istream& is) - inline SectionReader sectionReader(const std::string& fn) { - SectionReader tmp(fn); - return tmp; - } - - /// \brief Return a \ref SectionReader class - /// - /// This function just returns a \ref SectionReader class. - /// \relates SectionReader - /// \sa sectionReader(std::istream& is) - inline SectionReader sectionReader(const char* fn) { - SectionReader tmp(fn); - return tmp; - } - - /// \ingroup lemon_io - /// - /// \brief Reader for the contents of the \ref lgf-format "LGF" file - /// - /// This class can be used to read the sections, the map names and - /// the attributes from a file. Usually, the LEMON programs know - /// that, which type of graph, which maps and which attributes - /// should be read from a file, but in general tools (like glemon) - /// the contents of an LGF file should be guessed somehow. This class - /// reads the graph and stores the appropriate information for - /// reading the graph. - /// - ///\code - /// LgfContents contents("graph.lgf"); - /// contents.run(); - /// - /// // Does it contain any node section and arc section? - /// if (contents.nodeSectionNum() == 0 || contents.arcSectionNum()) { - /// std::cerr << "Failure, cannot find graph." << std::endl; - /// return -1; - /// } - /// std::cout << "The name of the default node section: " - /// << contents.nodeSection(0) << std::endl; - /// std::cout << "The number of the arc maps: " - /// << contents.arcMaps(0).size() << std::endl; - /// std::cout << "The name of second arc map: " - /// << contents.arcMaps(0)[1] << std::endl; - ///\endcode - class LgfContents { - private: - - std::istream* _is; - bool local_is; - - std::vector _node_sections; - std::vector _edge_sections; - std::vector _attribute_sections; - std::vector _extra_sections; - - std::vector _arc_sections; - - std::vector > _node_maps; - std::vector > _edge_maps; - - std::vector > _attributes; - - - int line_num; - std::istringstream line; - - public: - - /// \brief Constructor - /// - /// Construct an \e LGF contents reader, which reads from the given - /// input stream. - LgfContents(std::istream& is) - : _is(&is), local_is(false) {} - - /// \brief Constructor - /// - /// Construct an \e LGF contents reader, which reads from the given - /// file. - LgfContents(const std::string& fn) - : _is(new std::ifstream(fn.c_str())), local_is(true) { - if (!(*_is)) { - delete _is; - throw IoError("Cannot open file", fn); - } - } - - /// \brief Constructor - /// - /// Construct an \e LGF contents reader, which reads from the given - /// file. - LgfContents(const char* fn) - : _is(new std::ifstream(fn)), local_is(true) { - if (!(*_is)) { - delete _is; - throw IoError("Cannot open file", fn); - } - } - - /// \brief Destructor - ~LgfContents() { - if (local_is) delete _is; - } - - private: - - LgfContents(const LgfContents&); - LgfContents& operator=(const LgfContents&); - - public: - - - /// \name Node Sections - /// @{ - - /// \brief Gives back the number of node sections in the file. - /// - /// Gives back the number of node sections in the file. - int nodeSectionNum() const { - return _node_sections.size(); - } - - /// \brief Returns the node section name at the given position. - /// - /// Returns the node section name at the given position. - const std::string& nodeSection(int i) const { - return _node_sections[i]; - } - - /// \brief Gives back the node maps for the given section. - /// - /// Gives back the node maps for the given section. - const std::vector& nodeMapNames(int i) const { - return _node_maps[i]; - } - - /// @} - - /// \name Arc/Edge Sections - /// @{ - - /// \brief Gives back the number of arc/edge sections in the file. - /// - /// Gives back the number of arc/edge sections in the file. - /// \note It is synonym of \c edgeSectionNum(). - int arcSectionNum() const { - return _edge_sections.size(); - } - - /// \brief Returns the arc/edge section name at the given position. - /// - /// Returns the arc/edge section name at the given position. - /// \note It is synonym of \c edgeSection(). - const std::string& arcSection(int i) const { - return _edge_sections[i]; - } - - /// \brief Gives back the arc/edge maps for the given section. - /// - /// Gives back the arc/edge maps for the given section. - /// \note It is synonym of \c edgeMapNames(). - const std::vector& arcMapNames(int i) const { - return _edge_maps[i]; - } - - /// @} - - /// \name Synonyms - /// @{ - - /// \brief Gives back the number of arc/edge sections in the file. - /// - /// Gives back the number of arc/edge sections in the file. - /// \note It is synonym of \c arcSectionNum(). - int edgeSectionNum() const { - return _edge_sections.size(); - } - - /// \brief Returns the section name at the given position. - /// - /// Returns the section name at the given position. - /// \note It is synonym of \c arcSection(). - const std::string& edgeSection(int i) const { - return _edge_sections[i]; - } - - /// \brief Gives back the edge maps for the given section. - /// - /// Gives back the edge maps for the given section. - /// \note It is synonym of \c arcMapNames(). - const std::vector& edgeMapNames(int i) const { - return _edge_maps[i]; - } - - /// @} - - /// \name Attribute Sections - /// @{ - - /// \brief Gives back the number of attribute sections in the file. - /// - /// Gives back the number of attribute sections in the file. - int attributeSectionNum() const { - return _attribute_sections.size(); - } - - /// \brief Returns the attribute section name at the given position. - /// - /// Returns the attribute section name at the given position. - const std::string& attributeSectionNames(int i) const { - return _attribute_sections[i]; - } - - /// \brief Gives back the attributes for the given section. - /// - /// Gives back the attributes for the given section. - const std::vector& attributes(int i) const { - return _attributes[i]; - } - - /// @} - - /// \name Extra Sections - /// @{ - - /// \brief Gives back the number of extra sections in the file. - /// - /// Gives back the number of extra sections in the file. - int extraSectionNum() const { - return _extra_sections.size(); - } - - /// \brief Returns the extra section type at the given position. - /// - /// Returns the section type at the given position. - const std::string& extraSection(int i) const { - return _extra_sections[i]; - } - - /// @} - - private: - - bool readLine() { - std::string str; - while(++line_num, std::getline(*_is, str)) { - line.clear(); line.str(str); - char c; - if (line >> std::ws >> c && c != '#') { - line.putback(c); - return true; - } - } - return false; - } - - bool readSuccess() { - return static_cast(*_is); - } - - void skipSection() { - char c; - while (readSuccess() && line >> c && c != '@') { - readLine(); - } - if (readSuccess()) { - line.putback(c); - } - } - - void readMaps(std::vector& maps) { - char c; - if (!readLine() || !(line >> c) || c == '@') { - if (readSuccess() && line) line.putback(c); - return; - } - line.putback(c); - std::string map; - while (_reader_bits::readToken(line, map)) { - maps.push_back(map); - } - } - - void readAttributes(std::vector& attrs) { - readLine(); - char c; - while (readSuccess() && line >> c && c != '@') { - line.putback(c); - std::string attr; - _reader_bits::readToken(line, attr); - attrs.push_back(attr); - readLine(); - } - line.putback(c); - } - - public: - - /// \name Execution of the Contents Reader - /// @{ - - /// \brief Starts the reading - /// - /// This function starts the reading. - void run() { - - readLine(); - skipSection(); - - while (readSuccess()) { - - char c; - line >> c; - - std::string section, caption; - _reader_bits::readToken(line, section); - _reader_bits::readToken(line, caption); - - if (section == "nodes") { - _node_sections.push_back(caption); - _node_maps.push_back(std::vector()); - readMaps(_node_maps.back()); - readLine(); skipSection(); - } else if (section == "arcs" || section == "edges") { - _edge_sections.push_back(caption); - _arc_sections.push_back(section == "arcs"); - _edge_maps.push_back(std::vector()); - readMaps(_edge_maps.back()); - readLine(); skipSection(); - } else if (section == "attributes") { - _attribute_sections.push_back(caption); - _attributes.push_back(std::vector()); - readAttributes(_attributes.back()); - } else { - _extra_sections.push_back(section); - readLine(); skipSection(); - } - } - } - - /// @} - - }; -} - -#endif diff --git a/deps/lemon/lemon/lgf_writer.h b/deps/lemon/lemon/lgf_writer.h deleted file mode 100644 index 0695287d5..000000000 --- a/deps/lemon/lemon/lgf_writer.h +++ /dev/null @@ -1,2687 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\ingroup lemon_io -///\file -///\brief \ref lgf-format "LEMON Graph Format" writer. - - -#ifndef LEMON_LGF_WRITER_H -#define LEMON_LGF_WRITER_H - -#include -#include -#include - -#include - -#include -#include - -#include -#include - -#include -#include - -namespace lemon { - - namespace _writer_bits { - - template - struct DefaultConverter { - std::string operator()(const Value& value) { - std::ostringstream os; - os << value; - return os.str(); - } - }; - - template - bool operator<(const T&, const T&) { - throw FormatError("Label map is not comparable"); - } - - template - class MapLess { - public: - typedef _Map Map; - typedef typename Map::Key Item; - - private: - const Map& _map; - - public: - MapLess(const Map& map) : _map(map) {} - - bool operator()(const Item& left, const Item& right) { - return _map[left] < _map[right]; - } - }; - - template - class GraphArcMapLess { - public: - typedef _Map Map; - typedef _Graph Graph; - typedef typename Graph::Edge Item; - - private: - const Graph& _graph; - const Map& _map; - - public: - GraphArcMapLess(const Graph& graph, const Map& map) - : _graph(graph), _map(map) {} - - bool operator()(const Item& left, const Item& right) { - return _map[_graph.direct(left, _dir)] < - _map[_graph.direct(right, _dir)]; - } - }; - - template - class MapStorageBase { - public: - typedef _Item Item; - - public: - MapStorageBase() {} - virtual ~MapStorageBase() {} - - virtual std::string get(const Item& item) = 0; - virtual void sort(std::vector&) = 0; - }; - - template > - class MapStorage : public MapStorageBase<_Item> { - public: - typedef _Map Map; - typedef _Converter Converter; - typedef _Item Item; - - private: - const Map& _map; - Converter _converter; - - public: - MapStorage(const Map& map, const Converter& converter = Converter()) - : _map(map), _converter(converter) {} - virtual ~MapStorage() {} - - virtual std::string get(const Item& item) { - return _converter(_map[item]); - } - virtual void sort(std::vector& items) { - MapLess less(_map); - std::sort(items.begin(), items.end(), less); - } - }; - - template > - class GraphArcMapStorage : public MapStorageBase { - public: - typedef _Map Map; - typedef _Converter Converter; - typedef _Graph Graph; - typedef typename Graph::Edge Item; - static const bool dir = _dir; - - private: - const Graph& _graph; - const Map& _map; - Converter _converter; - - public: - GraphArcMapStorage(const Graph& graph, const Map& map, - const Converter& converter = Converter()) - : _graph(graph), _map(map), _converter(converter) {} - virtual ~GraphArcMapStorage() {} - - virtual std::string get(const Item& item) { - return _converter(_map[_graph.direct(item, dir)]); - } - virtual void sort(std::vector& items) { - GraphArcMapLess less(_graph, _map); - std::sort(items.begin(), items.end(), less); - } - }; - - class ValueStorageBase { - public: - ValueStorageBase() {} - virtual ~ValueStorageBase() {} - - virtual std::string get() = 0; - }; - - template > - class ValueStorage : public ValueStorageBase { - public: - typedef _Value Value; - typedef _Converter Converter; - - private: - const Value& _value; - Converter _converter; - - public: - ValueStorage(const Value& value, const Converter& converter = Converter()) - : _value(value), _converter(converter) {} - - virtual std::string get() { - return _converter(_value); - } - }; - - template > - struct MapLookUpConverter { - const Map& _map; - - MapLookUpConverter(const Map& map) - : _map(map) {} - - std::string operator()(const Value& value) { - typename Map::const_iterator it = _map.find(value); - if (it == _map.end()) { - throw FormatError("Item not found"); - } - return it->second; - } - }; - - template , - typename Map2 = std::map > - struct DoubleMapLookUpConverter { - const Map1& _map1; - const Map2& _map2; - - DoubleMapLookUpConverter(const Map1& map1, const Map2& map2) - : _map1(map1), _map2(map2) {} - - std::string operator()(const Value& value) { - typename Map1::const_iterator it1 = _map1.find(value); - typename Map1::const_iterator it2 = _map2.find(value); - if (it1 == _map1.end()) { - if (it2 == _map2.end()) { - throw FormatError("Item not found"); - } else { - return it2->second; - } - } else { - if (it2 == _map2.end()) { - return it1->second; - } else { - throw FormatError("Item is ambigous"); - } - } - } - }; - - template - struct GraphArcLookUpConverter { - const Graph& _graph; - const std::map& _map; - - GraphArcLookUpConverter(const Graph& graph, - const std::map& map) - : _graph(graph), _map(map) {} - - std::string operator()(const typename Graph::Arc& val) { - typename std::map - ::const_iterator it = _map.find(val); - if (it == _map.end()) { - throw FormatError("Item not found"); - } - return (_graph.direction(val) ? '+' : '-') + it->second; - } - }; - - inline bool isWhiteSpace(char c) { - return c == ' ' || c == '\t' || c == '\v' || - c == '\n' || c == '\r' || c == '\f'; - } - - inline bool isEscaped(char c) { - return c == '\\' || c == '\"' || c == '\'' || - c == '\a' || c == '\b'; - } - - inline static void writeEscape(std::ostream& os, char c) { - switch (c) { - case '\\': - os << "\\\\"; - return; - case '\"': - os << "\\\""; - return; - case '\a': - os << "\\a"; - return; - case '\b': - os << "\\b"; - return; - case '\f': - os << "\\f"; - return; - case '\r': - os << "\\r"; - return; - case '\n': - os << "\\n"; - return; - case '\t': - os << "\\t"; - return; - case '\v': - os << "\\v"; - return; - default: - if (c < 0x20) { - std::ios::fmtflags flags = os.flags(); - os << '\\' << std::oct << static_cast(c); - os.flags(flags); - } else { - os << c; - } - return; - } - } - - inline bool requireEscape(const std::string& str) { - if (str.empty() || str[0] == '@') return true; - std::istringstream is(str); - char c; - while (is.get(c)) { - if (isWhiteSpace(c) || isEscaped(c)) { - return true; - } - } - return false; - } - - inline std::ostream& writeToken(std::ostream& os, const std::string& str) { - - if (requireEscape(str)) { - os << '\"'; - for (std::string::const_iterator it = str.begin(); - it != str.end(); ++it) { - writeEscape(os, *it); - } - os << '\"'; - } else { - os << str; - } - return os; - } - - class Section { - public: - virtual ~Section() {} - virtual void process(std::ostream& os) = 0; - }; - - template - class LineSection : public Section { - private: - - Functor _functor; - - public: - - LineSection(const Functor& functor) : _functor(functor) {} - virtual ~LineSection() {} - - virtual void process(std::ostream& os) { - std::string line; - while (!(line = _functor()).empty()) os << line << std::endl; - } - }; - - template - class StreamSection : public Section { - private: - - Functor _functor; - - public: - - StreamSection(const Functor& functor) : _functor(functor) {} - virtual ~StreamSection() {} - - virtual void process(std::ostream& os) { - _functor(os); - } - }; - - } - - template - class DigraphWriter; - - template - DigraphWriter digraphWriter(const TDGR& digraph, - std::ostream& os = std::cout); - template - DigraphWriter digraphWriter(const TDGR& digraph, const std::string& fn); - - template - DigraphWriter digraphWriter(const TDGR& digraph, const char* fn); - - - /// \ingroup lemon_io - /// - /// \brief \ref lgf-format "LGF" writer for directed graphs - /// - /// This utility writes an \ref lgf-format "LGF" file. - /// - /// The writing method does a batch processing. The user creates a - /// writer object, then various writing rules can be added to the - /// writer, and eventually the writing is executed with the \c run() - /// member function. A map writing rule can be added to the writer - /// with the \c nodeMap() or \c arcMap() members. An optional - /// converter parameter can also be added as a standard functor - /// converting from the value type of the map to \c std::string. If it - /// is set, it will determine how the value type of the map is written to - /// the output stream. If the functor is not set, then a default - /// conversion will be used. The \c attribute(), \c node() and \c - /// arc() functions are used to add attribute writing rules. - /// - ///\code - /// DigraphWriter(digraph, std::cout). - /// nodeMap("coordinates", coord_map). - /// nodeMap("size", size). - /// nodeMap("title", title). - /// arcMap("capacity", cap_map). - /// node("source", src). - /// node("target", trg). - /// attribute("caption", caption). - /// run(); - ///\endcode - /// - /// - /// By default, the writer does not write additional captions to the - /// sections, but they can be give as an optional parameter of - /// the \c nodes(), \c arcs() or \c - /// attributes() functions. - /// - /// The \c skipNodes() and \c skipArcs() functions forbid the - /// writing of the sections. If two arc sections should be written - /// to the output, it can be done in two passes, the first pass - /// writes the node section and the first arc section, then the - /// second pass skips the node section and writes just the arc - /// section to the stream. The output stream can be retrieved with - /// the \c ostream() function, hence the second pass can append its - /// output to the output of the first pass. - template - class DigraphWriter { - public: - - typedef DGR Digraph; - TEMPLATE_DIGRAPH_TYPEDEFS(DGR); - - private: - - - std::ostream* _os; - bool local_os; - - const DGR& _digraph; - - std::string _nodes_caption; - std::string _arcs_caption; - std::string _attributes_caption; - - typedef std::map NodeIndex; - NodeIndex _node_index; - typedef std::map ArcIndex; - ArcIndex _arc_index; - - typedef std::vector* > > NodeMaps; - NodeMaps _node_maps; - - typedef std::vector* > >ArcMaps; - ArcMaps _arc_maps; - - typedef std::vector > Attributes; - Attributes _attributes; - - bool _skip_nodes; - bool _skip_arcs; - - public: - - /// \brief Constructor - /// - /// Construct a directed graph writer, which writes to the given - /// output stream. - DigraphWriter(const DGR& digraph, std::ostream& os = std::cout) - : _os(&os), local_os(false), _digraph(digraph), - _skip_nodes(false), _skip_arcs(false) {} - - /// \brief Constructor - /// - /// Construct a directed graph writer, which writes to the given - /// output file. - DigraphWriter(const DGR& digraph, const std::string& fn) - : _os(new std::ofstream(fn.c_str())), local_os(true), _digraph(digraph), - _skip_nodes(false), _skip_arcs(false) { - if (!(*_os)) { - delete _os; - throw IoError("Cannot write file", fn); - } - } - - /// \brief Constructor - /// - /// Construct a directed graph writer, which writes to the given - /// output file. - DigraphWriter(const DGR& digraph, const char* fn) - : _os(new std::ofstream(fn)), local_os(true), _digraph(digraph), - _skip_nodes(false), _skip_arcs(false) { - if (!(*_os)) { - delete _os; - throw IoError("Cannot write file", fn); - } - } - - /// \brief Destructor - ~DigraphWriter() { - for (typename NodeMaps::iterator it = _node_maps.begin(); - it != _node_maps.end(); ++it) { - delete it->second; - } - - for (typename ArcMaps::iterator it = _arc_maps.begin(); - it != _arc_maps.end(); ++it) { - delete it->second; - } - - for (typename Attributes::iterator it = _attributes.begin(); - it != _attributes.end(); ++it) { - delete it->second; - } - - if (local_os) { - delete _os; - } - } - - private: - - template - friend DigraphWriter digraphWriter(const TDGR& digraph, - std::ostream& os); - template - friend DigraphWriter digraphWriter(const TDGR& digraph, - const std::string& fn); - template - friend DigraphWriter digraphWriter(const TDGR& digraph, - const char *fn); - - DigraphWriter(DigraphWriter& other) - : _os(other._os), local_os(other.local_os), _digraph(other._digraph), - _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) { - - other._os = 0; - other.local_os = false; - - _node_index.swap(other._node_index); - _arc_index.swap(other._arc_index); - - _node_maps.swap(other._node_maps); - _arc_maps.swap(other._arc_maps); - _attributes.swap(other._attributes); - - _nodes_caption = other._nodes_caption; - _arcs_caption = other._arcs_caption; - _attributes_caption = other._attributes_caption; - } - - DigraphWriter& operator=(const DigraphWriter&); - - public: - - /// \name Writing Rules - /// @{ - - /// \brief Node map writing rule - /// - /// Add a node map writing rule to the writer. - template - DigraphWriter& nodeMap(const std::string& caption, const Map& map) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map); - _node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Node map writing rule - /// - /// Add a node map writing rule with specialized converter to the - /// writer. - template - DigraphWriter& nodeMap(const std::string& caption, const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map, converter); - _node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc map writing rule - /// - /// Add an arc map writing rule to the writer. - template - DigraphWriter& arcMap(const std::string& caption, const Map& map) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map); - _arc_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc map writing rule - /// - /// Add an arc map writing rule with specialized converter to the - /// writer. - template - DigraphWriter& arcMap(const std::string& caption, const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map, converter); - _arc_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Attribute writing rule - /// - /// Add an attribute writing rule to the writer. - template - DigraphWriter& attribute(const std::string& caption, const Value& value) { - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(value); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Attribute writing rule - /// - /// Add an attribute writing rule with specialized converter to the - /// writer. - template - DigraphWriter& attribute(const std::string& caption, const Value& value, - const Converter& converter = Converter()) { - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(value, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Node writing rule - /// - /// Add a node writing rule to the writer. - DigraphWriter& node(const std::string& caption, const Node& node) { - typedef _writer_bits::MapLookUpConverter Converter; - Converter converter(_node_index); - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(node, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc writing rule - /// - /// Add an arc writing rule to writer. - DigraphWriter& arc(const std::string& caption, const Arc& arc) { - typedef _writer_bits::MapLookUpConverter Converter; - Converter converter(_arc_index); - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(arc, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \name Section Captions - /// @{ - - /// \brief Add an additional caption to the \c \@nodes section - /// - /// Add an additional caption to the \c \@nodes section. - DigraphWriter& nodes(const std::string& caption) { - _nodes_caption = caption; - return *this; - } - - /// \brief Add an additional caption to the \c \@arcs section - /// - /// Add an additional caption to the \c \@arcs section. - DigraphWriter& arcs(const std::string& caption) { - _arcs_caption = caption; - return *this; - } - - /// \brief Add an additional caption to the \c \@attributes section - /// - /// Add an additional caption to the \c \@attributes section. - DigraphWriter& attributes(const std::string& caption) { - _attributes_caption = caption; - return *this; - } - - /// \name Skipping Section - /// @{ - - /// \brief Skip writing the node set - /// - /// The \c \@nodes section will not be written to the stream. - DigraphWriter& skipNodes() { - LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member"); - _skip_nodes = true; - return *this; - } - - /// \brief Skip writing arc set - /// - /// The \c \@arcs section will not be written to the stream. - DigraphWriter& skipArcs() { - LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member"); - _skip_arcs = true; - return *this; - } - - /// @} - - private: - - void writeNodes() { - _writer_bits::MapStorageBase* label = 0; - for (typename NodeMaps::iterator it = _node_maps.begin(); - it != _node_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - *_os << "@nodes"; - if (!_nodes_caption.empty()) { - _writer_bits::writeToken(*_os << ' ', _nodes_caption); - } - *_os << std::endl; - - if (label == 0) { - *_os << "label" << '\t'; - } - for (typename NodeMaps::iterator it = _node_maps.begin(); - it != _node_maps.end(); ++it) { - _writer_bits::writeToken(*_os, it->first) << '\t'; - } - *_os << std::endl; - - std::vector nodes; - for (NodeIt n(_digraph); n != INVALID; ++n) { - nodes.push_back(n); - } - - if (label == 0) { - IdMap id_map(_digraph); - _writer_bits::MapLess > id_less(id_map); - std::sort(nodes.begin(), nodes.end(), id_less); - } else { - label->sort(nodes); - } - - for (int i = 0; i < static_cast(nodes.size()); ++i) { - Node n = nodes[i]; - if (label == 0) { - std::ostringstream os; - os << _digraph.id(n); - _writer_bits::writeToken(*_os, os.str()); - *_os << '\t'; - _node_index.insert(std::make_pair(n, os.str())); - } - for (typename NodeMaps::iterator it = _node_maps.begin(); - it != _node_maps.end(); ++it) { - std::string value = it->second->get(n); - _writer_bits::writeToken(*_os, value); - if (it->first == "label") { - _node_index.insert(std::make_pair(n, value)); - } - *_os << '\t'; - } - *_os << std::endl; - } - } - - void createNodeIndex() { - _writer_bits::MapStorageBase* label = 0; - for (typename NodeMaps::iterator it = _node_maps.begin(); - it != _node_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - if (label == 0) { - for (NodeIt n(_digraph); n != INVALID; ++n) { - std::ostringstream os; - os << _digraph.id(n); - _node_index.insert(std::make_pair(n, os.str())); - } - } else { - for (NodeIt n(_digraph); n != INVALID; ++n) { - std::string value = label->get(n); - _node_index.insert(std::make_pair(n, value)); - } - } - } - - void writeArcs() { - _writer_bits::MapStorageBase* label = 0; - for (typename ArcMaps::iterator it = _arc_maps.begin(); - it != _arc_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - *_os << "@arcs"; - if (!_arcs_caption.empty()) { - _writer_bits::writeToken(*_os << ' ', _arcs_caption); - } - *_os << std::endl; - - *_os << '\t' << '\t'; - if (label == 0) { - *_os << "label" << '\t'; - } - for (typename ArcMaps::iterator it = _arc_maps.begin(); - it != _arc_maps.end(); ++it) { - _writer_bits::writeToken(*_os, it->first) << '\t'; - } - *_os << std::endl; - - std::vector arcs; - for (ArcIt n(_digraph); n != INVALID; ++n) { - arcs.push_back(n); - } - - if (label == 0) { - IdMap id_map(_digraph); - _writer_bits::MapLess > id_less(id_map); - std::sort(arcs.begin(), arcs.end(), id_less); - } else { - label->sort(arcs); - } - - for (int i = 0; i < static_cast(arcs.size()); ++i) { - Arc a = arcs[i]; - _writer_bits::writeToken(*_os, _node_index. - find(_digraph.source(a))->second); - *_os << '\t'; - _writer_bits::writeToken(*_os, _node_index. - find(_digraph.target(a))->second); - *_os << '\t'; - if (label == 0) { - std::ostringstream os; - os << _digraph.id(a); - _writer_bits::writeToken(*_os, os.str()); - *_os << '\t'; - _arc_index.insert(std::make_pair(a, os.str())); - } - for (typename ArcMaps::iterator it = _arc_maps.begin(); - it != _arc_maps.end(); ++it) { - std::string value = it->second->get(a); - _writer_bits::writeToken(*_os, value); - if (it->first == "label") { - _arc_index.insert(std::make_pair(a, value)); - } - *_os << '\t'; - } - *_os << std::endl; - } - } - - void createArcIndex() { - _writer_bits::MapStorageBase* label = 0; - for (typename ArcMaps::iterator it = _arc_maps.begin(); - it != _arc_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - if (label == 0) { - for (ArcIt a(_digraph); a != INVALID; ++a) { - std::ostringstream os; - os << _digraph.id(a); - _arc_index.insert(std::make_pair(a, os.str())); - } - } else { - for (ArcIt a(_digraph); a != INVALID; ++a) { - std::string value = label->get(a); - _arc_index.insert(std::make_pair(a, value)); - } - } - } - - void writeAttributes() { - if (_attributes.empty()) return; - *_os << "@attributes"; - if (!_attributes_caption.empty()) { - _writer_bits::writeToken(*_os << ' ', _attributes_caption); - } - *_os << std::endl; - for (typename Attributes::iterator it = _attributes.begin(); - it != _attributes.end(); ++it) { - _writer_bits::writeToken(*_os, it->first) << ' '; - _writer_bits::writeToken(*_os, it->second->get()); - *_os << std::endl; - } - } - - public: - - /// \name Execution of the Writer - /// @{ - - /// \brief Start the batch processing - /// - /// This function starts the batch processing. - void run() { - if (!_skip_nodes) { - writeNodes(); - } else { - createNodeIndex(); - } - if (!_skip_arcs) { - writeArcs(); - } else { - createArcIndex(); - } - writeAttributes(); - } - - /// \brief Give back the stream of the writer - /// - /// Give back the stream of the writer. - std::ostream& ostream() { - return *_os; - } - - /// @} - }; - - /// \ingroup lemon_io - /// - /// \brief Return a \ref lemon::DigraphWriter "DigraphWriter" class - /// - /// This function just returns a \ref lemon::DigraphWriter - /// "DigraphWriter" class. - /// - /// With this function a digraph can be write to a file or output - /// stream in \ref lgf-format "LGF" format with several maps and - /// attributes. For example, with the following code a network flow - /// problem can be written to the standard output, i.e. a digraph - /// with a \e capacity map on the arcs and \e source and \e target - /// nodes: - /// - ///\code - ///ListDigraph digraph; - ///ListDigraph::ArcMap cap(digraph); - ///ListDigraph::Node src, trg; - /// // Setting the capacity map and source and target nodes - ///digraphWriter(digraph, std::cout). - /// arcMap("capacity", cap). - /// node("source", src). - /// node("target", trg). - /// run(); - ///\endcode - /// - /// For a complete documentation, please see the - /// \ref lemon::DigraphWriter "DigraphWriter" - /// class documentation. - /// \warning Don't forget to put the \ref lemon::DigraphWriter::run() "run()" - /// to the end of the parameter list. - /// \relates DigraphWriter - /// \sa digraphWriter(const TDGR& digraph, const std::string& fn) - /// \sa digraphWriter(const TDGR& digraph, const char* fn) - template - DigraphWriter digraphWriter(const TDGR& digraph, std::ostream& os) { - DigraphWriter tmp(digraph, os); - return tmp; - } - - /// \brief Return a \ref DigraphWriter class - /// - /// This function just returns a \ref DigraphWriter class. - /// \relates DigraphWriter - /// \sa digraphWriter(const TDGR& digraph, std::ostream& os) - template - DigraphWriter digraphWriter(const TDGR& digraph, - const std::string& fn) { - DigraphWriter tmp(digraph, fn); - return tmp; - } - - /// \brief Return a \ref DigraphWriter class - /// - /// This function just returns a \ref DigraphWriter class. - /// \relates DigraphWriter - /// \sa digraphWriter(const TDGR& digraph, std::ostream& os) - template - DigraphWriter digraphWriter(const TDGR& digraph, const char* fn) { - DigraphWriter tmp(digraph, fn); - return tmp; - } - - template - class GraphWriter; - - template - GraphWriter graphWriter(const TGR& graph, std::ostream& os = std::cout); - template - GraphWriter graphWriter(const TGR& graph, const std::string& fn); - template - GraphWriter graphWriter(const TGR& graph, const char* fn); - - /// \ingroup lemon_io - /// - /// \brief \ref lgf-format "LGF" writer for undirected graphs - /// - /// This utility writes an \ref lgf-format "LGF" file. - /// - /// It can be used almost the same way as \c DigraphWriter. - /// The only difference is that this class can handle edges and - /// edge maps as well as arcs and arc maps. - /// - /// The arc maps are written into the file as two columns, the - /// caption of the columns are the name of the map prefixed with \c - /// '+' and \c '-'. The arcs are written into the \c \@attributes - /// section as a \c '+' or a \c '-' prefix (depends on the direction - /// of the arc) and the label of corresponding edge. - template - class GraphWriter { - public: - - typedef GR Graph; - TEMPLATE_GRAPH_TYPEDEFS(GR); - - private: - - - std::ostream* _os; - bool local_os; - - const GR& _graph; - - std::string _nodes_caption; - std::string _edges_caption; - std::string _attributes_caption; - - typedef std::map NodeIndex; - NodeIndex _node_index; - typedef std::map EdgeIndex; - EdgeIndex _edge_index; - - typedef std::vector* > > NodeMaps; - NodeMaps _node_maps; - - typedef std::vector* > >EdgeMaps; - EdgeMaps _edge_maps; - - typedef std::vector > Attributes; - Attributes _attributes; - - bool _skip_nodes; - bool _skip_edges; - - public: - - /// \brief Constructor - /// - /// Construct an undirected graph writer, which writes to the - /// given output stream. - GraphWriter(const GR& graph, std::ostream& os = std::cout) - : _os(&os), local_os(false), _graph(graph), - _skip_nodes(false), _skip_edges(false) {} - - /// \brief Constructor - /// - /// Construct a undirected graph writer, which writes to the given - /// output file. - GraphWriter(const GR& graph, const std::string& fn) - : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph), - _skip_nodes(false), _skip_edges(false) { - if (!(*_os)) { - delete _os; - throw IoError("Cannot write file", fn); - } - } - - /// \brief Constructor - /// - /// Construct a undirected graph writer, which writes to the given - /// output file. - GraphWriter(const GR& graph, const char* fn) - : _os(new std::ofstream(fn)), local_os(true), _graph(graph), - _skip_nodes(false), _skip_edges(false) { - if (!(*_os)) { - delete _os; - throw IoError("Cannot write file", fn); - } - } - - /// \brief Destructor - ~GraphWriter() { - for (typename NodeMaps::iterator it = _node_maps.begin(); - it != _node_maps.end(); ++it) { - delete it->second; - } - - for (typename EdgeMaps::iterator it = _edge_maps.begin(); - it != _edge_maps.end(); ++it) { - delete it->second; - } - - for (typename Attributes::iterator it = _attributes.begin(); - it != _attributes.end(); ++it) { - delete it->second; - } - - if (local_os) { - delete _os; - } - } - - private: - - template - friend GraphWriter graphWriter(const TGR& graph, std::ostream& os); - template - friend GraphWriter graphWriter(const TGR& graph, - const std::string& fn); - template - friend GraphWriter graphWriter(const TGR& graph, const char *fn); - - GraphWriter(GraphWriter& other) - : _os(other._os), local_os(other.local_os), _graph(other._graph), - _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { - - other._os = 0; - other.local_os = false; - - _node_index.swap(other._node_index); - _edge_index.swap(other._edge_index); - - _node_maps.swap(other._node_maps); - _edge_maps.swap(other._edge_maps); - _attributes.swap(other._attributes); - - _nodes_caption = other._nodes_caption; - _edges_caption = other._edges_caption; - _attributes_caption = other._attributes_caption; - } - - GraphWriter& operator=(const GraphWriter&); - - public: - - /// \name Writing Rules - /// @{ - - /// \brief Node map writing rule - /// - /// Add a node map writing rule to the writer. - template - GraphWriter& nodeMap(const std::string& caption, const Map& map) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map); - _node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Node map writing rule - /// - /// Add a node map writing rule with specialized converter to the - /// writer. - template - GraphWriter& nodeMap(const std::string& caption, const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map, converter); - _node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Edge map writing rule - /// - /// Add an edge map writing rule to the writer. - template - GraphWriter& edgeMap(const std::string& caption, const Map& map) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map); - _edge_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Edge map writing rule - /// - /// Add an edge map writing rule with specialized converter to the - /// writer. - template - GraphWriter& edgeMap(const std::string& caption, const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map, converter); - _edge_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc map writing rule - /// - /// Add an arc map writing rule to the writer. - template - GraphWriter& arcMap(const std::string& caption, const Map& map) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* forward_storage = - new _writer_bits::GraphArcMapStorage(_graph, map); - _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); - _writer_bits::MapStorageBase* backward_storage = - new _writer_bits::GraphArcMapStorage(_graph, map); - _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); - return *this; - } - - /// \brief Arc map writing rule - /// - /// Add an arc map writing rule with specialized converter to the - /// writer. - template - GraphWriter& arcMap(const std::string& caption, const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* forward_storage = - new _writer_bits::GraphArcMapStorage - (_graph, map, converter); - _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); - _writer_bits::MapStorageBase* backward_storage = - new _writer_bits::GraphArcMapStorage - (_graph, map, converter); - _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); - return *this; - } - - /// \brief Attribute writing rule - /// - /// Add an attribute writing rule to the writer. - template - GraphWriter& attribute(const std::string& caption, const Value& value) { - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(value); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Attribute writing rule - /// - /// Add an attribute writing rule with specialized converter to the - /// writer. - template - GraphWriter& attribute(const std::string& caption, const Value& value, - const Converter& converter = Converter()) { - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(value, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Node writing rule - /// - /// Add a node writing rule to the writer. - GraphWriter& node(const std::string& caption, const Node& node) { - typedef _writer_bits::MapLookUpConverter Converter; - Converter converter(_node_index); - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(node, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Edge writing rule - /// - /// Add an edge writing rule to writer. - GraphWriter& edge(const std::string& caption, const Edge& edge) { - typedef _writer_bits::MapLookUpConverter Converter; - Converter converter(_edge_index); - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(edge, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc writing rule - /// - /// Add an arc writing rule to writer. - GraphWriter& arc(const std::string& caption, const Arc& arc) { - typedef _writer_bits::GraphArcLookUpConverter Converter; - Converter converter(_graph, _edge_index); - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(arc, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \name Section Captions - /// @{ - - /// \brief Add an additional caption to the \c \@nodes section - /// - /// Add an additional caption to the \c \@nodes section. - GraphWriter& nodes(const std::string& caption) { - _nodes_caption = caption; - return *this; - } - - /// \brief Add an additional caption to the \c \@edges section - /// - /// Add an additional caption to the \c \@edges section. - GraphWriter& edges(const std::string& caption) { - _edges_caption = caption; - return *this; - } - - /// \brief Add an additional caption to the \c \@attributes section - /// - /// Add an additional caption to the \c \@attributes section. - GraphWriter& attributes(const std::string& caption) { - _attributes_caption = caption; - return *this; - } - - /// \name Skipping Section - /// @{ - - /// \brief Skip writing the node set - /// - /// The \c \@nodes section will not be written to the stream. - GraphWriter& skipNodes() { - LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member"); - _skip_nodes = true; - return *this; - } - - /// \brief Skip writing edge set - /// - /// The \c \@edges section will not be written to the stream. - GraphWriter& skipEdges() { - LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member"); - _skip_edges = true; - return *this; - } - - /// @} - - private: - - void writeNodes() { - _writer_bits::MapStorageBase* label = 0; - for (typename NodeMaps::iterator it = _node_maps.begin(); - it != _node_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - *_os << "@nodes"; - if (!_nodes_caption.empty()) { - _writer_bits::writeToken(*_os << ' ', _nodes_caption); - } - *_os << std::endl; - - if (label == 0) { - *_os << "label" << '\t'; - } - for (typename NodeMaps::iterator it = _node_maps.begin(); - it != _node_maps.end(); ++it) { - _writer_bits::writeToken(*_os, it->first) << '\t'; - } - *_os << std::endl; - - std::vector nodes; - for (NodeIt n(_graph); n != INVALID; ++n) { - nodes.push_back(n); - } - - if (label == 0) { - IdMap id_map(_graph); - _writer_bits::MapLess > id_less(id_map); - std::sort(nodes.begin(), nodes.end(), id_less); - } else { - label->sort(nodes); - } - - for (int i = 0; i < static_cast(nodes.size()); ++i) { - Node n = nodes[i]; - if (label == 0) { - std::ostringstream os; - os << _graph.id(n); - _writer_bits::writeToken(*_os, os.str()); - *_os << '\t'; - _node_index.insert(std::make_pair(n, os.str())); - } - for (typename NodeMaps::iterator it = _node_maps.begin(); - it != _node_maps.end(); ++it) { - std::string value = it->second->get(n); - _writer_bits::writeToken(*_os, value); - if (it->first == "label") { - _node_index.insert(std::make_pair(n, value)); - } - *_os << '\t'; - } - *_os << std::endl; - } - } - - void createNodeIndex() { - _writer_bits::MapStorageBase* label = 0; - for (typename NodeMaps::iterator it = _node_maps.begin(); - it != _node_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - if (label == 0) { - for (NodeIt n(_graph); n != INVALID; ++n) { - std::ostringstream os; - os << _graph.id(n); - _node_index.insert(std::make_pair(n, os.str())); - } - } else { - for (NodeIt n(_graph); n != INVALID; ++n) { - std::string value = label->get(n); - _node_index.insert(std::make_pair(n, value)); - } - } - } - - void writeEdges() { - _writer_bits::MapStorageBase* label = 0; - for (typename EdgeMaps::iterator it = _edge_maps.begin(); - it != _edge_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - *_os << "@edges"; - if (!_edges_caption.empty()) { - _writer_bits::writeToken(*_os << ' ', _edges_caption); - } - *_os << std::endl; - - *_os << '\t' << '\t'; - if (label == 0) { - *_os << "label" << '\t'; - } - for (typename EdgeMaps::iterator it = _edge_maps.begin(); - it != _edge_maps.end(); ++it) { - _writer_bits::writeToken(*_os, it->first) << '\t'; - } - *_os << std::endl; - - std::vector edges; - for (EdgeIt n(_graph); n != INVALID; ++n) { - edges.push_back(n); - } - - if (label == 0) { - IdMap id_map(_graph); - _writer_bits::MapLess > id_less(id_map); - std::sort(edges.begin(), edges.end(), id_less); - } else { - label->sort(edges); - } - - for (int i = 0; i < static_cast(edges.size()); ++i) { - Edge e = edges[i]; - _writer_bits::writeToken(*_os, _node_index. - find(_graph.u(e))->second); - *_os << '\t'; - _writer_bits::writeToken(*_os, _node_index. - find(_graph.v(e))->second); - *_os << '\t'; - if (label == 0) { - std::ostringstream os; - os << _graph.id(e); - _writer_bits::writeToken(*_os, os.str()); - *_os << '\t'; - _edge_index.insert(std::make_pair(e, os.str())); - } - for (typename EdgeMaps::iterator it = _edge_maps.begin(); - it != _edge_maps.end(); ++it) { - std::string value = it->second->get(e); - _writer_bits::writeToken(*_os, value); - if (it->first == "label") { - _edge_index.insert(std::make_pair(e, value)); - } - *_os << '\t'; - } - *_os << std::endl; - } - } - - void createEdgeIndex() { - _writer_bits::MapStorageBase* label = 0; - for (typename EdgeMaps::iterator it = _edge_maps.begin(); - it != _edge_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - if (label == 0) { - for (EdgeIt e(_graph); e != INVALID; ++e) { - std::ostringstream os; - os << _graph.id(e); - _edge_index.insert(std::make_pair(e, os.str())); - } - } else { - for (EdgeIt e(_graph); e != INVALID; ++e) { - std::string value = label->get(e); - _edge_index.insert(std::make_pair(e, value)); - } - } - } - - void writeAttributes() { - if (_attributes.empty()) return; - *_os << "@attributes"; - if (!_attributes_caption.empty()) { - _writer_bits::writeToken(*_os << ' ', _attributes_caption); - } - *_os << std::endl; - for (typename Attributes::iterator it = _attributes.begin(); - it != _attributes.end(); ++it) { - _writer_bits::writeToken(*_os, it->first) << ' '; - _writer_bits::writeToken(*_os, it->second->get()); - *_os << std::endl; - } - } - - public: - - /// \name Execution of the Writer - /// @{ - - /// \brief Start the batch processing - /// - /// This function starts the batch processing. - void run() { - if (!_skip_nodes) { - writeNodes(); - } else { - createNodeIndex(); - } - if (!_skip_edges) { - writeEdges(); - } else { - createEdgeIndex(); - } - writeAttributes(); - } - - /// \brief Give back the stream of the writer - /// - /// Give back the stream of the writer - std::ostream& ostream() { - return *_os; - } - - /// @} - }; - - /// \ingroup lemon_io - /// - /// \brief Return a \ref lemon::GraphWriter "GraphWriter" class - /// - /// This function just returns a \ref lemon::GraphWriter "GraphWriter" class. - /// - /// With this function a graph can be write to a file or output - /// stream in \ref lgf-format "LGF" format with several maps and - /// attributes. For example, with the following code a weighted - /// matching problem can be written to the standard output, i.e. a - /// graph with a \e weight map on the edges: - /// - ///\code - ///ListGraph graph; - ///ListGraph::EdgeMap weight(graph); - /// // Setting the weight map - ///graphWriter(graph, std::cout). - /// edgeMap("weight", weight). - /// run(); - ///\endcode - /// - /// For a complete documentation, please see the - /// \ref lemon::GraphWriter "GraphWriter" - /// class documentation. - /// \warning Don't forget to put the \ref lemon::GraphWriter::run() "run()" - /// to the end of the parameter list. - /// \relates GraphWriter - /// \sa graphWriter(const TGR& graph, const std::string& fn) - /// \sa graphWriter(const TGR& graph, const char* fn) - template - GraphWriter graphWriter(const TGR& graph, std::ostream& os) { - GraphWriter tmp(graph, os); - return tmp; - } - - /// \brief Return a \ref GraphWriter class - /// - /// This function just returns a \ref GraphWriter class. - /// \relates GraphWriter - /// \sa graphWriter(const TGR& graph, std::ostream& os) - template - GraphWriter graphWriter(const TGR& graph, const std::string& fn) { - GraphWriter tmp(graph, fn); - return tmp; - } - - /// \brief Return a \ref GraphWriter class - /// - /// This function just returns a \ref GraphWriter class. - /// \relates GraphWriter - /// \sa graphWriter(const TGR& graph, std::ostream& os) - template - GraphWriter graphWriter(const TGR& graph, const char* fn) { - GraphWriter tmp(graph, fn); - return tmp; - } - - template - class BpGraphWriter; - - template - BpGraphWriter bpGraphWriter(const TBGR& graph, - std::ostream& os = std::cout); - template - BpGraphWriter bpGraphWriter(const TBGR& graph, const std::string& fn); - template - BpGraphWriter bpGraphWriter(const TBGR& graph, const char* fn); - - /// \ingroup lemon_io - /// - /// \brief \ref lgf-format "LGF" writer for undirected bipartite graphs - /// - /// This utility writes an \ref lgf-format "LGF" file. - /// - /// It can be used almost the same way as \c GraphWriter, but it - /// reads the red and blue nodes from separate sections, and these - /// sections can contain different set of maps. - /// - /// The red and blue node maps are written to the corresponding - /// sections. The node maps are written to both of these sections - /// with the same map name. - template - class BpGraphWriter { - public: - - typedef BGR BpGraph; - TEMPLATE_BPGRAPH_TYPEDEFS(BGR); - - private: - - - std::ostream* _os; - bool local_os; - - const BGR& _graph; - - std::string _nodes_caption; - std::string _edges_caption; - std::string _attributes_caption; - - typedef std::map RedNodeIndex; - RedNodeIndex _red_node_index; - typedef std::map BlueNodeIndex; - BlueNodeIndex _blue_node_index; - typedef std::map EdgeIndex; - EdgeIndex _edge_index; - - typedef std::vector* > > RedNodeMaps; - RedNodeMaps _red_node_maps; - typedef std::vector* > > BlueNodeMaps; - BlueNodeMaps _blue_node_maps; - - typedef std::vector* > >EdgeMaps; - EdgeMaps _edge_maps; - - typedef std::vector > Attributes; - Attributes _attributes; - - bool _skip_nodes; - bool _skip_edges; - - public: - - /// \brief Constructor - /// - /// Construct a bipartite graph writer, which writes to the given - /// output stream. - BpGraphWriter(const BGR& graph, std::ostream& os = std::cout) - : _os(&os), local_os(false), _graph(graph), - _skip_nodes(false), _skip_edges(false) {} - - /// \brief Constructor - /// - /// Construct a bipartite graph writer, which writes to the given - /// output file. - BpGraphWriter(const BGR& graph, const std::string& fn) - : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph), - _skip_nodes(false), _skip_edges(false) { - if (!(*_os)) { - delete _os; - throw IoError("Cannot write file", fn); - } - } - - /// \brief Constructor - /// - /// Construct a bipartite graph writer, which writes to the given - /// output file. - BpGraphWriter(const BGR& graph, const char* fn) - : _os(new std::ofstream(fn)), local_os(true), _graph(graph), - _skip_nodes(false), _skip_edges(false) { - if (!(*_os)) { - delete _os; - throw IoError("Cannot write file", fn); - } - } - - /// \brief Destructor - ~BpGraphWriter() { - for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); - it != _red_node_maps.end(); ++it) { - delete it->second; - } - - for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); - it != _blue_node_maps.end(); ++it) { - delete it->second; - } - - for (typename EdgeMaps::iterator it = _edge_maps.begin(); - it != _edge_maps.end(); ++it) { - delete it->second; - } - - for (typename Attributes::iterator it = _attributes.begin(); - it != _attributes.end(); ++it) { - delete it->second; - } - - if (local_os) { - delete _os; - } - } - - private: - - template - friend BpGraphWriter bpGraphWriter(const TBGR& graph, - std::ostream& os); - template - friend BpGraphWriter bpGraphWriter(const TBGR& graph, - const std::string& fn); - template - friend BpGraphWriter bpGraphWriter(const TBGR& graph, const char *fn); - - BpGraphWriter(BpGraphWriter& other) - : _os(other._os), local_os(other.local_os), _graph(other._graph), - _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { - - other._os = 0; - other.local_os = false; - - _red_node_index.swap(other._red_node_index); - _blue_node_index.swap(other._blue_node_index); - _edge_index.swap(other._edge_index); - - _red_node_maps.swap(other._red_node_maps); - _blue_node_maps.swap(other._blue_node_maps); - _edge_maps.swap(other._edge_maps); - _attributes.swap(other._attributes); - - _nodes_caption = other._nodes_caption; - _edges_caption = other._edges_caption; - _attributes_caption = other._attributes_caption; - } - - BpGraphWriter& operator=(const BpGraphWriter&); - - public: - - /// \name Writing Rules - /// @{ - - /// \brief Node map writing rule - /// - /// Add a node map writing rule to the writer. - template - BpGraphWriter& nodeMap(const std::string& caption, const Map& map) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* red_storage = - new _writer_bits::MapStorage(map); - _red_node_maps.push_back(std::make_pair(caption, red_storage)); - _writer_bits::MapStorageBase* blue_storage = - new _writer_bits::MapStorage(map); - _blue_node_maps.push_back(std::make_pair(caption, blue_storage)); - return *this; - } - - /// \brief Node map writing rule - /// - /// Add a node map writing rule with specialized converter to the - /// writer. - template - BpGraphWriter& nodeMap(const std::string& caption, const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* red_storage = - new _writer_bits::MapStorage(map, converter); - _red_node_maps.push_back(std::make_pair(caption, red_storage)); - _writer_bits::MapStorageBase* blue_storage = - new _writer_bits::MapStorage(map, converter); - _blue_node_maps.push_back(std::make_pair(caption, blue_storage)); - return *this; - } - - /// \brief Red node map writing rule - /// - /// Add a red node map writing rule to the writer. - template - BpGraphWriter& redNodeMap(const std::string& caption, const Map& map) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map); - _red_node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Red node map writing rule - /// - /// Add a red node map writing rule with specialized converter to the - /// writer. - template - BpGraphWriter& redNodeMap(const std::string& caption, const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map, converter); - _red_node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Blue node map writing rule - /// - /// Add a blue node map writing rule to the writer. - template - BpGraphWriter& blueNodeMap(const std::string& caption, const Map& map) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map); - _blue_node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Blue node map writing rule - /// - /// Add a blue node map writing rule with specialized converter to the - /// writer. - template - BpGraphWriter& blueNodeMap(const std::string& caption, const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map, converter); - _blue_node_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Edge map writing rule - /// - /// Add an edge map writing rule to the writer. - template - BpGraphWriter& edgeMap(const std::string& caption, const Map& map) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map); - _edge_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Edge map writing rule - /// - /// Add an edge map writing rule with specialized converter to the - /// writer. - template - BpGraphWriter& edgeMap(const std::string& caption, const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* storage = - new _writer_bits::MapStorage(map, converter); - _edge_maps.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc map writing rule - /// - /// Add an arc map writing rule to the writer. - template - BpGraphWriter& arcMap(const std::string& caption, const Map& map) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* forward_storage = - new _writer_bits::GraphArcMapStorage(_graph, map); - _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); - _writer_bits::MapStorageBase* backward_storage = - new _writer_bits::GraphArcMapStorage(_graph, map); - _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); - return *this; - } - - /// \brief Arc map writing rule - /// - /// Add an arc map writing rule with specialized converter to the - /// writer. - template - BpGraphWriter& arcMap(const std::string& caption, const Map& map, - const Converter& converter = Converter()) { - checkConcept, Map>(); - _writer_bits::MapStorageBase* forward_storage = - new _writer_bits::GraphArcMapStorage - (_graph, map, converter); - _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); - _writer_bits::MapStorageBase* backward_storage = - new _writer_bits::GraphArcMapStorage - (_graph, map, converter); - _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); - return *this; - } - - /// \brief Attribute writing rule - /// - /// Add an attribute writing rule to the writer. - template - BpGraphWriter& attribute(const std::string& caption, const Value& value) { - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(value); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Attribute writing rule - /// - /// Add an attribute writing rule with specialized converter to the - /// writer. - template - BpGraphWriter& attribute(const std::string& caption, const Value& value, - const Converter& converter = Converter()) { - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(value, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Node writing rule - /// - /// Add a node writing rule to the writer. - BpGraphWriter& node(const std::string& caption, const Node& node) { - typedef _writer_bits::DoubleMapLookUpConverter< - Node, RedNodeIndex, BlueNodeIndex> Converter; - Converter converter(_red_node_index, _blue_node_index); - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(node, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Red node writing rule - /// - /// Add a red node writing rule to the writer. - BpGraphWriter& redNode(const std::string& caption, const RedNode& node) { - typedef _writer_bits::MapLookUpConverter Converter; - Converter converter(_red_node_index); - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(node, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Blue node writing rule - /// - /// Add a blue node writing rule to the writer. - BpGraphWriter& blueNode(const std::string& caption, const BlueNode& node) { - typedef _writer_bits::MapLookUpConverter Converter; - Converter converter(_blue_node_index); - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(node, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Edge writing rule - /// - /// Add an edge writing rule to writer. - BpGraphWriter& edge(const std::string& caption, const Edge& edge) { - typedef _writer_bits::MapLookUpConverter Converter; - Converter converter(_edge_index); - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(edge, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \brief Arc writing rule - /// - /// Add an arc writing rule to writer. - BpGraphWriter& arc(const std::string& caption, const Arc& arc) { - typedef _writer_bits::GraphArcLookUpConverter Converter; - Converter converter(_graph, _edge_index); - _writer_bits::ValueStorageBase* storage = - new _writer_bits::ValueStorage(arc, converter); - _attributes.push_back(std::make_pair(caption, storage)); - return *this; - } - - /// \name Section Captions - /// @{ - - /// \brief Add an additional caption to the \c \@red_nodes and - /// \c \@blue_nodes section - /// - /// Add an additional caption to the \c \@red_nodes and \c - /// \@blue_nodes section. - BpGraphWriter& nodes(const std::string& caption) { - _nodes_caption = caption; - return *this; - } - - /// \brief Add an additional caption to the \c \@edges section - /// - /// Add an additional caption to the \c \@edges section. - BpGraphWriter& edges(const std::string& caption) { - _edges_caption = caption; - return *this; - } - - /// \brief Add an additional caption to the \c \@attributes section - /// - /// Add an additional caption to the \c \@attributes section. - BpGraphWriter& attributes(const std::string& caption) { - _attributes_caption = caption; - return *this; - } - - /// \name Skipping Section - /// @{ - - /// \brief Skip writing the node set - /// - /// The \c \@red_nodes and \c \@blue_nodes section will not be - /// written to the stream. - BpGraphWriter& skipNodes() { - LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member"); - _skip_nodes = true; - return *this; - } - - /// \brief Skip writing edge set - /// - /// The \c \@edges section will not be written to the stream. - BpGraphWriter& skipEdges() { - LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member"); - _skip_edges = true; - return *this; - } - - /// @} - - private: - - void writeRedNodes() { - _writer_bits::MapStorageBase* label = 0; - for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); - it != _red_node_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - *_os << "@red_nodes"; - if (!_nodes_caption.empty()) { - _writer_bits::writeToken(*_os << ' ', _nodes_caption); - } - *_os << std::endl; - - if (label == 0) { - *_os << "label" << '\t'; - } - for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); - it != _red_node_maps.end(); ++it) { - _writer_bits::writeToken(*_os, it->first) << '\t'; - } - *_os << std::endl; - - std::vector nodes; - for (RedNodeIt n(_graph); n != INVALID; ++n) { - nodes.push_back(n); - } - - if (label == 0) { - IdMap id_map(_graph); - _writer_bits::MapLess > id_less(id_map); - std::sort(nodes.begin(), nodes.end(), id_less); - } else { - label->sort(nodes); - } - - for (int i = 0; i < static_cast(nodes.size()); ++i) { - RedNode n = nodes[i]; - if (label == 0) { - std::ostringstream os; - os << _graph.id(static_cast(n)); - _writer_bits::writeToken(*_os, os.str()); - *_os << '\t'; - _red_node_index.insert(std::make_pair(n, os.str())); - } - for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); - it != _red_node_maps.end(); ++it) { - std::string value = it->second->get(n); - _writer_bits::writeToken(*_os, value); - if (it->first == "label") { - _red_node_index.insert(std::make_pair(n, value)); - } - *_os << '\t'; - } - *_os << std::endl; - } - } - - void writeBlueNodes() { - _writer_bits::MapStorageBase* label = 0; - for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); - it != _blue_node_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - *_os << "@blue_nodes"; - if (!_nodes_caption.empty()) { - _writer_bits::writeToken(*_os << ' ', _nodes_caption); - } - *_os << std::endl; - - if (label == 0) { - *_os << "label" << '\t'; - } - for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); - it != _blue_node_maps.end(); ++it) { - _writer_bits::writeToken(*_os, it->first) << '\t'; - } - *_os << std::endl; - - std::vector nodes; - for (BlueNodeIt n(_graph); n != INVALID; ++n) { - nodes.push_back(n); - } - - if (label == 0) { - IdMap id_map(_graph); - _writer_bits::MapLess > id_less(id_map); - std::sort(nodes.begin(), nodes.end(), id_less); - } else { - label->sort(nodes); - } - - for (int i = 0; i < static_cast(nodes.size()); ++i) { - BlueNode n = nodes[i]; - if (label == 0) { - std::ostringstream os; - os << _graph.id(static_cast(n)); - _writer_bits::writeToken(*_os, os.str()); - *_os << '\t'; - _blue_node_index.insert(std::make_pair(n, os.str())); - } - for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); - it != _blue_node_maps.end(); ++it) { - std::string value = it->second->get(n); - _writer_bits::writeToken(*_os, value); - if (it->first == "label") { - _blue_node_index.insert(std::make_pair(n, value)); - } - *_os << '\t'; - } - *_os << std::endl; - } - } - - void createRedNodeIndex() { - _writer_bits::MapStorageBase* label = 0; - for (typename RedNodeMaps::iterator it = _red_node_maps.begin(); - it != _red_node_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - if (label == 0) { - for (RedNodeIt n(_graph); n != INVALID; ++n) { - std::ostringstream os; - os << _graph.id(n); - _red_node_index.insert(std::make_pair(n, os.str())); - } - } else { - for (RedNodeIt n(_graph); n != INVALID; ++n) { - std::string value = label->get(n); - _red_node_index.insert(std::make_pair(n, value)); - } - } - } - - void createBlueNodeIndex() { - _writer_bits::MapStorageBase* label = 0; - for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin(); - it != _blue_node_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - if (label == 0) { - for (BlueNodeIt n(_graph); n != INVALID; ++n) { - std::ostringstream os; - os << _graph.id(n); - _blue_node_index.insert(std::make_pair(n, os.str())); - } - } else { - for (BlueNodeIt n(_graph); n != INVALID; ++n) { - std::string value = label->get(n); - _blue_node_index.insert(std::make_pair(n, value)); - } - } - } - - void writeEdges() { - _writer_bits::MapStorageBase* label = 0; - for (typename EdgeMaps::iterator it = _edge_maps.begin(); - it != _edge_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - *_os << "@edges"; - if (!_edges_caption.empty()) { - _writer_bits::writeToken(*_os << ' ', _edges_caption); - } - *_os << std::endl; - - *_os << '\t' << '\t'; - if (label == 0) { - *_os << "label" << '\t'; - } - for (typename EdgeMaps::iterator it = _edge_maps.begin(); - it != _edge_maps.end(); ++it) { - _writer_bits::writeToken(*_os, it->first) << '\t'; - } - *_os << std::endl; - - std::vector edges; - for (EdgeIt n(_graph); n != INVALID; ++n) { - edges.push_back(n); - } - - if (label == 0) { - IdMap id_map(_graph); - _writer_bits::MapLess > id_less(id_map); - std::sort(edges.begin(), edges.end(), id_less); - } else { - label->sort(edges); - } - - for (int i = 0; i < static_cast(edges.size()); ++i) { - Edge e = edges[i]; - _writer_bits::writeToken(*_os, _red_node_index. - find(_graph.redNode(e))->second); - *_os << '\t'; - _writer_bits::writeToken(*_os, _blue_node_index. - find(_graph.blueNode(e))->second); - *_os << '\t'; - if (label == 0) { - std::ostringstream os; - os << _graph.id(e); - _writer_bits::writeToken(*_os, os.str()); - *_os << '\t'; - _edge_index.insert(std::make_pair(e, os.str())); - } - for (typename EdgeMaps::iterator it = _edge_maps.begin(); - it != _edge_maps.end(); ++it) { - std::string value = it->second->get(e); - _writer_bits::writeToken(*_os, value); - if (it->first == "label") { - _edge_index.insert(std::make_pair(e, value)); - } - *_os << '\t'; - } - *_os << std::endl; - } - } - - void createEdgeIndex() { - _writer_bits::MapStorageBase* label = 0; - for (typename EdgeMaps::iterator it = _edge_maps.begin(); - it != _edge_maps.end(); ++it) { - if (it->first == "label") { - label = it->second; - break; - } - } - - if (label == 0) { - for (EdgeIt e(_graph); e != INVALID; ++e) { - std::ostringstream os; - os << _graph.id(e); - _edge_index.insert(std::make_pair(e, os.str())); - } - } else { - for (EdgeIt e(_graph); e != INVALID; ++e) { - std::string value = label->get(e); - _edge_index.insert(std::make_pair(e, value)); - } - } - } - - void writeAttributes() { - if (_attributes.empty()) return; - *_os << "@attributes"; - if (!_attributes_caption.empty()) { - _writer_bits::writeToken(*_os << ' ', _attributes_caption); - } - *_os << std::endl; - for (typename Attributes::iterator it = _attributes.begin(); - it != _attributes.end(); ++it) { - _writer_bits::writeToken(*_os, it->first) << ' '; - _writer_bits::writeToken(*_os, it->second->get()); - *_os << std::endl; - } - } - - public: - - /// \name Execution of the Writer - /// @{ - - /// \brief Start the batch processing - /// - /// This function starts the batch processing. - void run() { - if (!_skip_nodes) { - writeRedNodes(); - writeBlueNodes(); - } else { - createRedNodeIndex(); - createBlueNodeIndex(); - } - if (!_skip_edges) { - writeEdges(); - } else { - createEdgeIndex(); - } - writeAttributes(); - } - - /// \brief Give back the stream of the writer - /// - /// Give back the stream of the writer - std::ostream& ostream() { - return *_os; - } - - /// @} - }; - - /// \ingroup lemon_io - /// - /// \brief Return a \ref lemon::BpGraphWriter "BpGraphWriter" class - /// - /// This function just returns a \ref lemon::BpGraphWriter - /// "BpGraphWriter" class. - /// - /// With this function a bipartite graph can be write to a file or output - /// stream in \ref lgf-format "LGF" format with several maps and - /// attributes. For example, with the following code a bipartite - /// weighted matching problem can be written to the standard output, - /// i.e. a graph with a \e weight map on the edges: - /// - ///\code - ///ListBpGraph graph; - ///ListBpGraph::EdgeMap weight(graph); - /// // Setting the weight map - ///bpGraphWriter(graph, std::cout). - /// edgeMap("weight", weight). - /// run(); - ///\endcode - /// - /// For a complete documentation, please see the - /// \ref lemon::BpGraphWriter "BpGraphWriter" - /// class documentation. - /// \warning Don't forget to put the \ref lemon::BpGraphWriter::run() "run()" - /// to the end of the parameter list. - /// \relates BpGraphWriter - /// \sa bpGraphWriter(const TBGR& graph, const std::string& fn) - /// \sa bpGraphWriter(const TBGR& graph, const char* fn) - template - BpGraphWriter bpGraphWriter(const TBGR& graph, std::ostream& os) { - BpGraphWriter tmp(graph, os); - return tmp; - } - - /// \brief Return a \ref BpGraphWriter class - /// - /// This function just returns a \ref BpGraphWriter class. - /// \relates BpGraphWriter - /// \sa graphWriter(const TBGR& graph, std::ostream& os) - template - BpGraphWriter bpGraphWriter(const TBGR& graph, const std::string& fn) { - BpGraphWriter tmp(graph, fn); - return tmp; - } - - /// \brief Return a \ref BpGraphWriter class - /// - /// This function just returns a \ref BpGraphWriter class. - /// \relates BpGraphWriter - /// \sa graphWriter(const TBGR& graph, std::ostream& os) - template - BpGraphWriter bpGraphWriter(const TBGR& graph, const char* fn) { - BpGraphWriter tmp(graph, fn); - return tmp; - } - - class SectionWriter; - - SectionWriter sectionWriter(std::istream& is); - SectionWriter sectionWriter(const std::string& fn); - SectionWriter sectionWriter(const char* fn); - - /// \ingroup lemon_io - /// - /// \brief Section writer class - /// - /// In the \ref lgf-format "LGF" file extra sections can be placed, - /// which contain any data in arbitrary format. Such sections can be - /// written with this class. A writing rule can be added to the - /// class with two different functions. With the \c sectionLines() - /// function a generator can write the section line-by-line, while - /// with the \c sectionStream() member the section can be written to - /// an output stream. - class SectionWriter { - private: - - std::ostream* _os; - bool local_os; - - typedef std::vector > - Sections; - - Sections _sections; - - public: - - /// \brief Constructor - /// - /// Construct a section writer, which writes to the given output - /// stream. - SectionWriter(std::ostream& os) - : _os(&os), local_os(false) {} - - /// \brief Constructor - /// - /// Construct a section writer, which writes into the given file. - SectionWriter(const std::string& fn) - : _os(new std::ofstream(fn.c_str())), local_os(true) { - if (!(*_os)) { - delete _os; - throw IoError("Cannot write file", fn); - } - } - - /// \brief Constructor - /// - /// Construct a section writer, which writes into the given file. - SectionWriter(const char* fn) - : _os(new std::ofstream(fn)), local_os(true) { - if (!(*_os)) { - delete _os; - throw IoError("Cannot write file", fn); - } - } - - /// \brief Destructor - ~SectionWriter() { - for (Sections::iterator it = _sections.begin(); - it != _sections.end(); ++it) { - delete it->second; - } - - if (local_os) { - delete _os; - } - - } - - private: - - friend SectionWriter sectionWriter(std::ostream& os); - friend SectionWriter sectionWriter(const std::string& fn); - friend SectionWriter sectionWriter(const char* fn); - - SectionWriter(SectionWriter& other) - : _os(other._os), local_os(other.local_os) { - - other._os = 0; - other.local_os = false; - - _sections.swap(other._sections); - } - - SectionWriter& operator=(const SectionWriter&); - - public: - - /// \name Section Writers - /// @{ - - /// \brief Add a section writer with line oriented writing - /// - /// The first parameter is the type descriptor of the section, the - /// second is a generator with std::string values. At the writing - /// process, the returned \c std::string will be written into the - /// output file until it is an empty string. - /// - /// For example, an integer vector is written into a section. - ///\code - /// @numbers - /// 12 45 23 78 - /// 4 28 38 28 - /// 23 6 16 - ///\endcode - /// - /// The generator is implemented as a struct. - ///\code - /// struct NumberSection { - /// std::vector::const_iterator _it, _end; - /// NumberSection(const std::vector& data) - /// : _it(data.begin()), _end(data.end()) {} - /// std::string operator()() { - /// int rem_in_line = 4; - /// std::ostringstream ls; - /// while (rem_in_line > 0 && _it != _end) { - /// ls << *(_it++) << ' '; - /// --rem_in_line; - /// } - /// return ls.str(); - /// } - /// }; - /// - /// // ... - /// - /// writer.sectionLines("numbers", NumberSection(vec)); - ///\endcode - template - SectionWriter& sectionLines(const std::string& type, Functor functor) { - LEMON_ASSERT(!type.empty(), "Type is empty."); - _sections.push_back(std::make_pair(type, - new _writer_bits::LineSection(functor))); - return *this; - } - - - /// \brief Add a section writer with stream oriented writing - /// - /// The first parameter is the type of the section, the second is - /// a functor, which takes a \c std::ostream& parameter. The - /// functor writes the section to the output stream. - /// \warning The last line must be closed with end-line character. - template - SectionWriter& sectionStream(const std::string& type, Functor functor) { - LEMON_ASSERT(!type.empty(), "Type is empty."); - _sections.push_back(std::make_pair(type, - new _writer_bits::StreamSection(functor))); - return *this; - } - - /// @} - - public: - - - /// \name Execution of the Writer - /// @{ - - /// \brief Start the batch processing - /// - /// This function starts the batch processing. - void run() { - - LEMON_ASSERT(_os != 0, "This writer is assigned to an other writer"); - - for (Sections::iterator it = _sections.begin(); - it != _sections.end(); ++it) { - (*_os) << '@' << it->first << std::endl; - it->second->process(*_os); - } - } - - /// \brief Give back the stream of the writer - /// - /// Returns the stream of the writer - std::ostream& ostream() { - return *_os; - } - - /// @} - - }; - - /// \ingroup lemon_io - /// - /// \brief Return a \ref SectionWriter class - /// - /// This function just returns a \ref SectionWriter class. - /// - /// Please see SectionWriter documentation about the custom section - /// output. - /// - /// \relates SectionWriter - /// \sa sectionWriter(const std::string& fn) - /// \sa sectionWriter(const char *fn) - inline SectionWriter sectionWriter(std::ostream& os) { - SectionWriter tmp(os); - return tmp; - } - - /// \brief Return a \ref SectionWriter class - /// - /// This function just returns a \ref SectionWriter class. - /// \relates SectionWriter - /// \sa sectionWriter(std::ostream& os) - inline SectionWriter sectionWriter(const std::string& fn) { - SectionWriter tmp(fn); - return tmp; - } - - /// \brief Return a \ref SectionWriter class - /// - /// This function just returns a \ref SectionWriter class. - /// \relates SectionWriter - /// \sa sectionWriter(std::ostream& os) - inline SectionWriter sectionWriter(const char* fn) { - SectionWriter tmp(fn); - return tmp; - } -} - -#endif diff --git a/deps/lemon/lemon/list_graph.h b/deps/lemon/lemon/list_graph.h deleted file mode 100644 index 2a236cf91..000000000 --- a/deps/lemon/lemon/list_graph.h +++ /dev/null @@ -1,2510 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_LIST_GRAPH_H -#define LEMON_LIST_GRAPH_H - -///\ingroup graphs -///\file -///\brief ListDigraph and ListGraph classes. - -#include -#include -#include - -#include -#include - -namespace lemon { - - class ListDigraph; - - class ListDigraphBase { - - protected: - struct NodeT { - int first_in, first_out; - int prev, next; - }; - - struct ArcT { - int target, source; - int prev_in, prev_out; - int next_in, next_out; - }; - - std::vector nodes; - - int first_node; - - int first_free_node; - - std::vector arcs; - - int first_free_arc; - - public: - - typedef ListDigraphBase Digraph; - - class Node { - friend class ListDigraphBase; - friend class ListDigraph; - protected: - - int id; - explicit Node(int pid) { id = pid;} - - public: - Node() {} - Node (Invalid) { id = -1; } - bool operator==(const Node& node) const {return id == node.id;} - bool operator!=(const Node& node) const {return id != node.id;} - bool operator<(const Node& node) const {return id < node.id;} - }; - - class Arc { - friend class ListDigraphBase; - friend class ListDigraph; - protected: - - int id; - explicit Arc(int pid) { id = pid;} - - public: - Arc() {} - Arc (Invalid) { id = -1; } - bool operator==(const Arc& arc) const {return id == arc.id;} - bool operator!=(const Arc& arc) const {return id != arc.id;} - bool operator<(const Arc& arc) const {return id < arc.id;} - }; - - - - ListDigraphBase() - : nodes(), first_node(-1), - first_free_node(-1), arcs(), first_free_arc(-1) {} - - - int maxNodeId() const { return nodes.size()-1; } - int maxArcId() const { return arcs.size()-1; } - - Node source(Arc e) const { return Node(arcs[e.id].source); } - Node target(Arc e) const { return Node(arcs[e.id].target); } - - - void first(Node& node) const { - node.id = first_node; - } - - void next(Node& node) const { - node.id = nodes[node.id].next; - } - - - void first(Arc& arc) const { - int n; - for(n = first_node; - n != -1 && nodes[n].first_out == -1; - n = nodes[n].next) {} - arc.id = (n == -1) ? -1 : nodes[n].first_out; - } - - void next(Arc& arc) const { - if (arcs[arc.id].next_out != -1) { - arc.id = arcs[arc.id].next_out; - } else { - int n; - for(n = nodes[arcs[arc.id].source].next; - n != -1 && nodes[n].first_out == -1; - n = nodes[n].next) {} - arc.id = (n == -1) ? -1 : nodes[n].first_out; - } - } - - void firstOut(Arc &e, const Node& v) const { - e.id = nodes[v.id].first_out; - } - void nextOut(Arc &e) const { - e.id=arcs[e.id].next_out; - } - - void firstIn(Arc &e, const Node& v) const { - e.id = nodes[v.id].first_in; - } - void nextIn(Arc &e) const { - e.id=arcs[e.id].next_in; - } - - - static int id(Node v) { return v.id; } - static int id(Arc e) { return e.id; } - - static Node nodeFromId(int id) { return Node(id);} - static Arc arcFromId(int id) { return Arc(id);} - - bool valid(Node n) const { - return n.id >= 0 && n.id < static_cast(nodes.size()) && - nodes[n.id].prev != -2; - } - - bool valid(Arc a) const { - return a.id >= 0 && a.id < static_cast(arcs.size()) && - arcs[a.id].prev_in != -2; - } - - Node addNode() { - int n; - - if(first_free_node==-1) { - n = nodes.size(); - nodes.push_back(NodeT()); - } else { - n = first_free_node; - first_free_node = nodes[n].next; - } - - nodes[n].next = first_node; - if(first_node != -1) nodes[first_node].prev = n; - first_node = n; - nodes[n].prev = -1; - - nodes[n].first_in = nodes[n].first_out = -1; - - return Node(n); - } - - Arc addArc(Node u, Node v) { - int n; - - if (first_free_arc == -1) { - n = arcs.size(); - arcs.push_back(ArcT()); - } else { - n = first_free_arc; - first_free_arc = arcs[n].next_in; - } - - arcs[n].source = u.id; - arcs[n].target = v.id; - - arcs[n].next_out = nodes[u.id].first_out; - if(nodes[u.id].first_out != -1) { - arcs[nodes[u.id].first_out].prev_out = n; - } - - arcs[n].next_in = nodes[v.id].first_in; - if(nodes[v.id].first_in != -1) { - arcs[nodes[v.id].first_in].prev_in = n; - } - - arcs[n].prev_in = arcs[n].prev_out = -1; - - nodes[u.id].first_out = nodes[v.id].first_in = n; - - return Arc(n); - } - - void erase(const Node& node) { - int n = node.id; - - if(nodes[n].next != -1) { - nodes[nodes[n].next].prev = nodes[n].prev; - } - - if(nodes[n].prev != -1) { - nodes[nodes[n].prev].next = nodes[n].next; - } else { - first_node = nodes[n].next; - } - - nodes[n].next = first_free_node; - first_free_node = n; - nodes[n].prev = -2; - - } - - void erase(const Arc& arc) { - int n = arc.id; - - if(arcs[n].next_in!=-1) { - arcs[arcs[n].next_in].prev_in = arcs[n].prev_in; - } - - if(arcs[n].prev_in!=-1) { - arcs[arcs[n].prev_in].next_in = arcs[n].next_in; - } else { - nodes[arcs[n].target].first_in = arcs[n].next_in; - } - - - if(arcs[n].next_out!=-1) { - arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; - } - - if(arcs[n].prev_out!=-1) { - arcs[arcs[n].prev_out].next_out = arcs[n].next_out; - } else { - nodes[arcs[n].source].first_out = arcs[n].next_out; - } - - arcs[n].next_in = first_free_arc; - first_free_arc = n; - arcs[n].prev_in = -2; - } - - void clear() { - arcs.clear(); - nodes.clear(); - first_node = first_free_node = first_free_arc = -1; - } - - protected: - void changeTarget(Arc e, Node n) - { - if(arcs[e.id].next_in != -1) - arcs[arcs[e.id].next_in].prev_in = arcs[e.id].prev_in; - if(arcs[e.id].prev_in != -1) - arcs[arcs[e.id].prev_in].next_in = arcs[e.id].next_in; - else nodes[arcs[e.id].target].first_in = arcs[e.id].next_in; - if (nodes[n.id].first_in != -1) { - arcs[nodes[n.id].first_in].prev_in = e.id; - } - arcs[e.id].target = n.id; - arcs[e.id].prev_in = -1; - arcs[e.id].next_in = nodes[n.id].first_in; - nodes[n.id].first_in = e.id; - } - void changeSource(Arc e, Node n) - { - if(arcs[e.id].next_out != -1) - arcs[arcs[e.id].next_out].prev_out = arcs[e.id].prev_out; - if(arcs[e.id].prev_out != -1) - arcs[arcs[e.id].prev_out].next_out = arcs[e.id].next_out; - else nodes[arcs[e.id].source].first_out = arcs[e.id].next_out; - if (nodes[n.id].first_out != -1) { - arcs[nodes[n.id].first_out].prev_out = e.id; - } - arcs[e.id].source = n.id; - arcs[e.id].prev_out = -1; - arcs[e.id].next_out = nodes[n.id].first_out; - nodes[n.id].first_out = e.id; - } - - }; - - typedef DigraphExtender ExtendedListDigraphBase; - - /// \addtogroup graphs - /// @{ - - ///A general directed graph structure. - - ///\ref ListDigraph is a versatile and fast directed graph - ///implementation based on linked lists that are stored in - ///\c std::vector structures. - /// - ///This type fully conforms to the \ref concepts::Digraph "Digraph concept" - ///and it also provides several useful additional functionalities. - ///Most of its member functions and nested classes are documented - ///only in the concept class. - /// - ///This class provides only linear time counting for nodes and arcs. - /// - ///\sa concepts::Digraph - ///\sa ListGraph - class ListDigraph : public ExtendedListDigraphBase { - typedef ExtendedListDigraphBase Parent; - - private: - /// Digraphs are \e not copy constructible. Use DigraphCopy instead. - ListDigraph(const ListDigraph &) :ExtendedListDigraphBase() {}; - /// \brief Assignment of a digraph to another one is \e not allowed. - /// Use DigraphCopy instead. - void operator=(const ListDigraph &) {} - public: - - /// Constructor - - /// Constructor. - /// - ListDigraph() {} - - ///Add a new node to the digraph. - - ///This function adds a new node to the digraph. - ///\return The new node. - Node addNode() { return Parent::addNode(); } - - ///Add a new arc to the digraph. - - ///This function adds a new arc to the digraph with source node \c s - ///and target node \c t. - ///\return The new arc. - Arc addArc(Node s, Node t) { - return Parent::addArc(s, t); - } - - ///\brief Erase a node from the digraph. - /// - ///This function erases the given node along with its outgoing and - ///incoming arcs from the digraph. - /// - ///\note All iterators referencing the removed node or the connected - ///arcs are invalidated, of course. - void erase(Node n) { Parent::erase(n); } - - ///\brief Erase an arc from the digraph. - /// - ///This function erases the given arc from the digraph. - /// - ///\note All iterators referencing the removed arc are invalidated, - ///of course. - void erase(Arc a) { Parent::erase(a); } - - /// Node validity check - - /// This function gives back \c true if the given node is valid, - /// i.e. it is a real node of the digraph. - /// - /// \warning A removed node could become valid again if new nodes are - /// added to the digraph. - bool valid(Node n) const { return Parent::valid(n); } - - /// Arc validity check - - /// This function gives back \c true if the given arc is valid, - /// i.e. it is a real arc of the digraph. - /// - /// \warning A removed arc could become valid again if new arcs are - /// added to the digraph. - bool valid(Arc a) const { return Parent::valid(a); } - - /// Change the target node of an arc - - /// This function changes the target node of the given arc \c a to \c n. - /// - ///\note \c ArcIt and \c OutArcIt iterators referencing the changed - ///arc remain valid, but \c InArcIt iterators are invalidated. - /// - ///\warning This functionality cannot be used together with the Snapshot - ///feature. - void changeTarget(Arc a, Node n) { - Parent::changeTarget(a,n); - } - /// Change the source node of an arc - - /// This function changes the source node of the given arc \c a to \c n. - /// - ///\note \c InArcIt iterators referencing the changed arc remain - ///valid, but \c ArcIt and \c OutArcIt iterators are invalidated. - /// - ///\warning This functionality cannot be used together with the Snapshot - ///feature. - void changeSource(Arc a, Node n) { - Parent::changeSource(a,n); - } - - /// Reverse the direction of an arc. - - /// This function reverses the direction of the given arc. - ///\note \c ArcIt, \c OutArcIt and \c InArcIt iterators referencing - ///the changed arc are invalidated. - /// - ///\warning This functionality cannot be used together with the Snapshot - ///feature. - void reverseArc(Arc a) { - Node t=target(a); - changeTarget(a,source(a)); - changeSource(a,t); - } - - ///Contract two nodes. - - ///This function contracts the given two nodes. - ///Node \c v is removed, but instead of deleting its - ///incident arcs, they are joined to node \c u. - ///If the last parameter \c r is \c true (this is the default value), - ///then the newly created loops are removed. - /// - ///\note The moved arcs are joined to node \c u using changeSource() - ///or changeTarget(), thus \c ArcIt and \c OutArcIt iterators are - ///invalidated for the outgoing arcs of node \c v and \c InArcIt - ///iterators are invalidated for the incoming arcs of \c v. - ///Moreover all iterators referencing node \c v or the removed - ///loops are also invalidated. Other iterators remain valid. - /// - ///\warning This functionality cannot be used together with the Snapshot - ///feature. - void contract(Node u, Node v, bool r = true) - { - for(OutArcIt e(*this,v);e!=INVALID;) { - OutArcIt f=e; - ++f; - if(r && target(e)==u) erase(e); - else changeSource(e,u); - e=f; - } - for(InArcIt e(*this,v);e!=INVALID;) { - InArcIt f=e; - ++f; - if(r && source(e)==u) erase(e); - else changeTarget(e,u); - e=f; - } - erase(v); - } - - ///Split a node. - - ///This function splits the given node. First, a new node is added - ///to the digraph, then the source of each outgoing arc of node \c n - ///is moved to this new node. - ///If the second parameter \c connect is \c true (this is the default - ///value), then a new arc from node \c n to the newly created node - ///is also added. - ///\return The newly created node. - /// - ///\note All iterators remain valid. - /// - ///\warning This functionality cannot be used together with the - ///Snapshot feature. - Node split(Node n, bool connect = true) { - Node b = addNode(); - nodes[b.id].first_out=nodes[n.id].first_out; - nodes[n.id].first_out=-1; - for(int i=nodes[b.id].first_out; i!=-1; i=arcs[i].next_out) { - arcs[i].source=b.id; - } - if (connect) addArc(n,b); - return b; - } - - ///Split an arc. - - ///This function splits the given arc. First, a new node \c v is - ///added to the digraph, then the target node of the original arc - ///is set to \c v. Finally, an arc from \c v to the original target - ///is added. - ///\return The newly created node. - /// - ///\note \c InArcIt iterators referencing the original arc are - ///invalidated. Other iterators remain valid. - /// - ///\warning This functionality cannot be used together with the - ///Snapshot feature. - Node split(Arc a) { - Node v = addNode(); - addArc(v,target(a)); - changeTarget(a,v); - return v; - } - - ///Clear the digraph. - - ///This function erases all nodes and arcs from the digraph. - /// - ///\note All iterators of the digraph are invalidated, of course. - void clear() { - Parent::clear(); - } - - /// Reserve memory for nodes. - - /// Using this function, it is possible to avoid superfluous memory - /// allocation: if you know that the digraph you want to build will - /// be large (e.g. it will contain millions of nodes and/or arcs), - /// then it is worth reserving space for this amount before starting - /// to build the digraph. - /// \sa reserveArc() - void reserveNode(int n) { nodes.reserve(n); }; - - /// Reserve memory for arcs. - - /// Using this function, it is possible to avoid superfluous memory - /// allocation: if you know that the digraph you want to build will - /// be large (e.g. it will contain millions of nodes and/or arcs), - /// then it is worth reserving space for this amount before starting - /// to build the digraph. - /// \sa reserveNode() - void reserveArc(int m) { arcs.reserve(m); }; - - /// \brief Class to make a snapshot of the digraph and restore - /// it later. - /// - /// Class to make a snapshot of the digraph and restore it later. - /// - /// The newly added nodes and arcs can be removed using the - /// restore() function. - /// - /// \note After a state is restored, you cannot restore a later state, - /// i.e. you cannot add the removed nodes and arcs again using - /// another Snapshot instance. - /// - /// \warning Node and arc deletions and other modifications (e.g. - /// reversing, contracting, splitting arcs or nodes) cannot be - /// restored. These events invalidate the snapshot. - /// However, the arcs and nodes that were added to the digraph after - /// making the current snapshot can be removed without invalidating it. - class Snapshot { - protected: - - typedef Parent::NodeNotifier NodeNotifier; - - class NodeObserverProxy : public NodeNotifier::ObserverBase { - public: - - NodeObserverProxy(Snapshot& _snapshot) - : snapshot(_snapshot) {} - - using NodeNotifier::ObserverBase::attach; - using NodeNotifier::ObserverBase::detach; - using NodeNotifier::ObserverBase::attached; - - protected: - - virtual void add(const Node& node) { - snapshot.addNode(node); - } - virtual void add(const std::vector& nodes) { - for (int i = nodes.size() - 1; i >= 0; ++i) { - snapshot.addNode(nodes[i]); - } - } - virtual void erase(const Node& node) { - snapshot.eraseNode(node); - } - virtual void erase(const std::vector& nodes) { - for (int i = 0; i < int(nodes.size()); ++i) { - snapshot.eraseNode(nodes[i]); - } - } - virtual void build() { - Node node; - std::vector nodes; - for (notifier()->first(node); node != INVALID; - notifier()->next(node)) { - nodes.push_back(node); - } - for (int i = nodes.size() - 1; i >= 0; --i) { - snapshot.addNode(nodes[i]); - } - } - virtual void clear() { - Node node; - for (notifier()->first(node); node != INVALID; - notifier()->next(node)) { - snapshot.eraseNode(node); - } - } - - Snapshot& snapshot; - }; - - class ArcObserverProxy : public ArcNotifier::ObserverBase { - public: - - ArcObserverProxy(Snapshot& _snapshot) - : snapshot(_snapshot) {} - - using ArcNotifier::ObserverBase::attach; - using ArcNotifier::ObserverBase::detach; - using ArcNotifier::ObserverBase::attached; - - protected: - - virtual void add(const Arc& arc) { - snapshot.addArc(arc); - } - virtual void add(const std::vector& arcs) { - for (int i = arcs.size() - 1; i >= 0; ++i) { - snapshot.addArc(arcs[i]); - } - } - virtual void erase(const Arc& arc) { - snapshot.eraseArc(arc); - } - virtual void erase(const std::vector& arcs) { - for (int i = 0; i < int(arcs.size()); ++i) { - snapshot.eraseArc(arcs[i]); - } - } - virtual void build() { - Arc arc; - std::vector arcs; - for (notifier()->first(arc); arc != INVALID; - notifier()->next(arc)) { - arcs.push_back(arc); - } - for (int i = arcs.size() - 1; i >= 0; --i) { - snapshot.addArc(arcs[i]); - } - } - virtual void clear() { - Arc arc; - for (notifier()->first(arc); arc != INVALID; - notifier()->next(arc)) { - snapshot.eraseArc(arc); - } - } - - Snapshot& snapshot; - }; - - ListDigraph *digraph; - - NodeObserverProxy node_observer_proxy; - ArcObserverProxy arc_observer_proxy; - - std::list added_nodes; - std::list added_arcs; - - - void addNode(const Node& node) { - added_nodes.push_front(node); - } - void eraseNode(const Node& node) { - std::list::iterator it = - std::find(added_nodes.begin(), added_nodes.end(), node); - if (it == added_nodes.end()) { - clear(); - arc_observer_proxy.detach(); - throw NodeNotifier::ImmediateDetach(); - } else { - added_nodes.erase(it); - } - } - - void addArc(const Arc& arc) { - added_arcs.push_front(arc); - } - void eraseArc(const Arc& arc) { - std::list::iterator it = - std::find(added_arcs.begin(), added_arcs.end(), arc); - if (it == added_arcs.end()) { - clear(); - node_observer_proxy.detach(); - throw ArcNotifier::ImmediateDetach(); - } else { - added_arcs.erase(it); - } - } - - void attach(ListDigraph &_digraph) { - digraph = &_digraph; - node_observer_proxy.attach(digraph->notifier(Node())); - arc_observer_proxy.attach(digraph->notifier(Arc())); - } - - void detach() { - node_observer_proxy.detach(); - arc_observer_proxy.detach(); - } - - bool attached() const { - return node_observer_proxy.attached(); - } - - void clear() { - added_nodes.clear(); - added_arcs.clear(); - } - - public: - - /// \brief Default constructor. - /// - /// Default constructor. - /// You have to call save() to actually make a snapshot. - Snapshot() - : digraph(0), node_observer_proxy(*this), - arc_observer_proxy(*this) {} - - /// \brief Constructor that immediately makes a snapshot. - /// - /// This constructor immediately makes a snapshot of the given digraph. - Snapshot(ListDigraph &gr) - : node_observer_proxy(*this), - arc_observer_proxy(*this) { - attach(gr); - } - - /// \brief Make a snapshot. - /// - /// This function makes a snapshot of the given digraph. - /// It can be called more than once. In case of a repeated - /// call, the previous snapshot gets lost. - void save(ListDigraph &gr) { - if (attached()) { - detach(); - clear(); - } - attach(gr); - } - - /// \brief Undo the changes until the last snapshot. - /// - /// This function undos the changes until the last snapshot - /// created by save() or Snapshot(ListDigraph&). - /// - /// \warning This method invalidates the snapshot, i.e. repeated - /// restoring is not supported unless you call save() again. - void restore() { - detach(); - for(std::list::iterator it = added_arcs.begin(); - it != added_arcs.end(); ++it) { - digraph->erase(*it); - } - for(std::list::iterator it = added_nodes.begin(); - it != added_nodes.end(); ++it) { - digraph->erase(*it); - } - clear(); - } - - /// \brief Returns \c true if the snapshot is valid. - /// - /// This function returns \c true if the snapshot is valid. - bool valid() const { - return attached(); - } - }; - - }; - - ///@} - - class ListGraphBase { - - protected: - - struct NodeT { - int first_out; - int prev, next; - }; - - struct ArcT { - int target; - int prev_out, next_out; - }; - - std::vector nodes; - - int first_node; - - int first_free_node; - - std::vector arcs; - - int first_free_arc; - - public: - - typedef ListGraphBase Graph; - - class Node { - friend class ListGraphBase; - protected: - - int id; - explicit Node(int pid) { id = pid;} - - public: - Node() {} - Node (Invalid) { id = -1; } - bool operator==(const Node& node) const {return id == node.id;} - bool operator!=(const Node& node) const {return id != node.id;} - bool operator<(const Node& node) const {return id < node.id;} - }; - - class Edge { - friend class ListGraphBase; - protected: - - int id; - explicit Edge(int pid) { id = pid;} - - public: - Edge() {} - Edge (Invalid) { id = -1; } - bool operator==(const Edge& edge) const {return id == edge.id;} - bool operator!=(const Edge& edge) const {return id != edge.id;} - bool operator<(const Edge& edge) const {return id < edge.id;} - }; - - class Arc { - friend class ListGraphBase; - protected: - - int id; - explicit Arc(int pid) { id = pid;} - - public: - operator Edge() const { - return id != -1 ? edgeFromId(id / 2) : INVALID; - } - - Arc() {} - Arc (Invalid) { id = -1; } - bool operator==(const Arc& arc) const {return id == arc.id;} - bool operator!=(const Arc& arc) const {return id != arc.id;} - bool operator<(const Arc& arc) const {return id < arc.id;} - }; - - ListGraphBase() - : nodes(), first_node(-1), - first_free_node(-1), arcs(), first_free_arc(-1) {} - - - int maxNodeId() const { return nodes.size()-1; } - int maxEdgeId() const { return arcs.size() / 2 - 1; } - int maxArcId() const { return arcs.size()-1; } - - Node source(Arc e) const { return Node(arcs[e.id ^ 1].target); } - Node target(Arc e) const { return Node(arcs[e.id].target); } - - Node u(Edge e) const { return Node(arcs[2 * e.id].target); } - Node v(Edge e) const { return Node(arcs[2 * e.id + 1].target); } - - static bool direction(Arc e) { - return (e.id & 1) == 1; - } - - static Arc direct(Edge e, bool d) { - return Arc(e.id * 2 + (d ? 1 : 0)); - } - - void first(Node& node) const { - node.id = first_node; - } - - void next(Node& node) const { - node.id = nodes[node.id].next; - } - - void first(Arc& e) const { - int n = first_node; - while (n != -1 && nodes[n].first_out == -1) { - n = nodes[n].next; - } - e.id = (n == -1) ? -1 : nodes[n].first_out; - } - - void next(Arc& e) const { - if (arcs[e.id].next_out != -1) { - e.id = arcs[e.id].next_out; - } else { - int n = nodes[arcs[e.id ^ 1].target].next; - while(n != -1 && nodes[n].first_out == -1) { - n = nodes[n].next; - } - e.id = (n == -1) ? -1 : nodes[n].first_out; - } - } - - void first(Edge& e) const { - int n = first_node; - while (n != -1) { - e.id = nodes[n].first_out; - while ((e.id & 1) != 1) { - e.id = arcs[e.id].next_out; - } - if (e.id != -1) { - e.id /= 2; - return; - } - n = nodes[n].next; - } - e.id = -1; - } - - void next(Edge& e) const { - int n = arcs[e.id * 2].target; - e.id = arcs[(e.id * 2) | 1].next_out; - while ((e.id & 1) != 1) { - e.id = arcs[e.id].next_out; - } - if (e.id != -1) { - e.id /= 2; - return; - } - n = nodes[n].next; - while (n != -1) { - e.id = nodes[n].first_out; - while ((e.id & 1) != 1) { - e.id = arcs[e.id].next_out; - } - if (e.id != -1) { - e.id /= 2; - return; - } - n = nodes[n].next; - } - e.id = -1; - } - - void firstOut(Arc &e, const Node& v) const { - e.id = nodes[v.id].first_out; - } - void nextOut(Arc &e) const { - e.id = arcs[e.id].next_out; - } - - void firstIn(Arc &e, const Node& v) const { - e.id = ((nodes[v.id].first_out) ^ 1); - if (e.id == -2) e.id = -1; - } - void nextIn(Arc &e) const { - e.id = ((arcs[e.id ^ 1].next_out) ^ 1); - if (e.id == -2) e.id = -1; - } - - void firstInc(Edge &e, bool& d, const Node& v) const { - int a = nodes[v.id].first_out; - if (a != -1 ) { - e.id = a / 2; - d = ((a & 1) == 1); - } else { - e.id = -1; - d = true; - } - } - void nextInc(Edge &e, bool& d) const { - int a = (arcs[(e.id * 2) | (d ? 1 : 0)].next_out); - if (a != -1 ) { - e.id = a / 2; - d = ((a & 1) == 1); - } else { - e.id = -1; - d = true; - } - } - - static int id(Node v) { return v.id; } - static int id(Arc e) { return e.id; } - static int id(Edge e) { return e.id; } - - static Node nodeFromId(int id) { return Node(id);} - static Arc arcFromId(int id) { return Arc(id);} - static Edge edgeFromId(int id) { return Edge(id);} - - bool valid(Node n) const { - return n.id >= 0 && n.id < static_cast(nodes.size()) && - nodes[n.id].prev != -2; - } - - bool valid(Arc a) const { - return a.id >= 0 && a.id < static_cast(arcs.size()) && - arcs[a.id].prev_out != -2; - } - - bool valid(Edge e) const { - return e.id >= 0 && 2 * e.id < static_cast(arcs.size()) && - arcs[2 * e.id].prev_out != -2; - } - - Node addNode() { - int n; - - if(first_free_node==-1) { - n = nodes.size(); - nodes.push_back(NodeT()); - } else { - n = first_free_node; - first_free_node = nodes[n].next; - } - - nodes[n].next = first_node; - if (first_node != -1) nodes[first_node].prev = n; - first_node = n; - nodes[n].prev = -1; - - nodes[n].first_out = -1; - - return Node(n); - } - - Edge addEdge(Node u, Node v) { - int n; - - if (first_free_arc == -1) { - n = arcs.size(); - arcs.push_back(ArcT()); - arcs.push_back(ArcT()); - } else { - n = first_free_arc; - first_free_arc = arcs[n].next_out; - } - - arcs[n].target = u.id; - arcs[n | 1].target = v.id; - - arcs[n].next_out = nodes[v.id].first_out; - if (nodes[v.id].first_out != -1) { - arcs[nodes[v.id].first_out].prev_out = n; - } - arcs[n].prev_out = -1; - nodes[v.id].first_out = n; - - arcs[n | 1].next_out = nodes[u.id].first_out; - if (nodes[u.id].first_out != -1) { - arcs[nodes[u.id].first_out].prev_out = (n | 1); - } - arcs[n | 1].prev_out = -1; - nodes[u.id].first_out = (n | 1); - - return Edge(n / 2); - } - - void erase(const Node& node) { - int n = node.id; - - if(nodes[n].next != -1) { - nodes[nodes[n].next].prev = nodes[n].prev; - } - - if(nodes[n].prev != -1) { - nodes[nodes[n].prev].next = nodes[n].next; - } else { - first_node = nodes[n].next; - } - - nodes[n].next = first_free_node; - first_free_node = n; - nodes[n].prev = -2; - } - - void erase(const Edge& edge) { - int n = edge.id * 2; - - if (arcs[n].next_out != -1) { - arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; - } - - if (arcs[n].prev_out != -1) { - arcs[arcs[n].prev_out].next_out = arcs[n].next_out; - } else { - nodes[arcs[n | 1].target].first_out = arcs[n].next_out; - } - - if (arcs[n | 1].next_out != -1) { - arcs[arcs[n | 1].next_out].prev_out = arcs[n | 1].prev_out; - } - - if (arcs[n | 1].prev_out != -1) { - arcs[arcs[n | 1].prev_out].next_out = arcs[n | 1].next_out; - } else { - nodes[arcs[n].target].first_out = arcs[n | 1].next_out; - } - - arcs[n].next_out = first_free_arc; - first_free_arc = n; - arcs[n].prev_out = -2; - arcs[n | 1].prev_out = -2; - - } - - void clear() { - arcs.clear(); - nodes.clear(); - first_node = first_free_node = first_free_arc = -1; - } - - protected: - - void changeV(Edge e, Node n) { - if(arcs[2 * e.id].next_out != -1) { - arcs[arcs[2 * e.id].next_out].prev_out = arcs[2 * e.id].prev_out; - } - if(arcs[2 * e.id].prev_out != -1) { - arcs[arcs[2 * e.id].prev_out].next_out = - arcs[2 * e.id].next_out; - } else { - nodes[arcs[(2 * e.id) | 1].target].first_out = - arcs[2 * e.id].next_out; - } - - if (nodes[n.id].first_out != -1) { - arcs[nodes[n.id].first_out].prev_out = 2 * e.id; - } - arcs[(2 * e.id) | 1].target = n.id; - arcs[2 * e.id].prev_out = -1; - arcs[2 * e.id].next_out = nodes[n.id].first_out; - nodes[n.id].first_out = 2 * e.id; - } - - void changeU(Edge e, Node n) { - if(arcs[(2 * e.id) | 1].next_out != -1) { - arcs[arcs[(2 * e.id) | 1].next_out].prev_out = - arcs[(2 * e.id) | 1].prev_out; - } - if(arcs[(2 * e.id) | 1].prev_out != -1) { - arcs[arcs[(2 * e.id) | 1].prev_out].next_out = - arcs[(2 * e.id) | 1].next_out; - } else { - nodes[arcs[2 * e.id].target].first_out = - arcs[(2 * e.id) | 1].next_out; - } - - if (nodes[n.id].first_out != -1) { - arcs[nodes[n.id].first_out].prev_out = ((2 * e.id) | 1); - } - arcs[2 * e.id].target = n.id; - arcs[(2 * e.id) | 1].prev_out = -1; - arcs[(2 * e.id) | 1].next_out = nodes[n.id].first_out; - nodes[n.id].first_out = ((2 * e.id) | 1); - } - - }; - - typedef GraphExtender ExtendedListGraphBase; - - - /// \addtogroup graphs - /// @{ - - ///A general undirected graph structure. - - ///\ref ListGraph is a versatile and fast undirected graph - ///implementation based on linked lists that are stored in - ///\c std::vector structures. - /// - ///This type fully conforms to the \ref concepts::Graph "Graph concept" - ///and it also provides several useful additional functionalities. - ///Most of its member functions and nested classes are documented - ///only in the concept class. - /// - ///This class provides only linear time counting for nodes, edges and arcs. - /// - ///\sa concepts::Graph - ///\sa ListDigraph - class ListGraph : public ExtendedListGraphBase { - typedef ExtendedListGraphBase Parent; - - private: - /// Graphs are \e not copy constructible. Use GraphCopy instead. - ListGraph(const ListGraph &) :ExtendedListGraphBase() {}; - /// \brief Assignment of a graph to another one is \e not allowed. - /// Use GraphCopy instead. - void operator=(const ListGraph &) {} - public: - /// Constructor - - /// Constructor. - /// - ListGraph() {} - - typedef Parent::OutArcIt IncEdgeIt; - - /// \brief Add a new node to the graph. - /// - /// This function adds a new node to the graph. - /// \return The new node. - Node addNode() { return Parent::addNode(); } - - /// \brief Add a new edge to the graph. - /// - /// This function adds a new edge to the graph between nodes - /// \c u and \c v with inherent orientation from node \c u to - /// node \c v. - /// \return The new edge. - Edge addEdge(Node u, Node v) { - return Parent::addEdge(u, v); - } - - ///\brief Erase a node from the graph. - /// - /// This function erases the given node along with its incident arcs - /// from the graph. - /// - /// \note All iterators referencing the removed node or the incident - /// edges are invalidated, of course. - void erase(Node n) { Parent::erase(n); } - - ///\brief Erase an edge from the graph. - /// - /// This function erases the given edge from the graph. - /// - /// \note All iterators referencing the removed edge are invalidated, - /// of course. - void erase(Edge e) { Parent::erase(e); } - /// Node validity check - - /// This function gives back \c true if the given node is valid, - /// i.e. it is a real node of the graph. - /// - /// \warning A removed node could become valid again if new nodes are - /// added to the graph. - bool valid(Node n) const { return Parent::valid(n); } - /// Edge validity check - - /// This function gives back \c true if the given edge is valid, - /// i.e. it is a real edge of the graph. - /// - /// \warning A removed edge could become valid again if new edges are - /// added to the graph. - bool valid(Edge e) const { return Parent::valid(e); } - /// Arc validity check - - /// This function gives back \c true if the given arc is valid, - /// i.e. it is a real arc of the graph. - /// - /// \warning A removed arc could become valid again if new edges are - /// added to the graph. - bool valid(Arc a) const { return Parent::valid(a); } - - /// \brief Change the first node of an edge. - /// - /// This function changes the first node of the given edge \c e to \c n. - /// - ///\note \c EdgeIt and \c ArcIt iterators referencing the - ///changed edge are invalidated and all other iterators whose - ///base node is the changed node are also invalidated. - /// - ///\warning This functionality cannot be used together with the - ///Snapshot feature. - void changeU(Edge e, Node n) { - Parent::changeU(e,n); - } - /// \brief Change the second node of an edge. - /// - /// This function changes the second node of the given edge \c e to \c n. - /// - ///\note \c EdgeIt iterators referencing the changed edge remain - ///valid, but \c ArcIt iterators referencing the changed edge and - ///all other iterators whose base node is the changed node are also - ///invalidated. - /// - ///\warning This functionality cannot be used together with the - ///Snapshot feature. - void changeV(Edge e, Node n) { - Parent::changeV(e,n); - } - - /// \brief Contract two nodes. - /// - /// This function contracts the given two nodes. - /// Node \c b is removed, but instead of deleting - /// its incident edges, they are joined to node \c a. - /// If the last parameter \c r is \c true (this is the default value), - /// then the newly created loops are removed. - /// - /// \note The moved edges are joined to node \c a using changeU() - /// or changeV(), thus all edge and arc iterators whose base node is - /// \c b are invalidated. - /// Moreover all iterators referencing node \c b or the removed - /// loops are also invalidated. Other iterators remain valid. - /// - ///\warning This functionality cannot be used together with the - ///Snapshot feature. - void contract(Node a, Node b, bool r = true) { - for(IncEdgeIt e(*this, b); e!=INVALID;) { - IncEdgeIt f = e; ++f; - if (r && runningNode(e) == a) { - erase(e); - } else if (u(e) == b) { - changeU(e, a); - } else { - changeV(e, a); - } - e = f; - } - erase(b); - } - - ///Clear the graph. - - ///This function erases all nodes and arcs from the graph. - /// - ///\note All iterators of the graph are invalidated, of course. - void clear() { - Parent::clear(); - } - - /// Reserve memory for nodes. - - /// Using this function, it is possible to avoid superfluous memory - /// allocation: if you know that the graph you want to build will - /// be large (e.g. it will contain millions of nodes and/or edges), - /// then it is worth reserving space for this amount before starting - /// to build the graph. - /// \sa reserveEdge() - void reserveNode(int n) { nodes.reserve(n); }; - - /// Reserve memory for edges. - - /// Using this function, it is possible to avoid superfluous memory - /// allocation: if you know that the graph you want to build will - /// be large (e.g. it will contain millions of nodes and/or edges), - /// then it is worth reserving space for this amount before starting - /// to build the graph. - /// \sa reserveNode() - void reserveEdge(int m) { arcs.reserve(2 * m); }; - - /// \brief Class to make a snapshot of the graph and restore - /// it later. - /// - /// Class to make a snapshot of the graph and restore it later. - /// - /// The newly added nodes and edges can be removed - /// using the restore() function. - /// - /// \note After a state is restored, you cannot restore a later state, - /// i.e. you cannot add the removed nodes and edges again using - /// another Snapshot instance. - /// - /// \warning Node and edge deletions and other modifications - /// (e.g. changing the end-nodes of edges or contracting nodes) - /// cannot be restored. These events invalidate the snapshot. - /// However, the edges and nodes that were added to the graph after - /// making the current snapshot can be removed without invalidating it. - class Snapshot { - protected: - - typedef Parent::NodeNotifier NodeNotifier; - - class NodeObserverProxy : public NodeNotifier::ObserverBase { - public: - - NodeObserverProxy(Snapshot& _snapshot) - : snapshot(_snapshot) {} - - using NodeNotifier::ObserverBase::attach; - using NodeNotifier::ObserverBase::detach; - using NodeNotifier::ObserverBase::attached; - - protected: - - virtual void add(const Node& node) { - snapshot.addNode(node); - } - virtual void add(const std::vector& nodes) { - for (int i = nodes.size() - 1; i >= 0; ++i) { - snapshot.addNode(nodes[i]); - } - } - virtual void erase(const Node& node) { - snapshot.eraseNode(node); - } - virtual void erase(const std::vector& nodes) { - for (int i = 0; i < int(nodes.size()); ++i) { - snapshot.eraseNode(nodes[i]); - } - } - virtual void build() { - Node node; - std::vector nodes; - for (notifier()->first(node); node != INVALID; - notifier()->next(node)) { - nodes.push_back(node); - } - for (int i = nodes.size() - 1; i >= 0; --i) { - snapshot.addNode(nodes[i]); - } - } - virtual void clear() { - Node node; - for (notifier()->first(node); node != INVALID; - notifier()->next(node)) { - snapshot.eraseNode(node); - } - } - - Snapshot& snapshot; - }; - - class EdgeObserverProxy : public EdgeNotifier::ObserverBase { - public: - - EdgeObserverProxy(Snapshot& _snapshot) - : snapshot(_snapshot) {} - - using EdgeNotifier::ObserverBase::attach; - using EdgeNotifier::ObserverBase::detach; - using EdgeNotifier::ObserverBase::attached; - - protected: - - virtual void add(const Edge& edge) { - snapshot.addEdge(edge); - } - virtual void add(const std::vector& edges) { - for (int i = edges.size() - 1; i >= 0; ++i) { - snapshot.addEdge(edges[i]); - } - } - virtual void erase(const Edge& edge) { - snapshot.eraseEdge(edge); - } - virtual void erase(const std::vector& edges) { - for (int i = 0; i < int(edges.size()); ++i) { - snapshot.eraseEdge(edges[i]); - } - } - virtual void build() { - Edge edge; - std::vector edges; - for (notifier()->first(edge); edge != INVALID; - notifier()->next(edge)) { - edges.push_back(edge); - } - for (int i = edges.size() - 1; i >= 0; --i) { - snapshot.addEdge(edges[i]); - } - } - virtual void clear() { - Edge edge; - for (notifier()->first(edge); edge != INVALID; - notifier()->next(edge)) { - snapshot.eraseEdge(edge); - } - } - - Snapshot& snapshot; - }; - - ListGraph *graph; - - NodeObserverProxy node_observer_proxy; - EdgeObserverProxy edge_observer_proxy; - - std::list added_nodes; - std::list added_edges; - - - void addNode(const Node& node) { - added_nodes.push_front(node); - } - void eraseNode(const Node& node) { - std::list::iterator it = - std::find(added_nodes.begin(), added_nodes.end(), node); - if (it == added_nodes.end()) { - clear(); - edge_observer_proxy.detach(); - throw NodeNotifier::ImmediateDetach(); - } else { - added_nodes.erase(it); - } - } - - void addEdge(const Edge& edge) { - added_edges.push_front(edge); - } - void eraseEdge(const Edge& edge) { - std::list::iterator it = - std::find(added_edges.begin(), added_edges.end(), edge); - if (it == added_edges.end()) { - clear(); - node_observer_proxy.detach(); - throw EdgeNotifier::ImmediateDetach(); - } else { - added_edges.erase(it); - } - } - - void attach(ListGraph &_graph) { - graph = &_graph; - node_observer_proxy.attach(graph->notifier(Node())); - edge_observer_proxy.attach(graph->notifier(Edge())); - } - - void detach() { - node_observer_proxy.detach(); - edge_observer_proxy.detach(); - } - - bool attached() const { - return node_observer_proxy.attached(); - } - - void clear() { - added_nodes.clear(); - added_edges.clear(); - } - - public: - - /// \brief Default constructor. - /// - /// Default constructor. - /// You have to call save() to actually make a snapshot. - Snapshot() - : graph(0), node_observer_proxy(*this), - edge_observer_proxy(*this) {} - - /// \brief Constructor that immediately makes a snapshot. - /// - /// This constructor immediately makes a snapshot of the given graph. - Snapshot(ListGraph &gr) - : node_observer_proxy(*this), - edge_observer_proxy(*this) { - attach(gr); - } - - /// \brief Make a snapshot. - /// - /// This function makes a snapshot of the given graph. - /// It can be called more than once. In case of a repeated - /// call, the previous snapshot gets lost. - void save(ListGraph &gr) { - if (attached()) { - detach(); - clear(); - } - attach(gr); - } - - /// \brief Undo the changes until the last snapshot. - /// - /// This function undos the changes until the last snapshot - /// created by save() or Snapshot(ListGraph&). - /// - /// \warning This method invalidates the snapshot, i.e. repeated - /// restoring is not supported unless you call save() again. - void restore() { - detach(); - for(std::list::iterator it = added_edges.begin(); - it != added_edges.end(); ++it) { - graph->erase(*it); - } - for(std::list::iterator it = added_nodes.begin(); - it != added_nodes.end(); ++it) { - graph->erase(*it); - } - clear(); - } - - /// \brief Returns \c true if the snapshot is valid. - /// - /// This function returns \c true if the snapshot is valid. - bool valid() const { - return attached(); - } - }; - }; - - /// @} - - class ListBpGraphBase { - - protected: - - struct NodeT { - int first_out; - int prev, next; - int partition_prev, partition_next; - int partition_index; - bool red; - }; - - struct ArcT { - int target; - int prev_out, next_out; - }; - - std::vector nodes; - - int first_node, first_red, first_blue; - int max_red, max_blue; - - int first_free_red, first_free_blue; - - std::vector arcs; - - int first_free_arc; - - public: - - typedef ListBpGraphBase BpGraph; - - class Node { - friend class ListBpGraphBase; - protected: - - int id; - explicit Node(int pid) { id = pid;} - - public: - Node() {} - Node (Invalid) { id = -1; } - bool operator==(const Node& node) const {return id == node.id;} - bool operator!=(const Node& node) const {return id != node.id;} - bool operator<(const Node& node) const {return id < node.id;} - }; - - class RedNode : public Node { - friend class ListBpGraphBase; - protected: - - explicit RedNode(int pid) : Node(pid) {} - - public: - RedNode() {} - RedNode(const RedNode& node) : Node(node) {} - RedNode(Invalid) : Node(INVALID){} - }; - - class BlueNode : public Node { - friend class ListBpGraphBase; - protected: - - explicit BlueNode(int pid) : Node(pid) {} - - public: - BlueNode() {} - BlueNode(const BlueNode& node) : Node(node) {} - BlueNode(Invalid) : Node(INVALID){} - }; - - class Edge { - friend class ListBpGraphBase; - protected: - - int id; - explicit Edge(int pid) { id = pid;} - - public: - Edge() {} - Edge (Invalid) { id = -1; } - bool operator==(const Edge& edge) const {return id == edge.id;} - bool operator!=(const Edge& edge) const {return id != edge.id;} - bool operator<(const Edge& edge) const {return id < edge.id;} - }; - - class Arc { - friend class ListBpGraphBase; - protected: - - int id; - explicit Arc(int pid) { id = pid;} - - public: - operator Edge() const { - return id != -1 ? edgeFromId(id / 2) : INVALID; - } - - Arc() {} - Arc (Invalid) { id = -1; } - bool operator==(const Arc& arc) const {return id == arc.id;} - bool operator!=(const Arc& arc) const {return id != arc.id;} - bool operator<(const Arc& arc) const {return id < arc.id;} - }; - - ListBpGraphBase() - : nodes(), first_node(-1), - first_red(-1), first_blue(-1), - max_red(-1), max_blue(-1), - first_free_red(-1), first_free_blue(-1), - arcs(), first_free_arc(-1) {} - - - bool red(Node n) const { return nodes[n.id].red; } - bool blue(Node n) const { return !nodes[n.id].red; } - - static RedNode asRedNodeUnsafe(Node n) { return RedNode(n.id); } - static BlueNode asBlueNodeUnsafe(Node n) { return BlueNode(n.id); } - - int maxNodeId() const { return nodes.size()-1; } - int maxRedId() const { return max_red; } - int maxBlueId() const { return max_blue; } - int maxEdgeId() const { return arcs.size() / 2 - 1; } - int maxArcId() const { return arcs.size()-1; } - - Node source(Arc e) const { return Node(arcs[e.id ^ 1].target); } - Node target(Arc e) const { return Node(arcs[e.id].target); } - - RedNode redNode(Edge e) const { - return RedNode(arcs[2 * e.id].target); - } - BlueNode blueNode(Edge e) const { - return BlueNode(arcs[2 * e.id + 1].target); - } - - static bool direction(Arc e) { - return (e.id & 1) == 1; - } - - static Arc direct(Edge e, bool d) { - return Arc(e.id * 2 + (d ? 1 : 0)); - } - - void first(Node& node) const { - node.id = first_node; - } - - void next(Node& node) const { - node.id = nodes[node.id].next; - } - - void first(RedNode& node) const { - node.id = first_red; - } - - void next(RedNode& node) const { - node.id = nodes[node.id].partition_next; - } - - void first(BlueNode& node) const { - node.id = first_blue; - } - - void next(BlueNode& node) const { - node.id = nodes[node.id].partition_next; - } - - void first(Arc& e) const { - int n = first_node; - while (n != -1 && nodes[n].first_out == -1) { - n = nodes[n].next; - } - e.id = (n == -1) ? -1 : nodes[n].first_out; - } - - void next(Arc& e) const { - if (arcs[e.id].next_out != -1) { - e.id = arcs[e.id].next_out; - } else { - int n = nodes[arcs[e.id ^ 1].target].next; - while(n != -1 && nodes[n].first_out == -1) { - n = nodes[n].next; - } - e.id = (n == -1) ? -1 : nodes[n].first_out; - } - } - - void first(Edge& e) const { - int n = first_node; - while (n != -1) { - e.id = nodes[n].first_out; - while ((e.id & 1) != 1) { - e.id = arcs[e.id].next_out; - } - if (e.id != -1) { - e.id /= 2; - return; - } - n = nodes[n].next; - } - e.id = -1; - } - - void next(Edge& e) const { - int n = arcs[e.id * 2].target; - e.id = arcs[(e.id * 2) | 1].next_out; - while ((e.id & 1) != 1) { - e.id = arcs[e.id].next_out; - } - if (e.id != -1) { - e.id /= 2; - return; - } - n = nodes[n].next; - while (n != -1) { - e.id = nodes[n].first_out; - while ((e.id & 1) != 1) { - e.id = arcs[e.id].next_out; - } - if (e.id != -1) { - e.id /= 2; - return; - } - n = nodes[n].next; - } - e.id = -1; - } - - void firstOut(Arc &e, const Node& v) const { - e.id = nodes[v.id].first_out; - } - void nextOut(Arc &e) const { - e.id = arcs[e.id].next_out; - } - - void firstIn(Arc &e, const Node& v) const { - e.id = ((nodes[v.id].first_out) ^ 1); - if (e.id == -2) e.id = -1; - } - void nextIn(Arc &e) const { - e.id = ((arcs[e.id ^ 1].next_out) ^ 1); - if (e.id == -2) e.id = -1; - } - - void firstInc(Edge &e, bool& d, const Node& v) const { - int a = nodes[v.id].first_out; - if (a != -1 ) { - e.id = a / 2; - d = ((a & 1) == 1); - } else { - e.id = -1; - d = true; - } - } - void nextInc(Edge &e, bool& d) const { - int a = (arcs[(e.id * 2) | (d ? 1 : 0)].next_out); - if (a != -1 ) { - e.id = a / 2; - d = ((a & 1) == 1); - } else { - e.id = -1; - d = true; - } - } - - static int id(Node v) { return v.id; } - int id(RedNode v) const { return nodes[v.id].partition_index; } - int id(BlueNode v) const { return nodes[v.id].partition_index; } - static int id(Arc e) { return e.id; } - static int id(Edge e) { return e.id; } - - static Node nodeFromId(int id) { return Node(id);} - static Arc arcFromId(int id) { return Arc(id);} - static Edge edgeFromId(int id) { return Edge(id);} - - bool valid(Node n) const { - return n.id >= 0 && n.id < static_cast(nodes.size()) && - nodes[n.id].prev != -2; - } - - bool valid(Arc a) const { - return a.id >= 0 && a.id < static_cast(arcs.size()) && - arcs[a.id].prev_out != -2; - } - - bool valid(Edge e) const { - return e.id >= 0 && 2 * e.id < static_cast(arcs.size()) && - arcs[2 * e.id].prev_out != -2; - } - - RedNode addRedNode() { - int n; - - if(first_free_red==-1) { - n = nodes.size(); - nodes.push_back(NodeT()); - nodes[n].partition_index = ++max_red; - nodes[n].red = true; - } else { - n = first_free_red; - first_free_red = nodes[n].next; - } - - nodes[n].next = first_node; - if (first_node != -1) nodes[first_node].prev = n; - first_node = n; - nodes[n].prev = -1; - - nodes[n].partition_next = first_red; - if (first_red != -1) nodes[first_red].partition_prev = n; - first_red = n; - nodes[n].partition_prev = -1; - - nodes[n].first_out = -1; - - return RedNode(n); - } - - BlueNode addBlueNode() { - int n; - - if(first_free_blue==-1) { - n = nodes.size(); - nodes.push_back(NodeT()); - nodes[n].partition_index = ++max_blue; - nodes[n].red = false; - } else { - n = first_free_blue; - first_free_blue = nodes[n].next; - } - - nodes[n].next = first_node; - if (first_node != -1) nodes[first_node].prev = n; - first_node = n; - nodes[n].prev = -1; - - nodes[n].partition_next = first_blue; - if (first_blue != -1) nodes[first_blue].partition_prev = n; - first_blue = n; - nodes[n].partition_prev = -1; - - nodes[n].first_out = -1; - - return BlueNode(n); - } - - Edge addEdge(Node u, Node v) { - int n; - - if (first_free_arc == -1) { - n = arcs.size(); - arcs.push_back(ArcT()); - arcs.push_back(ArcT()); - } else { - n = first_free_arc; - first_free_arc = arcs[n].next_out; - } - - arcs[n].target = u.id; - arcs[n | 1].target = v.id; - - arcs[n].next_out = nodes[v.id].first_out; - if (nodes[v.id].first_out != -1) { - arcs[nodes[v.id].first_out].prev_out = n; - } - arcs[n].prev_out = -1; - nodes[v.id].first_out = n; - - arcs[n | 1].next_out = nodes[u.id].first_out; - if (nodes[u.id].first_out != -1) { - arcs[nodes[u.id].first_out].prev_out = (n | 1); - } - arcs[n | 1].prev_out = -1; - nodes[u.id].first_out = (n | 1); - - return Edge(n / 2); - } - - void erase(const Node& node) { - int n = node.id; - - if(nodes[n].next != -1) { - nodes[nodes[n].next].prev = nodes[n].prev; - } - - if(nodes[n].prev != -1) { - nodes[nodes[n].prev].next = nodes[n].next; - } else { - first_node = nodes[n].next; - } - - if (nodes[n].partition_next != -1) { - nodes[nodes[n].partition_next].partition_prev = nodes[n].partition_prev; - } - - if (nodes[n].partition_prev != -1) { - nodes[nodes[n].partition_prev].partition_next = nodes[n].partition_next; - } else { - if (nodes[n].red) { - first_red = nodes[n].partition_next; - } else { - first_blue = nodes[n].partition_next; - } - } - - if (nodes[n].red) { - nodes[n].next = first_free_red; - first_free_red = n; - } else { - nodes[n].next = first_free_blue; - first_free_blue = n; - } - nodes[n].prev = -2; - } - - void erase(const Edge& edge) { - int n = edge.id * 2; - - if (arcs[n].next_out != -1) { - arcs[arcs[n].next_out].prev_out = arcs[n].prev_out; - } - - if (arcs[n].prev_out != -1) { - arcs[arcs[n].prev_out].next_out = arcs[n].next_out; - } else { - nodes[arcs[n | 1].target].first_out = arcs[n].next_out; - } - - if (arcs[n | 1].next_out != -1) { - arcs[arcs[n | 1].next_out].prev_out = arcs[n | 1].prev_out; - } - - if (arcs[n | 1].prev_out != -1) { - arcs[arcs[n | 1].prev_out].next_out = arcs[n | 1].next_out; - } else { - nodes[arcs[n].target].first_out = arcs[n | 1].next_out; - } - - arcs[n].next_out = first_free_arc; - first_free_arc = n; - arcs[n].prev_out = -2; - arcs[n | 1].prev_out = -2; - - } - - void clear() { - arcs.clear(); - nodes.clear(); - first_node = first_free_arc = first_red = first_blue = - max_red = max_blue = first_free_red = first_free_blue = -1; - } - - protected: - - void changeRed(Edge e, RedNode n) { - if(arcs[(2 * e.id) | 1].next_out != -1) { - arcs[arcs[(2 * e.id) | 1].next_out].prev_out = - arcs[(2 * e.id) | 1].prev_out; - } - if(arcs[(2 * e.id) | 1].prev_out != -1) { - arcs[arcs[(2 * e.id) | 1].prev_out].next_out = - arcs[(2 * e.id) | 1].next_out; - } else { - nodes[arcs[2 * e.id].target].first_out = - arcs[(2 * e.id) | 1].next_out; - } - - if (nodes[n.id].first_out != -1) { - arcs[nodes[n.id].first_out].prev_out = ((2 * e.id) | 1); - } - arcs[2 * e.id].target = n.id; - arcs[(2 * e.id) | 1].prev_out = -1; - arcs[(2 * e.id) | 1].next_out = nodes[n.id].first_out; - nodes[n.id].first_out = ((2 * e.id) | 1); - } - - void changeBlue(Edge e, BlueNode n) { - if(arcs[2 * e.id].next_out != -1) { - arcs[arcs[2 * e.id].next_out].prev_out = arcs[2 * e.id].prev_out; - } - if(arcs[2 * e.id].prev_out != -1) { - arcs[arcs[2 * e.id].prev_out].next_out = - arcs[2 * e.id].next_out; - } else { - nodes[arcs[(2 * e.id) | 1].target].first_out = - arcs[2 * e.id].next_out; - } - - if (nodes[n.id].first_out != -1) { - arcs[nodes[n.id].first_out].prev_out = 2 * e.id; - } - arcs[(2 * e.id) | 1].target = n.id; - arcs[2 * e.id].prev_out = -1; - arcs[2 * e.id].next_out = nodes[n.id].first_out; - nodes[n.id].first_out = 2 * e.id; - } - - }; - - typedef BpGraphExtender ExtendedListBpGraphBase; - - - /// \addtogroup graphs - /// @{ - - ///A general undirected graph structure. - - ///\ref ListBpGraph is a versatile and fast undirected graph - ///implementation based on linked lists that are stored in - ///\c std::vector structures. - /// - ///This type fully conforms to the \ref concepts::BpGraph "BpGraph concept" - ///and it also provides several useful additional functionalities. - ///Most of its member functions and nested classes are documented - ///only in the concept class. - /// - ///This class provides only linear time counting for nodes, edges and arcs. - /// - ///\sa concepts::BpGraph - ///\sa ListDigraph - class ListBpGraph : public ExtendedListBpGraphBase { - typedef ExtendedListBpGraphBase Parent; - - private: - /// BpGraphs are \e not copy constructible. Use BpGraphCopy instead. - ListBpGraph(const ListBpGraph &) :ExtendedListBpGraphBase() {}; - /// \brief Assignment of a graph to another one is \e not allowed. - /// Use BpGraphCopy instead. - void operator=(const ListBpGraph &) {} - public: - /// Constructor - - /// Constructor. - /// - ListBpGraph() {} - - typedef Parent::OutArcIt IncEdgeIt; - - /// \brief Add a new red node to the graph. - /// - /// This function adds a red new node to the graph. - /// \return The new node. - RedNode addRedNode() { return Parent::addRedNode(); } - - /// \brief Add a new blue node to the graph. - /// - /// This function adds a blue new node to the graph. - /// \return The new node. - BlueNode addBlueNode() { return Parent::addBlueNode(); } - - /// \brief Add a new edge to the graph. - /// - /// This function adds a new edge to the graph between nodes - /// \c u and \c v with inherent orientation from node \c u to - /// node \c v. - /// \return The new edge. - Edge addEdge(RedNode u, BlueNode v) { - return Parent::addEdge(u, v); - } - Edge addEdge(BlueNode v, RedNode u) { - return Parent::addEdge(u, v); - } - - ///\brief Erase a node from the graph. - /// - /// This function erases the given node along with its incident arcs - /// from the graph. - /// - /// \note All iterators referencing the removed node or the incident - /// edges are invalidated, of course. - void erase(Node n) { Parent::erase(n); } - - ///\brief Erase an edge from the graph. - /// - /// This function erases the given edge from the graph. - /// - /// \note All iterators referencing the removed edge are invalidated, - /// of course. - void erase(Edge e) { Parent::erase(e); } - /// Node validity check - - /// This function gives back \c true if the given node is valid, - /// i.e. it is a real node of the graph. - /// - /// \warning A removed node could become valid again if new nodes are - /// added to the graph. - bool valid(Node n) const { return Parent::valid(n); } - /// Edge validity check - - /// This function gives back \c true if the given edge is valid, - /// i.e. it is a real edge of the graph. - /// - /// \warning A removed edge could become valid again if new edges are - /// added to the graph. - bool valid(Edge e) const { return Parent::valid(e); } - /// Arc validity check - - /// This function gives back \c true if the given arc is valid, - /// i.e. it is a real arc of the graph. - /// - /// \warning A removed arc could become valid again if new edges are - /// added to the graph. - bool valid(Arc a) const { return Parent::valid(a); } - - /// \brief Change the red node of an edge. - /// - /// This function changes the red node of the given edge \c e to \c n. - /// - ///\note \c EdgeIt and \c ArcIt iterators referencing the - ///changed edge are invalidated and all other iterators whose - ///base node is the changed node are also invalidated. - /// - ///\warning This functionality cannot be used together with the - ///Snapshot feature. - void changeRed(Edge e, RedNode n) { - Parent::changeRed(e, n); - } - /// \brief Change the blue node of an edge. - /// - /// This function changes the blue node of the given edge \c e to \c n. - /// - ///\note \c EdgeIt iterators referencing the changed edge remain - ///valid, but \c ArcIt iterators referencing the changed edge and - ///all other iterators whose base node is the changed node are also - ///invalidated. - /// - ///\warning This functionality cannot be used together with the - ///Snapshot feature. - void changeBlue(Edge e, BlueNode n) { - Parent::changeBlue(e, n); - } - - ///Clear the graph. - - ///This function erases all nodes and arcs from the graph. - /// - ///\note All iterators of the graph are invalidated, of course. - void clear() { - Parent::clear(); - } - - /// Reserve memory for nodes. - - /// Using this function, it is possible to avoid superfluous memory - /// allocation: if you know that the graph you want to build will - /// be large (e.g. it will contain millions of nodes and/or edges), - /// then it is worth reserving space for this amount before starting - /// to build the graph. - /// \sa reserveEdge() - void reserveNode(int n) { nodes.reserve(n); }; - - /// Reserve memory for edges. - - /// Using this function, it is possible to avoid superfluous memory - /// allocation: if you know that the graph you want to build will - /// be large (e.g. it will contain millions of nodes and/or edges), - /// then it is worth reserving space for this amount before starting - /// to build the graph. - /// \sa reserveNode() - void reserveEdge(int m) { arcs.reserve(2 * m); }; - - /// \brief Class to make a snapshot of the graph and restore - /// it later. - /// - /// Class to make a snapshot of the graph and restore it later. - /// - /// The newly added nodes and edges can be removed - /// using the restore() function. - /// - /// \note After a state is restored, you cannot restore a later state, - /// i.e. you cannot add the removed nodes and edges again using - /// another Snapshot instance. - /// - /// \warning Node and edge deletions and other modifications - /// (e.g. changing the end-nodes of edges or contracting nodes) - /// cannot be restored. These events invalidate the snapshot. - /// However, the edges and nodes that were added to the graph after - /// making the current snapshot can be removed without invalidating it. - class Snapshot { - protected: - - typedef Parent::NodeNotifier NodeNotifier; - - class NodeObserverProxy : public NodeNotifier::ObserverBase { - public: - - NodeObserverProxy(Snapshot& _snapshot) - : snapshot(_snapshot) {} - - using NodeNotifier::ObserverBase::attach; - using NodeNotifier::ObserverBase::detach; - using NodeNotifier::ObserverBase::attached; - - protected: - - virtual void add(const Node& node) { - snapshot.addNode(node); - } - virtual void add(const std::vector& nodes) { - for (int i = nodes.size() - 1; i >= 0; ++i) { - snapshot.addNode(nodes[i]); - } - } - virtual void erase(const Node& node) { - snapshot.eraseNode(node); - } - virtual void erase(const std::vector& nodes) { - for (int i = 0; i < int(nodes.size()); ++i) { - snapshot.eraseNode(nodes[i]); - } - } - virtual void build() { - Node node; - std::vector nodes; - for (notifier()->first(node); node != INVALID; - notifier()->next(node)) { - nodes.push_back(node); - } - for (int i = nodes.size() - 1; i >= 0; --i) { - snapshot.addNode(nodes[i]); - } - } - virtual void clear() { - Node node; - for (notifier()->first(node); node != INVALID; - notifier()->next(node)) { - snapshot.eraseNode(node); - } - } - - Snapshot& snapshot; - }; - - class EdgeObserverProxy : public EdgeNotifier::ObserverBase { - public: - - EdgeObserverProxy(Snapshot& _snapshot) - : snapshot(_snapshot) {} - - using EdgeNotifier::ObserverBase::attach; - using EdgeNotifier::ObserverBase::detach; - using EdgeNotifier::ObserverBase::attached; - - protected: - - virtual void add(const Edge& edge) { - snapshot.addEdge(edge); - } - virtual void add(const std::vector& edges) { - for (int i = edges.size() - 1; i >= 0; ++i) { - snapshot.addEdge(edges[i]); - } - } - virtual void erase(const Edge& edge) { - snapshot.eraseEdge(edge); - } - virtual void erase(const std::vector& edges) { - for (int i = 0; i < int(edges.size()); ++i) { - snapshot.eraseEdge(edges[i]); - } - } - virtual void build() { - Edge edge; - std::vector edges; - for (notifier()->first(edge); edge != INVALID; - notifier()->next(edge)) { - edges.push_back(edge); - } - for (int i = edges.size() - 1; i >= 0; --i) { - snapshot.addEdge(edges[i]); - } - } - virtual void clear() { - Edge edge; - for (notifier()->first(edge); edge != INVALID; - notifier()->next(edge)) { - snapshot.eraseEdge(edge); - } - } - - Snapshot& snapshot; - }; - - ListBpGraph *graph; - - NodeObserverProxy node_observer_proxy; - EdgeObserverProxy edge_observer_proxy; - - std::list added_nodes; - std::list added_edges; - - - void addNode(const Node& node) { - added_nodes.push_front(node); - } - void eraseNode(const Node& node) { - std::list::iterator it = - std::find(added_nodes.begin(), added_nodes.end(), node); - if (it == added_nodes.end()) { - clear(); - edge_observer_proxy.detach(); - throw NodeNotifier::ImmediateDetach(); - } else { - added_nodes.erase(it); - } - } - - void addEdge(const Edge& edge) { - added_edges.push_front(edge); - } - void eraseEdge(const Edge& edge) { - std::list::iterator it = - std::find(added_edges.begin(), added_edges.end(), edge); - if (it == added_edges.end()) { - clear(); - node_observer_proxy.detach(); - throw EdgeNotifier::ImmediateDetach(); - } else { - added_edges.erase(it); - } - } - - void attach(ListBpGraph &_graph) { - graph = &_graph; - node_observer_proxy.attach(graph->notifier(Node())); - edge_observer_proxy.attach(graph->notifier(Edge())); - } - - void detach() { - node_observer_proxy.detach(); - edge_observer_proxy.detach(); - } - - bool attached() const { - return node_observer_proxy.attached(); - } - - void clear() { - added_nodes.clear(); - added_edges.clear(); - } - - public: - - /// \brief Default constructor. - /// - /// Default constructor. - /// You have to call save() to actually make a snapshot. - Snapshot() - : graph(0), node_observer_proxy(*this), - edge_observer_proxy(*this) {} - - /// \brief Constructor that immediately makes a snapshot. - /// - /// This constructor immediately makes a snapshot of the given graph. - Snapshot(ListBpGraph &gr) - : node_observer_proxy(*this), - edge_observer_proxy(*this) { - attach(gr); - } - - /// \brief Make a snapshot. - /// - /// This function makes a snapshot of the given graph. - /// It can be called more than once. In case of a repeated - /// call, the previous snapshot gets lost. - void save(ListBpGraph &gr) { - if (attached()) { - detach(); - clear(); - } - attach(gr); - } - - /// \brief Undo the changes until the last snapshot. - /// - /// This function undos the changes until the last snapshot - /// created by save() or Snapshot(ListBpGraph&). - /// - /// \warning This method invalidates the snapshot, i.e. repeated - /// restoring is not supported unless you call save() again. - void restore() { - detach(); - for(std::list::iterator it = added_edges.begin(); - it != added_edges.end(); ++it) { - graph->erase(*it); - } - for(std::list::iterator it = added_nodes.begin(); - it != added_nodes.end(); ++it) { - graph->erase(*it); - } - clear(); - } - - /// \brief Returns \c true if the snapshot is valid. - /// - /// This function returns \c true if the snapshot is valid. - bool valid() const { - return attached(); - } - }; - }; - - /// @} -} //namespace lemon - - -#endif diff --git a/deps/lemon/lemon/lp.h b/deps/lemon/lemon/lp.h deleted file mode 100644 index 79cd083c3..000000000 --- a/deps/lemon/lemon/lp.h +++ /dev/null @@ -1,98 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_LP_H -#define LEMON_LP_H - -#include - - -#ifdef LEMON_HAVE_GLPK -#include -#elif LEMON_HAVE_CPLEX -#include -#elif LEMON_HAVE_SOPLEX -#include -#else -#if LEMON_HAVE_CLP -#include -#endif -#if LEMON_HAVE_CBC -#include -#endif -#endif - -///\file -///\brief Defines a default LP solver -///\ingroup lp_group -namespace lemon { - -#ifdef DOXYGEN - ///The default LP solver identifier - - ///The default LP solver identifier. - ///\ingroup lp_group - /// - ///Currently, the possible values are \c _LEMON_GLPK, \c LEMON__CPLEX, - ///\c _LEMON_SOPLEX or \c LEMON__CLP -#define LEMON_DEFAULT_LP SOLVER - ///The default LP solver - - ///The default LP solver. - ///\ingroup lp_group - /// - ///Currently, it is either \c GlpkLp, \c CplexLp, \c SoplexLp or \c ClpLp - typedef GlpkLp Lp; - - ///The default MIP solver identifier - - ///The default MIP solver identifier. - ///\ingroup lp_group - /// - ///Currently, the possible values are \c _LEMON_GLPK, \c LEMON__CPLEX - ///or \c _LEMON_CBC -#define LEMON_DEFAULT_MIP SOLVER - ///The default MIP solver. - - ///The default MIP solver. - ///\ingroup lp_group - /// - ///Currently, it is either \c GlpkMip, \c CplexMip , \c CbcMip - typedef GlpkMip Mip; -#else -#if LEMON_DEFAULT_LP == _LEMON_GLPK - typedef GlpkLp Lp; -#elif LEMON_DEFAULT_LP == _LEMON_CPLEX - typedef CplexLp Lp; -#elif LEMON_DEFAULT_LP == _LEMON_SOPLEX - typedef SoplexLp Lp; -#elif LEMON_DEFAULT_LP == _LEMON_CLP - typedef ClpLp Lp; -#endif -#if LEMON_DEFAULT_MIP == _LEMON_GLPK - typedef GlpkMip Mip; -#elif LEMON_DEFAULT_MIP == _LEMON_CPLEX - typedef CplexMip Mip; -#elif LEMON_DEFAULT_MIP == _LEMON_CBC - typedef CbcMip Mip; -#endif -#endif - -} //namespace lemon - -#endif //LEMON_LP_H diff --git a/deps/lemon/lemon/lp_base.cc b/deps/lemon/lemon/lp_base.cc deleted file mode 100644 index 312fd631f..000000000 --- a/deps/lemon/lemon/lp_base.cc +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\file -///\brief The implementation of the LP solver interface. - -#include -namespace lemon { - - const LpBase::Value LpBase::INF = - std::numeric_limits::infinity(); - const LpBase::Value LpBase::NaN = - std::numeric_limits::quiet_NaN(); - -} //namespace lemon diff --git a/deps/lemon/lemon/lp_base.h b/deps/lemon/lemon/lp_base.h deleted file mode 100644 index e44aff336..000000000 --- a/deps/lemon/lemon/lp_base.h +++ /dev/null @@ -1,2149 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_LP_BASE_H -#define LEMON_LP_BASE_H - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -///\file -///\brief The interface of the LP solver interface. -///\ingroup lp_group -namespace lemon { - - ///Common base class for LP and MIP solvers - - ///Usually this class is not used directly, please use one of the concrete - ///implementations of the solver interface. - ///\ingroup lp_group - class LpBase { - - protected: - - _solver_bits::VarIndex rows; - _solver_bits::VarIndex cols; - - public: - - ///Possible outcomes of an LP solving procedure - enum SolveExitStatus { - /// = 0. It means that the problem has been successfully solved: either - ///an optimal solution has been found or infeasibility/unboundedness - ///has been proved. - SOLVED = 0, - /// = 1. Any other case (including the case when some user specified - ///limit has been exceeded). - UNSOLVED = 1 - }; - - ///Direction of the optimization - enum Sense { - /// Minimization - MIN, - /// Maximization - MAX - }; - - ///Enum for \c messageLevel() parameter - enum MessageLevel { - /// No output (default value). - MESSAGE_NOTHING, - /// Error messages only. - MESSAGE_ERROR, - /// Warnings. - MESSAGE_WARNING, - /// Normal output. - MESSAGE_NORMAL, - /// Verbose output. - MESSAGE_VERBOSE - }; - - - ///The floating point type used by the solver - typedef double Value; - ///The infinity constant - LEMON_DECLSPEC - static const Value INF; - ///The not a number constant - LEMON_DECLSPEC - static const Value NaN; - - friend class Col; - friend class ColIt; - friend class Row; - friend class RowIt; - - ///Refer to a column of the LP. - - ///This type is used to refer to a column of the LP. - /// - ///Its value remains valid and correct even after the addition or erase of - ///other columns. - /// - ///\note This class is similar to other Item types in LEMON, like - ///Node and Arc types in digraph. - class Col { - friend class LpBase; - protected: - int _id; - explicit Col(int id) : _id(id) {} - public: - typedef Value ExprValue; - typedef True LpCol; - /// Default constructor - - /// \warning The default constructor sets the Col to an - /// undefined value. - Col() {} - /// Invalid constructor \& conversion. - - /// This constructor initializes the Col to be invalid. - /// \sa Invalid for more details. - Col(const Invalid&) : _id(-1) {} - /// Equality operator - - /// Two \ref Col "Col"s are equal if and only if they point to - /// the same LP column or both are invalid. - bool operator==(Col c) const {return _id == c._id;} - /// Inequality operator - - /// \sa operator==(Col c) - /// - bool operator!=(Col c) const {return _id != c._id;} - /// Artificial ordering operator. - - /// To allow the use of this object in std::map or similar - /// associative container we require this. - /// - /// \note This operator only have to define some strict ordering of - /// the items; this order has nothing to do with the iteration - /// ordering of the items. - bool operator<(Col c) const {return _id < c._id;} - }; - - ///Iterator for iterate over the columns of an LP problem - - /// Its usage is quite simple, for example, you can count the number - /// of columns in an LP \c lp: - ///\code - /// int count=0; - /// for (LpBase::ColIt c(lp); c!=INVALID; ++c) ++count; - ///\endcode - class ColIt : public Col { - const LpBase *_solver; - public: - /// Default constructor - - /// \warning The default constructor sets the iterator - /// to an undefined value. - ColIt() {} - /// Sets the iterator to the first Col - - /// Sets the iterator to the first Col. - /// - ColIt(const LpBase &solver) : _solver(&solver) - { - _solver->cols.firstItem(_id); - } - /// Invalid constructor \& conversion - - /// Initialize the iterator to be invalid. - /// \sa Invalid for more details. - ColIt(const Invalid&) : Col(INVALID) {} - /// Next column - - /// Assign the iterator to the next column. - /// - ColIt &operator++() - { - _solver->cols.nextItem(_id); - return *this; - } - }; - - /// \brief Returns the ID of the column. - static int id(const Col& col) { return col._id; } - /// \brief Returns the column with the given ID. - /// - /// \pre The argument should be a valid column ID in the LP problem. - static Col colFromId(int id) { return Col(id); } - - ///Refer to a row of the LP. - - ///This type is used to refer to a row of the LP. - /// - ///Its value remains valid and correct even after the addition or erase of - ///other rows. - /// - ///\note This class is similar to other Item types in LEMON, like - ///Node and Arc types in digraph. - class Row { - friend class LpBase; - protected: - int _id; - explicit Row(int id) : _id(id) {} - public: - typedef Value ExprValue; - typedef True LpRow; - /// Default constructor - - /// \warning The default constructor sets the Row to an - /// undefined value. - Row() {} - /// Invalid constructor \& conversion. - - /// This constructor initializes the Row to be invalid. - /// \sa Invalid for more details. - Row(const Invalid&) : _id(-1) {} - /// Equality operator - - /// Two \ref Row "Row"s are equal if and only if they point to - /// the same LP row or both are invalid. - bool operator==(Row r) const {return _id == r._id;} - /// Inequality operator - - /// \sa operator==(Row r) - /// - bool operator!=(Row r) const {return _id != r._id;} - /// Artificial ordering operator. - - /// To allow the use of this object in std::map or similar - /// associative container we require this. - /// - /// \note This operator only have to define some strict ordering of - /// the items; this order has nothing to do with the iteration - /// ordering of the items. - bool operator<(Row r) const {return _id < r._id;} - }; - - ///Iterator for iterate over the rows of an LP problem - - /// Its usage is quite simple, for example, you can count the number - /// of rows in an LP \c lp: - ///\code - /// int count=0; - /// for (LpBase::RowIt c(lp); c!=INVALID; ++c) ++count; - ///\endcode - class RowIt : public Row { - const LpBase *_solver; - public: - /// Default constructor - - /// \warning The default constructor sets the iterator - /// to an undefined value. - RowIt() {} - /// Sets the iterator to the first Row - - /// Sets the iterator to the first Row. - /// - RowIt(const LpBase &solver) : _solver(&solver) - { - _solver->rows.firstItem(_id); - } - /// Invalid constructor \& conversion - - /// Initialize the iterator to be invalid. - /// \sa Invalid for more details. - RowIt(const Invalid&) : Row(INVALID) {} - /// Next row - - /// Assign the iterator to the next row. - /// - RowIt &operator++() - { - _solver->rows.nextItem(_id); - return *this; - } - }; - - /// \brief Returns the ID of the row. - static int id(const Row& row) { return row._id; } - /// \brief Returns the row with the given ID. - /// - /// \pre The argument should be a valid row ID in the LP problem. - static Row rowFromId(int id) { return Row(id); } - - public: - - ///Linear expression of variables and a constant component - - ///This data structure stores a linear expression of the variables - ///(\ref Col "Col"s) and also has a constant component. - /// - ///There are several ways to access and modify the contents of this - ///container. - ///\code - ///e[v]=5; - ///e[v]+=12; - ///e.erase(v); - ///\endcode - ///or you can also iterate through its elements. - ///\code - ///double s=0; - ///for(LpBase::Expr::ConstCoeffIt i(e);i!=INVALID;++i) - /// s+=*i * primal(i); - ///\endcode - ///(This code computes the primal value of the expression). - ///- Numbers (double's) - ///and variables (\ref Col "Col"s) directly convert to an - ///\ref Expr and the usual linear operations are defined, so - ///\code - ///v+w - ///2*v-3.12*(v-w/2)+2 - ///v*2.1+(3*v+(v*12+w+6)*3)/2 - ///\endcode - ///are valid expressions. - ///The usual assignment operations are also defined. - ///\code - ///e=v+w; - ///e+=2*v-3.12*(v-w/2)+2; - ///e*=3.4; - ///e/=5; - ///\endcode - ///- The constant member can be set and read by dereference - /// operator (unary *) - /// - ///\code - ///*e=12; - ///double c=*e; - ///\endcode - /// - ///\sa Constr - class Expr { - friend class LpBase; - public: - /// The key type of the expression - typedef LpBase::Col Key; - /// The value type of the expression - typedef LpBase::Value Value; - - protected: - Value const_comp; - std::map comps; - - public: - typedef True SolverExpr; - /// Default constructor - - /// Construct an empty expression, the coefficients and - /// the constant component are initialized to zero. - Expr() : const_comp(0) {} - /// Construct an expression from a column - - /// Construct an expression, which has a term with \c c variable - /// and 1.0 coefficient. - Expr(const Col &c) : const_comp(0) { - typedef std::map::value_type pair_type; - comps.insert(pair_type(id(c), 1)); - } - /// Construct an expression from a constant - - /// Construct an expression, which's constant component is \c v. - /// - Expr(const Value &v) : const_comp(v) {} - /// Returns the coefficient of the column - Value operator[](const Col& c) const { - std::map::const_iterator it=comps.find(id(c)); - if (it != comps.end()) { - return it->second; - } else { - return 0; - } - } - /// Returns the coefficient of the column - Value& operator[](const Col& c) { - return comps[id(c)]; - } - /// Sets the coefficient of the column - void set(const Col &c, const Value &v) { - if (v != 0.0) { - typedef std::map::value_type pair_type; - comps.insert(pair_type(id(c), v)); - } else { - comps.erase(id(c)); - } - } - /// Returns the constant component of the expression - Value& operator*() { return const_comp; } - /// Returns the constant component of the expression - const Value& operator*() const { return const_comp; } - /// \brief Removes the coefficients which's absolute value does - /// not exceed \c epsilon. It also sets to zero the constant - /// component, if it does not exceed epsilon in absolute value. - void simplify(Value epsilon = 0.0) { - std::map::iterator it=comps.begin(); - while (it != comps.end()) { - std::map::iterator jt=it; - ++jt; - if (std::fabs((*it).second) <= epsilon) comps.erase(it); - it=jt; - } - if (std::fabs(const_comp) <= epsilon) const_comp = 0; - } - - void simplify(Value epsilon = 0.0) const { - const_cast(this)->simplify(epsilon); - } - - ///Sets all coefficients and the constant component to 0. - void clear() { - comps.clear(); - const_comp=0; - } - - ///Compound assignment - Expr &operator+=(const Expr &e) { - for (std::map::const_iterator it=e.comps.begin(); - it!=e.comps.end(); ++it) - comps[it->first]+=it->second; - const_comp+=e.const_comp; - return *this; - } - ///Compound assignment - Expr &operator-=(const Expr &e) { - for (std::map::const_iterator it=e.comps.begin(); - it!=e.comps.end(); ++it) - comps[it->first]-=it->second; - const_comp-=e.const_comp; - return *this; - } - ///Multiply with a constant - Expr &operator*=(const Value &v) { - for (std::map::iterator it=comps.begin(); - it!=comps.end(); ++it) - it->second*=v; - const_comp*=v; - return *this; - } - ///Division with a constant - Expr &operator/=(const Value &c) { - for (std::map::iterator it=comps.begin(); - it!=comps.end(); ++it) - it->second/=c; - const_comp/=c; - return *this; - } - - ///Iterator over the expression - - ///The iterator iterates over the terms of the expression. - /// - ///\code - ///double s=0; - ///for(LpBase::Expr::CoeffIt i(e);i!=INVALID;++i) - /// s+= *i * primal(i); - ///\endcode - class CoeffIt { - private: - - std::map::iterator _it, _end; - - public: - - /// Sets the iterator to the first term - - /// Sets the iterator to the first term of the expression. - /// - CoeffIt(Expr& e) - : _it(e.comps.begin()), _end(e.comps.end()){} - - /// Convert the iterator to the column of the term - operator Col() const { - return colFromId(_it->first); - } - - /// Returns the coefficient of the term - Value& operator*() { return _it->second; } - - /// Returns the coefficient of the term - const Value& operator*() const { return _it->second; } - /// Next term - - /// Assign the iterator to the next term. - /// - CoeffIt& operator++() { ++_it; return *this; } - - /// Equality operator - bool operator==(Invalid) const { return _it == _end; } - /// Inequality operator - bool operator!=(Invalid) const { return _it != _end; } - }; - - /// Const iterator over the expression - - ///The iterator iterates over the terms of the expression. - /// - ///\code - ///double s=0; - ///for(LpBase::Expr::ConstCoeffIt i(e);i!=INVALID;++i) - /// s+=*i * primal(i); - ///\endcode - class ConstCoeffIt { - private: - - std::map::const_iterator _it, _end; - - public: - - /// Sets the iterator to the first term - - /// Sets the iterator to the first term of the expression. - /// - ConstCoeffIt(const Expr& e) - : _it(e.comps.begin()), _end(e.comps.end()){} - - /// Convert the iterator to the column of the term - operator Col() const { - return colFromId(_it->first); - } - - /// Returns the coefficient of the term - const Value& operator*() const { return _it->second; } - - /// Next term - - /// Assign the iterator to the next term. - /// - ConstCoeffIt& operator++() { ++_it; return *this; } - - /// Equality operator - bool operator==(Invalid) const { return _it == _end; } - /// Inequality operator - bool operator!=(Invalid) const { return _it != _end; } - }; - - }; - - ///Linear constraint - - ///This data stucture represents a linear constraint in the LP. - ///Basically it is a linear expression with a lower or an upper bound - ///(or both). These parts of the constraint can be obtained by the member - ///functions \ref expr(), \ref lowerBound() and \ref upperBound(), - ///respectively. - ///There are two ways to construct a constraint. - ///- You can set the linear expression and the bounds directly - /// by the functions above. - ///- The operators \<=, == and \>= - /// are defined between expressions, or even between constraints whenever - /// it makes sense. Therefore if \c e and \c f are linear expressions and - /// \c s and \c t are numbers, then the followings are valid expressions - /// and thus they can be used directly e.g. in \ref addRow() whenever - /// it makes sense. - ///\code - /// e<=s - /// e<=f - /// e==f - /// s<=e<=t - /// e>=t - ///\endcode - ///\warning The validity of a constraint is checked only at run - ///time, so e.g. \ref addRow(x[1]\<=x[2]<=5) will - ///compile, but will fail an assertion. - class Constr - { - public: - typedef LpBase::Expr Expr; - typedef Expr::Key Key; - typedef Expr::Value Value; - - protected: - Expr _expr; - Value _lb,_ub; - public: - ///\e - Constr() : _expr(), _lb(NaN), _ub(NaN) {} - ///\e - Constr(Value lb, const Expr &e, Value ub) : - _expr(e), _lb(lb), _ub(ub) {} - Constr(const Expr &e) : - _expr(e), _lb(NaN), _ub(NaN) {} - ///\e - void clear() - { - _expr.clear(); - _lb=_ub=NaN; - } - - ///Reference to the linear expression - Expr &expr() { return _expr; } - ///Cont reference to the linear expression - const Expr &expr() const { return _expr; } - ///Reference to the lower bound. - - ///\return - ///- \ref INF "INF": the constraint is lower unbounded. - ///- \ref NaN "NaN": lower bound has not been set. - ///- finite number: the lower bound - Value &lowerBound() { return _lb; } - ///The const version of \ref lowerBound() - const Value &lowerBound() const { return _lb; } - ///Reference to the upper bound. - - ///\return - ///- \ref INF "INF": the constraint is upper unbounded. - ///- \ref NaN "NaN": upper bound has not been set. - ///- finite number: the upper bound - Value &upperBound() { return _ub; } - ///The const version of \ref upperBound() - const Value &upperBound() const { return _ub; } - ///Is the constraint lower bounded? - bool lowerBounded() const { - return _lb != -INF && !isNaN(_lb); - } - ///Is the constraint upper bounded? - bool upperBounded() const { - return _ub != INF && !isNaN(_ub); - } - - }; - - ///Linear expression of rows - - ///This data structure represents a column of the matrix, - ///thas is it strores a linear expression of the dual variables - ///(\ref Row "Row"s). - /// - ///There are several ways to access and modify the contents of this - ///container. - ///\code - ///e[v]=5; - ///e[v]+=12; - ///e.erase(v); - ///\endcode - ///or you can also iterate through its elements. - ///\code - ///double s=0; - ///for(LpBase::DualExpr::ConstCoeffIt i(e);i!=INVALID;++i) - /// s+=*i; - ///\endcode - ///(This code computes the sum of all coefficients). - ///- Numbers (double's) - ///and variables (\ref Row "Row"s) directly convert to an - ///\ref DualExpr and the usual linear operations are defined, so - ///\code - ///v+w - ///2*v-3.12*(v-w/2) - ///v*2.1+(3*v+(v*12+w)*3)/2 - ///\endcode - ///are valid \ref DualExpr dual expressions. - ///The usual assignment operations are also defined. - ///\code - ///e=v+w; - ///e+=2*v-3.12*(v-w/2); - ///e*=3.4; - ///e/=5; - ///\endcode - /// - ///\sa Expr - class DualExpr { - friend class LpBase; - public: - /// The key type of the expression - typedef LpBase::Row Key; - /// The value type of the expression - typedef LpBase::Value Value; - - protected: - std::map comps; - - public: - typedef True SolverExpr; - /// Default constructor - - /// Construct an empty expression, the coefficients are - /// initialized to zero. - DualExpr() {} - /// Construct an expression from a row - - /// Construct an expression, which has a term with \c r dual - /// variable and 1.0 coefficient. - DualExpr(const Row &r) { - typedef std::map::value_type pair_type; - comps.insert(pair_type(id(r), 1)); - } - /// Returns the coefficient of the row - Value operator[](const Row& r) const { - std::map::const_iterator it = comps.find(id(r)); - if (it != comps.end()) { - return it->second; - } else { - return 0; - } - } - /// Returns the coefficient of the row - Value& operator[](const Row& r) { - return comps[id(r)]; - } - /// Sets the coefficient of the row - void set(const Row &r, const Value &v) { - if (v != 0.0) { - typedef std::map::value_type pair_type; - comps.insert(pair_type(id(r), v)); - } else { - comps.erase(id(r)); - } - } - /// \brief Removes the coefficients which's absolute value does - /// not exceed \c epsilon. - void simplify(Value epsilon = 0.0) { - std::map::iterator it=comps.begin(); - while (it != comps.end()) { - std::map::iterator jt=it; - ++jt; - if (std::fabs((*it).second) <= epsilon) comps.erase(it); - it=jt; - } - } - - void simplify(Value epsilon = 0.0) const { - const_cast(this)->simplify(epsilon); - } - - ///Sets all coefficients to 0. - void clear() { - comps.clear(); - } - ///Compound assignment - DualExpr &operator+=(const DualExpr &e) { - for (std::map::const_iterator it=e.comps.begin(); - it!=e.comps.end(); ++it) - comps[it->first]+=it->second; - return *this; - } - ///Compound assignment - DualExpr &operator-=(const DualExpr &e) { - for (std::map::const_iterator it=e.comps.begin(); - it!=e.comps.end(); ++it) - comps[it->first]-=it->second; - return *this; - } - ///Multiply with a constant - DualExpr &operator*=(const Value &v) { - for (std::map::iterator it=comps.begin(); - it!=comps.end(); ++it) - it->second*=v; - return *this; - } - ///Division with a constant - DualExpr &operator/=(const Value &v) { - for (std::map::iterator it=comps.begin(); - it!=comps.end(); ++it) - it->second/=v; - return *this; - } - - ///Iterator over the expression - - ///The iterator iterates over the terms of the expression. - /// - ///\code - ///double s=0; - ///for(LpBase::DualExpr::CoeffIt i(e);i!=INVALID;++i) - /// s+= *i * dual(i); - ///\endcode - class CoeffIt { - private: - - std::map::iterator _it, _end; - - public: - - /// Sets the iterator to the first term - - /// Sets the iterator to the first term of the expression. - /// - CoeffIt(DualExpr& e) - : _it(e.comps.begin()), _end(e.comps.end()){} - - /// Convert the iterator to the row of the term - operator Row() const { - return rowFromId(_it->first); - } - - /// Returns the coefficient of the term - Value& operator*() { return _it->second; } - - /// Returns the coefficient of the term - const Value& operator*() const { return _it->second; } - - /// Next term - - /// Assign the iterator to the next term. - /// - CoeffIt& operator++() { ++_it; return *this; } - - /// Equality operator - bool operator==(Invalid) const { return _it == _end; } - /// Inequality operator - bool operator!=(Invalid) const { return _it != _end; } - }; - - ///Iterator over the expression - - ///The iterator iterates over the terms of the expression. - /// - ///\code - ///double s=0; - ///for(LpBase::DualExpr::ConstCoeffIt i(e);i!=INVALID;++i) - /// s+= *i * dual(i); - ///\endcode - class ConstCoeffIt { - private: - - std::map::const_iterator _it, _end; - - public: - - /// Sets the iterator to the first term - - /// Sets the iterator to the first term of the expression. - /// - ConstCoeffIt(const DualExpr& e) - : _it(e.comps.begin()), _end(e.comps.end()){} - - /// Convert the iterator to the row of the term - operator Row() const { - return rowFromId(_it->first); - } - - /// Returns the coefficient of the term - const Value& operator*() const { return _it->second; } - - /// Next term - - /// Assign the iterator to the next term. - /// - ConstCoeffIt& operator++() { ++_it; return *this; } - - /// Equality operator - bool operator==(Invalid) const { return _it == _end; } - /// Inequality operator - bool operator!=(Invalid) const { return _it != _end; } - }; - }; - - - protected: - - class InsertIterator { - private: - - std::map& _host; - const _solver_bits::VarIndex& _index; - - public: - - typedef std::output_iterator_tag iterator_category; - typedef void difference_type; - typedef void value_type; - typedef void reference; - typedef void pointer; - - InsertIterator(std::map& host, - const _solver_bits::VarIndex& index) - : _host(host), _index(index) {} - - InsertIterator& operator=(const std::pair& value) { - typedef std::map::value_type pair_type; - _host.insert(pair_type(_index[value.first], value.second)); - return *this; - } - - InsertIterator& operator*() { return *this; } - InsertIterator& operator++() { return *this; } - InsertIterator operator++(int) { return *this; } - - }; - - class ExprIterator { - private: - std::map::const_iterator _host_it; - const _solver_bits::VarIndex& _index; - public: - - typedef std::bidirectional_iterator_tag iterator_category; - typedef std::ptrdiff_t difference_type; - typedef const std::pair value_type; - typedef value_type reference; - - class pointer { - public: - pointer(value_type& _value) : value(_value) {} - value_type* operator->() { return &value; } - private: - value_type value; - }; - - ExprIterator(const std::map::const_iterator& host_it, - const _solver_bits::VarIndex& index) - : _host_it(host_it), _index(index) {} - - reference operator*() { - return std::make_pair(_index(_host_it->first), _host_it->second); - } - - pointer operator->() { - return pointer(operator*()); - } - - ExprIterator& operator++() { ++_host_it; return *this; } - ExprIterator operator++(int) { - ExprIterator tmp(*this); ++_host_it; return tmp; - } - - ExprIterator& operator--() { --_host_it; return *this; } - ExprIterator operator--(int) { - ExprIterator tmp(*this); --_host_it; return tmp; - } - - bool operator==(const ExprIterator& it) const { - return _host_it == it._host_it; - } - - bool operator!=(const ExprIterator& it) const { - return _host_it != it._host_it; - } - - }; - - protected: - - //Abstract virtual functions - - virtual int _addColId(int col) { return cols.addIndex(col); } - virtual int _addRowId(int row) { return rows.addIndex(row); } - - virtual void _eraseColId(int col) { cols.eraseIndex(col); } - virtual void _eraseRowId(int row) { rows.eraseIndex(row); } - - virtual int _addCol() = 0; - virtual int _addRow() = 0; - - virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u) { - int row = _addRow(); - _setRowCoeffs(row, b, e); - _setRowLowerBound(row, l); - _setRowUpperBound(row, u); - return row; - } - - virtual void _eraseCol(int col) = 0; - virtual void _eraseRow(int row) = 0; - - virtual void _getColName(int col, std::string& name) const = 0; - virtual void _setColName(int col, const std::string& name) = 0; - virtual int _colByName(const std::string& name) const = 0; - - virtual void _getRowName(int row, std::string& name) const = 0; - virtual void _setRowName(int row, const std::string& name) = 0; - virtual int _rowByName(const std::string& name) const = 0; - - virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e) = 0; - virtual void _getRowCoeffs(int i, InsertIterator b) const = 0; - - virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e) = 0; - virtual void _getColCoeffs(int i, InsertIterator b) const = 0; - - virtual void _setCoeff(int row, int col, Value value) = 0; - virtual Value _getCoeff(int row, int col) const = 0; - - virtual void _setColLowerBound(int i, Value value) = 0; - virtual Value _getColLowerBound(int i) const = 0; - - virtual void _setColUpperBound(int i, Value value) = 0; - virtual Value _getColUpperBound(int i) const = 0; - - virtual void _setRowLowerBound(int i, Value value) = 0; - virtual Value _getRowLowerBound(int i) const = 0; - - virtual void _setRowUpperBound(int i, Value value) = 0; - virtual Value _getRowUpperBound(int i) const = 0; - - virtual void _setObjCoeffs(ExprIterator b, ExprIterator e) = 0; - virtual void _getObjCoeffs(InsertIterator b) const = 0; - - virtual void _setObjCoeff(int i, Value obj_coef) = 0; - virtual Value _getObjCoeff(int i) const = 0; - - virtual void _setSense(Sense) = 0; - virtual Sense _getSense() const = 0; - - virtual void _clear() = 0; - - virtual const char* _solverName() const = 0; - - virtual void _messageLevel(MessageLevel level) = 0; - - //Own protected stuff - - //Constant component of the objective function - Value obj_const_comp; - - LpBase() : rows(), cols(), obj_const_comp(0) {} - - public: - - ///Unsupported file format exception - class UnsupportedFormatError : public Exception - { - std::string _format; - mutable std::string _what; - public: - explicit UnsupportedFormatError(std::string format) throw() - : _format(format) { } - virtual ~UnsupportedFormatError() throw() {} - virtual const char* what() const throw() { - try { - _what.clear(); - std::ostringstream oss; - oss << "lemon::UnsupportedFormatError: " << _format; - _what = oss.str(); - } - catch (...) {} - if (!_what.empty()) return _what.c_str(); - else return "lemon::UnsupportedFormatError"; - } - }; - - protected: - virtual void _write(std::string, std::string format) const - { - throw UnsupportedFormatError(format); - } - - public: - - /// Virtual destructor - virtual ~LpBase() {} - - ///Gives back the name of the solver. - const char* solverName() const {return _solverName();} - - ///\name Build Up and Modify the LP - - ///@{ - - ///Add a new empty column (i.e a new variable) to the LP - Col addCol() { Col c; c._id = _addColId(_addCol()); return c;} - - ///\brief Adds several new columns (i.e variables) at once - /// - ///This magic function takes a container as its argument and fills - ///its elements with new columns (i.e. variables) - ///\param t can be - ///- a standard STL compatible iterable container with - ///\ref Col as its \c values_type like - ///\code - ///std::vector - ///std::list - ///\endcode - ///- a standard STL compatible iterable container with - ///\ref Col as its \c mapped_type like - ///\code - ///std::map - ///\endcode - ///- an iterable lemon \ref concepts::WriteMap "write map" like - ///\code - ///ListGraph::NodeMap - ///ListGraph::ArcMap - ///\endcode - ///\return The number of the created column. -#ifdef DOXYGEN - template - int addColSet(T &t) { return 0;} -#else - template - typename enable_if::type - addColSet(T &t,dummy<0> = 0) { - int s=0; - for(typename T::iterator i=t.begin();i!=t.end();++i) {*i=addCol();s++;} - return s; - } - template - typename enable_if::type - addColSet(T &t,dummy<1> = 1) { - int s=0; - for(typename T::iterator i=t.begin();i!=t.end();++i) { - i->second=addCol(); - s++; - } - return s; - } - template - typename enable_if::type - addColSet(T &t,dummy<2> = 2) { - int s=0; - for(typename T::MapIt i(t); i!=INVALID; ++i) - { - i.set(addCol()); - s++; - } - return s; - } -#endif - - ///Set a column (i.e a dual constraint) of the LP - - ///\param c is the column to be modified - ///\param e is a dual linear expression (see \ref DualExpr) - ///a better one. - void col(Col c, const DualExpr &e) { - e.simplify(); - _setColCoeffs(cols(id(c)), ExprIterator(e.comps.begin(), rows), - ExprIterator(e.comps.end(), rows)); - } - - ///Get a column (i.e a dual constraint) of the LP - - ///\param c is the column to get - ///\return the dual expression associated to the column - DualExpr col(Col c) const { - DualExpr e; - _getColCoeffs(cols(id(c)), InsertIterator(e.comps, rows)); - return e; - } - - ///Add a new column to the LP - - ///\param e is a dual linear expression (see \ref DualExpr) - ///\param o is the corresponding component of the objective - ///function. It is 0 by default. - ///\return The created column. - Col addCol(const DualExpr &e, Value o = 0) { - Col c=addCol(); - col(c,e); - objCoeff(c,o); - return c; - } - - ///Add a new empty row (i.e a new constraint) to the LP - - ///This function adds a new empty row (i.e a new constraint) to the LP. - ///\return The created row - Row addRow() { Row r; r._id = _addRowId(_addRow()); return r;} - - ///\brief Add several new rows (i.e constraints) at once - /// - ///This magic function takes a container as its argument and fills - ///its elements with new row (i.e. variables) - ///\param t can be - ///- a standard STL compatible iterable container with - ///\ref Row as its \c values_type like - ///\code - ///std::vector - ///std::list - ///\endcode - ///- a standard STL compatible iterable container with - ///\ref Row as its \c mapped_type like - ///\code - ///std::map - ///\endcode - ///- an iterable lemon \ref concepts::WriteMap "write map" like - ///\code - ///ListGraph::NodeMap - ///ListGraph::ArcMap - ///\endcode - ///\return The number of rows created. -#ifdef DOXYGEN - template - int addRowSet(T &t) { return 0;} -#else - template - typename enable_if::type - addRowSet(T &t, dummy<0> = 0) { - int s=0; - for(typename T::iterator i=t.begin();i!=t.end();++i) {*i=addRow();s++;} - return s; - } - template - typename enable_if::type - addRowSet(T &t, dummy<1> = 1) { - int s=0; - for(typename T::iterator i=t.begin();i!=t.end();++i) { - i->second=addRow(); - s++; - } - return s; - } - template - typename enable_if::type - addRowSet(T &t, dummy<2> = 2) { - int s=0; - for(typename T::MapIt i(t); i!=INVALID; ++i) - { - i.set(addRow()); - s++; - } - return s; - } -#endif - - ///Set a row (i.e a constraint) of the LP - - ///\param r is the row to be modified - ///\param l is lower bound (-\ref INF means no bound) - ///\param e is a linear expression (see \ref Expr) - ///\param u is the upper bound (\ref INF means no bound) - void row(Row r, Value l, const Expr &e, Value u) { - e.simplify(); - _setRowCoeffs(rows(id(r)), ExprIterator(e.comps.begin(), cols), - ExprIterator(e.comps.end(), cols)); - _setRowLowerBound(rows(id(r)),l - *e); - _setRowUpperBound(rows(id(r)),u - *e); - } - - ///Set a row (i.e a constraint) of the LP - - ///\param r is the row to be modified - ///\param c is a linear expression (see \ref Constr) - void row(Row r, const Constr &c) { - row(r, c.lowerBounded()?c.lowerBound():-INF, - c.expr(), c.upperBounded()?c.upperBound():INF); - } - - - ///Get a row (i.e a constraint) of the LP - - ///\param r is the row to get - ///\return the expression associated to the row - Expr row(Row r) const { - Expr e; - _getRowCoeffs(rows(id(r)), InsertIterator(e.comps, cols)); - return e; - } - - ///Add a new row (i.e a new constraint) to the LP - - ///\param l is the lower bound (-\ref INF means no bound) - ///\param e is a linear expression (see \ref Expr) - ///\param u is the upper bound (\ref INF means no bound) - ///\return The created row. - Row addRow(Value l,const Expr &e, Value u) { - Row r; - e.simplify(); - r._id = _addRowId(_addRow(l - *e, ExprIterator(e.comps.begin(), cols), - ExprIterator(e.comps.end(), cols), u - *e)); - return r; - } - - ///Add a new row (i.e a new constraint) to the LP - - ///\param c is a linear expression (see \ref Constr) - ///\return The created row. - Row addRow(const Constr &c) { - Row r; - c.expr().simplify(); - r._id = _addRowId(_addRow(c.lowerBounded()?c.lowerBound()-*c.expr():-INF, - ExprIterator(c.expr().comps.begin(), cols), - ExprIterator(c.expr().comps.end(), cols), - c.upperBounded()?c.upperBound()-*c.expr():INF)); - return r; - } - ///Erase a column (i.e a variable) from the LP - - ///\param c is the column to be deleted - void erase(Col c) { - _eraseCol(cols(id(c))); - _eraseColId(cols(id(c))); - } - ///Erase a row (i.e a constraint) from the LP - - ///\param r is the row to be deleted - void erase(Row r) { - _eraseRow(rows(id(r))); - _eraseRowId(rows(id(r))); - } - - /// Get the name of a column - - ///\param c is the coresponding column - ///\return The name of the colunm - std::string colName(Col c) const { - std::string name; - _getColName(cols(id(c)), name); - return name; - } - - /// Set the name of a column - - ///\param c is the coresponding column - ///\param name The name to be given - void colName(Col c, const std::string& name) { - _setColName(cols(id(c)), name); - } - - /// Get the column by its name - - ///\param name The name of the column - ///\return the proper column or \c INVALID - Col colByName(const std::string& name) const { - int k = _colByName(name); - return k != -1 ? Col(cols[k]) : Col(INVALID); - } - - /// Get the name of a row - - ///\param r is the coresponding row - ///\return The name of the row - std::string rowName(Row r) const { - std::string name; - _getRowName(rows(id(r)), name); - return name; - } - - /// Set the name of a row - - ///\param r is the coresponding row - ///\param name The name to be given - void rowName(Row r, const std::string& name) { - _setRowName(rows(id(r)), name); - } - - /// Get the row by its name - - ///\param name The name of the row - ///\return the proper row or \c INVALID - Row rowByName(const std::string& name) const { - int k = _rowByName(name); - return k != -1 ? Row(rows[k]) : Row(INVALID); - } - - /// Set an element of the coefficient matrix of the LP - - ///\param r is the row of the element to be modified - ///\param c is the column of the element to be modified - ///\param val is the new value of the coefficient - void coeff(Row r, Col c, Value val) { - _setCoeff(rows(id(r)),cols(id(c)), val); - } - - /// Get an element of the coefficient matrix of the LP - - ///\param r is the row of the element - ///\param c is the column of the element - ///\return the corresponding coefficient - Value coeff(Row r, Col c) const { - return _getCoeff(rows(id(r)),cols(id(c))); - } - - /// Set the lower bound of a column (i.e a variable) - - /// The lower bound of a variable (column) has to be given by an - /// extended number of type Value, i.e. a finite number of type - /// Value or -\ref INF. - void colLowerBound(Col c, Value value) { - _setColLowerBound(cols(id(c)),value); - } - - /// Get the lower bound of a column (i.e a variable) - - /// This function returns the lower bound for column (variable) \c c - /// (this might be -\ref INF as well). - ///\return The lower bound for column \c c - Value colLowerBound(Col c) const { - return _getColLowerBound(cols(id(c))); - } - - ///\brief Set the lower bound of several columns - ///(i.e variables) at once - /// - ///This magic function takes a container as its argument - ///and applies the function on all of its elements. - ///The lower bound of a variable (column) has to be given by an - ///extended number of type Value, i.e. a finite number of type - ///Value or -\ref INF. -#ifdef DOXYGEN - template - void colLowerBound(T &t, Value value) { return 0;} -#else - template - typename enable_if::type - colLowerBound(T &t, Value value,dummy<0> = 0) { - for(typename T::iterator i=t.begin();i!=t.end();++i) { - colLowerBound(*i, value); - } - } - template - typename enable_if::type - colLowerBound(T &t, Value value,dummy<1> = 1) { - for(typename T::iterator i=t.begin();i!=t.end();++i) { - colLowerBound(i->second, value); - } - } - template - typename enable_if::type - colLowerBound(T &t, Value value,dummy<2> = 2) { - for(typename T::MapIt i(t); i!=INVALID; ++i){ - colLowerBound(*i, value); - } - } -#endif - - /// Set the upper bound of a column (i.e a variable) - - /// The upper bound of a variable (column) has to be given by an - /// extended number of type Value, i.e. a finite number of type - /// Value or \ref INF. - void colUpperBound(Col c, Value value) { - _setColUpperBound(cols(id(c)),value); - }; - - /// Get the upper bound of a column (i.e a variable) - - /// This function returns the upper bound for column (variable) \c c - /// (this might be \ref INF as well). - /// \return The upper bound for column \c c - Value colUpperBound(Col c) const { - return _getColUpperBound(cols(id(c))); - } - - ///\brief Set the upper bound of several columns - ///(i.e variables) at once - /// - ///This magic function takes a container as its argument - ///and applies the function on all of its elements. - ///The upper bound of a variable (column) has to be given by an - ///extended number of type Value, i.e. a finite number of type - ///Value or \ref INF. -#ifdef DOXYGEN - template - void colUpperBound(T &t, Value value) { return 0;} -#else - template - typename enable_if::type - colUpperBound(T1 &t, Value value,dummy<0> = 0) { - for(typename T1::iterator i=t.begin();i!=t.end();++i) { - colUpperBound(*i, value); - } - } - template - typename enable_if::type - colUpperBound(T1 &t, Value value,dummy<1> = 1) { - for(typename T1::iterator i=t.begin();i!=t.end();++i) { - colUpperBound(i->second, value); - } - } - template - typename enable_if::type - colUpperBound(T1 &t, Value value,dummy<2> = 2) { - for(typename T1::MapIt i(t); i!=INVALID; ++i){ - colUpperBound(*i, value); - } - } -#endif - - /// Set the lower and the upper bounds of a column (i.e a variable) - - /// The lower and the upper bounds of - /// a variable (column) have to be given by an - /// extended number of type Value, i.e. a finite number of type - /// Value, -\ref INF or \ref INF. - void colBounds(Col c, Value lower, Value upper) { - _setColLowerBound(cols(id(c)),lower); - _setColUpperBound(cols(id(c)),upper); - } - - ///\brief Set the lower and the upper bound of several columns - ///(i.e variables) at once - /// - ///This magic function takes a container as its argument - ///and applies the function on all of its elements. - /// The lower and the upper bounds of - /// a variable (column) have to be given by an - /// extended number of type Value, i.e. a finite number of type - /// Value, -\ref INF or \ref INF. -#ifdef DOXYGEN - template - void colBounds(T &t, Value lower, Value upper) { return 0;} -#else - template - typename enable_if::type - colBounds(T2 &t, Value lower, Value upper,dummy<0> = 0) { - for(typename T2::iterator i=t.begin();i!=t.end();++i) { - colBounds(*i, lower, upper); - } - } - template - typename enable_if::type - colBounds(T2 &t, Value lower, Value upper,dummy<1> = 1) { - for(typename T2::iterator i=t.begin();i!=t.end();++i) { - colBounds(i->second, lower, upper); - } - } - template - typename enable_if::type - colBounds(T2 &t, Value lower, Value upper,dummy<2> = 2) { - for(typename T2::MapIt i(t); i!=INVALID; ++i){ - colBounds(*i, lower, upper); - } - } -#endif - - /// Set the lower bound of a row (i.e a constraint) - - /// The lower bound of a constraint (row) has to be given by an - /// extended number of type Value, i.e. a finite number of type - /// Value or -\ref INF. - void rowLowerBound(Row r, Value value) { - _setRowLowerBound(rows(id(r)),value); - } - - /// Get the lower bound of a row (i.e a constraint) - - /// This function returns the lower bound for row (constraint) \c c - /// (this might be -\ref INF as well). - ///\return The lower bound for row \c r - Value rowLowerBound(Row r) const { - return _getRowLowerBound(rows(id(r))); - } - - /// Set the upper bound of a row (i.e a constraint) - - /// The upper bound of a constraint (row) has to be given by an - /// extended number of type Value, i.e. a finite number of type - /// Value or -\ref INF. - void rowUpperBound(Row r, Value value) { - _setRowUpperBound(rows(id(r)),value); - } - - /// Get the upper bound of a row (i.e a constraint) - - /// This function returns the upper bound for row (constraint) \c c - /// (this might be -\ref INF as well). - ///\return The upper bound for row \c r - Value rowUpperBound(Row r) const { - return _getRowUpperBound(rows(id(r))); - } - - ///Set an element of the objective function - void objCoeff(Col c, Value v) {_setObjCoeff(cols(id(c)),v); }; - - ///Get an element of the objective function - Value objCoeff(Col c) const { return _getObjCoeff(cols(id(c))); }; - - ///Set the objective function - - ///\param e is a linear expression of type \ref Expr. - /// - void obj(const Expr& e) { - _setObjCoeffs(ExprIterator(e.comps.begin(), cols), - ExprIterator(e.comps.end(), cols)); - obj_const_comp = *e; - } - - ///Get the objective function - - ///\return the objective function as a linear expression of type - ///Expr. - Expr obj() const { - Expr e; - _getObjCoeffs(InsertIterator(e.comps, cols)); - *e = obj_const_comp; - return e; - } - - - ///Set the direction of optimization - void sense(Sense sense) { _setSense(sense); } - - ///Query the direction of the optimization - Sense sense() const {return _getSense(); } - - ///Set the sense to maximization - void max() { _setSense(MAX); } - - ///Set the sense to maximization - void min() { _setSense(MIN); } - - ///Clear the problem - void clear() { _clear(); rows.clear(); cols.clear(); } - - /// Set the message level of the solver - void messageLevel(MessageLevel level) { _messageLevel(level); } - - /// Write the problem to a file in the given format - - /// This function writes the problem to a file in the given format. - /// Different solver backends may support different formats. - /// Trying to write in an unsupported format will trigger - /// \ref UnsupportedFormatError. For the supported formats, - /// visit the documentation of the base class of the related backends - /// (\ref CplexBase, \ref GlpkBase etc.) - /// \param file The file path - /// \param format The output file format. - void write(std::string file, std::string format = "MPS") const - { - _write(file.c_str(),format.c_str()); - } - - ///@} - - }; - - /// Addition - - ///\relates LpBase::Expr - /// - inline LpBase::Expr operator+(const LpBase::Expr &a, const LpBase::Expr &b) { - LpBase::Expr tmp(a); - tmp+=b; - return tmp; - } - ///Substraction - - ///\relates LpBase::Expr - /// - inline LpBase::Expr operator-(const LpBase::Expr &a, const LpBase::Expr &b) { - LpBase::Expr tmp(a); - tmp-=b; - return tmp; - } - ///Multiply with constant - - ///\relates LpBase::Expr - /// - inline LpBase::Expr operator*(const LpBase::Expr &a, const LpBase::Value &b) { - LpBase::Expr tmp(a); - tmp*=b; - return tmp; - } - - ///Multiply with constant - - ///\relates LpBase::Expr - /// - inline LpBase::Expr operator*(const LpBase::Value &a, const LpBase::Expr &b) { - LpBase::Expr tmp(b); - tmp*=a; - return tmp; - } - ///Divide with constant - - ///\relates LpBase::Expr - /// - inline LpBase::Expr operator/(const LpBase::Expr &a, const LpBase::Value &b) { - LpBase::Expr tmp(a); - tmp/=b; - return tmp; - } - - ///Create constraint - - ///\relates LpBase::Constr - /// - inline LpBase::Constr operator<=(const LpBase::Expr &e, - const LpBase::Expr &f) { - return LpBase::Constr(0, f - e, LpBase::NaN); - } - - ///Create constraint - - ///\relates LpBase::Constr - /// - inline LpBase::Constr operator<=(const LpBase::Value &e, - const LpBase::Expr &f) { - return LpBase::Constr(e, f, LpBase::NaN); - } - - ///Create constraint - - ///\relates LpBase::Constr - /// - inline LpBase::Constr operator<=(const LpBase::Expr &e, - const LpBase::Value &f) { - return LpBase::Constr(LpBase::NaN, e, f); - } - - ///Create constraint - - ///\relates LpBase::Constr - /// - inline LpBase::Constr operator>=(const LpBase::Expr &e, - const LpBase::Expr &f) { - return LpBase::Constr(0, e - f, LpBase::NaN); - } - - - ///Create constraint - - ///\relates LpBase::Constr - /// - inline LpBase::Constr operator>=(const LpBase::Value &e, - const LpBase::Expr &f) { - return LpBase::Constr(LpBase::NaN, f, e); - } - - - ///Create constraint - - ///\relates LpBase::Constr - /// - inline LpBase::Constr operator>=(const LpBase::Expr &e, - const LpBase::Value &f) { - return LpBase::Constr(f, e, LpBase::NaN); - } - - ///Create constraint - - ///\relates LpBase::Constr - /// - inline LpBase::Constr operator==(const LpBase::Expr &e, - const LpBase::Value &f) { - return LpBase::Constr(f, e, f); - } - - ///Create constraint - - ///\relates LpBase::Constr - /// - inline LpBase::Constr operator==(const LpBase::Expr &e, - const LpBase::Expr &f) { - return LpBase::Constr(0, f - e, 0); - } - - ///Create constraint - - ///\relates LpBase::Constr - /// - inline LpBase::Constr operator<=(const LpBase::Value &n, - const LpBase::Constr &c) { - LpBase::Constr tmp(c); - LEMON_ASSERT(isNaN(tmp.lowerBound()), "Wrong LP constraint"); - tmp.lowerBound()=n; - return tmp; - } - ///Create constraint - - ///\relates LpBase::Constr - /// - inline LpBase::Constr operator<=(const LpBase::Constr &c, - const LpBase::Value &n) - { - LpBase::Constr tmp(c); - LEMON_ASSERT(isNaN(tmp.upperBound()), "Wrong LP constraint"); - tmp.upperBound()=n; - return tmp; - } - - ///Create constraint - - ///\relates LpBase::Constr - /// - inline LpBase::Constr operator>=(const LpBase::Value &n, - const LpBase::Constr &c) { - LpBase::Constr tmp(c); - LEMON_ASSERT(isNaN(tmp.upperBound()), "Wrong LP constraint"); - tmp.upperBound()=n; - return tmp; - } - ///Create constraint - - ///\relates LpBase::Constr - /// - inline LpBase::Constr operator>=(const LpBase::Constr &c, - const LpBase::Value &n) - { - LpBase::Constr tmp(c); - LEMON_ASSERT(isNaN(tmp.lowerBound()), "Wrong LP constraint"); - tmp.lowerBound()=n; - return tmp; - } - - ///Addition - - ///\relates LpBase::DualExpr - /// - inline LpBase::DualExpr operator+(const LpBase::DualExpr &a, - const LpBase::DualExpr &b) { - LpBase::DualExpr tmp(a); - tmp+=b; - return tmp; - } - ///Substraction - - ///\relates LpBase::DualExpr - /// - inline LpBase::DualExpr operator-(const LpBase::DualExpr &a, - const LpBase::DualExpr &b) { - LpBase::DualExpr tmp(a); - tmp-=b; - return tmp; - } - ///Multiply with constant - - ///\relates LpBase::DualExpr - /// - inline LpBase::DualExpr operator*(const LpBase::DualExpr &a, - const LpBase::Value &b) { - LpBase::DualExpr tmp(a); - tmp*=b; - return tmp; - } - - ///Multiply with constant - - ///\relates LpBase::DualExpr - /// - inline LpBase::DualExpr operator*(const LpBase::Value &a, - const LpBase::DualExpr &b) { - LpBase::DualExpr tmp(b); - tmp*=a; - return tmp; - } - ///Divide with constant - - ///\relates LpBase::DualExpr - /// - inline LpBase::DualExpr operator/(const LpBase::DualExpr &a, - const LpBase::Value &b) { - LpBase::DualExpr tmp(a); - tmp/=b; - return tmp; - } - - /// \ingroup lp_group - /// - /// \brief Common base class for LP solvers - /// - /// This class is an abstract base class for LP solvers. This class - /// provides a full interface for set and modify an LP problem, - /// solve it and retrieve the solution. You can use one of the - /// descendants as a concrete implementation, or the \c Lp - /// default LP solver. However, if you would like to handle LP - /// solvers as reference or pointer in a generic way, you can use - /// this class directly. - class LpSolver : virtual public LpBase { - public: - - /// The problem types for primal and dual problems - enum ProblemType { - /// = 0. Feasible solution hasn't been found (but may exist). - UNDEFINED = 0, - /// = 1. The problem has no feasible solution. - INFEASIBLE = 1, - /// = 2. Feasible solution found. - FEASIBLE = 2, - /// = 3. Optimal solution exists and found. - OPTIMAL = 3, - /// = 4. The cost function is unbounded. - UNBOUNDED = 4 - }; - - ///The basis status of variables - enum VarStatus { - /// The variable is in the basis - BASIC, - /// The variable is free, but not basic - FREE, - /// The variable has active lower bound - LOWER, - /// The variable has active upper bound - UPPER, - /// The variable is non-basic and fixed - FIXED - }; - - protected: - - virtual SolveExitStatus _solve() = 0; - - virtual Value _getPrimal(int i) const = 0; - virtual Value _getDual(int i) const = 0; - - virtual Value _getPrimalRay(int i) const = 0; - virtual Value _getDualRay(int i) const = 0; - - virtual Value _getPrimalValue() const = 0; - - virtual VarStatus _getColStatus(int i) const = 0; - virtual VarStatus _getRowStatus(int i) const = 0; - - virtual ProblemType _getPrimalType() const = 0; - virtual ProblemType _getDualType() const = 0; - - public: - - ///Allocate a new LP problem instance - virtual LpSolver* newSolver() const = 0; - ///Make a copy of the LP problem - virtual LpSolver* cloneSolver() const = 0; - - ///\name Solve the LP - - ///@{ - - ///\e Solve the LP problem at hand - /// - ///\return The result of the optimization procedure. Possible - ///values and their meanings can be found in the documentation of - ///\ref SolveExitStatus. - SolveExitStatus solve() { return _solve(); } - - ///@} - - ///\name Obtain the Solution - - ///@{ - - /// The type of the primal problem - ProblemType primalType() const { - return _getPrimalType(); - } - - /// The type of the dual problem - ProblemType dualType() const { - return _getDualType(); - } - - /// Return the primal value of the column - - /// Return the primal value of the column. - /// \pre The problem is solved. - Value primal(Col c) const { return _getPrimal(cols(id(c))); } - - /// Return the primal value of the expression - - /// Return the primal value of the expression, i.e. the dot - /// product of the primal solution and the expression. - /// \pre The problem is solved. - Value primal(const Expr& e) const { - double res = *e; - for (Expr::ConstCoeffIt c(e); c != INVALID; ++c) { - res += *c * primal(c); - } - return res; - } - /// Returns a component of the primal ray - - /// The primal ray is solution of the modified primal problem, - /// where we change each finite bound to 0, and we looking for a - /// negative objective value in case of minimization, and positive - /// objective value for maximization. If there is such solution, - /// that proofs the unsolvability of the dual problem, and if a - /// feasible primal solution exists, then the unboundness of - /// primal problem. - /// - /// \pre The problem is solved and the dual problem is infeasible. - /// \note Some solvers does not provide primal ray calculation - /// functions. - Value primalRay(Col c) const { return _getPrimalRay(cols(id(c))); } - - /// Return the dual value of the row - - /// Return the dual value of the row. - /// \pre The problem is solved. - Value dual(Row r) const { return _getDual(rows(id(r))); } - - /// Return the dual value of the dual expression - - /// Return the dual value of the dual expression, i.e. the dot - /// product of the dual solution and the dual expression. - /// \pre The problem is solved. - Value dual(const DualExpr& e) const { - double res = 0.0; - for (DualExpr::ConstCoeffIt r(e); r != INVALID; ++r) { - res += *r * dual(r); - } - return res; - } - - /// Returns a component of the dual ray - - /// The dual ray is solution of the modified primal problem, where - /// we change each finite bound to 0 (i.e. the objective function - /// coefficients in the primal problem), and we looking for a - /// ositive objective value. If there is such solution, that - /// proofs the unsolvability of the primal problem, and if a - /// feasible dual solution exists, then the unboundness of - /// dual problem. - /// - /// \pre The problem is solved and the primal problem is infeasible. - /// \note Some solvers does not provide dual ray calculation - /// functions. - Value dualRay(Row r) const { return _getDualRay(rows(id(r))); } - - /// Return the basis status of the column - - /// \see VarStatus - VarStatus colStatus(Col c) const { return _getColStatus(cols(id(c))); } - - /// Return the basis status of the row - - /// \see VarStatus - VarStatus rowStatus(Row r) const { return _getRowStatus(rows(id(r))); } - - ///The value of the objective function - - ///\return - ///- \ref INF or -\ref INF means either infeasibility or unboundedness - /// of the primal problem, depending on whether we minimize or maximize. - ///- \ref NaN if no primal solution is found. - ///- The (finite) objective value if an optimal solution is found. - Value primal() const { return _getPrimalValue()+obj_const_comp;} - ///@} - - protected: - - }; - - - /// \ingroup lp_group - /// - /// \brief Common base class for MIP solvers - /// - /// This class is an abstract base class for MIP solvers. This class - /// provides a full interface for set and modify an MIP problem, - /// solve it and retrieve the solution. You can use one of the - /// descendants as a concrete implementation, or the \c Lp - /// default MIP solver. However, if you would like to handle MIP - /// solvers as reference or pointer in a generic way, you can use - /// this class directly. - class MipSolver : virtual public LpBase { - public: - - /// The problem types for MIP problems - enum ProblemType { - /// = 0. Feasible solution hasn't been found (but may exist). - UNDEFINED = 0, - /// = 1. The problem has no feasible solution. - INFEASIBLE = 1, - /// = 2. Feasible solution found. - FEASIBLE = 2, - /// = 3. Optimal solution exists and found. - OPTIMAL = 3, - /// = 4. The cost function is unbounded. - ///The Mip or at least the relaxed problem is unbounded. - UNBOUNDED = 4 - }; - - ///Allocate a new MIP problem instance - virtual MipSolver* newSolver() const = 0; - ///Make a copy of the MIP problem - virtual MipSolver* cloneSolver() const = 0; - - ///\name Solve the MIP - - ///@{ - - /// Solve the MIP problem at hand - /// - ///\return The result of the optimization procedure. Possible - ///values and their meanings can be found in the documentation of - ///\ref SolveExitStatus. - SolveExitStatus solve() { return _solve(); } - - ///@} - - ///\name Set Column Type - ///@{ - - ///Possible variable (column) types (e.g. real, integer, binary etc.) - enum ColTypes { - /// = 0. Continuous variable (default). - REAL = 0, - /// = 1. Integer variable. - INTEGER = 1 - }; - - ///Sets the type of the given column to the given type - - ///Sets the type of the given column to the given type. - /// - void colType(Col c, ColTypes col_type) { - _setColType(cols(id(c)),col_type); - } - - ///Gives back the type of the column. - - ///Gives back the type of the column. - /// - ColTypes colType(Col c) const { - return _getColType(cols(id(c))); - } - ///@} - - ///\name Obtain the Solution - - ///@{ - - /// The type of the MIP problem - ProblemType type() const { - return _getType(); - } - - /// Return the value of the row in the solution - - /// Return the value of the row in the solution. - /// \pre The problem is solved. - Value sol(Col c) const { return _getSol(cols(id(c))); } - - /// Return the value of the expression in the solution - - /// Return the value of the expression in the solution, i.e. the - /// dot product of the solution and the expression. - /// \pre The problem is solved. - Value sol(const Expr& e) const { - double res = *e; - for (Expr::ConstCoeffIt c(e); c != INVALID; ++c) { - res += *c * sol(c); - } - return res; - } - ///The value of the objective function - - ///\return - ///- \ref INF or -\ref INF means either infeasibility or unboundedness - /// of the problem, depending on whether we minimize or maximize. - ///- \ref NaN if no primal solution is found. - ///- The (finite) objective value if an optimal solution is found. - Value solValue() const { return _getSolValue()+obj_const_comp;} - ///@} - - protected: - - virtual SolveExitStatus _solve() = 0; - virtual ColTypes _getColType(int col) const = 0; - virtual void _setColType(int col, ColTypes col_type) = 0; - virtual ProblemType _getType() const = 0; - virtual Value _getSol(int i) const = 0; - virtual Value _getSolValue() const = 0; - - }; - - - -} //namespace lemon - -#endif //LEMON_LP_BASE_H diff --git a/deps/lemon/lemon/lp_skeleton.cc b/deps/lemon/lemon/lp_skeleton.cc deleted file mode 100644 index fc1c143f3..000000000 --- a/deps/lemon/lemon/lp_skeleton.cc +++ /dev/null @@ -1,143 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -///\file -///\brief A skeleton file to implement LP solver interfaces -namespace lemon { - - int SkeletonSolverBase::_addCol() - { - return ++col_num; - } - - int SkeletonSolverBase::_addRow() - { - return ++row_num; - } - - int SkeletonSolverBase::_addRow(Value, ExprIterator, ExprIterator, Value) - { - return ++row_num; - } - - void SkeletonSolverBase::_eraseCol(int) {} - void SkeletonSolverBase::_eraseRow(int) {} - - void SkeletonSolverBase::_getColName(int, std::string &) const {} - void SkeletonSolverBase::_setColName(int, const std::string &) {} - int SkeletonSolverBase::_colByName(const std::string&) const { return -1; } - - void SkeletonSolverBase::_getRowName(int, std::string &) const {} - void SkeletonSolverBase::_setRowName(int, const std::string &) {} - int SkeletonSolverBase::_rowByName(const std::string&) const { return -1; } - - void SkeletonSolverBase::_setRowCoeffs(int, ExprIterator, ExprIterator) {} - void SkeletonSolverBase::_getRowCoeffs(int, InsertIterator) const {} - - void SkeletonSolverBase::_setColCoeffs(int, ExprIterator, ExprIterator) {} - void SkeletonSolverBase::_getColCoeffs(int, InsertIterator) const {} - - void SkeletonSolverBase::_setCoeff(int, int, Value) {} - SkeletonSolverBase::Value SkeletonSolverBase::_getCoeff(int, int) const - { return 0; } - - void SkeletonSolverBase::_setColLowerBound(int, Value) {} - SkeletonSolverBase::Value SkeletonSolverBase::_getColLowerBound(int) const - { return 0; } - - void SkeletonSolverBase::_setColUpperBound(int, Value) {} - SkeletonSolverBase::Value SkeletonSolverBase::_getColUpperBound(int) const - { return 0; } - - void SkeletonSolverBase::_setRowLowerBound(int, Value) {} - SkeletonSolverBase::Value SkeletonSolverBase::_getRowLowerBound(int) const - { return 0; } - - void SkeletonSolverBase::_setRowUpperBound(int, Value) {} - SkeletonSolverBase::Value SkeletonSolverBase::_getRowUpperBound(int) const - { return 0; } - - void SkeletonSolverBase::_setObjCoeffs(ExprIterator, ExprIterator) {} - void SkeletonSolverBase::_getObjCoeffs(InsertIterator) const {}; - - void SkeletonSolverBase::_setObjCoeff(int, Value) {} - SkeletonSolverBase::Value SkeletonSolverBase::_getObjCoeff(int) const - { return 0; } - - void SkeletonSolverBase::_setSense(Sense) {} - SkeletonSolverBase::Sense SkeletonSolverBase::_getSense() const - { return MIN; } - - void SkeletonSolverBase::_clear() { - row_num = col_num = 0; - } - - void SkeletonSolverBase::_messageLevel(MessageLevel) {} - - void SkeletonSolverBase::_write(std::string, std::string) const {} - - LpSkeleton::SolveExitStatus LpSkeleton::_solve() { return SOLVED; } - - LpSkeleton::Value LpSkeleton::_getPrimal(int) const { return 0; } - LpSkeleton::Value LpSkeleton::_getDual(int) const { return 0; } - LpSkeleton::Value LpSkeleton::_getPrimalValue() const { return 0; } - - LpSkeleton::Value LpSkeleton::_getPrimalRay(int) const { return 0; } - LpSkeleton::Value LpSkeleton::_getDualRay(int) const { return 0; } - - LpSkeleton::ProblemType LpSkeleton::_getPrimalType() const - { return UNDEFINED; } - - LpSkeleton::ProblemType LpSkeleton::_getDualType() const - { return UNDEFINED; } - - LpSkeleton::VarStatus LpSkeleton::_getColStatus(int) const - { return BASIC; } - - LpSkeleton::VarStatus LpSkeleton::_getRowStatus(int) const - { return BASIC; } - - LpSkeleton* LpSkeleton::newSolver() const - { return static_cast(0); } - - LpSkeleton* LpSkeleton::cloneSolver() const - { return static_cast(0); } - - const char* LpSkeleton::_solverName() const { return "LpSkeleton"; } - - MipSkeleton::SolveExitStatus MipSkeleton::_solve() - { return SOLVED; } - - MipSkeleton::Value MipSkeleton::_getSol(int) const { return 0; } - MipSkeleton::Value MipSkeleton::_getSolValue() const { return 0; } - - MipSkeleton::ProblemType MipSkeleton::_getType() const - { return UNDEFINED; } - - MipSkeleton* MipSkeleton::newSolver() const - { return static_cast(0); } - - MipSkeleton* MipSkeleton::cloneSolver() const - { return static_cast(0); } - - const char* MipSkeleton::_solverName() const { return "MipSkeleton"; } - -} //namespace lemon - diff --git a/deps/lemon/lemon/lp_skeleton.h b/deps/lemon/lemon/lp_skeleton.h deleted file mode 100644 index 27285a498..000000000 --- a/deps/lemon/lemon/lp_skeleton.h +++ /dev/null @@ -1,234 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_LP_SKELETON_H -#define LEMON_LP_SKELETON_H - -#include - -///\file -///\brief Skeleton file to implement LP/MIP solver interfaces -/// -///The classes in this file do nothing, but they can serve as skeletons when -///implementing an interface to new solvers. -namespace lemon { - - ///A skeleton class to implement LP/MIP solver base interface - - ///This class does nothing, but it can serve as a skeleton when - ///implementing an interface to new solvers. - class SkeletonSolverBase : public virtual LpBase { - int col_num,row_num; - - protected: - - SkeletonSolverBase() - : col_num(-1), row_num(-1) {} - - /// \e - virtual int _addCol(); - /// \e - virtual int _addRow(); - /// \e - virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); - /// \e - virtual void _eraseCol(int i); - /// \e - virtual void _eraseRow(int i); - - /// \e - virtual void _getColName(int col, std::string& name) const; - /// \e - virtual void _setColName(int col, const std::string& name); - /// \e - virtual int _colByName(const std::string& name) const; - - /// \e - virtual void _getRowName(int row, std::string& name) const; - /// \e - virtual void _setRowName(int row, const std::string& name); - /// \e - virtual int _rowByName(const std::string& name) const; - - /// \e - virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); - /// \e - virtual void _getRowCoeffs(int i, InsertIterator b) const; - /// \e - virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); - /// \e - virtual void _getColCoeffs(int i, InsertIterator b) const; - - /// Set one element of the coefficient matrix - virtual void _setCoeff(int row, int col, Value value); - - /// Get one element of the coefficient matrix - virtual Value _getCoeff(int row, int col) const; - - /// The lower bound of a variable (column) have to be given by an - /// extended number of type Value, i.e. a finite number of type - /// Value or -\ref INF. - virtual void _setColLowerBound(int i, Value value); - /// \e - - /// The lower bound of a variable (column) is an - /// extended number of type Value, i.e. a finite number of type - /// Value or -\ref INF. - virtual Value _getColLowerBound(int i) const; - - /// The upper bound of a variable (column) have to be given by an - /// extended number of type Value, i.e. a finite number of type - /// Value or \ref INF. - virtual void _setColUpperBound(int i, Value value); - /// \e - - /// The upper bound of a variable (column) is an - /// extended number of type Value, i.e. a finite number of type - /// Value or \ref INF. - virtual Value _getColUpperBound(int i) const; - - /// The lower bound of a constraint (row) have to be given by an - /// extended number of type Value, i.e. a finite number of type - /// Value or -\ref INF. - virtual void _setRowLowerBound(int i, Value value); - /// \e - - /// The lower bound of a constraint (row) is an - /// extended number of type Value, i.e. a finite number of type - /// Value or -\ref INF. - virtual Value _getRowLowerBound(int i) const; - - /// The upper bound of a constraint (row) have to be given by an - /// extended number of type Value, i.e. a finite number of type - /// Value or \ref INF. - virtual void _setRowUpperBound(int i, Value value); - /// \e - - /// The upper bound of a constraint (row) is an - /// extended number of type Value, i.e. a finite number of type - /// Value or \ref INF. - virtual Value _getRowUpperBound(int i) const; - - /// \e - virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); - /// \e - virtual void _getObjCoeffs(InsertIterator b) const; - - /// \e - virtual void _setObjCoeff(int i, Value obj_coef); - /// \e - virtual Value _getObjCoeff(int i) const; - - ///\e - virtual void _setSense(Sense); - ///\e - virtual Sense _getSense() const; - - ///\e - virtual void _clear(); - - ///\e - virtual void _messageLevel(MessageLevel); - - ///\e - virtual void _write(std::string file, std::string format) const; - - }; - - /// \brief Skeleton class for an LP solver interface - /// - ///This class does nothing, but it can serve as a skeleton when - ///implementing an interface to new solvers. - - ///\ingroup lp_group - class LpSkeleton : public LpSolver, public SkeletonSolverBase { - public: - ///\e - LpSkeleton() : LpSolver(), SkeletonSolverBase() {} - ///\e - virtual LpSkeleton* newSolver() const; - ///\e - virtual LpSkeleton* cloneSolver() const; - protected: - - ///\e - virtual SolveExitStatus _solve(); - - ///\e - virtual Value _getPrimal(int i) const; - ///\e - virtual Value _getDual(int i) const; - - ///\e - virtual Value _getPrimalValue() const; - - ///\e - virtual Value _getPrimalRay(int i) const; - ///\e - virtual Value _getDualRay(int i) const; - - ///\e - virtual ProblemType _getPrimalType() const; - ///\e - virtual ProblemType _getDualType() const; - - ///\e - virtual VarStatus _getColStatus(int i) const; - ///\e - virtual VarStatus _getRowStatus(int i) const; - - ///\e - virtual const char* _solverName() const; - - }; - - /// \brief Skeleton class for a MIP solver interface - /// - ///This class does nothing, but it can serve as a skeleton when - ///implementing an interface to new solvers. - ///\ingroup lp_group - class MipSkeleton : public MipSolver, public SkeletonSolverBase { - public: - ///\e - MipSkeleton() : MipSolver(), SkeletonSolverBase() {} - ///\e - virtual MipSkeleton* newSolver() const; - ///\e - virtual MipSkeleton* cloneSolver() const; - - protected: - ///\e - virtual SolveExitStatus _solve(); - - ///\e - virtual Value _getSol(int i) const; - - ///\e - virtual Value _getSolValue() const; - - ///\e - virtual ProblemType _getType() const; - - ///\e - virtual const char* _solverName() const; - - }; - -} //namespace lemon - -#endif diff --git a/deps/lemon/lemon/maps.h b/deps/lemon/lemon/maps.h deleted file mode 100644 index 1bc49e911..000000000 --- a/deps/lemon/lemon/maps.h +++ /dev/null @@ -1,4057 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_MAPS_H -#define LEMON_MAPS_H - -#include -#include -#include -#include - -#include - -///\file -///\ingroup maps -///\brief Miscellaneous property maps - -namespace lemon { - - /// \addtogroup maps - /// @{ - - /// Base class of maps. - - /// Base class of maps. It provides the necessary type definitions - /// required by the map %concepts. - template - class MapBase { - public: - /// \brief The key type of the map. - typedef K Key; - /// \brief The value type of the map. - /// (The type of objects associated with the keys). - typedef V Value; - }; - - - /// Null map. (a.k.a. DoNothingMap) - - /// This map can be used if you have to provide a map only for - /// its type definitions, or if you have to provide a writable map, - /// but data written to it is not required (i.e. it will be sent to - /// /dev/null). - /// It conforms to the \ref concepts::ReadWriteMap "ReadWriteMap" concept. - /// - /// \sa ConstMap - template - class NullMap : public MapBase { - public: - ///\e - typedef K Key; - ///\e - typedef V Value; - - /// Gives back a default constructed element. - Value operator[](const Key&) const { return Value(); } - /// Absorbs the value. - void set(const Key&, const Value&) {} - }; - - /// Returns a \c NullMap class - - /// This function just returns a \c NullMap class. - /// \relates NullMap - template - NullMap nullMap() { - return NullMap(); - } - - - /// Constant map. - - /// This \ref concepts::ReadMap "readable map" assigns a specified - /// value to each key. - /// - /// In other aspects it is equivalent to \c NullMap. - /// So it conforms to the \ref concepts::ReadWriteMap "ReadWriteMap" - /// concept, but it absorbs the data written to it. - /// - /// The simplest way of using this map is through the constMap() - /// function. - /// - /// \sa NullMap - /// \sa IdentityMap - template - class ConstMap : public MapBase { - private: - V _value; - public: - ///\e - typedef K Key; - ///\e - typedef V Value; - - /// Default constructor - - /// Default constructor. - /// The value of the map will be default constructed. - ConstMap() {} - - /// Constructor with specified initial value - - /// Constructor with specified initial value. - /// \param v The initial value of the map. - ConstMap(const Value &v) : _value(v) {} - - /// Gives back the specified value. - Value operator[](const Key&) const { return _value; } - - /// Absorbs the value. - void set(const Key&, const Value&) {} - - /// Sets the value that is assigned to each key. - void setAll(const Value &v) { - _value = v; - } - - template - ConstMap(const ConstMap &, const Value &v) : _value(v) {} - }; - - /// Returns a \c ConstMap class - - /// This function just returns a \c ConstMap class. - /// \relates ConstMap - template - inline ConstMap constMap(const V &v) { - return ConstMap(v); - } - - template - inline ConstMap constMap() { - return ConstMap(); - } - - - template - struct Const {}; - - /// Constant map with inlined constant value. - - /// This \ref concepts::ReadMap "readable map" assigns a specified - /// value to each key. - /// - /// In other aspects it is equivalent to \c NullMap. - /// So it conforms to the \ref concepts::ReadWriteMap "ReadWriteMap" - /// concept, but it absorbs the data written to it. - /// - /// The simplest way of using this map is through the constMap() - /// function. - /// - /// \sa NullMap - /// \sa IdentityMap - template - class ConstMap > : public MapBase { - public: - ///\e - typedef K Key; - ///\e - typedef V Value; - - /// Constructor. - ConstMap() {} - - /// Gives back the specified value. - Value operator[](const Key&) const { return v; } - - /// Absorbs the value. - void set(const Key&, const Value&) {} - }; - - /// Returns a \c ConstMap class with inlined constant value - - /// This function just returns a \c ConstMap class with inlined - /// constant value. - /// \relates ConstMap - template - inline ConstMap > constMap() { - return ConstMap >(); - } - - - /// Identity map. - - /// This \ref concepts::ReadMap "read-only map" gives back the given - /// key as value without any modification. - /// - /// \sa ConstMap - template - class IdentityMap : public MapBase { - public: - ///\e - typedef T Key; - ///\e - typedef T Value; - - /// Gives back the given value without any modification. - Value operator[](const Key &k) const { - return k; - } - }; - - /// Returns an \c IdentityMap class - - /// This function just returns an \c IdentityMap class. - /// \relates IdentityMap - template - inline IdentityMap identityMap() { - return IdentityMap(); - } - - - /// \brief Map for storing values for integer keys from the range - /// [0..size-1]. - /// - /// This map is essentially a wrapper for \c std::vector. It assigns - /// values to integer keys from the range [0..size-1]. - /// It can be used together with some data structures, e.g. - /// heap types and \c UnionFind, when the used items are small - /// integers. This map conforms to the \ref concepts::ReferenceMap - /// "ReferenceMap" concept. - /// - /// The simplest way of using this map is through the rangeMap() - /// function. - template - class RangeMap : public MapBase { - template - friend class RangeMap; - private: - - typedef std::vector Vector; - Vector _vector; - - public: - - /// Key type - typedef int Key; - /// Value type - typedef V Value; - /// Reference type - typedef typename Vector::reference Reference; - /// Const reference type - typedef typename Vector::const_reference ConstReference; - - typedef True ReferenceMapTag; - - public: - - /// Constructor with specified default value. - RangeMap(int size = 0, const Value &value = Value()) - : _vector(size, value) {} - - /// Constructs the map from an appropriate \c std::vector. - template - RangeMap(const std::vector& vector) - : _vector(vector.begin(), vector.end()) {} - - /// Constructs the map from another \c RangeMap. - template - RangeMap(const RangeMap &c) - : _vector(c._vector.begin(), c._vector.end()) {} - - /// Returns the size of the map. - int size() { - return _vector.size(); - } - - /// Resizes the map. - - /// Resizes the underlying \c std::vector container, so changes the - /// keyset of the map. - /// \param size The new size of the map. The new keyset will be the - /// range [0..size-1]. - /// \param value The default value to assign to the new keys. - void resize(int size, const Value &value = Value()) { - _vector.resize(size, value); - } - - private: - - RangeMap& operator=(const RangeMap&); - - public: - - ///\e - Reference operator[](const Key &k) { - return _vector[k]; - } - - ///\e - ConstReference operator[](const Key &k) const { - return _vector[k]; - } - - ///\e - void set(const Key &k, const Value &v) { - _vector[k] = v; - } - }; - - /// Returns a \c RangeMap class - - /// This function just returns a \c RangeMap class. - /// \relates RangeMap - template - inline RangeMap rangeMap(int size = 0, const V &value = V()) { - return RangeMap(size, value); - } - - /// \brief Returns a \c RangeMap class created from an appropriate - /// \c std::vector - - /// This function just returns a \c RangeMap class created from an - /// appropriate \c std::vector. - /// \relates RangeMap - template - inline RangeMap rangeMap(const std::vector &vector) { - return RangeMap(vector); - } - - - /// Map type based on \c std::map - - /// This map is essentially a wrapper for \c std::map with addition - /// that you can specify a default value for the keys that are not - /// stored actually. This value can be different from the default - /// contructed value (i.e. \c %Value()). - /// This type conforms to the \ref concepts::ReferenceMap "ReferenceMap" - /// concept. - /// - /// This map is useful if a default value should be assigned to most of - /// the keys and different values should be assigned only to a few - /// keys (i.e. the map is "sparse"). - /// The name of this type also refers to this important usage. - /// - /// Apart form that, this map can be used in many other cases since it - /// is based on \c std::map, which is a general associative container. - /// However, keep in mind that it is usually not as efficient as other - /// maps. - /// - /// The simplest way of using this map is through the sparseMap() - /// function. - template > - class SparseMap : public MapBase { - template - friend class SparseMap; - public: - - /// Key type - typedef K Key; - /// Value type - typedef V Value; - /// Reference type - typedef Value& Reference; - /// Const reference type - typedef const Value& ConstReference; - - typedef True ReferenceMapTag; - - private: - - typedef std::map Map; - Map _map; - Value _value; - - public: - - /// \brief Constructor with specified default value. - SparseMap(const Value &value = Value()) : _value(value) {} - /// \brief Constructs the map from an appropriate \c std::map, and - /// explicitly specifies a default value. - template - SparseMap(const std::map &map, - const Value &value = Value()) - : _map(map.begin(), map.end()), _value(value) {} - - /// \brief Constructs the map from another \c SparseMap. - template - SparseMap(const SparseMap &c) - : _map(c._map.begin(), c._map.end()), _value(c._value) {} - - private: - - SparseMap& operator=(const SparseMap&); - - public: - - ///\e - Reference operator[](const Key &k) { - typename Map::iterator it = _map.lower_bound(k); - if (it != _map.end() && !_map.key_comp()(k, it->first)) - return it->second; - else - return _map.insert(it, std::make_pair(k, _value))->second; - } - - ///\e - ConstReference operator[](const Key &k) const { - typename Map::const_iterator it = _map.find(k); - if (it != _map.end()) - return it->second; - else - return _value; - } - - ///\e - void set(const Key &k, const Value &v) { - typename Map::iterator it = _map.lower_bound(k); - if (it != _map.end() && !_map.key_comp()(k, it->first)) - it->second = v; - else - _map.insert(it, std::make_pair(k, v)); - } - - ///\e - void setAll(const Value &v) { - _value = v; - _map.clear(); - } - }; - - /// Returns a \c SparseMap class - - /// This function just returns a \c SparseMap class with specified - /// default value. - /// \relates SparseMap - template - inline SparseMap sparseMap(const V& value = V()) { - return SparseMap(value); - } - - template - inline SparseMap > sparseMap(const V& value = V()) { - return SparseMap >(value); - } - - /// \brief Returns a \c SparseMap class created from an appropriate - /// \c std::map - - /// This function just returns a \c SparseMap class created from an - /// appropriate \c std::map. - /// \relates SparseMap - template - inline SparseMap - sparseMap(const std::map &map, const V& value = V()) - { - return SparseMap(map, value); - } - - /// @} - - /// \addtogroup map_adaptors - /// @{ - - /// Composition of two maps - - /// This \ref concepts::ReadMap "read-only map" returns the - /// composition of two given maps. That is to say, if \c m1 is of - /// type \c M1 and \c m2 is of \c M2, then for - /// \code - /// ComposeMap cm(m1,m2); - /// \endcode - /// cm[x] will be equal to m1[m2[x]]. - /// - /// The \c Key type of the map is inherited from \c M2 and the - /// \c Value type is from \c M1. - /// \c M2::Value must be convertible to \c M1::Key. - /// - /// The simplest way of using this map is through the composeMap() - /// function. - /// - /// \sa CombineMap - template - class ComposeMap : public MapBase { - const M1 &_m1; - const M2 &_m2; - public: - ///\e - typedef typename M2::Key Key; - ///\e - typedef typename M1::Value Value; - - /// Constructor - ComposeMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} - - ///\e - typename MapTraits::ConstReturnValue - operator[](const Key &k) const { return _m1[_m2[k]]; } - }; - - /// Returns a \c ComposeMap class - - /// This function just returns a \c ComposeMap class. - /// - /// If \c m1 and \c m2 are maps and the \c Value type of \c m2 is - /// convertible to the \c Key of \c m1, then composeMap(m1,m2)[x] - /// will be equal to m1[m2[x]]. - /// - /// \relates ComposeMap - template - inline ComposeMap composeMap(const M1 &m1, const M2 &m2) { - return ComposeMap(m1, m2); - } - - - /// Combination of two maps using an STL (binary) functor. - - /// This \ref concepts::ReadMap "read-only map" takes two maps and a - /// binary functor and returns the combination of the two given maps - /// using the functor. - /// That is to say, if \c m1 is of type \c M1 and \c m2 is of \c M2 - /// and \c f is of \c F, then for - /// \code - /// CombineMap cm(m1,m2,f); - /// \endcode - /// cm[x] will be equal to f(m1[x],m2[x]). - /// - /// The \c Key type of the map is inherited from \c M1 (\c M1::Key - /// must be convertible to \c M2::Key) and the \c Value type is \c V. - /// \c M2::Value and \c M1::Value must be convertible to the - /// corresponding input parameter of \c F and the return type of \c F - /// must be convertible to \c V. - /// - /// The simplest way of using this map is through the combineMap() - /// function. - /// - /// \sa ComposeMap - template - class CombineMap : public MapBase { - const M1 &_m1; - const M2 &_m2; - F _f; - public: - ///\e - typedef typename M1::Key Key; - ///\e - typedef V Value; - - /// Constructor - CombineMap(const M1 &m1, const M2 &m2, const F &f = F()) - : _m1(m1), _m2(m2), _f(f) {} - ///\e - Value operator[](const Key &k) const { return _f(_m1[k],_m2[k]); } - }; - - /// Returns a \c CombineMap class - - /// This function just returns a \c CombineMap class. - /// - /// For example, if \c m1 and \c m2 are both maps with \c double - /// values, then - /// \code - /// combineMap(m1,m2,std::plus()) - /// \endcode - /// is equivalent to - /// \code - /// addMap(m1,m2) - /// \endcode - /// - /// This function is specialized for adaptable binary function - /// classes and C++ functions. - /// - /// \relates CombineMap - template - inline CombineMap - combineMap(const M1 &m1, const M2 &m2, const F &f) { - return CombineMap(m1,m2,f); - } - - template - inline CombineMap - combineMap(const M1 &m1, const M2 &m2, const F &f) { - return combineMap(m1,m2,f); - } - - template - inline CombineMap - combineMap(const M1 &m1, const M2 &m2, V (*f)(K1, K2)) { - return combineMap(m1,m2,f); - } - - - /// Converts an STL style (unary) functor to a map - - /// This \ref concepts::ReadMap "read-only map" returns the value - /// of a given functor. Actually, it just wraps the functor and - /// provides the \c Key and \c Value typedefs. - /// - /// Template parameters \c K and \c V will become its \c Key and - /// \c Value. In most cases they have to be given explicitly because - /// a functor typically does not provide \c argument_type and - /// \c result_type typedefs. - /// Parameter \c F is the type of the used functor. - /// - /// The simplest way of using this map is through the functorToMap() - /// function. - /// - /// \sa MapToFunctor - template - class FunctorToMap : public MapBase { - F _f; - public: - ///\e - typedef K Key; - ///\e - typedef V Value; - - /// Constructor - FunctorToMap(const F &f = F()) : _f(f) {} - ///\e - Value operator[](const Key &k) const { return _f(k); } - }; - - /// Returns a \c FunctorToMap class - - /// This function just returns a \c FunctorToMap class. - /// - /// This function is specialized for adaptable binary function - /// classes and C++ functions. - /// - /// \relates FunctorToMap - template - inline FunctorToMap functorToMap(const F &f) { - return FunctorToMap(f); - } - - template - inline FunctorToMap - functorToMap(const F &f) - { - return FunctorToMap(f); - } - - template - inline FunctorToMap functorToMap(V (*f)(K)) { - return FunctorToMap(f); - } - - - /// Converts a map to an STL style (unary) functor - - /// This class converts a map to an STL style (unary) functor. - /// That is it provides an operator() to read its values. - /// - /// For the sake of convenience it also works as a usual - /// \ref concepts::ReadMap "readable map", i.e. operator[] - /// and the \c Key and \c Value typedefs also exist. - /// - /// The simplest way of using this map is through the mapToFunctor() - /// function. - /// - ///\sa FunctorToMap - template - class MapToFunctor : public MapBase { - const M &_m; - public: - ///\e - typedef typename M::Key Key; - ///\e - typedef typename M::Value Value; - - typedef typename M::Key argument_type; - typedef typename M::Value result_type; - - /// Constructor - MapToFunctor(const M &m) : _m(m) {} - ///\e - Value operator()(const Key &k) const { return _m[k]; } - ///\e - Value operator[](const Key &k) const { return _m[k]; } - }; - - /// Returns a \c MapToFunctor class - - /// This function just returns a \c MapToFunctor class. - /// \relates MapToFunctor - template - inline MapToFunctor mapToFunctor(const M &m) { - return MapToFunctor(m); - } - - - /// \brief Map adaptor to convert the \c Value type of a map to - /// another type using the default conversion. - - /// Map adaptor to convert the \c Value type of a \ref concepts::ReadMap - /// "readable map" to another type using the default conversion. - /// The \c Key type of it is inherited from \c M and the \c Value - /// type is \c V. - /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept. - /// - /// The simplest way of using this map is through the convertMap() - /// function. - template - class ConvertMap : public MapBase { - const M &_m; - public: - ///\e - typedef typename M::Key Key; - ///\e - typedef V Value; - - /// Constructor - - /// Constructor. - /// \param m The underlying map. - ConvertMap(const M &m) : _m(m) {} - - ///\e - Value operator[](const Key &k) const { return _m[k]; } - }; - - /// Returns a \c ConvertMap class - - /// This function just returns a \c ConvertMap class. - /// \relates ConvertMap - template - inline ConvertMap convertMap(const M &map) { - return ConvertMap(map); - } - - - /// Applies all map setting operations to two maps - - /// This map has two \ref concepts::WriteMap "writable map" parameters - /// and each write request will be passed to both of them. - /// If \c M1 is also \ref concepts::ReadMap "readable", then the read - /// operations will return the corresponding values of \c M1. - /// - /// The \c Key and \c Value types are inherited from \c M1. - /// The \c Key and \c Value of \c M2 must be convertible from those - /// of \c M1. - /// - /// The simplest way of using this map is through the forkMap() - /// function. - template - class ForkMap : public MapBase { - M1 &_m1; - M2 &_m2; - public: - ///\e - typedef typename M1::Key Key; - ///\e - typedef typename M1::Value Value; - - /// Constructor - ForkMap(M1 &m1, M2 &m2) : _m1(m1), _m2(m2) {} - /// Returns the value associated with the given key in the first map. - Value operator[](const Key &k) const { return _m1[k]; } - /// Sets the value associated with the given key in both maps. - void set(const Key &k, const Value &v) { _m1.set(k,v); _m2.set(k,v); } - }; - - /// Returns a \c ForkMap class - - /// This function just returns a \c ForkMap class. - /// \relates ForkMap - template - inline ForkMap forkMap(M1 &m1, M2 &m2) { - return ForkMap(m1,m2); - } - - - /// Sum of two maps - - /// This \ref concepts::ReadMap "read-only map" returns the sum - /// of the values of the two given maps. - /// Its \c Key and \c Value types are inherited from \c M1. - /// The \c Key and \c Value of \c M2 must be convertible to those of - /// \c M1. - /// - /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for - /// \code - /// AddMap am(m1,m2); - /// \endcode - /// am[x] will be equal to m1[x]+m2[x]. - /// - /// The simplest way of using this map is through the addMap() - /// function. - /// - /// \sa SubMap, MulMap, DivMap - /// \sa ShiftMap, ShiftWriteMap - template - class AddMap : public MapBase { - const M1 &_m1; - const M2 &_m2; - public: - ///\e - typedef typename M1::Key Key; - ///\e - typedef typename M1::Value Value; - - /// Constructor - AddMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} - ///\e - Value operator[](const Key &k) const { return _m1[k]+_m2[k]; } - }; - - /// Returns an \c AddMap class - - /// This function just returns an \c AddMap class. - /// - /// For example, if \c m1 and \c m2 are both maps with \c double - /// values, then addMap(m1,m2)[x] will be equal to - /// m1[x]+m2[x]. - /// - /// \relates AddMap - template - inline AddMap addMap(const M1 &m1, const M2 &m2) { - return AddMap(m1,m2); - } - - - /// Difference of two maps - - /// This \ref concepts::ReadMap "read-only map" returns the difference - /// of the values of the two given maps. - /// Its \c Key and \c Value types are inherited from \c M1. - /// The \c Key and \c Value of \c M2 must be convertible to those of - /// \c M1. - /// - /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for - /// \code - /// SubMap sm(m1,m2); - /// \endcode - /// sm[x] will be equal to m1[x]-m2[x]. - /// - /// The simplest way of using this map is through the subMap() - /// function. - /// - /// \sa AddMap, MulMap, DivMap - template - class SubMap : public MapBase { - const M1 &_m1; - const M2 &_m2; - public: - ///\e - typedef typename M1::Key Key; - ///\e - typedef typename M1::Value Value; - - /// Constructor - SubMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} - ///\e - Value operator[](const Key &k) const { return _m1[k]-_m2[k]; } - }; - - /// Returns a \c SubMap class - - /// This function just returns a \c SubMap class. - /// - /// For example, if \c m1 and \c m2 are both maps with \c double - /// values, then subMap(m1,m2)[x] will be equal to - /// m1[x]-m2[x]. - /// - /// \relates SubMap - template - inline SubMap subMap(const M1 &m1, const M2 &m2) { - return SubMap(m1,m2); - } - - - /// Product of two maps - - /// This \ref concepts::ReadMap "read-only map" returns the product - /// of the values of the two given maps. - /// Its \c Key and \c Value types are inherited from \c M1. - /// The \c Key and \c Value of \c M2 must be convertible to those of - /// \c M1. - /// - /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for - /// \code - /// MulMap mm(m1,m2); - /// \endcode - /// mm[x] will be equal to m1[x]*m2[x]. - /// - /// The simplest way of using this map is through the mulMap() - /// function. - /// - /// \sa AddMap, SubMap, DivMap - /// \sa ScaleMap, ScaleWriteMap - template - class MulMap : public MapBase { - const M1 &_m1; - const M2 &_m2; - public: - ///\e - typedef typename M1::Key Key; - ///\e - typedef typename M1::Value Value; - - /// Constructor - MulMap(const M1 &m1,const M2 &m2) : _m1(m1), _m2(m2) {} - ///\e - Value operator[](const Key &k) const { return _m1[k]*_m2[k]; } - }; - - /// Returns a \c MulMap class - - /// This function just returns a \c MulMap class. - /// - /// For example, if \c m1 and \c m2 are both maps with \c double - /// values, then mulMap(m1,m2)[x] will be equal to - /// m1[x]*m2[x]. - /// - /// \relates MulMap - template - inline MulMap mulMap(const M1 &m1,const M2 &m2) { - return MulMap(m1,m2); - } - - - /// Quotient of two maps - - /// This \ref concepts::ReadMap "read-only map" returns the quotient - /// of the values of the two given maps. - /// Its \c Key and \c Value types are inherited from \c M1. - /// The \c Key and \c Value of \c M2 must be convertible to those of - /// \c M1. - /// - /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for - /// \code - /// DivMap dm(m1,m2); - /// \endcode - /// dm[x] will be equal to m1[x]/m2[x]. - /// - /// The simplest way of using this map is through the divMap() - /// function. - /// - /// \sa AddMap, SubMap, MulMap - template - class DivMap : public MapBase { - const M1 &_m1; - const M2 &_m2; - public: - ///\e - typedef typename M1::Key Key; - ///\e - typedef typename M1::Value Value; - - /// Constructor - DivMap(const M1 &m1,const M2 &m2) : _m1(m1), _m2(m2) {} - ///\e - Value operator[](const Key &k) const { return _m1[k]/_m2[k]; } - }; - - /// Returns a \c DivMap class - - /// This function just returns a \c DivMap class. - /// - /// For example, if \c m1 and \c m2 are both maps with \c double - /// values, then divMap(m1,m2)[x] will be equal to - /// m1[x]/m2[x]. - /// - /// \relates DivMap - template - inline DivMap divMap(const M1 &m1,const M2 &m2) { - return DivMap(m1,m2); - } - - - /// Shifts a map with a constant. - - /// This \ref concepts::ReadMap "read-only map" returns the sum of - /// the given map and a constant value (i.e. it shifts the map with - /// the constant). Its \c Key and \c Value are inherited from \c M. - /// - /// Actually, - /// \code - /// ShiftMap sh(m,v); - /// \endcode - /// is equivalent to - /// \code - /// ConstMap cm(v); - /// AddMap > sh(m,cm); - /// \endcode - /// - /// The simplest way of using this map is through the shiftMap() - /// function. - /// - /// \sa ShiftWriteMap - template - class ShiftMap : public MapBase { - const M &_m; - C _v; - public: - ///\e - typedef typename M::Key Key; - ///\e - typedef typename M::Value Value; - - /// Constructor - - /// Constructor. - /// \param m The undelying map. - /// \param v The constant value. - ShiftMap(const M &m, const C &v) : _m(m), _v(v) {} - ///\e - Value operator[](const Key &k) const { return _m[k]+_v; } - }; - - /// Shifts a map with a constant (read-write version). - - /// This \ref concepts::ReadWriteMap "read-write map" returns the sum - /// of the given map and a constant value (i.e. it shifts the map with - /// the constant). Its \c Key and \c Value are inherited from \c M. - /// It makes also possible to write the map. - /// - /// The simplest way of using this map is through the shiftWriteMap() - /// function. - /// - /// \sa ShiftMap - template - class ShiftWriteMap : public MapBase { - M &_m; - C _v; - public: - ///\e - typedef typename M::Key Key; - ///\e - typedef typename M::Value Value; - - /// Constructor - - /// Constructor. - /// \param m The undelying map. - /// \param v The constant value. - ShiftWriteMap(M &m, const C &v) : _m(m), _v(v) {} - ///\e - Value operator[](const Key &k) const { return _m[k]+_v; } - ///\e - void set(const Key &k, const Value &v) { _m.set(k, v-_v); } - }; - - /// Returns a \c ShiftMap class - - /// This function just returns a \c ShiftMap class. - /// - /// For example, if \c m is a map with \c double values and \c v is - /// \c double, then shiftMap(m,v)[x] will be equal to - /// m[x]+v. - /// - /// \relates ShiftMap - template - inline ShiftMap shiftMap(const M &m, const C &v) { - return ShiftMap(m,v); - } - - /// Returns a \c ShiftWriteMap class - - /// This function just returns a \c ShiftWriteMap class. - /// - /// For example, if \c m is a map with \c double values and \c v is - /// \c double, then shiftWriteMap(m,v)[x] will be equal to - /// m[x]+v. - /// Moreover it makes also possible to write the map. - /// - /// \relates ShiftWriteMap - template - inline ShiftWriteMap shiftWriteMap(M &m, const C &v) { - return ShiftWriteMap(m,v); - } - - - /// Scales a map with a constant. - - /// This \ref concepts::ReadMap "read-only map" returns the value of - /// the given map multiplied from the left side with a constant value. - /// Its \c Key and \c Value are inherited from \c M. - /// - /// Actually, - /// \code - /// ScaleMap sc(m,v); - /// \endcode - /// is equivalent to - /// \code - /// ConstMap cm(v); - /// MulMap, M> sc(cm,m); - /// \endcode - /// - /// The simplest way of using this map is through the scaleMap() - /// function. - /// - /// \sa ScaleWriteMap - template - class ScaleMap : public MapBase { - const M &_m; - C _v; - public: - ///\e - typedef typename M::Key Key; - ///\e - typedef typename M::Value Value; - - /// Constructor - - /// Constructor. - /// \param m The undelying map. - /// \param v The constant value. - ScaleMap(const M &m, const C &v) : _m(m), _v(v) {} - ///\e - Value operator[](const Key &k) const { return _v*_m[k]; } - }; - - /// Scales a map with a constant (read-write version). - - /// This \ref concepts::ReadWriteMap "read-write map" returns the value of - /// the given map multiplied from the left side with a constant value. - /// Its \c Key and \c Value are inherited from \c M. - /// It can also be used as write map if the \c / operator is defined - /// between \c Value and \c C and the given multiplier is not zero. - /// - /// The simplest way of using this map is through the scaleWriteMap() - /// function. - /// - /// \sa ScaleMap - template - class ScaleWriteMap : public MapBase { - M &_m; - C _v; - public: - ///\e - typedef typename M::Key Key; - ///\e - typedef typename M::Value Value; - - /// Constructor - - /// Constructor. - /// \param m The undelying map. - /// \param v The constant value. - ScaleWriteMap(M &m, const C &v) : _m(m), _v(v) {} - ///\e - Value operator[](const Key &k) const { return _v*_m[k]; } - ///\e - void set(const Key &k, const Value &v) { _m.set(k, v/_v); } - }; - - /// Returns a \c ScaleMap class - - /// This function just returns a \c ScaleMap class. - /// - /// For example, if \c m is a map with \c double values and \c v is - /// \c double, then scaleMap(m,v)[x] will be equal to - /// v*m[x]. - /// - /// \relates ScaleMap - template - inline ScaleMap scaleMap(const M &m, const C &v) { - return ScaleMap(m,v); - } - - /// Returns a \c ScaleWriteMap class - - /// This function just returns a \c ScaleWriteMap class. - /// - /// For example, if \c m is a map with \c double values and \c v is - /// \c double, then scaleWriteMap(m,v)[x] will be equal to - /// v*m[x]. - /// Moreover it makes also possible to write the map. - /// - /// \relates ScaleWriteMap - template - inline ScaleWriteMap scaleWriteMap(M &m, const C &v) { - return ScaleWriteMap(m,v); - } - - - /// Negative of a map - - /// This \ref concepts::ReadMap "read-only map" returns the negative - /// of the values of the given map (using the unary \c - operator). - /// Its \c Key and \c Value are inherited from \c M. - /// - /// If M::Value is \c int, \c double etc., then - /// \code - /// NegMap neg(m); - /// \endcode - /// is equivalent to - /// \code - /// ScaleMap neg(m,-1); - /// \endcode - /// - /// The simplest way of using this map is through the negMap() - /// function. - /// - /// \sa NegWriteMap - template - class NegMap : public MapBase { - const M& _m; - public: - ///\e - typedef typename M::Key Key; - ///\e - typedef typename M::Value Value; - - /// Constructor - NegMap(const M &m) : _m(m) {} - ///\e - Value operator[](const Key &k) const { return -_m[k]; } - }; - - /// Negative of a map (read-write version) - - /// This \ref concepts::ReadWriteMap "read-write map" returns the - /// negative of the values of the given map (using the unary \c - - /// operator). - /// Its \c Key and \c Value are inherited from \c M. - /// It makes also possible to write the map. - /// - /// If M::Value is \c int, \c double etc., then - /// \code - /// NegWriteMap neg(m); - /// \endcode - /// is equivalent to - /// \code - /// ScaleWriteMap neg(m,-1); - /// \endcode - /// - /// The simplest way of using this map is through the negWriteMap() - /// function. - /// - /// \sa NegMap - template - class NegWriteMap : public MapBase { - M &_m; - public: - ///\e - typedef typename M::Key Key; - ///\e - typedef typename M::Value Value; - - /// Constructor - NegWriteMap(M &m) : _m(m) {} - ///\e - Value operator[](const Key &k) const { return -_m[k]; } - ///\e - void set(const Key &k, const Value &v) { _m.set(k, -v); } - }; - - /// Returns a \c NegMap class - - /// This function just returns a \c NegMap class. - /// - /// For example, if \c m is a map with \c double values, then - /// negMap(m)[x] will be equal to -m[x]. - /// - /// \relates NegMap - template - inline NegMap negMap(const M &m) { - return NegMap(m); - } - - /// Returns a \c NegWriteMap class - - /// This function just returns a \c NegWriteMap class. - /// - /// For example, if \c m is a map with \c double values, then - /// negWriteMap(m)[x] will be equal to -m[x]. - /// Moreover it makes also possible to write the map. - /// - /// \relates NegWriteMap - template - inline NegWriteMap negWriteMap(M &m) { - return NegWriteMap(m); - } - - - /// Absolute value of a map - - /// This \ref concepts::ReadMap "read-only map" returns the absolute - /// value of the values of the given map. - /// Its \c Key and \c Value are inherited from \c M. - /// \c Value must be comparable to \c 0 and the unary \c - - /// operator must be defined for it, of course. - /// - /// The simplest way of using this map is through the absMap() - /// function. - template - class AbsMap : public MapBase { - const M &_m; - public: - ///\e - typedef typename M::Key Key; - ///\e - typedef typename M::Value Value; - - /// Constructor - AbsMap(const M &m) : _m(m) {} - ///\e - Value operator[](const Key &k) const { - Value tmp = _m[k]; - return tmp >= 0 ? tmp : -tmp; - } - - }; - - /// Returns an \c AbsMap class - - /// This function just returns an \c AbsMap class. - /// - /// For example, if \c m is a map with \c double values, then - /// absMap(m)[x] will be equal to m[x] if - /// it is positive or zero and -m[x] if m[x] is - /// negative. - /// - /// \relates AbsMap - template - inline AbsMap absMap(const M &m) { - return AbsMap(m); - } - - /// @} - - // Logical maps and map adaptors: - - /// \addtogroup maps - /// @{ - - /// Constant \c true map. - - /// This \ref concepts::ReadMap "read-only map" assigns \c true to - /// each key. - /// - /// Note that - /// \code - /// TrueMap tm; - /// \endcode - /// is equivalent to - /// \code - /// ConstMap tm(true); - /// \endcode - /// - /// \sa FalseMap - /// \sa ConstMap - template - class TrueMap : public MapBase { - public: - ///\e - typedef K Key; - ///\e - typedef bool Value; - - /// Gives back \c true. - Value operator[](const Key&) const { return true; } - }; - - /// Returns a \c TrueMap class - - /// This function just returns a \c TrueMap class. - /// \relates TrueMap - template - inline TrueMap trueMap() { - return TrueMap(); - } - - - /// Constant \c false map. - - /// This \ref concepts::ReadMap "read-only map" assigns \c false to - /// each key. - /// - /// Note that - /// \code - /// FalseMap fm; - /// \endcode - /// is equivalent to - /// \code - /// ConstMap fm(false); - /// \endcode - /// - /// \sa TrueMap - /// \sa ConstMap - template - class FalseMap : public MapBase { - public: - ///\e - typedef K Key; - ///\e - typedef bool Value; - - /// Gives back \c false. - Value operator[](const Key&) const { return false; } - }; - - /// Returns a \c FalseMap class - - /// This function just returns a \c FalseMap class. - /// \relates FalseMap - template - inline FalseMap falseMap() { - return FalseMap(); - } - - /// @} - - /// \addtogroup map_adaptors - /// @{ - - /// Logical 'and' of two maps - - /// This \ref concepts::ReadMap "read-only map" returns the logical - /// 'and' of the values of the two given maps. - /// Its \c Key type is inherited from \c M1 and its \c Value type is - /// \c bool. \c M2::Key must be convertible to \c M1::Key. - /// - /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for - /// \code - /// AndMap am(m1,m2); - /// \endcode - /// am[x] will be equal to m1[x]&&m2[x]. - /// - /// The simplest way of using this map is through the andMap() - /// function. - /// - /// \sa OrMap - /// \sa NotMap, NotWriteMap - template - class AndMap : public MapBase { - const M1 &_m1; - const M2 &_m2; - public: - ///\e - typedef typename M1::Key Key; - ///\e - typedef bool Value; - - /// Constructor - AndMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} - ///\e - Value operator[](const Key &k) const { return _m1[k]&&_m2[k]; } - }; - - /// Returns an \c AndMap class - - /// This function just returns an \c AndMap class. - /// - /// For example, if \c m1 and \c m2 are both maps with \c bool values, - /// then andMap(m1,m2)[x] will be equal to - /// m1[x]&&m2[x]. - /// - /// \relates AndMap - template - inline AndMap andMap(const M1 &m1, const M2 &m2) { - return AndMap(m1,m2); - } - - - /// Logical 'or' of two maps - - /// This \ref concepts::ReadMap "read-only map" returns the logical - /// 'or' of the values of the two given maps. - /// Its \c Key type is inherited from \c M1 and its \c Value type is - /// \c bool. \c M2::Key must be convertible to \c M1::Key. - /// - /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for - /// \code - /// OrMap om(m1,m2); - /// \endcode - /// om[x] will be equal to m1[x]||m2[x]. - /// - /// The simplest way of using this map is through the orMap() - /// function. - /// - /// \sa AndMap - /// \sa NotMap, NotWriteMap - template - class OrMap : public MapBase { - const M1 &_m1; - const M2 &_m2; - public: - ///\e - typedef typename M1::Key Key; - ///\e - typedef bool Value; - - /// Constructor - OrMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} - ///\e - Value operator[](const Key &k) const { return _m1[k]||_m2[k]; } - }; - - /// Returns an \c OrMap class - - /// This function just returns an \c OrMap class. - /// - /// For example, if \c m1 and \c m2 are both maps with \c bool values, - /// then orMap(m1,m2)[x] will be equal to - /// m1[x]||m2[x]. - /// - /// \relates OrMap - template - inline OrMap orMap(const M1 &m1, const M2 &m2) { - return OrMap(m1,m2); - } - - - /// Logical 'not' of a map - - /// This \ref concepts::ReadMap "read-only map" returns the logical - /// negation of the values of the given map. - /// Its \c Key is inherited from \c M and its \c Value is \c bool. - /// - /// The simplest way of using this map is through the notMap() - /// function. - /// - /// \sa NotWriteMap - template - class NotMap : public MapBase { - const M &_m; - public: - ///\e - typedef typename M::Key Key; - ///\e - typedef bool Value; - - /// Constructor - NotMap(const M &m) : _m(m) {} - ///\e - Value operator[](const Key &k) const { return !_m[k]; } - }; - - /// Logical 'not' of a map (read-write version) - - /// This \ref concepts::ReadWriteMap "read-write map" returns the - /// logical negation of the values of the given map. - /// Its \c Key is inherited from \c M and its \c Value is \c bool. - /// It makes also possible to write the map. When a value is set, - /// the opposite value is set to the original map. - /// - /// The simplest way of using this map is through the notWriteMap() - /// function. - /// - /// \sa NotMap - template - class NotWriteMap : public MapBase { - M &_m; - public: - ///\e - typedef typename M::Key Key; - ///\e - typedef bool Value; - - /// Constructor - NotWriteMap(M &m) : _m(m) {} - ///\e - Value operator[](const Key &k) const { return !_m[k]; } - ///\e - void set(const Key &k, bool v) { _m.set(k, !v); } - }; - - /// Returns a \c NotMap class - - /// This function just returns a \c NotMap class. - /// - /// For example, if \c m is a map with \c bool values, then - /// notMap(m)[x] will be equal to !m[x]. - /// - /// \relates NotMap - template - inline NotMap notMap(const M &m) { - return NotMap(m); - } - - /// Returns a \c NotWriteMap class - - /// This function just returns a \c NotWriteMap class. - /// - /// For example, if \c m is a map with \c bool values, then - /// notWriteMap(m)[x] will be equal to !m[x]. - /// Moreover it makes also possible to write the map. - /// - /// \relates NotWriteMap - template - inline NotWriteMap notWriteMap(M &m) { - return NotWriteMap(m); - } - - - /// Combination of two maps using the \c == operator - - /// This \ref concepts::ReadMap "read-only map" assigns \c true to - /// the keys for which the corresponding values of the two maps are - /// equal. - /// Its \c Key type is inherited from \c M1 and its \c Value type is - /// \c bool. \c M2::Key must be convertible to \c M1::Key. - /// - /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for - /// \code - /// EqualMap em(m1,m2); - /// \endcode - /// em[x] will be equal to m1[x]==m2[x]. - /// - /// The simplest way of using this map is through the equalMap() - /// function. - /// - /// \sa LessMap - template - class EqualMap : public MapBase { - const M1 &_m1; - const M2 &_m2; - public: - ///\e - typedef typename M1::Key Key; - ///\e - typedef bool Value; - - /// Constructor - EqualMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} - ///\e - Value operator[](const Key &k) const { return _m1[k]==_m2[k]; } - }; - - /// Returns an \c EqualMap class - - /// This function just returns an \c EqualMap class. - /// - /// For example, if \c m1 and \c m2 are maps with keys and values of - /// the same type, then equalMap(m1,m2)[x] will be equal to - /// m1[x]==m2[x]. - /// - /// \relates EqualMap - template - inline EqualMap equalMap(const M1 &m1, const M2 &m2) { - return EqualMap(m1,m2); - } - - - /// Combination of two maps using the \c < operator - - /// This \ref concepts::ReadMap "read-only map" assigns \c true to - /// the keys for which the corresponding value of the first map is - /// less then the value of the second map. - /// Its \c Key type is inherited from \c M1 and its \c Value type is - /// \c bool. \c M2::Key must be convertible to \c M1::Key. - /// - /// If \c m1 is of type \c M1 and \c m2 is of \c M2, then for - /// \code - /// LessMap lm(m1,m2); - /// \endcode - /// lm[x] will be equal to m1[x]. - /// - /// The simplest way of using this map is through the lessMap() - /// function. - /// - /// \sa EqualMap - template - class LessMap : public MapBase { - const M1 &_m1; - const M2 &_m2; - public: - ///\e - typedef typename M1::Key Key; - ///\e - typedef bool Value; - - /// Constructor - LessMap(const M1 &m1, const M2 &m2) : _m1(m1), _m2(m2) {} - ///\e - Value operator[](const Key &k) const { return _m1[k]<_m2[k]; } - }; - - /// Returns an \c LessMap class - - /// This function just returns an \c LessMap class. - /// - /// For example, if \c m1 and \c m2 are maps with keys and values of - /// the same type, then lessMap(m1,m2)[x] will be equal to - /// m1[x]. - /// - /// \relates LessMap - template - inline LessMap lessMap(const M1 &m1, const M2 &m2) { - return LessMap(m1,m2); - } - - namespace _maps_bits { - - template - struct IteratorTraits { - typedef typename std::iterator_traits<_Iterator>::value_type Value; - }; - - template - struct IteratorTraits<_Iterator, - typename exists::type> - { - typedef typename _Iterator::container_type::value_type Value; - }; - - } - - /// @} - - /// \addtogroup maps - /// @{ - - /// \brief Writable bool map for logging each \c true assigned element - /// - /// A \ref concepts::WriteMap "writable" bool map for logging - /// each \c true assigned element, i.e it copies subsequently each - /// keys set to \c true to the given iterator. - /// The most important usage of it is storing certain nodes or arcs - /// that were marked \c true by an algorithm. - /// - /// There are several algorithms that provide solutions through bool - /// maps and most of them assign \c true at most once for each key. - /// In these cases it is a natural request to store each \c true - /// assigned elements (in order of the assignment), which can be - /// easily done with LoggerBoolMap. - /// - /// The simplest way of using this map is through the loggerBoolMap() - /// function. - /// - /// \tparam IT The type of the iterator. - /// \tparam KEY The key type of the map. The default value set - /// according to the iterator type should work in most cases. - /// - /// \note The container of the iterator must contain enough space - /// for the elements or the iterator should be an inserter iterator. -#ifdef DOXYGEN - template -#else - template ::Value> -#endif - class LoggerBoolMap : public MapBase { - public: - - ///\e - typedef KEY Key; - ///\e - typedef bool Value; - ///\e - typedef IT Iterator; - - /// Constructor - LoggerBoolMap(Iterator it) - : _begin(it), _end(it) {} - - /// Gives back the given iterator set for the first key - Iterator begin() const { - return _begin; - } - - /// Gives back the the 'after the last' iterator - Iterator end() const { - return _end; - } - - /// The set function of the map - void set(const Key& key, Value value) { - if (value) { - *_end++ = key; - } - } - - private: - Iterator _begin; - Iterator _end; - }; - - /// Returns a \c LoggerBoolMap class - - /// This function just returns a \c LoggerBoolMap class. - /// - /// The most important usage of it is storing certain nodes or arcs - /// that were marked \c true by an algorithm. - /// For example, it makes easier to store the nodes in the processing - /// order of Dfs algorithm, as the following examples show. - /// \code - /// std::vector v; - /// dfs(g).processedMap(loggerBoolMap(std::back_inserter(v))).run(s); - /// \endcode - /// \code - /// std::vector v(countNodes(g)); - /// dfs(g).processedMap(loggerBoolMap(v.begin())).run(s); - /// \endcode - /// - /// \note The container of the iterator must contain enough space - /// for the elements or the iterator should be an inserter iterator. - /// - /// \note LoggerBoolMap is just \ref concepts::WriteMap "writable", so - /// it cannot be used when a readable map is needed, for example, as - /// \c ReachedMap for \c Bfs, \c Dfs and \c Dijkstra algorithms. - /// - /// \relates LoggerBoolMap - template - inline LoggerBoolMap loggerBoolMap(Iterator it) { - return LoggerBoolMap(it); - } - - /// @} - - /// \addtogroup graph_maps - /// @{ - - /// \brief Provides an immutable and unique id for each item in a graph. - /// - /// IdMap provides a unique and immutable id for each item of the - /// same type (\c Node, \c Arc or \c Edge) in a graph. This id is - /// - \b unique: different items get different ids, - /// - \b immutable: the id of an item does not change (even if you - /// delete other nodes). - /// - /// Using this map you get access (i.e. can read) the inner id values of - /// the items stored in the graph, which is returned by the \c id() - /// function of the graph. This map can be inverted with its member - /// class \c InverseMap or with the \c operator()() member. - /// - /// \tparam GR The graph type. - /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or - /// \c GR::Edge). - /// - /// \see RangeIdMap - template - class IdMap : public MapBase { - public: - /// The graph type of IdMap. - typedef GR Graph; - typedef GR Digraph; - /// The key type of IdMap (\c Node, \c Arc or \c Edge). - typedef K Item; - /// The key type of IdMap (\c Node, \c Arc or \c Edge). - typedef K Key; - /// The value type of IdMap. - typedef int Value; - - /// \brief Constructor. - /// - /// Constructor of the map. - explicit IdMap(const Graph& graph) : _graph(&graph) {} - - /// \brief Gives back the \e id of the item. - /// - /// Gives back the immutable and unique \e id of the item. - int operator[](const Item& item) const { return _graph->id(item);} - - /// \brief Gives back the \e item by its id. - /// - /// Gives back the \e item by its id. - Item operator()(int id) { return _graph->fromId(id, Item()); } - - private: - const Graph* _graph; - - public: - - /// \brief The inverse map type of IdMap. - /// - /// The inverse map type of IdMap. The subscript operator gives back - /// an item by its id. - /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept. - /// \see inverse() - class InverseMap { - public: - - /// \brief Constructor. - /// - /// Constructor for creating an id-to-item map. - explicit InverseMap(const Graph& graph) : _graph(&graph) {} - - /// \brief Constructor. - /// - /// Constructor for creating an id-to-item map. - explicit InverseMap(const IdMap& map) : _graph(map._graph) {} - - /// \brief Gives back an item by its id. - /// - /// Gives back an item by its id. - Item operator[](int id) const { return _graph->fromId(id, Item());} - - private: - const Graph* _graph; - }; - - /// \brief Gives back the inverse of the map. - /// - /// Gives back the inverse of the IdMap. - InverseMap inverse() const { return InverseMap(*_graph);} - }; - - /// \brief Returns an \c IdMap class. - /// - /// This function just returns an \c IdMap class. - /// \relates IdMap - template - inline IdMap idMap(const GR& graph) { - return IdMap(graph); - } - - /// \brief General cross reference graph map type. - - /// This class provides simple invertable graph maps. - /// It wraps a standard graph map (\c NodeMap, \c ArcMap or \c EdgeMap) - /// and if a key is set to a new value, then stores it in the inverse map. - /// The graph items can be accessed by their values either using - /// \c InverseMap or \c operator()(), and the values of the map can be - /// accessed with an STL compatible forward iterator (\c ValueIt). - /// - /// This map is intended to be used when all associated values are - /// different (the map is actually invertable) or there are only a few - /// items with the same value. - /// Otherwise consider to use \c IterableValueMap, which is more - /// suitable and more efficient for such cases. It provides iterators - /// to traverse the items with the same associated value, but - /// it does not have \c InverseMap. - /// - /// This type is not reference map, so it cannot be modified with - /// the subscript operator. - /// - /// \tparam GR The graph type. - /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or - /// \c GR::Edge). - /// \tparam V The value type of the map. - /// - /// \see IterableValueMap - template - class CrossRefMap - : protected ItemSetTraits::template Map::Type { - private: - - typedef typename ItemSetTraits:: - template Map::Type Map; - - typedef std::multimap Container; - Container _inv_map; - - public: - - /// The graph type of CrossRefMap. - typedef GR Graph; - typedef GR Digraph; - /// The key type of CrossRefMap (\c Node, \c Arc or \c Edge). - typedef K Item; - /// The key type of CrossRefMap (\c Node, \c Arc or \c Edge). - typedef K Key; - /// The value type of CrossRefMap. - typedef V Value; - - /// \brief Constructor. - /// - /// Construct a new CrossRefMap for the given graph. - explicit CrossRefMap(const Graph& graph) : Map(graph) {} - - /// \brief Forward iterator for values. - /// - /// This iterator is an STL compatible forward - /// iterator on the values of the map. The values can - /// be accessed in the [beginValue, endValue) range. - /// They are considered with multiplicity, so each value is - /// traversed for each item it is assigned to. - class ValueIt - : public std::iterator { - friend class CrossRefMap; - private: - ValueIt(typename Container::const_iterator _it) - : it(_it) {} - public: - - /// Constructor - ValueIt() {} - - /// \e - ValueIt& operator++() { ++it; return *this; } - /// \e - ValueIt operator++(int) { - ValueIt tmp(*this); - operator++(); - return tmp; - } - - /// \e - const Value& operator*() const { return it->first; } - /// \e - const Value* operator->() const { return &(it->first); } - - /// \e - bool operator==(ValueIt jt) const { return it == jt.it; } - /// \e - bool operator!=(ValueIt jt) const { return it != jt.it; } - - private: - typename Container::const_iterator it; - }; - - /// Alias for \c ValueIt - typedef ValueIt ValueIterator; - - /// \brief Returns an iterator to the first value. - /// - /// Returns an STL compatible iterator to the - /// first value of the map. The values of the - /// map can be accessed in the [beginValue, endValue) - /// range. - ValueIt beginValue() const { - return ValueIt(_inv_map.begin()); - } - - /// \brief Returns an iterator after the last value. - /// - /// Returns an STL compatible iterator after the - /// last value of the map. The values of the - /// map can be accessed in the [beginValue, endValue) - /// range. - ValueIt endValue() const { - return ValueIt(_inv_map.end()); - } - - /// \brief Sets the value associated with the given key. - /// - /// Sets the value associated with the given key. - void set(const Key& key, const Value& val) { - Value oldval = Map::operator[](key); - typename Container::iterator it; - for (it = _inv_map.equal_range(oldval).first; - it != _inv_map.equal_range(oldval).second; ++it) { - if (it->second == key) { - _inv_map.erase(it); - break; - } - } - _inv_map.insert(std::make_pair(val, key)); - Map::set(key, val); - } - - /// \brief Returns the value associated with the given key. - /// - /// Returns the value associated with the given key. - typename MapTraits::ConstReturnValue - operator[](const Key& key) const { - return Map::operator[](key); - } - - /// \brief Gives back an item by its value. - /// - /// This function gives back an item that is assigned to - /// the given value or \c INVALID if no such item exists. - /// If there are more items with the same associated value, - /// only one of them is returned. - Key operator()(const Value& val) const { - typename Container::const_iterator it = _inv_map.find(val); - return it != _inv_map.end() ? it->second : INVALID; - } - - /// \brief Returns the number of items with the given value. - /// - /// This function returns the number of items with the given value - /// associated with it. - int count(const Value &val) const { - return _inv_map.count(val); - } - - protected: - - /// \brief Erase the key from the map and the inverse map. - /// - /// Erase the key from the map and the inverse map. It is called by the - /// \c AlterationNotifier. - virtual void erase(const Key& key) { - Value val = Map::operator[](key); - typename Container::iterator it; - for (it = _inv_map.equal_range(val).first; - it != _inv_map.equal_range(val).second; ++it) { - if (it->second == key) { - _inv_map.erase(it); - break; - } - } - Map::erase(key); - } - - /// \brief Erase more keys from the map and the inverse map. - /// - /// Erase more keys from the map and the inverse map. It is called by the - /// \c AlterationNotifier. - virtual void erase(const std::vector& keys) { - for (int i = 0; i < int(keys.size()); ++i) { - Value val = Map::operator[](keys[i]); - typename Container::iterator it; - for (it = _inv_map.equal_range(val).first; - it != _inv_map.equal_range(val).second; ++it) { - if (it->second == keys[i]) { - _inv_map.erase(it); - break; - } - } - } - Map::erase(keys); - } - - /// \brief Clear the keys from the map and the inverse map. - /// - /// Clear the keys from the map and the inverse map. It is called by the - /// \c AlterationNotifier. - virtual void clear() { - _inv_map.clear(); - Map::clear(); - } - - public: - - /// \brief The inverse map type of CrossRefMap. - /// - /// The inverse map type of CrossRefMap. The subscript operator gives - /// back an item by its value. - /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept. - /// \see inverse() - class InverseMap { - public: - /// \brief Constructor - /// - /// Constructor of the InverseMap. - explicit InverseMap(const CrossRefMap& inverted) - : _inverted(inverted) {} - - /// The value type of the InverseMap. - typedef typename CrossRefMap::Key Value; - /// The key type of the InverseMap. - typedef typename CrossRefMap::Value Key; - - /// \brief Subscript operator. - /// - /// Subscript operator. It gives back an item - /// that is assigned to the given value or \c INVALID - /// if no such item exists. - Value operator[](const Key& key) const { - return _inverted(key); - } - - private: - const CrossRefMap& _inverted; - }; - - /// \brief Gives back the inverse of the map. - /// - /// Gives back the inverse of the CrossRefMap. - InverseMap inverse() const { - return InverseMap(*this); - } - - }; - - /// \brief Provides continuous and unique id for the - /// items of a graph. - /// - /// RangeIdMap provides a unique and continuous - /// id for each item of a given type (\c Node, \c Arc or - /// \c Edge) in a graph. This id is - /// - \b unique: different items get different ids, - /// - \b continuous: the range of the ids is the set of integers - /// between 0 and \c n-1, where \c n is the number of the items of - /// this type (\c Node, \c Arc or \c Edge). - /// - So, the ids can change when deleting an item of the same type. - /// - /// Thus this id is not (necessarily) the same as what can get using - /// the \c id() function of the graph or \ref IdMap. - /// This map can be inverted with its member class \c InverseMap, - /// or with the \c operator()() member. - /// - /// \tparam GR The graph type. - /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or - /// \c GR::Edge). - /// - /// \see IdMap - template - class RangeIdMap - : protected ItemSetTraits::template Map::Type { - - typedef typename ItemSetTraits::template Map::Type Map; - - public: - /// The graph type of RangeIdMap. - typedef GR Graph; - typedef GR Digraph; - /// The key type of RangeIdMap (\c Node, \c Arc or \c Edge). - typedef K Item; - /// The key type of RangeIdMap (\c Node, \c Arc or \c Edge). - typedef K Key; - /// The value type of RangeIdMap. - typedef int Value; - - /// \brief Constructor. - /// - /// Constructor. - explicit RangeIdMap(const Graph& gr) : Map(gr) { - Item it; - const typename Map::Notifier* nf = Map::notifier(); - for (nf->first(it); it != INVALID; nf->next(it)) { - Map::set(it, _inv_map.size()); - _inv_map.push_back(it); - } - } - - protected: - - /// \brief Adds a new key to the map. - /// - /// Add a new key to the map. It is called by the - /// \c AlterationNotifier. - virtual void add(const Item& item) { - Map::add(item); - Map::set(item, _inv_map.size()); - _inv_map.push_back(item); - } - - /// \brief Add more new keys to the map. - /// - /// Add more new keys to the map. It is called by the - /// \c AlterationNotifier. - virtual void add(const std::vector& items) { - Map::add(items); - for (int i = 0; i < int(items.size()); ++i) { - Map::set(items[i], _inv_map.size()); - _inv_map.push_back(items[i]); - } - } - - /// \brief Erase the key from the map. - /// - /// Erase the key from the map. It is called by the - /// \c AlterationNotifier. - virtual void erase(const Item& item) { - Map::set(_inv_map.back(), Map::operator[](item)); - _inv_map[Map::operator[](item)] = _inv_map.back(); - _inv_map.pop_back(); - Map::erase(item); - } - - /// \brief Erase more keys from the map. - /// - /// Erase more keys from the map. It is called by the - /// \c AlterationNotifier. - virtual void erase(const std::vector& items) { - for (int i = 0; i < int(items.size()); ++i) { - Map::set(_inv_map.back(), Map::operator[](items[i])); - _inv_map[Map::operator[](items[i])] = _inv_map.back(); - _inv_map.pop_back(); - } - Map::erase(items); - } - - /// \brief Build the unique map. - /// - /// Build the unique map. It is called by the - /// \c AlterationNotifier. - virtual void build() { - Map::build(); - Item it; - const typename Map::Notifier* nf = Map::notifier(); - for (nf->first(it); it != INVALID; nf->next(it)) { - Map::set(it, _inv_map.size()); - _inv_map.push_back(it); - } - } - - /// \brief Clear the keys from the map. - /// - /// Clear the keys from the map. It is called by the - /// \c AlterationNotifier. - virtual void clear() { - _inv_map.clear(); - Map::clear(); - } - - public: - - /// \brief Returns the maximal value plus one. - /// - /// Returns the maximal value plus one in the map. - unsigned int size() const { - return _inv_map.size(); - } - - /// \brief Swaps the position of the two items in the map. - /// - /// Swaps the position of the two items in the map. - void swap(const Item& p, const Item& q) { - int pi = Map::operator[](p); - int qi = Map::operator[](q); - Map::set(p, qi); - _inv_map[qi] = p; - Map::set(q, pi); - _inv_map[pi] = q; - } - - /// \brief Gives back the \e range \e id of the item - /// - /// Gives back the \e range \e id of the item. - int operator[](const Item& item) const { - return Map::operator[](item); - } - - /// \brief Gives back the item belonging to a \e range \e id - /// - /// Gives back the item belonging to the given \e range \e id. - Item operator()(int id) const { - return _inv_map[id]; - } - - private: - - typedef std::vector Container; - Container _inv_map; - - public: - - /// \brief The inverse map type of RangeIdMap. - /// - /// The inverse map type of RangeIdMap. The subscript operator gives - /// back an item by its \e range \e id. - /// This type conforms to the \ref concepts::ReadMap "ReadMap" concept. - class InverseMap { - public: - /// \brief Constructor - /// - /// Constructor of the InverseMap. - explicit InverseMap(const RangeIdMap& inverted) - : _inverted(inverted) {} - - - /// The value type of the InverseMap. - typedef typename RangeIdMap::Key Value; - /// The key type of the InverseMap. - typedef typename RangeIdMap::Value Key; - - /// \brief Subscript operator. - /// - /// Subscript operator. It gives back the item - /// that the given \e range \e id currently belongs to. - Value operator[](const Key& key) const { - return _inverted(key); - } - - /// \brief Size of the map. - /// - /// Returns the size of the map. - unsigned int size() const { - return _inverted.size(); - } - - private: - const RangeIdMap& _inverted; - }; - - /// \brief Gives back the inverse of the map. - /// - /// Gives back the inverse of the RangeIdMap. - const InverseMap inverse() const { - return InverseMap(*this); - } - }; - - /// \brief Returns a \c RangeIdMap class. - /// - /// This function just returns an \c RangeIdMap class. - /// \relates RangeIdMap - template - inline RangeIdMap rangeIdMap(const GR& graph) { - return RangeIdMap(graph); - } - - /// \brief Dynamic iterable \c bool map. - /// - /// This class provides a special graph map type which can store a - /// \c bool value for graph items (\c Node, \c Arc or \c Edge). - /// For both \c true and \c false values it is possible to iterate on - /// the keys mapped to the value. - /// - /// This type is a reference map, so it can be modified with the - /// subscript operator. - /// - /// \tparam GR The graph type. - /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or - /// \c GR::Edge). - /// - /// \see IterableIntMap, IterableValueMap - /// \see CrossRefMap - template - class IterableBoolMap - : protected ItemSetTraits::template Map::Type { - private: - typedef GR Graph; - - typedef typename ItemSetTraits::ItemIt KeyIt; - typedef typename ItemSetTraits::template Map::Type Parent; - - std::vector _array; - int _sep; - - public: - - /// Indicates that the map is reference map. - typedef True ReferenceMapTag; - - /// The key type - typedef K Key; - /// The value type - typedef bool Value; - /// The const reference type. - typedef const Value& ConstReference; - - private: - - int position(const Key& key) const { - return Parent::operator[](key); - } - - public: - - /// \brief Reference to the value of the map. - /// - /// This class is similar to the \c bool type. It can be converted to - /// \c bool and it provides the same operators. - class Reference { - friend class IterableBoolMap; - private: - Reference(IterableBoolMap& map, const Key& key) - : _key(key), _map(map) {} - public: - - Reference& operator=(const Reference& value) { - _map.set(_key, static_cast(value)); - return *this; - } - - operator bool() const { - return static_cast(_map)[_key]; - } - - Reference& operator=(bool value) { - _map.set(_key, value); - return *this; - } - Reference& operator&=(bool value) { - _map.set(_key, _map[_key] & value); - return *this; - } - Reference& operator|=(bool value) { - _map.set(_key, _map[_key] | value); - return *this; - } - Reference& operator^=(bool value) { - _map.set(_key, _map[_key] ^ value); - return *this; - } - private: - Key _key; - IterableBoolMap& _map; - }; - - /// \brief Constructor of the map with a default value. - /// - /// Constructor of the map with a default value. - explicit IterableBoolMap(const Graph& graph, bool def = false) - : Parent(graph) { - typename Parent::Notifier* nf = Parent::notifier(); - Key it; - for (nf->first(it); it != INVALID; nf->next(it)) { - Parent::set(it, _array.size()); - _array.push_back(it); - } - _sep = (def ? _array.size() : 0); - } - - /// \brief Const subscript operator of the map. - /// - /// Const subscript operator of the map. - bool operator[](const Key& key) const { - return position(key) < _sep; - } - - /// \brief Subscript operator of the map. - /// - /// Subscript operator of the map. - Reference operator[](const Key& key) { - return Reference(*this, key); - } - - /// \brief Set operation of the map. - /// - /// Set operation of the map. - void set(const Key& key, bool value) { - int pos = position(key); - if (value) { - if (pos < _sep) return; - Key tmp = _array[_sep]; - _array[_sep] = key; - Parent::set(key, _sep); - _array[pos] = tmp; - Parent::set(tmp, pos); - ++_sep; - } else { - if (pos >= _sep) return; - --_sep; - Key tmp = _array[_sep]; - _array[_sep] = key; - Parent::set(key, _sep); - _array[pos] = tmp; - Parent::set(tmp, pos); - } - } - - /// \brief Set all items. - /// - /// Set all items in the map. - /// \note Constant time operation. - void setAll(bool value) { - _sep = (value ? _array.size() : 0); - } - - /// \brief Returns the number of the keys mapped to \c true. - /// - /// Returns the number of the keys mapped to \c true. - int trueNum() const { - return _sep; - } - - /// \brief Returns the number of the keys mapped to \c false. - /// - /// Returns the number of the keys mapped to \c false. - int falseNum() const { - return _array.size() - _sep; - } - - /// \brief Iterator for the keys mapped to \c true. - /// - /// Iterator for the keys mapped to \c true. It works - /// like a graph item iterator, it can be converted to - /// the key type of the map, incremented with \c ++ operator, and - /// if the iterator leaves the last valid key, it will be equal to - /// \c INVALID. - class TrueIt : public Key { - public: - typedef Key Parent; - - /// \brief Creates an iterator. - /// - /// Creates an iterator. It iterates on the - /// keys mapped to \c true. - /// \param map The IterableBoolMap. - explicit TrueIt(const IterableBoolMap& map) - : Parent(map._sep > 0 ? map._array[map._sep - 1] : INVALID), - _map(&map) {} - - /// \brief Invalid constructor \& conversion. - /// - /// This constructor initializes the iterator to be invalid. - /// \sa Invalid for more details. - TrueIt(Invalid) : Parent(INVALID), _map(0) {} - - /// \brief Increment operator. - /// - /// Increment operator. - TrueIt& operator++() { - int pos = _map->position(*this); - Parent::operator=(pos > 0 ? _map->_array[pos - 1] : INVALID); - return *this; - } - - private: - const IterableBoolMap* _map; - }; - - /// \brief Iterator for the keys mapped to \c false. - /// - /// Iterator for the keys mapped to \c false. It works - /// like a graph item iterator, it can be converted to - /// the key type of the map, incremented with \c ++ operator, and - /// if the iterator leaves the last valid key, it will be equal to - /// \c INVALID. - class FalseIt : public Key { - public: - typedef Key Parent; - - /// \brief Creates an iterator. - /// - /// Creates an iterator. It iterates on the - /// keys mapped to \c false. - /// \param map The IterableBoolMap. - explicit FalseIt(const IterableBoolMap& map) - : Parent(map._sep < int(map._array.size()) ? - map._array.back() : INVALID), _map(&map) {} - - /// \brief Invalid constructor \& conversion. - /// - /// This constructor initializes the iterator to be invalid. - /// \sa Invalid for more details. - FalseIt(Invalid) : Parent(INVALID), _map(0) {} - - /// \brief Increment operator. - /// - /// Increment operator. - FalseIt& operator++() { - int pos = _map->position(*this); - Parent::operator=(pos > _map->_sep ? _map->_array[pos - 1] : INVALID); - return *this; - } - - private: - const IterableBoolMap* _map; - }; - - /// \brief Iterator for the keys mapped to a given value. - /// - /// Iterator for the keys mapped to a given value. It works - /// like a graph item iterator, it can be converted to - /// the key type of the map, incremented with \c ++ operator, and - /// if the iterator leaves the last valid key, it will be equal to - /// \c INVALID. - class ItemIt : public Key { - public: - typedef Key Parent; - - /// \brief Creates an iterator with a value. - /// - /// Creates an iterator with a value. It iterates on the - /// keys mapped to the given value. - /// \param map The IterableBoolMap. - /// \param value The value. - ItemIt(const IterableBoolMap& map, bool value) - : Parent(value ? - (map._sep > 0 ? - map._array[map._sep - 1] : INVALID) : - (map._sep < int(map._array.size()) ? - map._array.back() : INVALID)), _map(&map) {} - - /// \brief Invalid constructor \& conversion. - /// - /// This constructor initializes the iterator to be invalid. - /// \sa Invalid for more details. - ItemIt(Invalid) : Parent(INVALID), _map(0) {} - - /// \brief Increment operator. - /// - /// Increment operator. - ItemIt& operator++() { - int pos = _map->position(*this); - int _sep = pos >= _map->_sep ? _map->_sep : 0; - Parent::operator=(pos > _sep ? _map->_array[pos - 1] : INVALID); - return *this; - } - - private: - const IterableBoolMap* _map; - }; - - protected: - - virtual void add(const Key& key) { - Parent::add(key); - Parent::set(key, _array.size()); - _array.push_back(key); - } - - virtual void add(const std::vector& keys) { - Parent::add(keys); - for (int i = 0; i < int(keys.size()); ++i) { - Parent::set(keys[i], _array.size()); - _array.push_back(keys[i]); - } - } - - virtual void erase(const Key& key) { - int pos = position(key); - if (pos < _sep) { - --_sep; - Parent::set(_array[_sep], pos); - _array[pos] = _array[_sep]; - Parent::set(_array.back(), _sep); - _array[_sep] = _array.back(); - _array.pop_back(); - } else { - Parent::set(_array.back(), pos); - _array[pos] = _array.back(); - _array.pop_back(); - } - Parent::erase(key); - } - - virtual void erase(const std::vector& keys) { - for (int i = 0; i < int(keys.size()); ++i) { - int pos = position(keys[i]); - if (pos < _sep) { - --_sep; - Parent::set(_array[_sep], pos); - _array[pos] = _array[_sep]; - Parent::set(_array.back(), _sep); - _array[_sep] = _array.back(); - _array.pop_back(); - } else { - Parent::set(_array.back(), pos); - _array[pos] = _array.back(); - _array.pop_back(); - } - } - Parent::erase(keys); - } - - virtual void build() { - Parent::build(); - typename Parent::Notifier* nf = Parent::notifier(); - Key it; - for (nf->first(it); it != INVALID; nf->next(it)) { - Parent::set(it, _array.size()); - _array.push_back(it); - } - _sep = 0; - } - - virtual void clear() { - _array.clear(); - _sep = 0; - Parent::clear(); - } - - }; - - - namespace _maps_bits { - template - struct IterableIntMapNode { - IterableIntMapNode() : value(-1) {} - IterableIntMapNode(int _value) : value(_value) {} - Item prev, next; - int value; - }; - } - - /// \brief Dynamic iterable integer map. - /// - /// This class provides a special graph map type which can store an - /// integer value for graph items (\c Node, \c Arc or \c Edge). - /// For each non-negative value it is possible to iterate on the keys - /// mapped to the value. - /// - /// This map is intended to be used with small integer values, for which - /// it is efficient, and supports iteration only for non-negative values. - /// If you need large values and/or iteration for negative integers, - /// consider to use \ref IterableValueMap instead. - /// - /// This type is a reference map, so it can be modified with the - /// subscript operator. - /// - /// \note The size of the data structure depends on the largest - /// value in the map. - /// - /// \tparam GR The graph type. - /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or - /// \c GR::Edge). - /// - /// \see IterableBoolMap, IterableValueMap - /// \see CrossRefMap - template - class IterableIntMap - : protected ItemSetTraits:: - template Map<_maps_bits::IterableIntMapNode >::Type { - public: - typedef typename ItemSetTraits:: - template Map<_maps_bits::IterableIntMapNode >::Type Parent; - - /// The key type - typedef K Key; - /// The value type - typedef int Value; - /// The graph type - typedef GR Graph; - - /// \brief Constructor of the map. - /// - /// Constructor of the map. It sets all values to -1. - explicit IterableIntMap(const Graph& graph) - : Parent(graph) {} - - /// \brief Constructor of the map with a given value. - /// - /// Constructor of the map with a given value. - explicit IterableIntMap(const Graph& graph, int value) - : Parent(graph, _maps_bits::IterableIntMapNode(value)) { - if (value >= 0) { - for (typename Parent::ItemIt it(*this); it != INVALID; ++it) { - lace(it); - } - } - } - - private: - - void unlace(const Key& key) { - typename Parent::Value& node = Parent::operator[](key); - if (node.value < 0) return; - if (node.prev != INVALID) { - Parent::operator[](node.prev).next = node.next; - } else { - _first[node.value] = node.next; - } - if (node.next != INVALID) { - Parent::operator[](node.next).prev = node.prev; - } - while (!_first.empty() && _first.back() == INVALID) { - _first.pop_back(); - } - } - - void lace(const Key& key) { - typename Parent::Value& node = Parent::operator[](key); - if (node.value < 0) return; - if (node.value >= int(_first.size())) { - _first.resize(node.value + 1, INVALID); - } - node.prev = INVALID; - node.next = _first[node.value]; - if (node.next != INVALID) { - Parent::operator[](node.next).prev = key; - } - _first[node.value] = key; - } - - public: - - /// Indicates that the map is reference map. - typedef True ReferenceMapTag; - - /// \brief Reference to the value of the map. - /// - /// This class is similar to the \c int type. It can - /// be converted to \c int and it has the same operators. - class Reference { - friend class IterableIntMap; - private: - Reference(IterableIntMap& map, const Key& key) - : _key(key), _map(map) {} - public: - - Reference& operator=(const Reference& value) { - _map.set(_key, static_cast(value)); - return *this; - } - - operator const int&() const { - return static_cast(_map)[_key]; - } - - Reference& operator=(int value) { - _map.set(_key, value); - return *this; - } - Reference& operator++() { - _map.set(_key, _map[_key] + 1); - return *this; - } - int operator++(int) { - int value = _map[_key]; - _map.set(_key, value + 1); - return value; - } - Reference& operator--() { - _map.set(_key, _map[_key] - 1); - return *this; - } - int operator--(int) { - int value = _map[_key]; - _map.set(_key, value - 1); - return value; - } - Reference& operator+=(int value) { - _map.set(_key, _map[_key] + value); - return *this; - } - Reference& operator-=(int value) { - _map.set(_key, _map[_key] - value); - return *this; - } - Reference& operator*=(int value) { - _map.set(_key, _map[_key] * value); - return *this; - } - Reference& operator/=(int value) { - _map.set(_key, _map[_key] / value); - return *this; - } - Reference& operator%=(int value) { - _map.set(_key, _map[_key] % value); - return *this; - } - Reference& operator&=(int value) { - _map.set(_key, _map[_key] & value); - return *this; - } - Reference& operator|=(int value) { - _map.set(_key, _map[_key] | value); - return *this; - } - Reference& operator^=(int value) { - _map.set(_key, _map[_key] ^ value); - return *this; - } - Reference& operator<<=(int value) { - _map.set(_key, _map[_key] << value); - return *this; - } - Reference& operator>>=(int value) { - _map.set(_key, _map[_key] >> value); - return *this; - } - - private: - Key _key; - IterableIntMap& _map; - }; - - /// The const reference type. - typedef const Value& ConstReference; - - /// \brief Gives back the maximal value plus one. - /// - /// Gives back the maximal value plus one. - int size() const { - return _first.size(); - } - - /// \brief Set operation of the map. - /// - /// Set operation of the map. - void set(const Key& key, const Value& value) { - unlace(key); - Parent::operator[](key).value = value; - lace(key); - } - - /// \brief Const subscript operator of the map. - /// - /// Const subscript operator of the map. - const Value& operator[](const Key& key) const { - return Parent::operator[](key).value; - } - - /// \brief Subscript operator of the map. - /// - /// Subscript operator of the map. - Reference operator[](const Key& key) { - return Reference(*this, key); - } - - /// \brief Iterator for the keys with the same value. - /// - /// Iterator for the keys with the same value. It works - /// like a graph item iterator, it can be converted to - /// the item type of the map, incremented with \c ++ operator, and - /// if the iterator leaves the last valid item, it will be equal to - /// \c INVALID. - class ItemIt : public Key { - public: - typedef Key Parent; - - /// \brief Invalid constructor \& conversion. - /// - /// This constructor initializes the iterator to be invalid. - /// \sa Invalid for more details. - ItemIt(Invalid) : Parent(INVALID), _map(0) {} - - /// \brief Creates an iterator with a value. - /// - /// Creates an iterator with a value. It iterates on the - /// keys mapped to the given value. - /// \param map The IterableIntMap. - /// \param value The value. - ItemIt(const IterableIntMap& map, int value) : _map(&map) { - if (value < 0 || value >= int(_map->_first.size())) { - Parent::operator=(INVALID); - } else { - Parent::operator=(_map->_first[value]); - } - } - - /// \brief Increment operator. - /// - /// Increment operator. - ItemIt& operator++() { - Parent::operator=(_map->IterableIntMap::Parent:: - operator[](static_cast(*this)).next); - return *this; - } - - private: - const IterableIntMap* _map; - }; - - protected: - - virtual void erase(const Key& key) { - unlace(key); - Parent::erase(key); - } - - virtual void erase(const std::vector& keys) { - for (int i = 0; i < int(keys.size()); ++i) { - unlace(keys[i]); - } - Parent::erase(keys); - } - - virtual void clear() { - _first.clear(); - Parent::clear(); - } - - private: - std::vector _first; - }; - - namespace _maps_bits { - template - struct IterableValueMapNode { - IterableValueMapNode(Value _value = Value()) : value(_value) {} - Item prev, next; - Value value; - }; - } - - /// \brief Dynamic iterable map for comparable values. - /// - /// This class provides a special graph map type which can store a - /// comparable value for graph items (\c Node, \c Arc or \c Edge). - /// For each value it is possible to iterate on the keys mapped to - /// the value (\c ItemIt), and the values of the map can be accessed - /// with an STL compatible forward iterator (\c ValueIt). - /// The map stores a linked list for each value, which contains - /// the items mapped to the value, and the used values are stored - /// in balanced binary tree (\c std::map). - /// - /// \ref IterableBoolMap and \ref IterableIntMap are similar classes - /// specialized for \c bool and \c int values, respectively. - /// - /// This type is not reference map, so it cannot be modified with - /// the subscript operator. - /// - /// \tparam GR The graph type. - /// \tparam K The key type of the map (\c GR::Node, \c GR::Arc or - /// \c GR::Edge). - /// \tparam V The value type of the map. It can be any comparable - /// value type. - /// - /// \see IterableBoolMap, IterableIntMap - /// \see CrossRefMap - template - class IterableValueMap - : protected ItemSetTraits:: - template Map<_maps_bits::IterableValueMapNode >::Type { - public: - typedef typename ItemSetTraits:: - template Map<_maps_bits::IterableValueMapNode >::Type Parent; - - /// The key type - typedef K Key; - /// The value type - typedef V Value; - /// The graph type - typedef GR Graph; - - public: - - /// \brief Constructor of the map with a given value. - /// - /// Constructor of the map with a given value. - explicit IterableValueMap(const Graph& graph, - const Value& value = Value()) - : Parent(graph, _maps_bits::IterableValueMapNode(value)) { - for (typename Parent::ItemIt it(*this); it != INVALID; ++it) { - lace(it); - } - } - - protected: - - void unlace(const Key& key) { - typename Parent::Value& node = Parent::operator[](key); - if (node.prev != INVALID) { - Parent::operator[](node.prev).next = node.next; - } else { - if (node.next != INVALID) { - _first[node.value] = node.next; - } else { - _first.erase(node.value); - } - } - if (node.next != INVALID) { - Parent::operator[](node.next).prev = node.prev; - } - } - - void lace(const Key& key) { - typename Parent::Value& node = Parent::operator[](key); - typename std::map::iterator it = _first.find(node.value); - if (it == _first.end()) { - node.prev = node.next = INVALID; - _first.insert(std::make_pair(node.value, key)); - } else { - node.prev = INVALID; - node.next = it->second; - if (node.next != INVALID) { - Parent::operator[](node.next).prev = key; - } - it->second = key; - } - } - - public: - - /// \brief Forward iterator for values. - /// - /// This iterator is an STL compatible forward - /// iterator on the values of the map. The values can - /// be accessed in the [beginValue, endValue) range. - class ValueIt - : public std::iterator { - friend class IterableValueMap; - private: - ValueIt(typename std::map::const_iterator _it) - : it(_it) {} - public: - - /// Constructor - ValueIt() {} - - /// \e - ValueIt& operator++() { ++it; return *this; } - /// \e - ValueIt operator++(int) { - ValueIt tmp(*this); - operator++(); - return tmp; - } - - /// \e - const Value& operator*() const { return it->first; } - /// \e - const Value* operator->() const { return &(it->first); } - - /// \e - bool operator==(ValueIt jt) const { return it == jt.it; } - /// \e - bool operator!=(ValueIt jt) const { return it != jt.it; } - - private: - typename std::map::const_iterator it; - }; - - /// \brief Returns an iterator to the first value. - /// - /// Returns an STL compatible iterator to the - /// first value of the map. The values of the - /// map can be accessed in the [beginValue, endValue) - /// range. - ValueIt beginValue() const { - return ValueIt(_first.begin()); - } - - /// \brief Returns an iterator after the last value. - /// - /// Returns an STL compatible iterator after the - /// last value of the map. The values of the - /// map can be accessed in the [beginValue, endValue) - /// range. - ValueIt endValue() const { - return ValueIt(_first.end()); - } - - /// \brief Set operation of the map. - /// - /// Set operation of the map. - void set(const Key& key, const Value& value) { - unlace(key); - Parent::operator[](key).value = value; - lace(key); - } - - /// \brief Const subscript operator of the map. - /// - /// Const subscript operator of the map. - const Value& operator[](const Key& key) const { - return Parent::operator[](key).value; - } - - /// \brief Iterator for the keys with the same value. - /// - /// Iterator for the keys with the same value. It works - /// like a graph item iterator, it can be converted to - /// the item type of the map, incremented with \c ++ operator, and - /// if the iterator leaves the last valid item, it will be equal to - /// \c INVALID. - class ItemIt : public Key { - public: - typedef Key Parent; - - /// \brief Invalid constructor \& conversion. - /// - /// This constructor initializes the iterator to be invalid. - /// \sa Invalid for more details. - ItemIt(Invalid) : Parent(INVALID), _map(0) {} - - /// \brief Creates an iterator with a value. - /// - /// Creates an iterator with a value. It iterates on the - /// keys which have the given value. - /// \param map The IterableValueMap - /// \param value The value - ItemIt(const IterableValueMap& map, const Value& value) : _map(&map) { - typename std::map::const_iterator it = - map._first.find(value); - if (it == map._first.end()) { - Parent::operator=(INVALID); - } else { - Parent::operator=(it->second); - } - } - - /// \brief Increment operator. - /// - /// Increment Operator. - ItemIt& operator++() { - Parent::operator=(_map->IterableValueMap::Parent:: - operator[](static_cast(*this)).next); - return *this; - } - - - private: - const IterableValueMap* _map; - }; - - protected: - - virtual void add(const Key& key) { - Parent::add(key); - lace(key); - } - - virtual void add(const std::vector& keys) { - Parent::add(keys); - for (int i = 0; i < int(keys.size()); ++i) { - lace(keys[i]); - } - } - - virtual void erase(const Key& key) { - unlace(key); - Parent::erase(key); - } - - virtual void erase(const std::vector& keys) { - for (int i = 0; i < int(keys.size()); ++i) { - unlace(keys[i]); - } - Parent::erase(keys); - } - - virtual void build() { - Parent::build(); - for (typename Parent::ItemIt it(*this); it != INVALID; ++it) { - lace(it); - } - } - - virtual void clear() { - _first.clear(); - Parent::clear(); - } - - private: - std::map _first; - }; - - /// \brief Map of the source nodes of arcs in a digraph. - /// - /// SourceMap provides access for the source node of each arc in a digraph, - /// which is returned by the \c source() function of the digraph. - /// \tparam GR The digraph type. - /// \see TargetMap - template - class SourceMap { - public: - - /// The key type (the \c Arc type of the digraph). - typedef typename GR::Arc Key; - /// The value type (the \c Node type of the digraph). - typedef typename GR::Node Value; - - /// \brief Constructor - /// - /// Constructor. - /// \param digraph The digraph that the map belongs to. - explicit SourceMap(const GR& digraph) : _graph(digraph) {} - - /// \brief Returns the source node of the given arc. - /// - /// Returns the source node of the given arc. - Value operator[](const Key& arc) const { - return _graph.source(arc); - } - - private: - const GR& _graph; - }; - - /// \brief Returns a \c SourceMap class. - /// - /// This function just returns an \c SourceMap class. - /// \relates SourceMap - template - inline SourceMap sourceMap(const GR& graph) { - return SourceMap(graph); - } - - /// \brief Map of the target nodes of arcs in a digraph. - /// - /// TargetMap provides access for the target node of each arc in a digraph, - /// which is returned by the \c target() function of the digraph. - /// \tparam GR The digraph type. - /// \see SourceMap - template - class TargetMap { - public: - - /// The key type (the \c Arc type of the digraph). - typedef typename GR::Arc Key; - /// The value type (the \c Node type of the digraph). - typedef typename GR::Node Value; - - /// \brief Constructor - /// - /// Constructor. - /// \param digraph The digraph that the map belongs to. - explicit TargetMap(const GR& digraph) : _graph(digraph) {} - - /// \brief Returns the target node of the given arc. - /// - /// Returns the target node of the given arc. - Value operator[](const Key& e) const { - return _graph.target(e); - } - - private: - const GR& _graph; - }; - - /// \brief Returns a \c TargetMap class. - /// - /// This function just returns a \c TargetMap class. - /// \relates TargetMap - template - inline TargetMap targetMap(const GR& graph) { - return TargetMap(graph); - } - - /// \brief Map of the "forward" directed arc view of edges in a graph. - /// - /// ForwardMap provides access for the "forward" directed arc view of - /// each edge in a graph, which is returned by the \c direct() function - /// of the graph with \c true parameter. - /// \tparam GR The graph type. - /// \see BackwardMap - template - class ForwardMap { - public: - - /// The key type (the \c Edge type of the digraph). - typedef typename GR::Edge Key; - /// The value type (the \c Arc type of the digraph). - typedef typename GR::Arc Value; - - /// \brief Constructor - /// - /// Constructor. - /// \param graph The graph that the map belongs to. - explicit ForwardMap(const GR& graph) : _graph(graph) {} - - /// \brief Returns the "forward" directed arc view of the given edge. - /// - /// Returns the "forward" directed arc view of the given edge. - Value operator[](const Key& key) const { - return _graph.direct(key, true); - } - - private: - const GR& _graph; - }; - - /// \brief Returns a \c ForwardMap class. - /// - /// This function just returns an \c ForwardMap class. - /// \relates ForwardMap - template - inline ForwardMap forwardMap(const GR& graph) { - return ForwardMap(graph); - } - - /// \brief Map of the "backward" directed arc view of edges in a graph. - /// - /// BackwardMap provides access for the "backward" directed arc view of - /// each edge in a graph, which is returned by the \c direct() function - /// of the graph with \c false parameter. - /// \tparam GR The graph type. - /// \see ForwardMap - template - class BackwardMap { - public: - - /// The key type (the \c Edge type of the digraph). - typedef typename GR::Edge Key; - /// The value type (the \c Arc type of the digraph). - typedef typename GR::Arc Value; - - /// \brief Constructor - /// - /// Constructor. - /// \param graph The graph that the map belongs to. - explicit BackwardMap(const GR& graph) : _graph(graph) {} - - /// \brief Returns the "backward" directed arc view of the given edge. - /// - /// Returns the "backward" directed arc view of the given edge. - Value operator[](const Key& key) const { - return _graph.direct(key, false); - } - - private: - const GR& _graph; - }; - - /// \brief Returns a \c BackwardMap class - - /// This function just returns a \c BackwardMap class. - /// \relates BackwardMap - template - inline BackwardMap backwardMap(const GR& graph) { - return BackwardMap(graph); - } - - /// \brief Map of the in-degrees of nodes in a digraph. - /// - /// This map returns the in-degree of a node. Once it is constructed, - /// the degrees are stored in a standard \c NodeMap, so each query is done - /// in constant time. On the other hand, the values are updated automatically - /// whenever the digraph changes. - /// - /// \warning Besides \c addNode() and \c addArc(), a digraph structure - /// may provide alternative ways to modify the digraph. - /// The correct behavior of InDegMap is not guarantied if these additional - /// features are used. For example, the functions - /// \ref ListDigraph::changeSource() "changeSource()", - /// \ref ListDigraph::changeTarget() "changeTarget()" and - /// \ref ListDigraph::reverseArc() "reverseArc()" - /// of \ref ListDigraph will \e not update the degree values correctly. - /// - /// \sa OutDegMap - template - class InDegMap - : protected ItemSetTraits - ::ItemNotifier::ObserverBase { - - public: - - /// The graph type of InDegMap - typedef GR Graph; - typedef GR Digraph; - /// The key type - typedef typename Digraph::Node Key; - /// The value type - typedef int Value; - - typedef typename ItemSetTraits - ::ItemNotifier::ObserverBase Parent; - - private: - - class AutoNodeMap - : public ItemSetTraits::template Map::Type { - public: - - typedef typename ItemSetTraits:: - template Map::Type Parent; - - AutoNodeMap(const Digraph& digraph) : Parent(digraph, 0) {} - - virtual void add(const Key& key) { - Parent::add(key); - Parent::set(key, 0); - } - - virtual void add(const std::vector& keys) { - Parent::add(keys); - for (int i = 0; i < int(keys.size()); ++i) { - Parent::set(keys[i], 0); - } - } - - virtual void build() { - Parent::build(); - Key it; - typename Parent::Notifier* nf = Parent::notifier(); - for (nf->first(it); it != INVALID; nf->next(it)) { - Parent::set(it, 0); - } - } - }; - - public: - - /// \brief Constructor. - /// - /// Constructor for creating an in-degree map. - explicit InDegMap(const Digraph& graph) - : _digraph(graph), _deg(graph) { - Parent::attach(_digraph.notifier(typename Digraph::Arc())); - - for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) { - _deg[it] = countInArcs(_digraph, it); - } - } - - /// \brief Gives back the in-degree of a Node. - /// - /// Gives back the in-degree of a Node. - int operator[](const Key& key) const { - return _deg[key]; - } - - protected: - - typedef typename Digraph::Arc Arc; - - virtual void add(const Arc& arc) { - ++_deg[_digraph.target(arc)]; - } - - virtual void add(const std::vector& arcs) { - for (int i = 0; i < int(arcs.size()); ++i) { - ++_deg[_digraph.target(arcs[i])]; - } - } - - virtual void erase(const Arc& arc) { - --_deg[_digraph.target(arc)]; - } - - virtual void erase(const std::vector& arcs) { - for (int i = 0; i < int(arcs.size()); ++i) { - --_deg[_digraph.target(arcs[i])]; - } - } - - virtual void build() { - for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) { - _deg[it] = countInArcs(_digraph, it); - } - } - - virtual void clear() { - for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) { - _deg[it] = 0; - } - } - private: - - const Digraph& _digraph; - AutoNodeMap _deg; - }; - - /// \brief Map of the out-degrees of nodes in a digraph. - /// - /// This map returns the out-degree of a node. Once it is constructed, - /// the degrees are stored in a standard \c NodeMap, so each query is done - /// in constant time. On the other hand, the values are updated automatically - /// whenever the digraph changes. - /// - /// \warning Besides \c addNode() and \c addArc(), a digraph structure - /// may provide alternative ways to modify the digraph. - /// The correct behavior of OutDegMap is not guarantied if these additional - /// features are used. For example, the functions - /// \ref ListDigraph::changeSource() "changeSource()", - /// \ref ListDigraph::changeTarget() "changeTarget()" and - /// \ref ListDigraph::reverseArc() "reverseArc()" - /// of \ref ListDigraph will \e not update the degree values correctly. - /// - /// \sa InDegMap - template - class OutDegMap - : protected ItemSetTraits - ::ItemNotifier::ObserverBase { - - public: - - /// The graph type of OutDegMap - typedef GR Graph; - typedef GR Digraph; - /// The key type - typedef typename Digraph::Node Key; - /// The value type - typedef int Value; - - typedef typename ItemSetTraits - ::ItemNotifier::ObserverBase Parent; - - private: - - class AutoNodeMap - : public ItemSetTraits::template Map::Type { - public: - - typedef typename ItemSetTraits:: - template Map::Type Parent; - - AutoNodeMap(const Digraph& digraph) : Parent(digraph, 0) {} - - virtual void add(const Key& key) { - Parent::add(key); - Parent::set(key, 0); - } - virtual void add(const std::vector& keys) { - Parent::add(keys); - for (int i = 0; i < int(keys.size()); ++i) { - Parent::set(keys[i], 0); - } - } - virtual void build() { - Parent::build(); - Key it; - typename Parent::Notifier* nf = Parent::notifier(); - for (nf->first(it); it != INVALID; nf->next(it)) { - Parent::set(it, 0); - } - } - }; - - public: - - /// \brief Constructor. - /// - /// Constructor for creating an out-degree map. - explicit OutDegMap(const Digraph& graph) - : _digraph(graph), _deg(graph) { - Parent::attach(_digraph.notifier(typename Digraph::Arc())); - - for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) { - _deg[it] = countOutArcs(_digraph, it); - } - } - - /// \brief Gives back the out-degree of a Node. - /// - /// Gives back the out-degree of a Node. - int operator[](const Key& key) const { - return _deg[key]; - } - - protected: - - typedef typename Digraph::Arc Arc; - - virtual void add(const Arc& arc) { - ++_deg[_digraph.source(arc)]; - } - - virtual void add(const std::vector& arcs) { - for (int i = 0; i < int(arcs.size()); ++i) { - ++_deg[_digraph.source(arcs[i])]; - } - } - - virtual void erase(const Arc& arc) { - --_deg[_digraph.source(arc)]; - } - - virtual void erase(const std::vector& arcs) { - for (int i = 0; i < int(arcs.size()); ++i) { - --_deg[_digraph.source(arcs[i])]; - } - } - - virtual void build() { - for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) { - _deg[it] = countOutArcs(_digraph, it); - } - } - - virtual void clear() { - for(typename Digraph::NodeIt it(_digraph); it != INVALID; ++it) { - _deg[it] = 0; - } - } - private: - - const Digraph& _digraph; - AutoNodeMap _deg; - }; - - /// \brief Potential difference map - /// - /// PotentialDifferenceMap returns the difference between the potentials of - /// the source and target nodes of each arc in a digraph, i.e. it returns - /// \code - /// potential[gr.target(arc)] - potential[gr.source(arc)]. - /// \endcode - /// \tparam GR The digraph type. - /// \tparam POT A node map storing the potentials. - template - class PotentialDifferenceMap { - public: - /// Key type - typedef typename GR::Arc Key; - /// Value type - typedef typename POT::Value Value; - - /// \brief Constructor - /// - /// Contructor of the map. - explicit PotentialDifferenceMap(const GR& gr, - const POT& potential) - : _digraph(gr), _potential(potential) {} - - /// \brief Returns the potential difference for the given arc. - /// - /// Returns the potential difference for the given arc, i.e. - /// \code - /// potential[gr.target(arc)] - potential[gr.source(arc)]. - /// \endcode - Value operator[](const Key& arc) const { - return _potential[_digraph.target(arc)] - - _potential[_digraph.source(arc)]; - } - - private: - const GR& _digraph; - const POT& _potential; - }; - - /// \brief Returns a PotentialDifferenceMap. - /// - /// This function just returns a PotentialDifferenceMap. - /// \relates PotentialDifferenceMap - template - PotentialDifferenceMap - potentialDifferenceMap(const GR& gr, const POT& potential) { - return PotentialDifferenceMap(gr, potential); - } - - - /// \brief Copy the values of a graph map to another map. - /// - /// This function copies the values of a graph map to another graph map. - /// \c To::Key must be equal or convertible to \c From::Key and - /// \c From::Value must be equal or convertible to \c To::Value. - /// - /// For example, an edge map of \c int value type can be copied to - /// an arc map of \c double value type in an undirected graph, but - /// an arc map cannot be copied to an edge map. - /// Note that even a \ref ConstMap can be copied to a standard graph map, - /// but \ref mapFill() can also be used for this purpose. - /// - /// \param gr The graph for which the maps are defined. - /// \param from The map from which the values have to be copied. - /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. - /// \param to The map to which the values have to be copied. - /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. - template - void mapCopy(const GR& gr, const From& from, To& to) { - typedef typename To::Key Item; - typedef typename ItemSetTraits::ItemIt ItemIt; - - for (ItemIt it(gr); it != INVALID; ++it) { - to.set(it, from[it]); - } - } - - /// \brief Compare two graph maps. - /// - /// This function compares the values of two graph maps. It returns - /// \c true if the maps assign the same value for all items in the graph. - /// The \c Key type of the maps (\c Node, \c Arc or \c Edge) must be equal - /// and their \c Value types must be comparable using \c %operator==(). - /// - /// \param gr The graph for which the maps are defined. - /// \param map1 The first map. - /// \param map2 The second map. - template - bool mapCompare(const GR& gr, const Map1& map1, const Map2& map2) { - typedef typename Map2::Key Item; - typedef typename ItemSetTraits::ItemIt ItemIt; - - for (ItemIt it(gr); it != INVALID; ++it) { - if (!(map1[it] == map2[it])) return false; - } - return true; - } - - /// \brief Return an item having minimum value of a graph map. - /// - /// This function returns an item (\c Node, \c Arc or \c Edge) having - /// minimum value of the given graph map. - /// If the item set is empty, it returns \c INVALID. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. - template - typename Map::Key mapMin(const GR& gr, const Map& map) { - return mapMin(gr, map, std::less()); - } - - /// \brief Return an item having minimum value of a graph map. - /// - /// This function returns an item (\c Node, \c Arc or \c Edge) having - /// minimum value of the given graph map. - /// If the item set is empty, it returns \c INVALID. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. - /// \param comp Comparison function object. - template - typename Map::Key mapMin(const GR& gr, const Map& map, const Comp& comp) { - typedef typename Map::Key Item; - typedef typename Map::Value Value; - typedef typename ItemSetTraits::ItemIt ItemIt; - - ItemIt min_item(gr); - if (min_item == INVALID) return INVALID; - Value min = map[min_item]; - for (ItemIt it(gr); it != INVALID; ++it) { - if (comp(map[it], min)) { - min = map[it]; - min_item = it; - } - } - return min_item; - } - - /// \brief Return an item having maximum value of a graph map. - /// - /// This function returns an item (\c Node, \c Arc or \c Edge) having - /// maximum value of the given graph map. - /// If the item set is empty, it returns \c INVALID. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. - template - typename Map::Key mapMax(const GR& gr, const Map& map) { - return mapMax(gr, map, std::less()); - } - - /// \brief Return an item having maximum value of a graph map. - /// - /// This function returns an item (\c Node, \c Arc or \c Edge) having - /// maximum value of the given graph map. - /// If the item set is empty, it returns \c INVALID. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. - /// \param comp Comparison function object. - template - typename Map::Key mapMax(const GR& gr, const Map& map, const Comp& comp) { - typedef typename Map::Key Item; - typedef typename Map::Value Value; - typedef typename ItemSetTraits::ItemIt ItemIt; - - ItemIt max_item(gr); - if (max_item == INVALID) return INVALID; - Value max = map[max_item]; - for (ItemIt it(gr); it != INVALID; ++it) { - if (comp(max, map[it])) { - max = map[it]; - max_item = it; - } - } - return max_item; - } - - /// \brief Return the minimum value of a graph map. - /// - /// This function returns the minimum value of the given graph map. - /// The corresponding item set of the graph must not be empty. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. - template - typename Map::Value mapMinValue(const GR& gr, const Map& map) { - return map[mapMin(gr, map, std::less())]; - } - - /// \brief Return the minimum value of a graph map. - /// - /// This function returns the minimum value of the given graph map. - /// The corresponding item set of the graph must not be empty. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. - /// \param comp Comparison function object. - template - typename Map::Value - mapMinValue(const GR& gr, const Map& map, const Comp& comp) { - return map[mapMin(gr, map, comp)]; - } - - /// \brief Return the maximum value of a graph map. - /// - /// This function returns the maximum value of the given graph map. - /// The corresponding item set of the graph must not be empty. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. - template - typename Map::Value mapMaxValue(const GR& gr, const Map& map) { - return map[mapMax(gr, map, std::less())]; - } - - /// \brief Return the maximum value of a graph map. - /// - /// This function returns the maximum value of the given graph map. - /// The corresponding item set of the graph must not be empty. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. - /// \param comp Comparison function object. - template - typename Map::Value - mapMaxValue(const GR& gr, const Map& map, const Comp& comp) { - return map[mapMax(gr, map, comp)]; - } - - /// \brief Return an item having a specified value in a graph map. - /// - /// This function returns an item (\c Node, \c Arc or \c Edge) having - /// the specified assigned value in the given graph map. - /// If no such item exists, it returns \c INVALID. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. - /// \param val The value that have to be found. - template - typename Map::Key - mapFind(const GR& gr, const Map& map, const typename Map::Value& val) { - typedef typename Map::Key Item; - typedef typename ItemSetTraits::ItemIt ItemIt; - - for (ItemIt it(gr); it != INVALID; ++it) { - if (map[it] == val) return it; - } - return INVALID; - } - - /// \brief Return an item having value for which a certain predicate is - /// true in a graph map. - /// - /// This function returns an item (\c Node, \c Arc or \c Edge) having - /// such assigned value for which the specified predicate is true - /// in the given graph map. - /// If no such item exists, it returns \c INVALID. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. - /// \param pred The predicate function object. - template - typename Map::Key - mapFindIf(const GR& gr, const Map& map, const Pred& pred) { - typedef typename Map::Key Item; - typedef typename ItemSetTraits::ItemIt ItemIt; - - for (ItemIt it(gr); it != INVALID; ++it) { - if (pred(map[it])) return it; - } - return INVALID; - } - - /// \brief Return the number of items having a specified value in a - /// graph map. - /// - /// This function returns the number of items (\c Node, \c Arc or \c Edge) - /// having the specified assigned value in the given graph map. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. - /// \param val The value that have to be counted. - template - int mapCount(const GR& gr, const Map& map, const typename Map::Value& val) { - typedef typename Map::Key Item; - typedef typename ItemSetTraits::ItemIt ItemIt; - - int cnt = 0; - for (ItemIt it(gr); it != INVALID; ++it) { - if (map[it] == val) ++cnt; - } - return cnt; - } - - /// \brief Return the number of items having values for which a certain - /// predicate is true in a graph map. - /// - /// This function returns the number of items (\c Node, \c Arc or \c Edge) - /// having such assigned values for which the specified predicate is true - /// in the given graph map. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. - /// \param pred The predicate function object. - template - int mapCountIf(const GR& gr, const Map& map, const Pred& pred) { - typedef typename Map::Key Item; - typedef typename ItemSetTraits::ItemIt ItemIt; - - int cnt = 0; - for (ItemIt it(gr); it != INVALID; ++it) { - if (pred(map[it])) ++cnt; - } - return cnt; - } - - /// \brief Fill a graph map with a certain value. - /// - /// This function sets the specified value for all items (\c Node, - /// \c Arc or \c Edge) in the given graph map. - /// - /// \param gr The graph for which the map is defined. - /// \param map The graph map. It must conform to the - /// \ref concepts::WriteMap "WriteMap" concept. - /// \param val The value. - template - void mapFill(const GR& gr, Map& map, const typename Map::Value& val) { - typedef typename Map::Key Item; - typedef typename ItemSetTraits::ItemIt ItemIt; - - for (ItemIt it(gr); it != INVALID; ++it) { - map.set(it, val); - } - } - - /// @} -} - -#endif // LEMON_MAPS_H diff --git a/deps/lemon/lemon/matching.h b/deps/lemon/lemon/matching.h deleted file mode 100644 index 5ee234128..000000000 --- a/deps/lemon/lemon/matching.h +++ /dev/null @@ -1,3505 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_MATCHING_H -#define LEMON_MATCHING_H - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -///\ingroup matching -///\file -///\brief Maximum matching algorithms in general graphs. - -namespace lemon { - - /// \ingroup matching - /// - /// \brief Maximum cardinality matching in general graphs - /// - /// This class implements Edmonds' alternating forest matching algorithm - /// for finding a maximum cardinality matching in a general undirected graph. - /// It can be started from an arbitrary initial matching - /// (the default is the empty one). - /// - /// The dual solution of the problem is a map of the nodes to - /// \ref MaxMatching::Status "Status", having values \c EVEN (or \c D), - /// \c ODD (or \c A) and \c MATCHED (or \c C) defining the Gallai-Edmonds - /// decomposition of the graph. The nodes in \c EVEN/D induce a subgraph - /// with factor-critical components, the nodes in \c ODD/A form the - /// canonical barrier, and the nodes in \c MATCHED/C induce a graph having - /// a perfect matching. The number of the factor-critical components - /// minus the number of barrier nodes is a lower bound on the - /// unmatched nodes, and the matching is optimal if and only if this bound is - /// tight. This decomposition can be obtained using \ref status() or - /// \ref statusMap() after running the algorithm. - /// - /// \tparam GR The undirected graph type the algorithm runs on. - template - class MaxMatching { - public: - - /// The graph type of the algorithm - typedef GR Graph; - /// The type of the matching map - typedef typename Graph::template NodeMap - MatchingMap; - - ///\brief Status constants for Gallai-Edmonds decomposition. - /// - ///These constants are used for indicating the Gallai-Edmonds - ///decomposition of a graph. The nodes with status \c EVEN (or \c D) - ///induce a subgraph with factor-critical components, the nodes with - ///status \c ODD (or \c A) form the canonical barrier, and the nodes - ///with status \c MATCHED (or \c C) induce a subgraph having a - ///perfect matching. - enum Status { - EVEN = 1, ///< = 1. (\c D is an alias for \c EVEN.) - D = 1, - MATCHED = 0, ///< = 0. (\c C is an alias for \c MATCHED.) - C = 0, - ODD = -1, ///< = -1. (\c A is an alias for \c ODD.) - A = -1, - UNMATCHED = -2 ///< = -2. - }; - - /// The type of the status map - typedef typename Graph::template NodeMap StatusMap; - - private: - - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - typedef UnionFindEnum BlossomSet; - typedef ExtendFindEnum TreeSet; - typedef RangeMap NodeIntMap; - typedef MatchingMap EarMap; - typedef std::vector NodeQueue; - - const Graph& _graph; - MatchingMap* _matching; - StatusMap* _status; - - EarMap* _ear; - - IntNodeMap* _blossom_set_index; - BlossomSet* _blossom_set; - NodeIntMap* _blossom_rep; - - IntNodeMap* _tree_set_index; - TreeSet* _tree_set; - - NodeQueue _node_queue; - int _process, _postpone, _last; - - int _node_num; - - private: - - void createStructures() { - _node_num = countNodes(_graph); - if (!_matching) { - _matching = new MatchingMap(_graph); - } - if (!_status) { - _status = new StatusMap(_graph); - } - if (!_ear) { - _ear = new EarMap(_graph); - } - if (!_blossom_set) { - _blossom_set_index = new IntNodeMap(_graph); - _blossom_set = new BlossomSet(*_blossom_set_index); - } - if (!_blossom_rep) { - _blossom_rep = new NodeIntMap(_node_num); - } - if (!_tree_set) { - _tree_set_index = new IntNodeMap(_graph); - _tree_set = new TreeSet(*_tree_set_index); - } - _node_queue.resize(_node_num); - } - - void destroyStructures() { - if (_matching) { - delete _matching; - } - if (_status) { - delete _status; - } - if (_ear) { - delete _ear; - } - if (_blossom_set) { - delete _blossom_set; - delete _blossom_set_index; - } - if (_blossom_rep) { - delete _blossom_rep; - } - if (_tree_set) { - delete _tree_set_index; - delete _tree_set; - } - } - - void processDense(const Node& n) { - _process = _postpone = _last = 0; - _node_queue[_last++] = n; - - while (_process != _last) { - Node u = _node_queue[_process++]; - for (OutArcIt a(_graph, u); a != INVALID; ++a) { - Node v = _graph.target(a); - if ((*_status)[v] == MATCHED) { - extendOnArc(a); - } else if ((*_status)[v] == UNMATCHED) { - augmentOnArc(a); - return; - } - } - } - - while (_postpone != _last) { - Node u = _node_queue[_postpone++]; - - for (OutArcIt a(_graph, u); a != INVALID ; ++a) { - Node v = _graph.target(a); - - if ((*_status)[v] == EVEN) { - if (_blossom_set->find(u) != _blossom_set->find(v)) { - shrinkOnEdge(a); - } - } - - while (_process != _last) { - Node w = _node_queue[_process++]; - for (OutArcIt b(_graph, w); b != INVALID; ++b) { - Node x = _graph.target(b); - if ((*_status)[x] == MATCHED) { - extendOnArc(b); - } else if ((*_status)[x] == UNMATCHED) { - augmentOnArc(b); - return; - } - } - } - } - } - } - - void processSparse(const Node& n) { - _process = _last = 0; - _node_queue[_last++] = n; - while (_process != _last) { - Node u = _node_queue[_process++]; - for (OutArcIt a(_graph, u); a != INVALID; ++a) { - Node v = _graph.target(a); - - if ((*_status)[v] == EVEN) { - if (_blossom_set->find(u) != _blossom_set->find(v)) { - shrinkOnEdge(a); - } - } else if ((*_status)[v] == MATCHED) { - extendOnArc(a); - } else if ((*_status)[v] == UNMATCHED) { - augmentOnArc(a); - return; - } - } - } - } - - void shrinkOnEdge(const Edge& e) { - Node nca = INVALID; - - { - std::set left_set, right_set; - - Node left = (*_blossom_rep)[_blossom_set->find(_graph.u(e))]; - left_set.insert(left); - - Node right = (*_blossom_rep)[_blossom_set->find(_graph.v(e))]; - right_set.insert(right); - - while (true) { - if ((*_matching)[left] == INVALID) break; - left = _graph.target((*_matching)[left]); - left = (*_blossom_rep)[_blossom_set-> - find(_graph.target((*_ear)[left]))]; - if (right_set.find(left) != right_set.end()) { - nca = left; - break; - } - left_set.insert(left); - - if ((*_matching)[right] == INVALID) break; - right = _graph.target((*_matching)[right]); - right = (*_blossom_rep)[_blossom_set-> - find(_graph.target((*_ear)[right]))]; - if (left_set.find(right) != left_set.end()) { - nca = right; - break; - } - right_set.insert(right); - } - - if (nca == INVALID) { - if ((*_matching)[left] == INVALID) { - nca = right; - while (left_set.find(nca) == left_set.end()) { - nca = _graph.target((*_matching)[nca]); - nca =(*_blossom_rep)[_blossom_set-> - find(_graph.target((*_ear)[nca]))]; - } - } else { - nca = left; - while (right_set.find(nca) == right_set.end()) { - nca = _graph.target((*_matching)[nca]); - nca = (*_blossom_rep)[_blossom_set-> - find(_graph.target((*_ear)[nca]))]; - } - } - } - } - - { - - Node node = _graph.u(e); - Arc arc = _graph.direct(e, true); - Node base = (*_blossom_rep)[_blossom_set->find(node)]; - - while (base != nca) { - (*_ear)[node] = arc; - - Node n = node; - while (n != base) { - n = _graph.target((*_matching)[n]); - Arc a = (*_ear)[n]; - n = _graph.target(a); - (*_ear)[n] = _graph.oppositeArc(a); - } - node = _graph.target((*_matching)[base]); - _tree_set->erase(base); - _tree_set->erase(node); - _blossom_set->insert(node, _blossom_set->find(base)); - (*_status)[node] = EVEN; - _node_queue[_last++] = node; - arc = _graph.oppositeArc((*_ear)[node]); - node = _graph.target((*_ear)[node]); - base = (*_blossom_rep)[_blossom_set->find(node)]; - _blossom_set->join(_graph.target(arc), base); - } - } - - (*_blossom_rep)[_blossom_set->find(nca)] = nca; - - { - - Node node = _graph.v(e); - Arc arc = _graph.direct(e, false); - Node base = (*_blossom_rep)[_blossom_set->find(node)]; - - while (base != nca) { - (*_ear)[node] = arc; - - Node n = node; - while (n != base) { - n = _graph.target((*_matching)[n]); - Arc a = (*_ear)[n]; - n = _graph.target(a); - (*_ear)[n] = _graph.oppositeArc(a); - } - node = _graph.target((*_matching)[base]); - _tree_set->erase(base); - _tree_set->erase(node); - _blossom_set->insert(node, _blossom_set->find(base)); - (*_status)[node] = EVEN; - _node_queue[_last++] = node; - arc = _graph.oppositeArc((*_ear)[node]); - node = _graph.target((*_ear)[node]); - base = (*_blossom_rep)[_blossom_set->find(node)]; - _blossom_set->join(_graph.target(arc), base); - } - } - - (*_blossom_rep)[_blossom_set->find(nca)] = nca; - } - - void extendOnArc(const Arc& a) { - Node base = _graph.source(a); - Node odd = _graph.target(a); - - (*_ear)[odd] = _graph.oppositeArc(a); - Node even = _graph.target((*_matching)[odd]); - (*_blossom_rep)[_blossom_set->insert(even)] = even; - (*_status)[odd] = ODD; - (*_status)[even] = EVEN; - int tree = _tree_set->find((*_blossom_rep)[_blossom_set->find(base)]); - _tree_set->insert(odd, tree); - _tree_set->insert(even, tree); - _node_queue[_last++] = even; - - } - - void augmentOnArc(const Arc& a) { - Node even = _graph.source(a); - Node odd = _graph.target(a); - - int tree = _tree_set->find((*_blossom_rep)[_blossom_set->find(even)]); - - (*_matching)[odd] = _graph.oppositeArc(a); - (*_status)[odd] = MATCHED; - - Arc arc = (*_matching)[even]; - (*_matching)[even] = a; - - while (arc != INVALID) { - odd = _graph.target(arc); - arc = (*_ear)[odd]; - even = _graph.target(arc); - (*_matching)[odd] = arc; - arc = (*_matching)[even]; - (*_matching)[even] = _graph.oppositeArc((*_matching)[odd]); - } - - for (typename TreeSet::ItemIt it(*_tree_set, tree); - it != INVALID; ++it) { - if ((*_status)[it] == ODD) { - (*_status)[it] = MATCHED; - } else { - int blossom = _blossom_set->find(it); - for (typename BlossomSet::ItemIt jt(*_blossom_set, blossom); - jt != INVALID; ++jt) { - (*_status)[jt] = MATCHED; - } - _blossom_set->eraseClass(blossom); - } - } - _tree_set->eraseClass(tree); - - } - - public: - - /// \brief Constructor - /// - /// Constructor. - MaxMatching(const Graph& graph) - : _graph(graph), _matching(0), _status(0), _ear(0), - _blossom_set_index(0), _blossom_set(0), _blossom_rep(0), - _tree_set_index(0), _tree_set(0) {} - - ~MaxMatching() { - destroyStructures(); - } - - /// \name Execution Control - /// The simplest way to execute the algorithm is to use the - /// \c run() member function.\n - /// If you need better control on the execution, you have to call - /// one of the functions \ref init(), \ref greedyInit() or - /// \ref matchingInit() first, then you can start the algorithm with - /// \ref startSparse() or \ref startDense(). - - ///@{ - - /// \brief Set the initial matching to the empty matching. - /// - /// This function sets the initial matching to the empty matching. - void init() { - createStructures(); - for(NodeIt n(_graph); n != INVALID; ++n) { - (*_matching)[n] = INVALID; - (*_status)[n] = UNMATCHED; - } - } - - /// \brief Find an initial matching in a greedy way. - /// - /// This function finds an initial matching in a greedy way. - void greedyInit() { - createStructures(); - for (NodeIt n(_graph); n != INVALID; ++n) { - (*_matching)[n] = INVALID; - (*_status)[n] = UNMATCHED; - } - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_matching)[n] == INVALID) { - for (OutArcIt a(_graph, n); a != INVALID ; ++a) { - Node v = _graph.target(a); - if ((*_matching)[v] == INVALID && v != n) { - (*_matching)[n] = a; - (*_status)[n] = MATCHED; - (*_matching)[v] = _graph.oppositeArc(a); - (*_status)[v] = MATCHED; - break; - } - } - } - } - } - - - /// \brief Initialize the matching from a map. - /// - /// This function initializes the matching from a \c bool valued edge - /// map. This map should have the property that there are no two incident - /// edges with \c true value, i.e. it really contains a matching. - /// \return \c true if the map contains a matching. - template - bool matchingInit(const MatchingMap& matching) { - createStructures(); - - for (NodeIt n(_graph); n != INVALID; ++n) { - (*_matching)[n] = INVALID; - (*_status)[n] = UNMATCHED; - } - for(EdgeIt e(_graph); e!=INVALID; ++e) { - if (matching[e]) { - - Node u = _graph.u(e); - if ((*_matching)[u] != INVALID) return false; - (*_matching)[u] = _graph.direct(e, true); - (*_status)[u] = MATCHED; - - Node v = _graph.v(e); - if ((*_matching)[v] != INVALID) return false; - (*_matching)[v] = _graph.direct(e, false); - (*_status)[v] = MATCHED; - } - } - return true; - } - - /// \brief Start Edmonds' algorithm - /// - /// This function runs the original Edmonds' algorithm. - /// - /// \pre \ref init(), \ref greedyInit() or \ref matchingInit() must be - /// called before using this function. - void startSparse() { - for(NodeIt n(_graph); n != INVALID; ++n) { - if ((*_status)[n] == UNMATCHED) { - (*_blossom_rep)[_blossom_set->insert(n)] = n; - _tree_set->insert(n); - (*_status)[n] = EVEN; - processSparse(n); - } - } - } - - /// \brief Start Edmonds' algorithm with a heuristic improvement - /// for dense graphs - /// - /// This function runs Edmonds' algorithm with a heuristic of postponing - /// shrinks, therefore resulting in a faster algorithm for dense graphs. - /// - /// \pre \ref init(), \ref greedyInit() or \ref matchingInit() must be - /// called before using this function. - void startDense() { - for(NodeIt n(_graph); n != INVALID; ++n) { - if ((*_status)[n] == UNMATCHED) { - (*_blossom_rep)[_blossom_set->insert(n)] = n; - _tree_set->insert(n); - (*_status)[n] = EVEN; - processDense(n); - } - } - } - - - /// \brief Run Edmonds' algorithm - /// - /// This function runs Edmonds' algorithm. An additional heuristic of - /// postponing shrinks is used for relatively dense graphs - /// (for which m>=2*n holds). - void run() { - if (countEdges(_graph) < 2 * countNodes(_graph)) { - greedyInit(); - startSparse(); - } else { - init(); - startDense(); - } - } - - /// @} - - /// \name Primal Solution - /// Functions to get the primal solution, i.e. the maximum matching. - - /// @{ - - /// \brief Return the size (cardinality) of the matching. - /// - /// This function returns the size (cardinality) of the current matching. - /// After run() it returns the size of the maximum matching in the graph. - int matchingSize() const { - int size = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_matching)[n] != INVALID) { - ++size; - } - } - return size / 2; - } - - /// \brief Return \c true if the given edge is in the matching. - /// - /// This function returns \c true if the given edge is in the current - /// matching. - bool matching(const Edge& edge) const { - return edge == (*_matching)[_graph.u(edge)]; - } - - /// \brief Return the matching arc (or edge) incident to the given node. - /// - /// This function returns the matching arc (or edge) incident to the - /// given node in the current matching or \c INVALID if the node is - /// not covered by the matching. - Arc matching(const Node& n) const { - return (*_matching)[n]; - } - - /// \brief Return a const reference to the matching map. - /// - /// This function returns a const reference to a node map that stores - /// the matching arc (or edge) incident to each node. - const MatchingMap& matchingMap() const { - return *_matching; - } - - /// \brief Return the mate of the given node. - /// - /// This function returns the mate of the given node in the current - /// matching or \c INVALID if the node is not covered by the matching. - Node mate(const Node& n) const { - return (*_matching)[n] != INVALID ? - _graph.target((*_matching)[n]) : INVALID; - } - - /// @} - - /// \name Dual Solution - /// Functions to get the dual solution, i.e. the Gallai-Edmonds - /// decomposition. - - /// @{ - - /// \brief Return the status of the given node in the Edmonds-Gallai - /// decomposition. - /// - /// This function returns the \ref Status "status" of the given node - /// in the Edmonds-Gallai decomposition. - Status status(const Node& n) const { - return (*_status)[n]; - } - - /// \brief Return a const reference to the status map, which stores - /// the Edmonds-Gallai decomposition. - /// - /// This function returns a const reference to a node map that stores the - /// \ref Status "status" of each node in the Edmonds-Gallai decomposition. - const StatusMap& statusMap() const { - return *_status; - } - - /// \brief Return \c true if the given node is in the barrier. - /// - /// This function returns \c true if the given node is in the barrier. - bool barrier(const Node& n) const { - return (*_status)[n] == ODD; - } - - /// @} - - }; - - /// \ingroup matching - /// - /// \brief Weighted matching in general graphs - /// - /// This class provides an efficient implementation of Edmond's - /// maximum weighted matching algorithm. The implementation is based - /// on extensive use of priority queues and provides - /// \f$O(nm\log n)\f$ time complexity. - /// - /// The maximum weighted matching problem is to find a subset of the - /// edges in an undirected graph with maximum overall weight for which - /// each node has at most one incident edge. - /// It can be formulated with the following linear program. - /// \f[ \sum_{e \in \delta(u)}x_e \le 1 \quad \forall u\in V\f] - /** \f[ \sum_{e \in \gamma(B)}x_e \le \frac{\vert B \vert - 1}{2} - \quad \forall B\in\mathcal{O}\f] */ - /// \f[x_e \ge 0\quad \forall e\in E\f] - /// \f[\max \sum_{e\in E}x_ew_e\f] - /// where \f$\delta(X)\f$ is the set of edges incident to a node in - /// \f$X\f$, \f$\gamma(X)\f$ is the set of edges with both ends in - /// \f$X\f$ and \f$\mathcal{O}\f$ is the set of odd cardinality - /// subsets of the nodes. - /// - /// The algorithm calculates an optimal matching and a proof of the - /// optimality. The solution of the dual problem can be used to check - /// the result of the algorithm. The dual linear problem is the - /// following. - /** \f[ y_u + y_v + \sum_{B \in \mathcal{O}, uv \in \gamma(B)} - z_B \ge w_{uv} \quad \forall uv\in E\f] */ - /// \f[y_u \ge 0 \quad \forall u \in V\f] - /// \f[z_B \ge 0 \quad \forall B \in \mathcal{O}\f] - /** \f[\min \sum_{u \in V}y_u + \sum_{B \in \mathcal{O}} - \frac{\vert B \vert - 1}{2}z_B\f] */ - /// - /// The algorithm can be executed with the run() function. - /// After it the matching (the primal solution) and the dual solution - /// can be obtained using the query functions and the - /// \ref MaxWeightedMatching::BlossomIt "BlossomIt" nested class, - /// which is able to iterate on the nodes of a blossom. - /// If the value type is integer, then the dual solution is multiplied - /// by \ref MaxWeightedMatching::dualScale "4". - /// - /// \tparam GR The undirected graph type the algorithm runs on. - /// \tparam WM The type edge weight map. The default type is - /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". -#ifdef DOXYGEN - template -#else - template > -#endif - class MaxWeightedMatching { - public: - - /// The graph type of the algorithm - typedef GR Graph; - /// The type of the edge weight map - typedef WM WeightMap; - /// The value type of the edge weights - typedef typename WeightMap::Value Value; - - /// The type of the matching map - typedef typename Graph::template NodeMap - MatchingMap; - - /// \brief Scaling factor for dual solution - /// - /// Scaling factor for dual solution. It is equal to 4 or 1 - /// according to the value type. - static const int dualScale = - std::numeric_limits::is_integer ? 4 : 1; - - private: - - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - typedef typename Graph::template NodeMap NodePotential; - typedef std::vector BlossomNodeList; - - struct BlossomVariable { - int begin, end; - Value value; - - BlossomVariable(int _begin, int _end, Value _value) - : begin(_begin), end(_end), value(_value) {} - - }; - - typedef std::vector BlossomPotential; - - const Graph& _graph; - const WeightMap& _weight; - - MatchingMap* _matching; - - NodePotential* _node_potential; - - BlossomPotential _blossom_potential; - BlossomNodeList _blossom_node_list; - - int _node_num; - int _blossom_num; - - typedef RangeMap IntIntMap; - - enum Status { - EVEN = -1, MATCHED = 0, ODD = 1 - }; - - typedef HeapUnionFind BlossomSet; - struct BlossomData { - int tree; - Status status; - Arc pred, next; - Value pot, offset; - Node base; - }; - - IntNodeMap *_blossom_index; - BlossomSet *_blossom_set; - RangeMap* _blossom_data; - - IntNodeMap *_node_index; - IntArcMap *_node_heap_index; - - struct NodeData { - - NodeData(IntArcMap& node_heap_index) - : heap(node_heap_index) {} - - int blossom; - Value pot; - BinHeap heap; - std::map heap_index; - - int tree; - }; - - RangeMap* _node_data; - - typedef ExtendFindEnum TreeSet; - - IntIntMap *_tree_set_index; - TreeSet *_tree_set; - - IntNodeMap *_delta1_index; - BinHeap *_delta1; - - IntIntMap *_delta2_index; - BinHeap *_delta2; - - IntEdgeMap *_delta3_index; - BinHeap *_delta3; - - IntIntMap *_delta4_index; - BinHeap *_delta4; - - Value _delta_sum; - int _unmatched; - - typedef MaxWeightedFractionalMatching FractionalMatching; - FractionalMatching *_fractional; - - void createStructures() { - _node_num = countNodes(_graph); - _blossom_num = _node_num * 3 / 2; - - if (!_matching) { - _matching = new MatchingMap(_graph); - } - - if (!_node_potential) { - _node_potential = new NodePotential(_graph); - } - - if (!_blossom_set) { - _blossom_index = new IntNodeMap(_graph); - _blossom_set = new BlossomSet(*_blossom_index); - _blossom_data = new RangeMap(_blossom_num); - } else if (_blossom_data->size() != _blossom_num) { - delete _blossom_data; - _blossom_data = new RangeMap(_blossom_num); - } - - if (!_node_index) { - _node_index = new IntNodeMap(_graph); - _node_heap_index = new IntArcMap(_graph); - _node_data = new RangeMap(_node_num, - NodeData(*_node_heap_index)); - } else { - delete _node_data; - _node_data = new RangeMap(_node_num, - NodeData(*_node_heap_index)); - } - - if (!_tree_set) { - _tree_set_index = new IntIntMap(_blossom_num); - _tree_set = new TreeSet(*_tree_set_index); - } else { - _tree_set_index->resize(_blossom_num); - } - - if (!_delta1) { - _delta1_index = new IntNodeMap(_graph); - _delta1 = new BinHeap(*_delta1_index); - } - - if (!_delta2) { - _delta2_index = new IntIntMap(_blossom_num); - _delta2 = new BinHeap(*_delta2_index); - } else { - _delta2_index->resize(_blossom_num); - } - - if (!_delta3) { - _delta3_index = new IntEdgeMap(_graph); - _delta3 = new BinHeap(*_delta3_index); - } - - if (!_delta4) { - _delta4_index = new IntIntMap(_blossom_num); - _delta4 = new BinHeap(*_delta4_index); - } else { - _delta4_index->resize(_blossom_num); - } - } - - void destroyStructures() { - if (_matching) { - delete _matching; - } - if (_node_potential) { - delete _node_potential; - } - if (_blossom_set) { - delete _blossom_index; - delete _blossom_set; - delete _blossom_data; - } - - if (_node_index) { - delete _node_index; - delete _node_heap_index; - delete _node_data; - } - - if (_tree_set) { - delete _tree_set_index; - delete _tree_set; - } - if (_delta1) { - delete _delta1_index; - delete _delta1; - } - if (_delta2) { - delete _delta2_index; - delete _delta2; - } - if (_delta3) { - delete _delta3_index; - delete _delta3; - } - if (_delta4) { - delete _delta4_index; - delete _delta4; - } - } - - void matchedToEven(int blossom, int tree) { - if (_delta2->state(blossom) == _delta2->IN_HEAP) { - _delta2->erase(blossom); - } - - if (!_blossom_set->trivial(blossom)) { - (*_blossom_data)[blossom].pot -= - 2 * (_delta_sum - (*_blossom_data)[blossom].offset); - } - - for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); - n != INVALID; ++n) { - - _blossom_set->increase(n, std::numeric_limits::max()); - int ni = (*_node_index)[n]; - - (*_node_data)[ni].heap.clear(); - (*_node_data)[ni].heap_index.clear(); - - (*_node_data)[ni].pot += _delta_sum - (*_blossom_data)[blossom].offset; - - _delta1->push(n, (*_node_data)[ni].pot); - - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.source(e); - int vb = _blossom_set->find(v); - int vi = (*_node_index)[v]; - - Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - - dualScale * _weight[e]; - - if ((*_blossom_data)[vb].status == EVEN) { - if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { - _delta3->push(e, rw / 2); - } - } else { - typename std::map::iterator it = - (*_node_data)[vi].heap_index.find(tree); - - if (it != (*_node_data)[vi].heap_index.end()) { - if ((*_node_data)[vi].heap[it->second] > rw) { - (*_node_data)[vi].heap.replace(it->second, e); - (*_node_data)[vi].heap.decrease(e, rw); - it->second = e; - } - } else { - (*_node_data)[vi].heap.push(e, rw); - (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e)); - } - - if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) { - _blossom_set->decrease(v, (*_node_data)[vi].heap.prio()); - - if ((*_blossom_data)[vb].status == MATCHED) { - if (_delta2->state(vb) != _delta2->IN_HEAP) { - _delta2->push(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset) { - _delta2->decrease(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } - } - } - } - } - } - (*_blossom_data)[blossom].offset = 0; - } - - void matchedToOdd(int blossom) { - if (_delta2->state(blossom) == _delta2->IN_HEAP) { - _delta2->erase(blossom); - } - (*_blossom_data)[blossom].offset += _delta_sum; - if (!_blossom_set->trivial(blossom)) { - _delta4->push(blossom, (*_blossom_data)[blossom].pot / 2 + - (*_blossom_data)[blossom].offset); - } - } - - void evenToMatched(int blossom, int tree) { - if (!_blossom_set->trivial(blossom)) { - (*_blossom_data)[blossom].pot += 2 * _delta_sum; - } - - for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); - n != INVALID; ++n) { - int ni = (*_node_index)[n]; - (*_node_data)[ni].pot -= _delta_sum; - - _delta1->erase(n); - - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.source(e); - int vb = _blossom_set->find(v); - int vi = (*_node_index)[v]; - - Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - - dualScale * _weight[e]; - - if (vb == blossom) { - if (_delta3->state(e) == _delta3->IN_HEAP) { - _delta3->erase(e); - } - } else if ((*_blossom_data)[vb].status == EVEN) { - - if (_delta3->state(e) == _delta3->IN_HEAP) { - _delta3->erase(e); - } - - int vt = _tree_set->find(vb); - - if (vt != tree) { - - Arc r = _graph.oppositeArc(e); - - typename std::map::iterator it = - (*_node_data)[ni].heap_index.find(vt); - - if (it != (*_node_data)[ni].heap_index.end()) { - if ((*_node_data)[ni].heap[it->second] > rw) { - (*_node_data)[ni].heap.replace(it->second, r); - (*_node_data)[ni].heap.decrease(r, rw); - it->second = r; - } - } else { - (*_node_data)[ni].heap.push(r, rw); - (*_node_data)[ni].heap_index.insert(std::make_pair(vt, r)); - } - - if ((*_blossom_set)[n] > (*_node_data)[ni].heap.prio()) { - _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); - - if (_delta2->state(blossom) != _delta2->IN_HEAP) { - _delta2->push(blossom, _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset); - } else if ((*_delta2)[blossom] > - _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset){ - _delta2->decrease(blossom, _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset); - } - } - } - } else { - - typename std::map::iterator it = - (*_node_data)[vi].heap_index.find(tree); - - if (it != (*_node_data)[vi].heap_index.end()) { - (*_node_data)[vi].heap.erase(it->second); - (*_node_data)[vi].heap_index.erase(it); - if ((*_node_data)[vi].heap.empty()) { - _blossom_set->increase(v, std::numeric_limits::max()); - } else if ((*_blossom_set)[v] < (*_node_data)[vi].heap.prio()) { - _blossom_set->increase(v, (*_node_data)[vi].heap.prio()); - } - - if ((*_blossom_data)[vb].status == MATCHED) { - if (_blossom_set->classPrio(vb) == - std::numeric_limits::max()) { - _delta2->erase(vb); - } else if ((*_delta2)[vb] < _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset) { - _delta2->increase(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } - } - } - } - } - } - } - - void oddToMatched(int blossom) { - (*_blossom_data)[blossom].offset -= _delta_sum; - - if (_blossom_set->classPrio(blossom) != - std::numeric_limits::max()) { - _delta2->push(blossom, _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset); - } - - if (!_blossom_set->trivial(blossom)) { - _delta4->erase(blossom); - } - } - - void oddToEven(int blossom, int tree) { - if (!_blossom_set->trivial(blossom)) { - _delta4->erase(blossom); - (*_blossom_data)[blossom].pot -= - 2 * (2 * _delta_sum - (*_blossom_data)[blossom].offset); - } - - for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); - n != INVALID; ++n) { - int ni = (*_node_index)[n]; - - _blossom_set->increase(n, std::numeric_limits::max()); - - (*_node_data)[ni].heap.clear(); - (*_node_data)[ni].heap_index.clear(); - (*_node_data)[ni].pot += - 2 * _delta_sum - (*_blossom_data)[blossom].offset; - - _delta1->push(n, (*_node_data)[ni].pot); - - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.source(e); - int vb = _blossom_set->find(v); - int vi = (*_node_index)[v]; - - Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - - dualScale * _weight[e]; - - if ((*_blossom_data)[vb].status == EVEN) { - if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { - _delta3->push(e, rw / 2); - } - } else { - - typename std::map::iterator it = - (*_node_data)[vi].heap_index.find(tree); - - if (it != (*_node_data)[vi].heap_index.end()) { - if ((*_node_data)[vi].heap[it->second] > rw) { - (*_node_data)[vi].heap.replace(it->second, e); - (*_node_data)[vi].heap.decrease(e, rw); - it->second = e; - } - } else { - (*_node_data)[vi].heap.push(e, rw); - (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e)); - } - - if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) { - _blossom_set->decrease(v, (*_node_data)[vi].heap.prio()); - - if ((*_blossom_data)[vb].status == MATCHED) { - if (_delta2->state(vb) != _delta2->IN_HEAP) { - _delta2->push(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset) { - _delta2->decrease(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } - } - } - } - } - } - (*_blossom_data)[blossom].offset = 0; - } - - void alternatePath(int even, int tree) { - int odd; - - evenToMatched(even, tree); - (*_blossom_data)[even].status = MATCHED; - - while ((*_blossom_data)[even].pred != INVALID) { - odd = _blossom_set->find(_graph.target((*_blossom_data)[even].pred)); - (*_blossom_data)[odd].status = MATCHED; - oddToMatched(odd); - (*_blossom_data)[odd].next = (*_blossom_data)[odd].pred; - - even = _blossom_set->find(_graph.target((*_blossom_data)[odd].pred)); - (*_blossom_data)[even].status = MATCHED; - evenToMatched(even, tree); - (*_blossom_data)[even].next = - _graph.oppositeArc((*_blossom_data)[odd].pred); - } - - } - - void destroyTree(int tree) { - for (TreeSet::ItemIt b(*_tree_set, tree); b != INVALID; ++b) { - if ((*_blossom_data)[b].status == EVEN) { - (*_blossom_data)[b].status = MATCHED; - evenToMatched(b, tree); - } else if ((*_blossom_data)[b].status == ODD) { - (*_blossom_data)[b].status = MATCHED; - oddToMatched(b); - } - } - _tree_set->eraseClass(tree); - } - - - void unmatchNode(const Node& node) { - int blossom = _blossom_set->find(node); - int tree = _tree_set->find(blossom); - - alternatePath(blossom, tree); - destroyTree(tree); - - (*_blossom_data)[blossom].base = node; - (*_blossom_data)[blossom].next = INVALID; - } - - void augmentOnEdge(const Edge& edge) { - - int left = _blossom_set->find(_graph.u(edge)); - int right = _blossom_set->find(_graph.v(edge)); - - int left_tree = _tree_set->find(left); - alternatePath(left, left_tree); - destroyTree(left_tree); - - int right_tree = _tree_set->find(right); - alternatePath(right, right_tree); - destroyTree(right_tree); - - (*_blossom_data)[left].next = _graph.direct(edge, true); - (*_blossom_data)[right].next = _graph.direct(edge, false); - } - - void augmentOnArc(const Arc& arc) { - - int left = _blossom_set->find(_graph.source(arc)); - int right = _blossom_set->find(_graph.target(arc)); - - (*_blossom_data)[left].status = MATCHED; - - int right_tree = _tree_set->find(right); - alternatePath(right, right_tree); - destroyTree(right_tree); - - (*_blossom_data)[left].next = arc; - (*_blossom_data)[right].next = _graph.oppositeArc(arc); - } - - void extendOnArc(const Arc& arc) { - int base = _blossom_set->find(_graph.target(arc)); - int tree = _tree_set->find(base); - - int odd = _blossom_set->find(_graph.source(arc)); - _tree_set->insert(odd, tree); - (*_blossom_data)[odd].status = ODD; - matchedToOdd(odd); - (*_blossom_data)[odd].pred = arc; - - int even = _blossom_set->find(_graph.target((*_blossom_data)[odd].next)); - (*_blossom_data)[even].pred = (*_blossom_data)[even].next; - _tree_set->insert(even, tree); - (*_blossom_data)[even].status = EVEN; - matchedToEven(even, tree); - } - - void shrinkOnEdge(const Edge& edge, int tree) { - int nca = -1; - std::vector left_path, right_path; - - { - std::set left_set, right_set; - int left = _blossom_set->find(_graph.u(edge)); - left_path.push_back(left); - left_set.insert(left); - - int right = _blossom_set->find(_graph.v(edge)); - right_path.push_back(right); - right_set.insert(right); - - while (true) { - - if ((*_blossom_data)[left].pred == INVALID) break; - - left = - _blossom_set->find(_graph.target((*_blossom_data)[left].pred)); - left_path.push_back(left); - left = - _blossom_set->find(_graph.target((*_blossom_data)[left].pred)); - left_path.push_back(left); - - left_set.insert(left); - - if (right_set.find(left) != right_set.end()) { - nca = left; - break; - } - - if ((*_blossom_data)[right].pred == INVALID) break; - - right = - _blossom_set->find(_graph.target((*_blossom_data)[right].pred)); - right_path.push_back(right); - right = - _blossom_set->find(_graph.target((*_blossom_data)[right].pred)); - right_path.push_back(right); - - right_set.insert(right); - - if (left_set.find(right) != left_set.end()) { - nca = right; - break; - } - - } - - if (nca == -1) { - if ((*_blossom_data)[left].pred == INVALID) { - nca = right; - while (left_set.find(nca) == left_set.end()) { - nca = - _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); - right_path.push_back(nca); - nca = - _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); - right_path.push_back(nca); - } - } else { - nca = left; - while (right_set.find(nca) == right_set.end()) { - nca = - _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); - left_path.push_back(nca); - nca = - _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); - left_path.push_back(nca); - } - } - } - } - - std::vector subblossoms; - Arc prev; - - prev = _graph.direct(edge, true); - for (int i = 0; left_path[i] != nca; i += 2) { - subblossoms.push_back(left_path[i]); - (*_blossom_data)[left_path[i]].next = prev; - _tree_set->erase(left_path[i]); - - subblossoms.push_back(left_path[i + 1]); - (*_blossom_data)[left_path[i + 1]].status = EVEN; - oddToEven(left_path[i + 1], tree); - _tree_set->erase(left_path[i + 1]); - prev = _graph.oppositeArc((*_blossom_data)[left_path[i + 1]].pred); - } - - int k = 0; - while (right_path[k] != nca) ++k; - - subblossoms.push_back(nca); - (*_blossom_data)[nca].next = prev; - - for (int i = k - 2; i >= 0; i -= 2) { - subblossoms.push_back(right_path[i + 1]); - (*_blossom_data)[right_path[i + 1]].status = EVEN; - oddToEven(right_path[i + 1], tree); - _tree_set->erase(right_path[i + 1]); - - (*_blossom_data)[right_path[i + 1]].next = - (*_blossom_data)[right_path[i + 1]].pred; - - subblossoms.push_back(right_path[i]); - _tree_set->erase(right_path[i]); - } - - int surface = - _blossom_set->join(subblossoms.begin(), subblossoms.end()); - - for (int i = 0; i < int(subblossoms.size()); ++i) { - if (!_blossom_set->trivial(subblossoms[i])) { - (*_blossom_data)[subblossoms[i]].pot += 2 * _delta_sum; - } - (*_blossom_data)[subblossoms[i]].status = MATCHED; - } - - (*_blossom_data)[surface].pot = -2 * _delta_sum; - (*_blossom_data)[surface].offset = 0; - (*_blossom_data)[surface].status = EVEN; - (*_blossom_data)[surface].pred = (*_blossom_data)[nca].pred; - (*_blossom_data)[surface].next = (*_blossom_data)[nca].pred; - - _tree_set->insert(surface, tree); - _tree_set->erase(nca); - } - - void splitBlossom(int blossom) { - Arc next = (*_blossom_data)[blossom].next; - Arc pred = (*_blossom_data)[blossom].pred; - - int tree = _tree_set->find(blossom); - - (*_blossom_data)[blossom].status = MATCHED; - oddToMatched(blossom); - if (_delta2->state(blossom) == _delta2->IN_HEAP) { - _delta2->erase(blossom); - } - - std::vector subblossoms; - _blossom_set->split(blossom, std::back_inserter(subblossoms)); - - Value offset = (*_blossom_data)[blossom].offset; - int b = _blossom_set->find(_graph.source(pred)); - int d = _blossom_set->find(_graph.source(next)); - - int ib = -1, id = -1; - for (int i = 0; i < int(subblossoms.size()); ++i) { - if (subblossoms[i] == b) ib = i; - if (subblossoms[i] == d) id = i; - - (*_blossom_data)[subblossoms[i]].offset = offset; - if (!_blossom_set->trivial(subblossoms[i])) { - (*_blossom_data)[subblossoms[i]].pot -= 2 * offset; - } - if (_blossom_set->classPrio(subblossoms[i]) != - std::numeric_limits::max()) { - _delta2->push(subblossoms[i], - _blossom_set->classPrio(subblossoms[i]) - - (*_blossom_data)[subblossoms[i]].offset); - } - } - - if (id > ib ? ((id - ib) % 2 == 0) : ((ib - id) % 2 == 1)) { - for (int i = (id + 1) % subblossoms.size(); - i != ib; i = (i + 2) % subblossoms.size()) { - int sb = subblossoms[i]; - int tb = subblossoms[(i + 1) % subblossoms.size()]; - (*_blossom_data)[sb].next = - _graph.oppositeArc((*_blossom_data)[tb].next); - } - - for (int i = ib; i != id; i = (i + 2) % subblossoms.size()) { - int sb = subblossoms[i]; - int tb = subblossoms[(i + 1) % subblossoms.size()]; - int ub = subblossoms[(i + 2) % subblossoms.size()]; - - (*_blossom_data)[sb].status = ODD; - matchedToOdd(sb); - _tree_set->insert(sb, tree); - (*_blossom_data)[sb].pred = pred; - (*_blossom_data)[sb].next = - _graph.oppositeArc((*_blossom_data)[tb].next); - - pred = (*_blossom_data)[ub].next; - - (*_blossom_data)[tb].status = EVEN; - matchedToEven(tb, tree); - _tree_set->insert(tb, tree); - (*_blossom_data)[tb].pred = (*_blossom_data)[tb].next; - } - - (*_blossom_data)[subblossoms[id]].status = ODD; - matchedToOdd(subblossoms[id]); - _tree_set->insert(subblossoms[id], tree); - (*_blossom_data)[subblossoms[id]].next = next; - (*_blossom_data)[subblossoms[id]].pred = pred; - - } else { - - for (int i = (ib + 1) % subblossoms.size(); - i != id; i = (i + 2) % subblossoms.size()) { - int sb = subblossoms[i]; - int tb = subblossoms[(i + 1) % subblossoms.size()]; - (*_blossom_data)[sb].next = - _graph.oppositeArc((*_blossom_data)[tb].next); - } - - for (int i = id; i != ib; i = (i + 2) % subblossoms.size()) { - int sb = subblossoms[i]; - int tb = subblossoms[(i + 1) % subblossoms.size()]; - int ub = subblossoms[(i + 2) % subblossoms.size()]; - - (*_blossom_data)[sb].status = ODD; - matchedToOdd(sb); - _tree_set->insert(sb, tree); - (*_blossom_data)[sb].next = next; - (*_blossom_data)[sb].pred = - _graph.oppositeArc((*_blossom_data)[tb].next); - - (*_blossom_data)[tb].status = EVEN; - matchedToEven(tb, tree); - _tree_set->insert(tb, tree); - (*_blossom_data)[tb].pred = - (*_blossom_data)[tb].next = - _graph.oppositeArc((*_blossom_data)[ub].next); - next = (*_blossom_data)[ub].next; - } - - (*_blossom_data)[subblossoms[ib]].status = ODD; - matchedToOdd(subblossoms[ib]); - _tree_set->insert(subblossoms[ib], tree); - (*_blossom_data)[subblossoms[ib]].next = next; - (*_blossom_data)[subblossoms[ib]].pred = pred; - } - _tree_set->erase(blossom); - } - - void extractBlossom(int blossom, const Node& base, const Arc& matching) { - if (_blossom_set->trivial(blossom)) { - int bi = (*_node_index)[base]; - Value pot = (*_node_data)[bi].pot; - - (*_matching)[base] = matching; - _blossom_node_list.push_back(base); - (*_node_potential)[base] = pot; - } else { - - Value pot = (*_blossom_data)[blossom].pot; - int bn = _blossom_node_list.size(); - - std::vector subblossoms; - _blossom_set->split(blossom, std::back_inserter(subblossoms)); - int b = _blossom_set->find(base); - int ib = -1; - for (int i = 0; i < int(subblossoms.size()); ++i) { - if (subblossoms[i] == b) { ib = i; break; } - } - - for (int i = 1; i < int(subblossoms.size()); i += 2) { - int sb = subblossoms[(ib + i) % subblossoms.size()]; - int tb = subblossoms[(ib + i + 1) % subblossoms.size()]; - - Arc m = (*_blossom_data)[tb].next; - extractBlossom(sb, _graph.target(m), _graph.oppositeArc(m)); - extractBlossom(tb, _graph.source(m), m); - } - extractBlossom(subblossoms[ib], base, matching); - - int en = _blossom_node_list.size(); - - _blossom_potential.push_back(BlossomVariable(bn, en, pot)); - } - } - - void extractMatching() { - std::vector blossoms; - for (typename BlossomSet::ClassIt c(*_blossom_set); c != INVALID; ++c) { - blossoms.push_back(c); - } - - for (int i = 0; i < int(blossoms.size()); ++i) { - if ((*_blossom_data)[blossoms[i]].next != INVALID) { - - Value offset = (*_blossom_data)[blossoms[i]].offset; - (*_blossom_data)[blossoms[i]].pot += 2 * offset; - for (typename BlossomSet::ItemIt n(*_blossom_set, blossoms[i]); - n != INVALID; ++n) { - (*_node_data)[(*_node_index)[n]].pot -= offset; - } - - Arc matching = (*_blossom_data)[blossoms[i]].next; - Node base = _graph.source(matching); - extractBlossom(blossoms[i], base, matching); - } else { - Node base = (*_blossom_data)[blossoms[i]].base; - extractBlossom(blossoms[i], base, INVALID); - } - } - } - - public: - - /// \brief Constructor - /// - /// Constructor. - MaxWeightedMatching(const Graph& graph, const WeightMap& weight) - : _graph(graph), _weight(weight), _matching(0), - _node_potential(0), _blossom_potential(), _blossom_node_list(), - _node_num(0), _blossom_num(0), - - _blossom_index(0), _blossom_set(0), _blossom_data(0), - _node_index(0), _node_heap_index(0), _node_data(0), - _tree_set_index(0), _tree_set(0), - - _delta1_index(0), _delta1(0), - _delta2_index(0), _delta2(0), - _delta3_index(0), _delta3(0), - _delta4_index(0), _delta4(0), - - _delta_sum(), _unmatched(0), - - _fractional(0) - {} - - ~MaxWeightedMatching() { - destroyStructures(); - if (_fractional) { - delete _fractional; - } - } - - /// \name Execution Control - /// The simplest way to execute the algorithm is to use the - /// \ref run() member function. - - ///@{ - - /// \brief Initialize the algorithm - /// - /// This function initializes the algorithm. - void init() { - createStructures(); - - _blossom_node_list.clear(); - _blossom_potential.clear(); - - for (ArcIt e(_graph); e != INVALID; ++e) { - (*_node_heap_index)[e] = BinHeap::PRE_HEAP; - } - for (NodeIt n(_graph); n != INVALID; ++n) { - (*_delta1_index)[n] = _delta1->PRE_HEAP; - } - for (EdgeIt e(_graph); e != INVALID; ++e) { - (*_delta3_index)[e] = _delta3->PRE_HEAP; - } - for (int i = 0; i < _blossom_num; ++i) { - (*_delta2_index)[i] = _delta2->PRE_HEAP; - (*_delta4_index)[i] = _delta4->PRE_HEAP; - } - - _unmatched = _node_num; - - _delta1->clear(); - _delta2->clear(); - _delta3->clear(); - _delta4->clear(); - _blossom_set->clear(); - _tree_set->clear(); - - int index = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - Value max = 0; - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - if (_graph.target(e) == n) continue; - if ((dualScale * _weight[e]) / 2 > max) { - max = (dualScale * _weight[e]) / 2; - } - } - (*_node_index)[n] = index; - (*_node_data)[index].heap_index.clear(); - (*_node_data)[index].heap.clear(); - (*_node_data)[index].pot = max; - _delta1->push(n, max); - int blossom = - _blossom_set->insert(n, std::numeric_limits::max()); - - _tree_set->insert(blossom); - - (*_blossom_data)[blossom].status = EVEN; - (*_blossom_data)[blossom].pred = INVALID; - (*_blossom_data)[blossom].next = INVALID; - (*_blossom_data)[blossom].pot = 0; - (*_blossom_data)[blossom].offset = 0; - ++index; - } - for (EdgeIt e(_graph); e != INVALID; ++e) { - int si = (*_node_index)[_graph.u(e)]; - int ti = (*_node_index)[_graph.v(e)]; - if (_graph.u(e) != _graph.v(e)) { - _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot - - dualScale * _weight[e]) / 2); - } - } - } - - /// \brief Initialize the algorithm with fractional matching - /// - /// This function initializes the algorithm with a fractional - /// matching. This initialization is also called jumpstart heuristic. - void fractionalInit() { - createStructures(); - - _blossom_node_list.clear(); - _blossom_potential.clear(); - - if (_fractional == 0) { - _fractional = new FractionalMatching(_graph, _weight, false); - } - _fractional->run(); - - for (ArcIt e(_graph); e != INVALID; ++e) { - (*_node_heap_index)[e] = BinHeap::PRE_HEAP; - } - for (NodeIt n(_graph); n != INVALID; ++n) { - (*_delta1_index)[n] = _delta1->PRE_HEAP; - } - for (EdgeIt e(_graph); e != INVALID; ++e) { - (*_delta3_index)[e] = _delta3->PRE_HEAP; - } - for (int i = 0; i < _blossom_num; ++i) { - (*_delta2_index)[i] = _delta2->PRE_HEAP; - (*_delta4_index)[i] = _delta4->PRE_HEAP; - } - - _unmatched = 0; - - _delta1->clear(); - _delta2->clear(); - _delta3->clear(); - _delta4->clear(); - _blossom_set->clear(); - _tree_set->clear(); - - int index = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - Value pot = _fractional->nodeValue(n); - (*_node_index)[n] = index; - (*_node_data)[index].pot = pot; - (*_node_data)[index].heap_index.clear(); - (*_node_data)[index].heap.clear(); - int blossom = - _blossom_set->insert(n, std::numeric_limits::max()); - - (*_blossom_data)[blossom].status = MATCHED; - (*_blossom_data)[blossom].pred = INVALID; - (*_blossom_data)[blossom].next = _fractional->matching(n); - if (_fractional->matching(n) == INVALID) { - (*_blossom_data)[blossom].base = n; - } - (*_blossom_data)[blossom].pot = 0; - (*_blossom_data)[blossom].offset = 0; - ++index; - } - - typename Graph::template NodeMap processed(_graph, false); - for (NodeIt n(_graph); n != INVALID; ++n) { - if (processed[n]) continue; - processed[n] = true; - if (_fractional->matching(n) == INVALID) continue; - int num = 1; - Node v = _graph.target(_fractional->matching(n)); - while (n != v) { - processed[v] = true; - v = _graph.target(_fractional->matching(v)); - ++num; - } - - if (num % 2 == 1) { - std::vector subblossoms(num); - - subblossoms[--num] = _blossom_set->find(n); - _delta1->push(n, _fractional->nodeValue(n)); - v = _graph.target(_fractional->matching(n)); - while (n != v) { - subblossoms[--num] = _blossom_set->find(v); - _delta1->push(v, _fractional->nodeValue(v)); - v = _graph.target(_fractional->matching(v)); - } - - int surface = - _blossom_set->join(subblossoms.begin(), subblossoms.end()); - (*_blossom_data)[surface].status = EVEN; - (*_blossom_data)[surface].pred = INVALID; - (*_blossom_data)[surface].next = INVALID; - (*_blossom_data)[surface].pot = 0; - (*_blossom_data)[surface].offset = 0; - - _tree_set->insert(surface); - ++_unmatched; - } - } - - for (EdgeIt e(_graph); e != INVALID; ++e) { - int si = (*_node_index)[_graph.u(e)]; - int sb = _blossom_set->find(_graph.u(e)); - int ti = (*_node_index)[_graph.v(e)]; - int tb = _blossom_set->find(_graph.v(e)); - if ((*_blossom_data)[sb].status == EVEN && - (*_blossom_data)[tb].status == EVEN && sb != tb) { - _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot - - dualScale * _weight[e]) / 2); - } - } - - for (NodeIt n(_graph); n != INVALID; ++n) { - int nb = _blossom_set->find(n); - if ((*_blossom_data)[nb].status != MATCHED) continue; - int ni = (*_node_index)[n]; - - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.target(e); - int vb = _blossom_set->find(v); - int vi = (*_node_index)[v]; - - Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - - dualScale * _weight[e]; - - if ((*_blossom_data)[vb].status == EVEN) { - - int vt = _tree_set->find(vb); - - typename std::map::iterator it = - (*_node_data)[ni].heap_index.find(vt); - - if (it != (*_node_data)[ni].heap_index.end()) { - if ((*_node_data)[ni].heap[it->second] > rw) { - (*_node_data)[ni].heap.replace(it->second, e); - (*_node_data)[ni].heap.decrease(e, rw); - it->second = e; - } - } else { - (*_node_data)[ni].heap.push(e, rw); - (*_node_data)[ni].heap_index.insert(std::make_pair(vt, e)); - } - } - } - - if (!(*_node_data)[ni].heap.empty()) { - _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); - _delta2->push(nb, _blossom_set->classPrio(nb)); - } - } - } - - /// \brief Start the algorithm - /// - /// This function starts the algorithm. - /// - /// \pre \ref init() or \ref fractionalInit() must be called - /// before using this function. - void start() { - enum OpType { - D1, D2, D3, D4 - }; - - while (_unmatched > 0) { - Value d1 = !_delta1->empty() ? - _delta1->prio() : std::numeric_limits::max(); - - Value d2 = !_delta2->empty() ? - _delta2->prio() : std::numeric_limits::max(); - - Value d3 = !_delta3->empty() ? - _delta3->prio() : std::numeric_limits::max(); - - Value d4 = !_delta4->empty() ? - _delta4->prio() : std::numeric_limits::max(); - - _delta_sum = d3; OpType ot = D3; - if (d1 < _delta_sum) { _delta_sum = d1; ot = D1; } - if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } - if (d4 < _delta_sum) { _delta_sum = d4; ot = D4; } - - switch (ot) { - case D1: - { - Node n = _delta1->top(); - unmatchNode(n); - --_unmatched; - } - break; - case D2: - { - int blossom = _delta2->top(); - Node n = _blossom_set->classTop(blossom); - Arc a = (*_node_data)[(*_node_index)[n]].heap.top(); - if ((*_blossom_data)[blossom].next == INVALID) { - augmentOnArc(a); - --_unmatched; - } else { - extendOnArc(a); - } - } - break; - case D3: - { - Edge e = _delta3->top(); - - int left_blossom = _blossom_set->find(_graph.u(e)); - int right_blossom = _blossom_set->find(_graph.v(e)); - - if (left_blossom == right_blossom) { - _delta3->pop(); - } else { - int left_tree = _tree_set->find(left_blossom); - int right_tree = _tree_set->find(right_blossom); - - if (left_tree == right_tree) { - shrinkOnEdge(e, left_tree); - } else { - augmentOnEdge(e); - _unmatched -= 2; - } - } - } break; - case D4: - splitBlossom(_delta4->top()); - break; - } - } - extractMatching(); - } - - /// \brief Run the algorithm. - /// - /// This method runs the \c %MaxWeightedMatching algorithm. - /// - /// \note mwm.run() is just a shortcut of the following code. - /// \code - /// mwm.fractionalInit(); - /// mwm.start(); - /// \endcode - void run() { - fractionalInit(); - start(); - } - - /// @} - - /// \name Primal Solution - /// Functions to get the primal solution, i.e. the maximum weighted - /// matching.\n - /// Either \ref run() or \ref start() function should be called before - /// using them. - - /// @{ - - /// \brief Return the weight of the matching. - /// - /// This function returns the weight of the found matching. - /// - /// \pre Either run() or start() must be called before using this function. - Value matchingWeight() const { - Value sum = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_matching)[n] != INVALID) { - sum += _weight[(*_matching)[n]]; - } - } - return sum / 2; - } - - /// \brief Return the size (cardinality) of the matching. - /// - /// This function returns the size (cardinality) of the found matching. - /// - /// \pre Either run() or start() must be called before using this function. - int matchingSize() const { - int num = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_matching)[n] != INVALID) { - ++num; - } - } - return num /= 2; - } - - /// \brief Return \c true if the given edge is in the matching. - /// - /// This function returns \c true if the given edge is in the found - /// matching. - /// - /// \pre Either run() or start() must be called before using this function. - bool matching(const Edge& edge) const { - return edge == (*_matching)[_graph.u(edge)]; - } - - /// \brief Return the matching arc (or edge) incident to the given node. - /// - /// This function returns the matching arc (or edge) incident to the - /// given node in the found matching or \c INVALID if the node is - /// not covered by the matching. - /// - /// \pre Either run() or start() must be called before using this function. - Arc matching(const Node& node) const { - return (*_matching)[node]; - } - - /// \brief Return a const reference to the matching map. - /// - /// This function returns a const reference to a node map that stores - /// the matching arc (or edge) incident to each node. - const MatchingMap& matchingMap() const { - return *_matching; - } - - /// \brief Return the mate of the given node. - /// - /// This function returns the mate of the given node in the found - /// matching or \c INVALID if the node is not covered by the matching. - /// - /// \pre Either run() or start() must be called before using this function. - Node mate(const Node& node) const { - return (*_matching)[node] != INVALID ? - _graph.target((*_matching)[node]) : INVALID; - } - - /// @} - - /// \name Dual Solution - /// Functions to get the dual solution.\n - /// Either \ref run() or \ref start() function should be called before - /// using them. - - /// @{ - - /// \brief Return the value of the dual solution. - /// - /// This function returns the value of the dual solution. - /// It should be equal to the primal value scaled by \ref dualScale - /// "dual scale". - /// - /// \pre Either run() or start() must be called before using this function. - Value dualValue() const { - Value sum = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - sum += nodeValue(n); - } - for (int i = 0; i < blossomNum(); ++i) { - sum += blossomValue(i) * (blossomSize(i) / 2); - } - return sum; - } - - /// \brief Return the dual value (potential) of the given node. - /// - /// This function returns the dual value (potential) of the given node. - /// - /// \pre Either run() or start() must be called before using this function. - Value nodeValue(const Node& n) const { - return (*_node_potential)[n]; - } - - /// \brief Return the number of the blossoms in the basis. - /// - /// This function returns the number of the blossoms in the basis. - /// - /// \pre Either run() or start() must be called before using this function. - /// \see BlossomIt - int blossomNum() const { - return _blossom_potential.size(); - } - - /// \brief Return the number of the nodes in the given blossom. - /// - /// This function returns the number of the nodes in the given blossom. - /// - /// \pre Either run() or start() must be called before using this function. - /// \see BlossomIt - int blossomSize(int k) const { - return _blossom_potential[k].end - _blossom_potential[k].begin; - } - - /// \brief Return the dual value (ptential) of the given blossom. - /// - /// This function returns the dual value (ptential) of the given blossom. - /// - /// \pre Either run() or start() must be called before using this function. - Value blossomValue(int k) const { - return _blossom_potential[k].value; - } - - /// \brief Iterator for obtaining the nodes of a blossom. - /// - /// This class provides an iterator for obtaining the nodes of the - /// given blossom. It lists a subset of the nodes. - /// Before using this iterator, you must allocate a - /// MaxWeightedMatching class and execute it. - class BlossomIt { - public: - - /// \brief Constructor. - /// - /// Constructor to get the nodes of the given variable. - /// - /// \pre Either \ref MaxWeightedMatching::run() "algorithm.run()" or - /// \ref MaxWeightedMatching::start() "algorithm.start()" must be - /// called before initializing this iterator. - BlossomIt(const MaxWeightedMatching& algorithm, int variable) - : _algorithm(&algorithm) - { - _index = _algorithm->_blossom_potential[variable].begin; - _last = _algorithm->_blossom_potential[variable].end; - } - - /// \brief Conversion to \c Node. - /// - /// Conversion to \c Node. - operator Node() const { - return _algorithm->_blossom_node_list[_index]; - } - - /// \brief Increment operator. - /// - /// Increment operator. - BlossomIt& operator++() { - ++_index; - return *this; - } - - /// \brief Validity checking - /// - /// Checks whether the iterator is invalid. - bool operator==(Invalid) const { return _index == _last; } - - /// \brief Validity checking - /// - /// Checks whether the iterator is valid. - bool operator!=(Invalid) const { return _index != _last; } - - private: - const MaxWeightedMatching* _algorithm; - int _last; - int _index; - }; - - /// @} - - }; - - /// \ingroup matching - /// - /// \brief Weighted perfect matching in general graphs - /// - /// This class provides an efficient implementation of Edmond's - /// maximum weighted perfect matching algorithm. The implementation - /// is based on extensive use of priority queues and provides - /// \f$O(nm\log n)\f$ time complexity. - /// - /// The maximum weighted perfect matching problem is to find a subset of - /// the edges in an undirected graph with maximum overall weight for which - /// each node has exactly one incident edge. - /// It can be formulated with the following linear program. - /// \f[ \sum_{e \in \delta(u)}x_e = 1 \quad \forall u\in V\f] - /** \f[ \sum_{e \in \gamma(B)}x_e \le \frac{\vert B \vert - 1}{2} - \quad \forall B\in\mathcal{O}\f] */ - /// \f[x_e \ge 0\quad \forall e\in E\f] - /// \f[\max \sum_{e\in E}x_ew_e\f] - /// where \f$\delta(X)\f$ is the set of edges incident to a node in - /// \f$X\f$, \f$\gamma(X)\f$ is the set of edges with both ends in - /// \f$X\f$ and \f$\mathcal{O}\f$ is the set of odd cardinality - /// subsets of the nodes. - /// - /// The algorithm calculates an optimal matching and a proof of the - /// optimality. The solution of the dual problem can be used to check - /// the result of the algorithm. The dual linear problem is the - /// following. - /** \f[ y_u + y_v + \sum_{B \in \mathcal{O}, uv \in \gamma(B)}z_B \ge - w_{uv} \quad \forall uv\in E\f] */ - /// \f[z_B \ge 0 \quad \forall B \in \mathcal{O}\f] - /** \f[\min \sum_{u \in V}y_u + \sum_{B \in \mathcal{O}} - \frac{\vert B \vert - 1}{2}z_B\f] */ - /// - /// The algorithm can be executed with the run() function. - /// After it the matching (the primal solution) and the dual solution - /// can be obtained using the query functions and the - /// \ref MaxWeightedPerfectMatching::BlossomIt "BlossomIt" nested class, - /// which is able to iterate on the nodes of a blossom. - /// If the value type is integer, then the dual solution is multiplied - /// by \ref MaxWeightedMatching::dualScale "4". - /// - /// \tparam GR The undirected graph type the algorithm runs on. - /// \tparam WM The type edge weight map. The default type is - /// \ref concepts::Graph::EdgeMap "GR::EdgeMap". -#ifdef DOXYGEN - template -#else - template > -#endif - class MaxWeightedPerfectMatching { - public: - - /// The graph type of the algorithm - typedef GR Graph; - /// The type of the edge weight map - typedef WM WeightMap; - /// The value type of the edge weights - typedef typename WeightMap::Value Value; - - /// \brief Scaling factor for dual solution - /// - /// Scaling factor for dual solution, it is equal to 4 or 1 - /// according to the value type. - static const int dualScale = - std::numeric_limits::is_integer ? 4 : 1; - - /// The type of the matching map - typedef typename Graph::template NodeMap - MatchingMap; - - private: - - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - typedef typename Graph::template NodeMap NodePotential; - typedef std::vector BlossomNodeList; - - struct BlossomVariable { - int begin, end; - Value value; - - BlossomVariable(int _begin, int _end, Value _value) - : begin(_begin), end(_end), value(_value) {} - - }; - - typedef std::vector BlossomPotential; - - const Graph& _graph; - const WeightMap& _weight; - - MatchingMap* _matching; - - NodePotential* _node_potential; - - BlossomPotential _blossom_potential; - BlossomNodeList _blossom_node_list; - - int _node_num; - int _blossom_num; - - typedef RangeMap IntIntMap; - - enum Status { - EVEN = -1, MATCHED = 0, ODD = 1 - }; - - typedef HeapUnionFind BlossomSet; - struct BlossomData { - int tree; - Status status; - Arc pred, next; - Value pot, offset; - }; - - IntNodeMap *_blossom_index; - BlossomSet *_blossom_set; - RangeMap* _blossom_data; - - IntNodeMap *_node_index; - IntArcMap *_node_heap_index; - - struct NodeData { - - NodeData(IntArcMap& node_heap_index) - : heap(node_heap_index) {} - - int blossom; - Value pot; - BinHeap heap; - std::map heap_index; - - int tree; - }; - - RangeMap* _node_data; - - typedef ExtendFindEnum TreeSet; - - IntIntMap *_tree_set_index; - TreeSet *_tree_set; - - IntIntMap *_delta2_index; - BinHeap *_delta2; - - IntEdgeMap *_delta3_index; - BinHeap *_delta3; - - IntIntMap *_delta4_index; - BinHeap *_delta4; - - Value _delta_sum; - int _unmatched; - - typedef MaxWeightedPerfectFractionalMatching - FractionalMatching; - FractionalMatching *_fractional; - - void createStructures() { - _node_num = countNodes(_graph); - _blossom_num = _node_num * 3 / 2; - - if (!_matching) { - _matching = new MatchingMap(_graph); - } - - if (!_node_potential) { - _node_potential = new NodePotential(_graph); - } - - if (!_blossom_set) { - _blossom_index = new IntNodeMap(_graph); - _blossom_set = new BlossomSet(*_blossom_index); - _blossom_data = new RangeMap(_blossom_num); - } else if (_blossom_data->size() != _blossom_num) { - delete _blossom_data; - _blossom_data = new RangeMap(_blossom_num); - } - - if (!_node_index) { - _node_index = new IntNodeMap(_graph); - _node_heap_index = new IntArcMap(_graph); - _node_data = new RangeMap(_node_num, - NodeData(*_node_heap_index)); - } else if (_node_data->size() != _node_num) { - delete _node_data; - _node_data = new RangeMap(_node_num, - NodeData(*_node_heap_index)); - } - - if (!_tree_set) { - _tree_set_index = new IntIntMap(_blossom_num); - _tree_set = new TreeSet(*_tree_set_index); - } else { - _tree_set_index->resize(_blossom_num); - } - - if (!_delta2) { - _delta2_index = new IntIntMap(_blossom_num); - _delta2 = new BinHeap(*_delta2_index); - } else { - _delta2_index->resize(_blossom_num); - } - - if (!_delta3) { - _delta3_index = new IntEdgeMap(_graph); - _delta3 = new BinHeap(*_delta3_index); - } - - if (!_delta4) { - _delta4_index = new IntIntMap(_blossom_num); - _delta4 = new BinHeap(*_delta4_index); - } else { - _delta4_index->resize(_blossom_num); - } - } - - void destroyStructures() { - if (_matching) { - delete _matching; - } - if (_node_potential) { - delete _node_potential; - } - if (_blossom_set) { - delete _blossom_index; - delete _blossom_set; - delete _blossom_data; - } - - if (_node_index) { - delete _node_index; - delete _node_heap_index; - delete _node_data; - } - - if (_tree_set) { - delete _tree_set_index; - delete _tree_set; - } - if (_delta2) { - delete _delta2_index; - delete _delta2; - } - if (_delta3) { - delete _delta3_index; - delete _delta3; - } - if (_delta4) { - delete _delta4_index; - delete _delta4; - } - } - - void matchedToEven(int blossom, int tree) { - if (_delta2->state(blossom) == _delta2->IN_HEAP) { - _delta2->erase(blossom); - } - - if (!_blossom_set->trivial(blossom)) { - (*_blossom_data)[blossom].pot -= - 2 * (_delta_sum - (*_blossom_data)[blossom].offset); - } - - for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); - n != INVALID; ++n) { - - _blossom_set->increase(n, std::numeric_limits::max()); - int ni = (*_node_index)[n]; - - (*_node_data)[ni].heap.clear(); - (*_node_data)[ni].heap_index.clear(); - - (*_node_data)[ni].pot += _delta_sum - (*_blossom_data)[blossom].offset; - - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.source(e); - int vb = _blossom_set->find(v); - int vi = (*_node_index)[v]; - - Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - - dualScale * _weight[e]; - - if ((*_blossom_data)[vb].status == EVEN) { - if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { - _delta3->push(e, rw / 2); - } - } else { - typename std::map::iterator it = - (*_node_data)[vi].heap_index.find(tree); - - if (it != (*_node_data)[vi].heap_index.end()) { - if ((*_node_data)[vi].heap[it->second] > rw) { - (*_node_data)[vi].heap.replace(it->second, e); - (*_node_data)[vi].heap.decrease(e, rw); - it->second = e; - } - } else { - (*_node_data)[vi].heap.push(e, rw); - (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e)); - } - - if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) { - _blossom_set->decrease(v, (*_node_data)[vi].heap.prio()); - - if ((*_blossom_data)[vb].status == MATCHED) { - if (_delta2->state(vb) != _delta2->IN_HEAP) { - _delta2->push(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset){ - _delta2->decrease(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } - } - } - } - } - } - (*_blossom_data)[blossom].offset = 0; - } - - void matchedToOdd(int blossom) { - if (_delta2->state(blossom) == _delta2->IN_HEAP) { - _delta2->erase(blossom); - } - (*_blossom_data)[blossom].offset += _delta_sum; - if (!_blossom_set->trivial(blossom)) { - _delta4->push(blossom, (*_blossom_data)[blossom].pot / 2 + - (*_blossom_data)[blossom].offset); - } - } - - void evenToMatched(int blossom, int tree) { - if (!_blossom_set->trivial(blossom)) { - (*_blossom_data)[blossom].pot += 2 * _delta_sum; - } - - for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); - n != INVALID; ++n) { - int ni = (*_node_index)[n]; - (*_node_data)[ni].pot -= _delta_sum; - - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.source(e); - int vb = _blossom_set->find(v); - int vi = (*_node_index)[v]; - - Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - - dualScale * _weight[e]; - - if (vb == blossom) { - if (_delta3->state(e) == _delta3->IN_HEAP) { - _delta3->erase(e); - } - } else if ((*_blossom_data)[vb].status == EVEN) { - - if (_delta3->state(e) == _delta3->IN_HEAP) { - _delta3->erase(e); - } - - int vt = _tree_set->find(vb); - - if (vt != tree) { - - Arc r = _graph.oppositeArc(e); - - typename std::map::iterator it = - (*_node_data)[ni].heap_index.find(vt); - - if (it != (*_node_data)[ni].heap_index.end()) { - if ((*_node_data)[ni].heap[it->second] > rw) { - (*_node_data)[ni].heap.replace(it->second, r); - (*_node_data)[ni].heap.decrease(r, rw); - it->second = r; - } - } else { - (*_node_data)[ni].heap.push(r, rw); - (*_node_data)[ni].heap_index.insert(std::make_pair(vt, r)); - } - - if ((*_blossom_set)[n] > (*_node_data)[ni].heap.prio()) { - _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); - - if (_delta2->state(blossom) != _delta2->IN_HEAP) { - _delta2->push(blossom, _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset); - } else if ((*_delta2)[blossom] > - _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset){ - _delta2->decrease(blossom, _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset); - } - } - } - } else { - - typename std::map::iterator it = - (*_node_data)[vi].heap_index.find(tree); - - if (it != (*_node_data)[vi].heap_index.end()) { - (*_node_data)[vi].heap.erase(it->second); - (*_node_data)[vi].heap_index.erase(it); - if ((*_node_data)[vi].heap.empty()) { - _blossom_set->increase(v, std::numeric_limits::max()); - } else if ((*_blossom_set)[v] < (*_node_data)[vi].heap.prio()) { - _blossom_set->increase(v, (*_node_data)[vi].heap.prio()); - } - - if ((*_blossom_data)[vb].status == MATCHED) { - if (_blossom_set->classPrio(vb) == - std::numeric_limits::max()) { - _delta2->erase(vb); - } else if ((*_delta2)[vb] < _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset) { - _delta2->increase(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } - } - } - } - } - } - } - - void oddToMatched(int blossom) { - (*_blossom_data)[blossom].offset -= _delta_sum; - - if (_blossom_set->classPrio(blossom) != - std::numeric_limits::max()) { - _delta2->push(blossom, _blossom_set->classPrio(blossom) - - (*_blossom_data)[blossom].offset); - } - - if (!_blossom_set->trivial(blossom)) { - _delta4->erase(blossom); - } - } - - void oddToEven(int blossom, int tree) { - if (!_blossom_set->trivial(blossom)) { - _delta4->erase(blossom); - (*_blossom_data)[blossom].pot -= - 2 * (2 * _delta_sum - (*_blossom_data)[blossom].offset); - } - - for (typename BlossomSet::ItemIt n(*_blossom_set, blossom); - n != INVALID; ++n) { - int ni = (*_node_index)[n]; - - _blossom_set->increase(n, std::numeric_limits::max()); - - (*_node_data)[ni].heap.clear(); - (*_node_data)[ni].heap_index.clear(); - (*_node_data)[ni].pot += - 2 * _delta_sum - (*_blossom_data)[blossom].offset; - - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.source(e); - int vb = _blossom_set->find(v); - int vi = (*_node_index)[v]; - - Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - - dualScale * _weight[e]; - - if ((*_blossom_data)[vb].status == EVEN) { - if (_delta3->state(e) != _delta3->IN_HEAP && blossom != vb) { - _delta3->push(e, rw / 2); - } - } else { - - typename std::map::iterator it = - (*_node_data)[vi].heap_index.find(tree); - - if (it != (*_node_data)[vi].heap_index.end()) { - if ((*_node_data)[vi].heap[it->second] > rw) { - (*_node_data)[vi].heap.replace(it->second, e); - (*_node_data)[vi].heap.decrease(e, rw); - it->second = e; - } - } else { - (*_node_data)[vi].heap.push(e, rw); - (*_node_data)[vi].heap_index.insert(std::make_pair(tree, e)); - } - - if ((*_blossom_set)[v] > (*_node_data)[vi].heap.prio()) { - _blossom_set->decrease(v, (*_node_data)[vi].heap.prio()); - - if ((*_blossom_data)[vb].status == MATCHED) { - if (_delta2->state(vb) != _delta2->IN_HEAP) { - _delta2->push(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } else if ((*_delta2)[vb] > _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset) { - _delta2->decrease(vb, _blossom_set->classPrio(vb) - - (*_blossom_data)[vb].offset); - } - } - } - } - } - } - (*_blossom_data)[blossom].offset = 0; - } - - void alternatePath(int even, int tree) { - int odd; - - evenToMatched(even, tree); - (*_blossom_data)[even].status = MATCHED; - - while ((*_blossom_data)[even].pred != INVALID) { - odd = _blossom_set->find(_graph.target((*_blossom_data)[even].pred)); - (*_blossom_data)[odd].status = MATCHED; - oddToMatched(odd); - (*_blossom_data)[odd].next = (*_blossom_data)[odd].pred; - - even = _blossom_set->find(_graph.target((*_blossom_data)[odd].pred)); - (*_blossom_data)[even].status = MATCHED; - evenToMatched(even, tree); - (*_blossom_data)[even].next = - _graph.oppositeArc((*_blossom_data)[odd].pred); - } - - } - - void destroyTree(int tree) { - for (TreeSet::ItemIt b(*_tree_set, tree); b != INVALID; ++b) { - if ((*_blossom_data)[b].status == EVEN) { - (*_blossom_data)[b].status = MATCHED; - evenToMatched(b, tree); - } else if ((*_blossom_data)[b].status == ODD) { - (*_blossom_data)[b].status = MATCHED; - oddToMatched(b); - } - } - _tree_set->eraseClass(tree); - } - - void augmentOnEdge(const Edge& edge) { - - int left = _blossom_set->find(_graph.u(edge)); - int right = _blossom_set->find(_graph.v(edge)); - - int left_tree = _tree_set->find(left); - alternatePath(left, left_tree); - destroyTree(left_tree); - - int right_tree = _tree_set->find(right); - alternatePath(right, right_tree); - destroyTree(right_tree); - - (*_blossom_data)[left].next = _graph.direct(edge, true); - (*_blossom_data)[right].next = _graph.direct(edge, false); - } - - void extendOnArc(const Arc& arc) { - int base = _blossom_set->find(_graph.target(arc)); - int tree = _tree_set->find(base); - - int odd = _blossom_set->find(_graph.source(arc)); - _tree_set->insert(odd, tree); - (*_blossom_data)[odd].status = ODD; - matchedToOdd(odd); - (*_blossom_data)[odd].pred = arc; - - int even = _blossom_set->find(_graph.target((*_blossom_data)[odd].next)); - (*_blossom_data)[even].pred = (*_blossom_data)[even].next; - _tree_set->insert(even, tree); - (*_blossom_data)[even].status = EVEN; - matchedToEven(even, tree); - } - - void shrinkOnEdge(const Edge& edge, int tree) { - int nca = -1; - std::vector left_path, right_path; - - { - std::set left_set, right_set; - int left = _blossom_set->find(_graph.u(edge)); - left_path.push_back(left); - left_set.insert(left); - - int right = _blossom_set->find(_graph.v(edge)); - right_path.push_back(right); - right_set.insert(right); - - while (true) { - - if ((*_blossom_data)[left].pred == INVALID) break; - - left = - _blossom_set->find(_graph.target((*_blossom_data)[left].pred)); - left_path.push_back(left); - left = - _blossom_set->find(_graph.target((*_blossom_data)[left].pred)); - left_path.push_back(left); - - left_set.insert(left); - - if (right_set.find(left) != right_set.end()) { - nca = left; - break; - } - - if ((*_blossom_data)[right].pred == INVALID) break; - - right = - _blossom_set->find(_graph.target((*_blossom_data)[right].pred)); - right_path.push_back(right); - right = - _blossom_set->find(_graph.target((*_blossom_data)[right].pred)); - right_path.push_back(right); - - right_set.insert(right); - - if (left_set.find(right) != left_set.end()) { - nca = right; - break; - } - - } - - if (nca == -1) { - if ((*_blossom_data)[left].pred == INVALID) { - nca = right; - while (left_set.find(nca) == left_set.end()) { - nca = - _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); - right_path.push_back(nca); - nca = - _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); - right_path.push_back(nca); - } - } else { - nca = left; - while (right_set.find(nca) == right_set.end()) { - nca = - _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); - left_path.push_back(nca); - nca = - _blossom_set->find(_graph.target((*_blossom_data)[nca].pred)); - left_path.push_back(nca); - } - } - } - } - - std::vector subblossoms; - Arc prev; - - prev = _graph.direct(edge, true); - for (int i = 0; left_path[i] != nca; i += 2) { - subblossoms.push_back(left_path[i]); - (*_blossom_data)[left_path[i]].next = prev; - _tree_set->erase(left_path[i]); - - subblossoms.push_back(left_path[i + 1]); - (*_blossom_data)[left_path[i + 1]].status = EVEN; - oddToEven(left_path[i + 1], tree); - _tree_set->erase(left_path[i + 1]); - prev = _graph.oppositeArc((*_blossom_data)[left_path[i + 1]].pred); - } - - int k = 0; - while (right_path[k] != nca) ++k; - - subblossoms.push_back(nca); - (*_blossom_data)[nca].next = prev; - - for (int i = k - 2; i >= 0; i -= 2) { - subblossoms.push_back(right_path[i + 1]); - (*_blossom_data)[right_path[i + 1]].status = EVEN; - oddToEven(right_path[i + 1], tree); - _tree_set->erase(right_path[i + 1]); - - (*_blossom_data)[right_path[i + 1]].next = - (*_blossom_data)[right_path[i + 1]].pred; - - subblossoms.push_back(right_path[i]); - _tree_set->erase(right_path[i]); - } - - int surface = - _blossom_set->join(subblossoms.begin(), subblossoms.end()); - - for (int i = 0; i < int(subblossoms.size()); ++i) { - if (!_blossom_set->trivial(subblossoms[i])) { - (*_blossom_data)[subblossoms[i]].pot += 2 * _delta_sum; - } - (*_blossom_data)[subblossoms[i]].status = MATCHED; - } - - (*_blossom_data)[surface].pot = -2 * _delta_sum; - (*_blossom_data)[surface].offset = 0; - (*_blossom_data)[surface].status = EVEN; - (*_blossom_data)[surface].pred = (*_blossom_data)[nca].pred; - (*_blossom_data)[surface].next = (*_blossom_data)[nca].pred; - - _tree_set->insert(surface, tree); - _tree_set->erase(nca); - } - - void splitBlossom(int blossom) { - Arc next = (*_blossom_data)[blossom].next; - Arc pred = (*_blossom_data)[blossom].pred; - - int tree = _tree_set->find(blossom); - - (*_blossom_data)[blossom].status = MATCHED; - oddToMatched(blossom); - if (_delta2->state(blossom) == _delta2->IN_HEAP) { - _delta2->erase(blossom); - } - - std::vector subblossoms; - _blossom_set->split(blossom, std::back_inserter(subblossoms)); - - Value offset = (*_blossom_data)[blossom].offset; - int b = _blossom_set->find(_graph.source(pred)); - int d = _blossom_set->find(_graph.source(next)); - - int ib = -1, id = -1; - for (int i = 0; i < int(subblossoms.size()); ++i) { - if (subblossoms[i] == b) ib = i; - if (subblossoms[i] == d) id = i; - - (*_blossom_data)[subblossoms[i]].offset = offset; - if (!_blossom_set->trivial(subblossoms[i])) { - (*_blossom_data)[subblossoms[i]].pot -= 2 * offset; - } - if (_blossom_set->classPrio(subblossoms[i]) != - std::numeric_limits::max()) { - _delta2->push(subblossoms[i], - _blossom_set->classPrio(subblossoms[i]) - - (*_blossom_data)[subblossoms[i]].offset); - } - } - - if (id > ib ? ((id - ib) % 2 == 0) : ((ib - id) % 2 == 1)) { - for (int i = (id + 1) % subblossoms.size(); - i != ib; i = (i + 2) % subblossoms.size()) { - int sb = subblossoms[i]; - int tb = subblossoms[(i + 1) % subblossoms.size()]; - (*_blossom_data)[sb].next = - _graph.oppositeArc((*_blossom_data)[tb].next); - } - - for (int i = ib; i != id; i = (i + 2) % subblossoms.size()) { - int sb = subblossoms[i]; - int tb = subblossoms[(i + 1) % subblossoms.size()]; - int ub = subblossoms[(i + 2) % subblossoms.size()]; - - (*_blossom_data)[sb].status = ODD; - matchedToOdd(sb); - _tree_set->insert(sb, tree); - (*_blossom_data)[sb].pred = pred; - (*_blossom_data)[sb].next = - _graph.oppositeArc((*_blossom_data)[tb].next); - - pred = (*_blossom_data)[ub].next; - - (*_blossom_data)[tb].status = EVEN; - matchedToEven(tb, tree); - _tree_set->insert(tb, tree); - (*_blossom_data)[tb].pred = (*_blossom_data)[tb].next; - } - - (*_blossom_data)[subblossoms[id]].status = ODD; - matchedToOdd(subblossoms[id]); - _tree_set->insert(subblossoms[id], tree); - (*_blossom_data)[subblossoms[id]].next = next; - (*_blossom_data)[subblossoms[id]].pred = pred; - - } else { - - for (int i = (ib + 1) % subblossoms.size(); - i != id; i = (i + 2) % subblossoms.size()) { - int sb = subblossoms[i]; - int tb = subblossoms[(i + 1) % subblossoms.size()]; - (*_blossom_data)[sb].next = - _graph.oppositeArc((*_blossom_data)[tb].next); - } - - for (int i = id; i != ib; i = (i + 2) % subblossoms.size()) { - int sb = subblossoms[i]; - int tb = subblossoms[(i + 1) % subblossoms.size()]; - int ub = subblossoms[(i + 2) % subblossoms.size()]; - - (*_blossom_data)[sb].status = ODD; - matchedToOdd(sb); - _tree_set->insert(sb, tree); - (*_blossom_data)[sb].next = next; - (*_blossom_data)[sb].pred = - _graph.oppositeArc((*_blossom_data)[tb].next); - - (*_blossom_data)[tb].status = EVEN; - matchedToEven(tb, tree); - _tree_set->insert(tb, tree); - (*_blossom_data)[tb].pred = - (*_blossom_data)[tb].next = - _graph.oppositeArc((*_blossom_data)[ub].next); - next = (*_blossom_data)[ub].next; - } - - (*_blossom_data)[subblossoms[ib]].status = ODD; - matchedToOdd(subblossoms[ib]); - _tree_set->insert(subblossoms[ib], tree); - (*_blossom_data)[subblossoms[ib]].next = next; - (*_blossom_data)[subblossoms[ib]].pred = pred; - } - _tree_set->erase(blossom); - } - - void extractBlossom(int blossom, const Node& base, const Arc& matching) { - if (_blossom_set->trivial(blossom)) { - int bi = (*_node_index)[base]; - Value pot = (*_node_data)[bi].pot; - - (*_matching)[base] = matching; - _blossom_node_list.push_back(base); - (*_node_potential)[base] = pot; - } else { - - Value pot = (*_blossom_data)[blossom].pot; - int bn = _blossom_node_list.size(); - - std::vector subblossoms; - _blossom_set->split(blossom, std::back_inserter(subblossoms)); - int b = _blossom_set->find(base); - int ib = -1; - for (int i = 0; i < int(subblossoms.size()); ++i) { - if (subblossoms[i] == b) { ib = i; break; } - } - - for (int i = 1; i < int(subblossoms.size()); i += 2) { - int sb = subblossoms[(ib + i) % subblossoms.size()]; - int tb = subblossoms[(ib + i + 1) % subblossoms.size()]; - - Arc m = (*_blossom_data)[tb].next; - extractBlossom(sb, _graph.target(m), _graph.oppositeArc(m)); - extractBlossom(tb, _graph.source(m), m); - } - extractBlossom(subblossoms[ib], base, matching); - - int en = _blossom_node_list.size(); - - _blossom_potential.push_back(BlossomVariable(bn, en, pot)); - } - } - - void extractMatching() { - std::vector blossoms; - for (typename BlossomSet::ClassIt c(*_blossom_set); c != INVALID; ++c) { - blossoms.push_back(c); - } - - for (int i = 0; i < int(blossoms.size()); ++i) { - - Value offset = (*_blossom_data)[blossoms[i]].offset; - (*_blossom_data)[blossoms[i]].pot += 2 * offset; - for (typename BlossomSet::ItemIt n(*_blossom_set, blossoms[i]); - n != INVALID; ++n) { - (*_node_data)[(*_node_index)[n]].pot -= offset; - } - - Arc matching = (*_blossom_data)[blossoms[i]].next; - Node base = _graph.source(matching); - extractBlossom(blossoms[i], base, matching); - } - } - - public: - - /// \brief Constructor - /// - /// Constructor. - MaxWeightedPerfectMatching(const Graph& graph, const WeightMap& weight) - : _graph(graph), _weight(weight), _matching(0), - _node_potential(0), _blossom_potential(), _blossom_node_list(), - _node_num(0), _blossom_num(0), - - _blossom_index(0), _blossom_set(0), _blossom_data(0), - _node_index(0), _node_heap_index(0), _node_data(0), - _tree_set_index(0), _tree_set(0), - - _delta2_index(0), _delta2(0), - _delta3_index(0), _delta3(0), - _delta4_index(0), _delta4(0), - - _delta_sum(), _unmatched(0), - - _fractional(0) - {} - - ~MaxWeightedPerfectMatching() { - destroyStructures(); - if (_fractional) { - delete _fractional; - } - } - - /// \name Execution Control - /// The simplest way to execute the algorithm is to use the - /// \ref run() member function. - - ///@{ - - /// \brief Initialize the algorithm - /// - /// This function initializes the algorithm. - void init() { - createStructures(); - - _blossom_node_list.clear(); - _blossom_potential.clear(); - - for (ArcIt e(_graph); e != INVALID; ++e) { - (*_node_heap_index)[e] = BinHeap::PRE_HEAP; - } - for (EdgeIt e(_graph); e != INVALID; ++e) { - (*_delta3_index)[e] = _delta3->PRE_HEAP; - } - for (int i = 0; i < _blossom_num; ++i) { - (*_delta2_index)[i] = _delta2->PRE_HEAP; - (*_delta4_index)[i] = _delta4->PRE_HEAP; - } - - _unmatched = _node_num; - - _delta2->clear(); - _delta3->clear(); - _delta4->clear(); - _blossom_set->clear(); - _tree_set->clear(); - - int index = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - Value max = - std::numeric_limits::max(); - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - if (_graph.target(e) == n) continue; - if ((dualScale * _weight[e]) / 2 > max) { - max = (dualScale * _weight[e]) / 2; - } - } - (*_node_index)[n] = index; - (*_node_data)[index].heap_index.clear(); - (*_node_data)[index].heap.clear(); - (*_node_data)[index].pot = max; - int blossom = - _blossom_set->insert(n, std::numeric_limits::max()); - - _tree_set->insert(blossom); - - (*_blossom_data)[blossom].status = EVEN; - (*_blossom_data)[blossom].pred = INVALID; - (*_blossom_data)[blossom].next = INVALID; - (*_blossom_data)[blossom].pot = 0; - (*_blossom_data)[blossom].offset = 0; - ++index; - } - for (EdgeIt e(_graph); e != INVALID; ++e) { - int si = (*_node_index)[_graph.u(e)]; - int ti = (*_node_index)[_graph.v(e)]; - if (_graph.u(e) != _graph.v(e)) { - _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot - - dualScale * _weight[e]) / 2); - } - } - } - - /// \brief Initialize the algorithm with fractional matching - /// - /// This function initializes the algorithm with a fractional - /// matching. This initialization is also called jumpstart heuristic. - void fractionalInit() { - createStructures(); - - _blossom_node_list.clear(); - _blossom_potential.clear(); - - if (_fractional == 0) { - _fractional = new FractionalMatching(_graph, _weight, false); - } - if (!_fractional->run()) { - _unmatched = -1; - return; - } - - for (ArcIt e(_graph); e != INVALID; ++e) { - (*_node_heap_index)[e] = BinHeap::PRE_HEAP; - } - for (EdgeIt e(_graph); e != INVALID; ++e) { - (*_delta3_index)[e] = _delta3->PRE_HEAP; - } - for (int i = 0; i < _blossom_num; ++i) { - (*_delta2_index)[i] = _delta2->PRE_HEAP; - (*_delta4_index)[i] = _delta4->PRE_HEAP; - } - - _unmatched = 0; - - _delta2->clear(); - _delta3->clear(); - _delta4->clear(); - _blossom_set->clear(); - _tree_set->clear(); - - int index = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - Value pot = _fractional->nodeValue(n); - (*_node_index)[n] = index; - (*_node_data)[index].pot = pot; - (*_node_data)[index].heap_index.clear(); - (*_node_data)[index].heap.clear(); - int blossom = - _blossom_set->insert(n, std::numeric_limits::max()); - - (*_blossom_data)[blossom].status = MATCHED; - (*_blossom_data)[blossom].pred = INVALID; - (*_blossom_data)[blossom].next = _fractional->matching(n); - (*_blossom_data)[blossom].pot = 0; - (*_blossom_data)[blossom].offset = 0; - ++index; - } - - typename Graph::template NodeMap processed(_graph, false); - for (NodeIt n(_graph); n != INVALID; ++n) { - if (processed[n]) continue; - processed[n] = true; - if (_fractional->matching(n) == INVALID) continue; - int num = 1; - Node v = _graph.target(_fractional->matching(n)); - while (n != v) { - processed[v] = true; - v = _graph.target(_fractional->matching(v)); - ++num; - } - - if (num % 2 == 1) { - std::vector subblossoms(num); - - subblossoms[--num] = _blossom_set->find(n); - v = _graph.target(_fractional->matching(n)); - while (n != v) { - subblossoms[--num] = _blossom_set->find(v); - v = _graph.target(_fractional->matching(v)); - } - - int surface = - _blossom_set->join(subblossoms.begin(), subblossoms.end()); - (*_blossom_data)[surface].status = EVEN; - (*_blossom_data)[surface].pred = INVALID; - (*_blossom_data)[surface].next = INVALID; - (*_blossom_data)[surface].pot = 0; - (*_blossom_data)[surface].offset = 0; - - _tree_set->insert(surface); - ++_unmatched; - } - } - - for (EdgeIt e(_graph); e != INVALID; ++e) { - int si = (*_node_index)[_graph.u(e)]; - int sb = _blossom_set->find(_graph.u(e)); - int ti = (*_node_index)[_graph.v(e)]; - int tb = _blossom_set->find(_graph.v(e)); - if ((*_blossom_data)[sb].status == EVEN && - (*_blossom_data)[tb].status == EVEN && sb != tb) { - _delta3->push(e, ((*_node_data)[si].pot + (*_node_data)[ti].pot - - dualScale * _weight[e]) / 2); - } - } - - for (NodeIt n(_graph); n != INVALID; ++n) { - int nb = _blossom_set->find(n); - if ((*_blossom_data)[nb].status != MATCHED) continue; - int ni = (*_node_index)[n]; - - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.target(e); - int vb = _blossom_set->find(v); - int vi = (*_node_index)[v]; - - Value rw = (*_node_data)[ni].pot + (*_node_data)[vi].pot - - dualScale * _weight[e]; - - if ((*_blossom_data)[vb].status == EVEN) { - - int vt = _tree_set->find(vb); - - typename std::map::iterator it = - (*_node_data)[ni].heap_index.find(vt); - - if (it != (*_node_data)[ni].heap_index.end()) { - if ((*_node_data)[ni].heap[it->second] > rw) { - (*_node_data)[ni].heap.replace(it->second, e); - (*_node_data)[ni].heap.decrease(e, rw); - it->second = e; - } - } else { - (*_node_data)[ni].heap.push(e, rw); - (*_node_data)[ni].heap_index.insert(std::make_pair(vt, e)); - } - } - } - - if (!(*_node_data)[ni].heap.empty()) { - _blossom_set->decrease(n, (*_node_data)[ni].heap.prio()); - _delta2->push(nb, _blossom_set->classPrio(nb)); - } - } - } - - /// \brief Start the algorithm - /// - /// This function starts the algorithm. - /// - /// \pre \ref init() or \ref fractionalInit() must be called before - /// using this function. - bool start() { - enum OpType { - D2, D3, D4 - }; - - if (_unmatched == -1) return false; - - while (_unmatched > 0) { - Value d2 = !_delta2->empty() ? - _delta2->prio() : std::numeric_limits::max(); - - Value d3 = !_delta3->empty() ? - _delta3->prio() : std::numeric_limits::max(); - - Value d4 = !_delta4->empty() ? - _delta4->prio() : std::numeric_limits::max(); - - _delta_sum = d3; OpType ot = D3; - if (d2 < _delta_sum) { _delta_sum = d2; ot = D2; } - if (d4 < _delta_sum) { _delta_sum = d4; ot = D4; } - - if (_delta_sum == std::numeric_limits::max()) { - return false; - } - - switch (ot) { - case D2: - { - int blossom = _delta2->top(); - Node n = _blossom_set->classTop(blossom); - Arc e = (*_node_data)[(*_node_index)[n]].heap.top(); - extendOnArc(e); - } - break; - case D3: - { - Edge e = _delta3->top(); - - int left_blossom = _blossom_set->find(_graph.u(e)); - int right_blossom = _blossom_set->find(_graph.v(e)); - - if (left_blossom == right_blossom) { - _delta3->pop(); - } else { - int left_tree = _tree_set->find(left_blossom); - int right_tree = _tree_set->find(right_blossom); - - if (left_tree == right_tree) { - shrinkOnEdge(e, left_tree); - } else { - augmentOnEdge(e); - _unmatched -= 2; - } - } - } break; - case D4: - splitBlossom(_delta4->top()); - break; - } - } - extractMatching(); - return true; - } - - /// \brief Run the algorithm. - /// - /// This method runs the \c %MaxWeightedPerfectMatching algorithm. - /// - /// \note mwpm.run() is just a shortcut of the following code. - /// \code - /// mwpm.fractionalInit(); - /// mwpm.start(); - /// \endcode - bool run() { - fractionalInit(); - return start(); - } - - /// @} - - /// \name Primal Solution - /// Functions to get the primal solution, i.e. the maximum weighted - /// perfect matching.\n - /// Either \ref run() or \ref start() function should be called before - /// using them. - - /// @{ - - /// \brief Return the weight of the matching. - /// - /// This function returns the weight of the found matching. - /// - /// \pre Either run() or start() must be called before using this function. - Value matchingWeight() const { - Value sum = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - if ((*_matching)[n] != INVALID) { - sum += _weight[(*_matching)[n]]; - } - } - return sum / 2; - } - - /// \brief Return \c true if the given edge is in the matching. - /// - /// This function returns \c true if the given edge is in the found - /// matching. - /// - /// \pre Either run() or start() must be called before using this function. - bool matching(const Edge& edge) const { - return static_cast((*_matching)[_graph.u(edge)]) == edge; - } - - /// \brief Return the matching arc (or edge) incident to the given node. - /// - /// This function returns the matching arc (or edge) incident to the - /// given node in the found matching or \c INVALID if the node is - /// not covered by the matching. - /// - /// \pre Either run() or start() must be called before using this function. - Arc matching(const Node& node) const { - return (*_matching)[node]; - } - - /// \brief Return a const reference to the matching map. - /// - /// This function returns a const reference to a node map that stores - /// the matching arc (or edge) incident to each node. - const MatchingMap& matchingMap() const { - return *_matching; - } - - /// \brief Return the mate of the given node. - /// - /// This function returns the mate of the given node in the found - /// matching or \c INVALID if the node is not covered by the matching. - /// - /// \pre Either run() or start() must be called before using this function. - Node mate(const Node& node) const { - return _graph.target((*_matching)[node]); - } - - /// @} - - /// \name Dual Solution - /// Functions to get the dual solution.\n - /// Either \ref run() or \ref start() function should be called before - /// using them. - - /// @{ - - /// \brief Return the value of the dual solution. - /// - /// This function returns the value of the dual solution. - /// It should be equal to the primal value scaled by \ref dualScale - /// "dual scale". - /// - /// \pre Either run() or start() must be called before using this function. - Value dualValue() const { - Value sum = 0; - for (NodeIt n(_graph); n != INVALID; ++n) { - sum += nodeValue(n); - } - for (int i = 0; i < blossomNum(); ++i) { - sum += blossomValue(i) * (blossomSize(i) / 2); - } - return sum; - } - - /// \brief Return the dual value (potential) of the given node. - /// - /// This function returns the dual value (potential) of the given node. - /// - /// \pre Either run() or start() must be called before using this function. - Value nodeValue(const Node& n) const { - return (*_node_potential)[n]; - } - - /// \brief Return the number of the blossoms in the basis. - /// - /// This function returns the number of the blossoms in the basis. - /// - /// \pre Either run() or start() must be called before using this function. - /// \see BlossomIt - int blossomNum() const { - return _blossom_potential.size(); - } - - /// \brief Return the number of the nodes in the given blossom. - /// - /// This function returns the number of the nodes in the given blossom. - /// - /// \pre Either run() or start() must be called before using this function. - /// \see BlossomIt - int blossomSize(int k) const { - return _blossom_potential[k].end - _blossom_potential[k].begin; - } - - /// \brief Return the dual value (ptential) of the given blossom. - /// - /// This function returns the dual value (ptential) of the given blossom. - /// - /// \pre Either run() or start() must be called before using this function. - Value blossomValue(int k) const { - return _blossom_potential[k].value; - } - - /// \brief Iterator for obtaining the nodes of a blossom. - /// - /// This class provides an iterator for obtaining the nodes of the - /// given blossom. It lists a subset of the nodes. - /// Before using this iterator, you must allocate a - /// MaxWeightedPerfectMatching class and execute it. - class BlossomIt { - public: - - /// \brief Constructor. - /// - /// Constructor to get the nodes of the given variable. - /// - /// \pre Either \ref MaxWeightedPerfectMatching::run() "algorithm.run()" - /// or \ref MaxWeightedPerfectMatching::start() "algorithm.start()" - /// must be called before initializing this iterator. - BlossomIt(const MaxWeightedPerfectMatching& algorithm, int variable) - : _algorithm(&algorithm) - { - _index = _algorithm->_blossom_potential[variable].begin; - _last = _algorithm->_blossom_potential[variable].end; - } - - /// \brief Conversion to \c Node. - /// - /// Conversion to \c Node. - operator Node() const { - return _algorithm->_blossom_node_list[_index]; - } - - /// \brief Increment operator. - /// - /// Increment operator. - BlossomIt& operator++() { - ++_index; - return *this; - } - - /// \brief Validity checking - /// - /// This function checks whether the iterator is invalid. - bool operator==(Invalid) const { return _index == _last; } - - /// \brief Validity checking - /// - /// This function checks whether the iterator is valid. - bool operator!=(Invalid) const { return _index != _last; } - - private: - const MaxWeightedPerfectMatching* _algorithm; - int _last; - int _index; - }; - - /// @} - - }; - -} //END OF NAMESPACE LEMON - -#endif //LEMON_MATCHING_H diff --git a/deps/lemon/lemon/math.h b/deps/lemon/lemon/math.h deleted file mode 100644 index 5da50b07a..000000000 --- a/deps/lemon/lemon/math.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_MATH_H -#define LEMON_MATH_H - -///\ingroup misc -///\file -///\brief Some extensions to the standard \c cmath library. -/// -///Some extensions to the standard \c cmath library. -/// -///This file includes the standard math library (cmath). - -#include - -namespace lemon { - - /// \addtogroup misc - /// @{ - - /// The Euler constant - const long double E = 2.7182818284590452353602874713526625L; - /// log_2(e) - const long double LOG2E = 1.4426950408889634073599246810018921L; - /// log_10(e) - const long double LOG10E = 0.4342944819032518276511289189166051L; - /// ln(2) - const long double LN2 = 0.6931471805599453094172321214581766L; - /// ln(10) - const long double LN10 = 2.3025850929940456840179914546843642L; - /// pi - const long double PI = 3.1415926535897932384626433832795029L; - /// pi/2 - const long double PI_2 = 1.5707963267948966192313216916397514L; - /// pi/4 - const long double PI_4 = 0.7853981633974483096156608458198757L; - /// sqrt(2) - const long double SQRT2 = 1.4142135623730950488016887242096981L; - /// 1/sqrt(2) - const long double SQRT1_2 = 0.7071067811865475244008443621048490L; - - ///Check whether the parameter is NaN or not - - ///This function checks whether the parameter is NaN or not. - ///Is should be equivalent with std::isnan(), but it is not - ///provided by all compilers. - inline bool isNaN(double v) - { - return v!=v; - } - - ///Round a value to its closest integer - inline double round(double r) { - return (r > 0.0) ? std::floor(r + 0.5) : std::ceil(r - 0.5); - } - - /// @} - -} //namespace lemon - -#endif //LEMON_MATH_H diff --git a/deps/lemon/lemon/max_cardinality_search.h b/deps/lemon/lemon/max_cardinality_search.h deleted file mode 100644 index bfa9edb77..000000000 --- a/deps/lemon/lemon/max_cardinality_search.h +++ /dev/null @@ -1,794 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_MAX_CARDINALITY_SEARCH_H -#define LEMON_MAX_CARDINALITY_SEARCH_H - - -/// \ingroup search -/// \file -/// \brief Maximum cardinality search in undirected digraphs. - -#include -#include - -#include -#include - -#include - -namespace lemon { - - /// \brief Default traits class of MaxCardinalitySearch class. - /// - /// Default traits class of MaxCardinalitySearch class. - /// \param Digraph Digraph type. - /// \param CapacityMap Type of capacity map. - template - struct MaxCardinalitySearchDefaultTraits { - /// The digraph type the algorithm runs on. - typedef GR Digraph; - - template - struct CapMapSelector { - - typedef CM CapacityMap; - - static CapacityMap *createCapacityMap(const Digraph& g) { - return new CapacityMap(g); - } - }; - - template - struct CapMapSelector > > { - - typedef ConstMap > CapacityMap; - - static CapacityMap *createCapacityMap(const Digraph&) { - return new CapacityMap; - } - }; - - /// \brief The type of the map that stores the arc capacities. - /// - /// The type of the map that stores the arc capacities. - /// It must meet the \ref concepts::ReadMap "ReadMap" concept. - typedef typename CapMapSelector::CapacityMap CapacityMap; - - /// \brief The type of the capacity of the arcs. - typedef typename CapacityMap::Value Value; - - /// \brief Instantiates a CapacityMap. - /// - /// This function instantiates a \ref CapacityMap. - /// \param digraph is the digraph, to which we would like to define - /// the CapacityMap. - static CapacityMap *createCapacityMap(const Digraph& digraph) { - return CapMapSelector::createCapacityMap(digraph); - } - - /// \brief The cross reference type used by heap. - /// - /// The cross reference type used by heap. - /// Usually it is \c Digraph::NodeMap. - typedef typename Digraph::template NodeMap HeapCrossRef; - - /// \brief Instantiates a HeapCrossRef. - /// - /// This function instantiates a \ref HeapCrossRef. - /// \param digraph is the digraph, to which we would like to define the - /// HeapCrossRef. - static HeapCrossRef *createHeapCrossRef(const Digraph &digraph) { - return new HeapCrossRef(digraph); - } - - template - struct HeapSelector { - template - struct Selector { - typedef BinHeap > Heap; - }; - }; - - template - struct HeapSelector > > { - template - struct Selector { - typedef BucketHeap Heap; - }; - }; - - /// \brief The heap type used by MaxCardinalitySearch algorithm. - /// - /// The heap type used by MaxCardinalitySearch algorithm. It should - /// maximalize the priorities. The default heap type is - /// the \ref BinHeap, but it is specialized when the - /// CapacityMap is ConstMap > - /// to BucketHeap. - /// - /// \sa MaxCardinalitySearch - typedef typename HeapSelector - ::template Selector - ::Heap Heap; - - /// \brief Instantiates a Heap. - /// - /// This function instantiates a \ref Heap. - /// \param crossref The cross reference of the heap. - static Heap *createHeap(HeapCrossRef& crossref) { - return new Heap(crossref); - } - - /// \brief The type of the map that stores whether a node is processed. - /// - /// The type of the map that stores whether a node is processed. - /// It must meet the \ref concepts::WriteMap "WriteMap" concept. - /// By default it is a NullMap. - typedef NullMap ProcessedMap; - - /// \brief Instantiates a ProcessedMap. - /// - /// This function instantiates a \ref ProcessedMap. - /// \param digraph is the digraph, to which - /// we would like to define the \ref ProcessedMap -#ifdef DOXYGEN - static ProcessedMap *createProcessedMap(const Digraph &digraph) -#else - static ProcessedMap *createProcessedMap(const Digraph &) -#endif - { - return new ProcessedMap(); - } - - /// \brief The type of the map that stores the cardinalities of the nodes. - /// - /// The type of the map that stores the cardinalities of the nodes. - /// It must meet the \ref concepts::WriteMap "WriteMap" concept. - typedef typename Digraph::template NodeMap CardinalityMap; - - /// \brief Instantiates a CardinalityMap. - /// - /// This function instantiates a \ref CardinalityMap. - /// \param digraph is the digraph, to which we would like to - /// define the \ref CardinalityMap - static CardinalityMap *createCardinalityMap(const Digraph &digraph) { - return new CardinalityMap(digraph); - } - - - }; - - /// \ingroup search - /// - /// \brief Maximum Cardinality Search algorithm class. - /// - /// This class provides an efficient implementation of Maximum Cardinality - /// Search algorithm. The maximum cardinality search first chooses any - /// node of the digraph. Then every time it chooses one unprocessed node - /// with maximum cardinality, i.e the sum of capacities on out arcs - /// to the nodes - /// which were previusly processed. - /// If there is a cut in the digraph the algorithm should choose - /// again any unprocessed node of the digraph. - - /// The arc capacities are passed to the algorithm using a - /// \ref concepts::ReadMap "ReadMap", so it is easy to change it to any - /// kind of capacity. - /// - /// The type of the capacity is determined by the \ref - /// concepts::ReadMap::Value "Value" of the capacity map. - /// - /// It is also possible to change the underlying priority heap. - /// - /// - /// \param GR The digraph type the algorithm runs on. The value of - /// Digraph is not used directly by the search algorithm, it - /// is only passed to \ref MaxCardinalitySearchDefaultTraits. - /// \param CAP This read-only ArcMap determines the capacities of - /// the arcs. It is read once for each arc, so the map may involve in - /// relatively time consuming process to compute the arc capacity if - /// it is necessary. The default map type is \ref - /// ConstMap "ConstMap >". The value - /// of CapacityMap is not used directly by search algorithm, it is only - /// passed to \ref MaxCardinalitySearchDefaultTraits. - /// \param TR Traits class to set various data types used by the - /// algorithm. The default traits class is - /// \ref MaxCardinalitySearchDefaultTraits - /// "MaxCardinalitySearchDefaultTraits". - /// See \ref MaxCardinalitySearchDefaultTraits - /// for the documentation of a MaxCardinalitySearch traits class. - -#ifdef DOXYGEN - template -#else - template >, - typename TR = - MaxCardinalitySearchDefaultTraits > -#endif - class MaxCardinalitySearch { - public: - - typedef TR Traits; - ///The type of the underlying digraph. - typedef typename Traits::Digraph Digraph; - - ///The type of the capacity of the arcs. - typedef typename Traits::CapacityMap::Value Value; - ///The type of the map that stores the arc capacities. - typedef typename Traits::CapacityMap CapacityMap; - ///The type of the map indicating if a node is processed. - typedef typename Traits::ProcessedMap ProcessedMap; - ///The type of the map that stores the cardinalities of the nodes. - typedef typename Traits::CardinalityMap CardinalityMap; - ///The cross reference type used for the current heap. - typedef typename Traits::HeapCrossRef HeapCrossRef; - ///The heap type used by the algorithm. It maximizes the priorities. - typedef typename Traits::Heap Heap; - private: - // Pointer to the underlying digraph. - const Digraph *_graph; - // Pointer to the capacity map - const CapacityMap *_capacity; - // Indicates if \ref _capacity is locally allocated (\c true) or not. - bool local_capacity; - // Pointer to the map of cardinality. - CardinalityMap *_cardinality; - // Indicates if \ref _cardinality is locally allocated (\c true) or not. - bool local_cardinality; - // Pointer to the map of processed status of the nodes. - ProcessedMap *_processed; - // Indicates if \ref _processed is locally allocated (\c true) or not. - bool local_processed; - // Pointer to the heap cross references. - HeapCrossRef *_heap_cross_ref; - // Indicates if \ref _heap_cross_ref is locally allocated (\c true) or not. - bool local_heap_cross_ref; - // Pointer to the heap. - Heap *_heap; - // Indicates if \ref _heap is locally allocated (\c true) or not. - bool local_heap; - - public : - - typedef MaxCardinalitySearch Create; - - ///\name Named template parameters - - ///@{ - - template - struct DefCapacityMapTraits : public Traits { - typedef T CapacityMap; - static CapacityMap *createCapacityMap(const Digraph &) { - LEMON_ASSERT(false,"Uninitialized parameter."); - return 0; - } - }; - /// \brief \ref named-templ-param "Named parameter" for setting - /// CapacityMap type - /// - /// \ref named-templ-param "Named parameter" for setting CapacityMap type - /// for the algorithm. - template - struct SetCapacityMap - : public MaxCardinalitySearch > { - typedef MaxCardinalitySearch > Create; - }; - - template - struct DefCardinalityMapTraits : public Traits { - typedef T CardinalityMap; - static CardinalityMap *createCardinalityMap(const Digraph &) - { - LEMON_ASSERT(false,"Uninitialized parameter."); - return 0; - } - }; - /// \brief \ref named-templ-param "Named parameter" for setting - /// CardinalityMap type - /// - /// \ref named-templ-param "Named parameter" for setting CardinalityMap - /// type for the algorithm. - template - struct SetCardinalityMap - : public MaxCardinalitySearch > { - typedef MaxCardinalitySearch > Create; - }; - - template - struct DefProcessedMapTraits : public Traits { - typedef T ProcessedMap; - static ProcessedMap *createProcessedMap(const Digraph &) { - LEMON_ASSERT(false,"Uninitialized parameter."); - return 0; - } - }; - /// \brief \ref named-templ-param "Named parameter" for setting - /// ProcessedMap type - /// - /// \ref named-templ-param "Named parameter" for setting ProcessedMap type - /// for the algorithm. - template - struct SetProcessedMap - : public MaxCardinalitySearch > { - typedef MaxCardinalitySearch > Create; - }; - - template - struct DefHeapTraits : public Traits { - typedef CR HeapCrossRef; - typedef H Heap; - static HeapCrossRef *createHeapCrossRef(const Digraph &) { - LEMON_ASSERT(false,"Uninitialized parameter."); - return 0; - } - static Heap *createHeap(HeapCrossRef &) { - LEMON_ASSERT(false,"Uninitialized parameter."); - return 0; - } - }; - /// \brief \ref named-templ-param "Named parameter" for setting heap - /// and cross reference type - /// - /// \ref named-templ-param "Named parameter" for setting heap and cross - /// reference type for the algorithm. - template > - struct SetHeap - : public MaxCardinalitySearch > { - typedef MaxCardinalitySearch< Digraph, CapacityMap, - DefHeapTraits > Create; - }; - - template - struct DefStandardHeapTraits : public Traits { - typedef CR HeapCrossRef; - typedef H Heap; - static HeapCrossRef *createHeapCrossRef(const Digraph &digraph) { - return new HeapCrossRef(digraph); - } - static Heap *createHeap(HeapCrossRef &crossref) { - return new Heap(crossref); - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting heap and - /// cross reference type with automatic allocation - /// - /// \ref named-templ-param "Named parameter" for setting heap and cross - /// reference type. It can allocate the heap and the cross reference - /// object if the cross reference's constructor waits for the digraph as - /// parameter and the heap's constructor waits for the cross reference. - template > - struct SetStandardHeap - : public MaxCardinalitySearch > { - typedef MaxCardinalitySearch > - Create; - }; - - ///@} - - - protected: - - MaxCardinalitySearch() {} - - public: - - /// \brief Constructor. - /// - ///\param digraph the digraph the algorithm will run on. - ///\param capacity the capacity map used by the algorithm. - MaxCardinalitySearch(const Digraph& digraph, - const CapacityMap& capacity) : - _graph(&digraph), - _capacity(&capacity), local_capacity(false), - _cardinality(0), local_cardinality(false), - _processed(0), local_processed(false), - _heap_cross_ref(0), local_heap_cross_ref(false), - _heap(0), local_heap(false) - { } - - /// \brief Constructor. - /// - ///\param digraph the digraph the algorithm will run on. - /// - ///A constant 1 capacity map will be allocated. - MaxCardinalitySearch(const Digraph& digraph) : - _graph(&digraph), - _capacity(0), local_capacity(false), - _cardinality(0), local_cardinality(false), - _processed(0), local_processed(false), - _heap_cross_ref(0), local_heap_cross_ref(false), - _heap(0), local_heap(false) - { } - - /// \brief Destructor. - ~MaxCardinalitySearch() { - if(local_capacity) delete _capacity; - if(local_cardinality) delete _cardinality; - if(local_processed) delete _processed; - if(local_heap_cross_ref) delete _heap_cross_ref; - if(local_heap) delete _heap; - } - - /// \brief Sets the capacity map. - /// - /// Sets the capacity map. - /// \return (*this) - MaxCardinalitySearch &capacityMap(const CapacityMap &m) { - if (local_capacity) { - delete _capacity; - local_capacity=false; - } - _capacity=&m; - return *this; - } - - /// \brief Returns a const reference to the capacity map. - /// - /// Returns a const reference to the capacity map used by - /// the algorithm. - const CapacityMap &capacityMap() const { - return *_capacity; - } - - /// \brief Sets the map storing the cardinalities calculated by the - /// algorithm. - /// - /// Sets the map storing the cardinalities calculated by the algorithm. - /// If you don't use this function before calling \ref run(), - /// it will allocate one. The destuctor deallocates this - /// automatically allocated map, of course. - /// \return (*this) - MaxCardinalitySearch &cardinalityMap(CardinalityMap &m) { - if(local_cardinality) { - delete _cardinality; - local_cardinality=false; - } - _cardinality = &m; - return *this; - } - - /// \brief Sets the map storing the processed nodes. - /// - /// Sets the map storing the processed nodes. - /// If you don't use this function before calling \ref run(), - /// it will allocate one. The destuctor deallocates this - /// automatically allocated map, of course. - /// \return (*this) - MaxCardinalitySearch &processedMap(ProcessedMap &m) - { - if(local_processed) { - delete _processed; - local_processed=false; - } - _processed = &m; - return *this; - } - - /// \brief Returns a const reference to the cardinality map. - /// - /// Returns a const reference to the cardinality map used by - /// the algorithm. - const ProcessedMap &processedMap() const { - return *_processed; - } - - /// \brief Sets the heap and the cross reference used by algorithm. - /// - /// Sets the heap and the cross reference used by algorithm. - /// If you don't use this function before calling \ref run(), - /// it will allocate one. The destuctor deallocates this - /// automatically allocated map, of course. - /// \return (*this) - MaxCardinalitySearch &heap(Heap& hp, HeapCrossRef &cr) { - if(local_heap_cross_ref) { - delete _heap_cross_ref; - local_heap_cross_ref = false; - } - _heap_cross_ref = &cr; - if(local_heap) { - delete _heap; - local_heap = false; - } - _heap = &hp; - return *this; - } - - /// \brief Returns a const reference to the heap. - /// - /// Returns a const reference to the heap used by - /// the algorithm. - const Heap &heap() const { - return *_heap; - } - - /// \brief Returns a const reference to the cross reference. - /// - /// Returns a const reference to the cross reference - /// of the heap. - const HeapCrossRef &heapCrossRef() const { - return *_heap_cross_ref; - } - - private: - - typedef typename Digraph::Node Node; - typedef typename Digraph::NodeIt NodeIt; - typedef typename Digraph::Arc Arc; - typedef typename Digraph::InArcIt InArcIt; - - void create_maps() { - if(!_capacity) { - local_capacity = true; - _capacity = Traits::createCapacityMap(*_graph); - } - if(!_cardinality) { - local_cardinality = true; - _cardinality = Traits::createCardinalityMap(*_graph); - } - if(!_processed) { - local_processed = true; - _processed = Traits::createProcessedMap(*_graph); - } - if (!_heap_cross_ref) { - local_heap_cross_ref = true; - _heap_cross_ref = Traits::createHeapCrossRef(*_graph); - } - if (!_heap) { - local_heap = true; - _heap = Traits::createHeap(*_heap_cross_ref); - } - } - - void finalizeNodeData(Node node, Value capacity) { - _processed->set(node, true); - _cardinality->set(node, capacity); - } - - public: - /// \name Execution control - /// The simplest way to execute the algorithm is to use - /// one of the member functions called \ref run(). - /// \n - /// If you need more control on the execution, - /// first you must call \ref init(), then you can add several source nodes - /// with \ref addSource(). - /// Finally \ref start() will perform the computation. - - ///@{ - - /// \brief Initializes the internal data structures. - /// - /// Initializes the internal data structures, and clears the heap. - void init() { - create_maps(); - _heap->clear(); - for (NodeIt it(*_graph) ; it != INVALID ; ++it) { - _processed->set(it, false); - _heap_cross_ref->set(it, Heap::PRE_HEAP); - } - } - - /// \brief Adds a new source node. - /// - /// Adds a new source node to the priority heap. - /// - /// It checks if the node has not yet been added to the heap. - void addSource(Node source, Value capacity = 0) { - if(_heap->state(source) == Heap::PRE_HEAP) { - _heap->push(source, capacity); - } - } - - /// \brief Processes the next node in the priority heap - /// - /// Processes the next node in the priority heap. - /// - /// \return The processed node. - /// - /// \warning The priority heap must not be empty! - Node processNextNode() { - Node node = _heap->top(); - finalizeNodeData(node, _heap->prio()); - _heap->pop(); - - for (InArcIt it(*_graph, node); it != INVALID; ++it) { - Node source = _graph->source(it); - switch (_heap->state(source)) { - case Heap::PRE_HEAP: - _heap->push(source, (*_capacity)[it]); - break; - case Heap::IN_HEAP: - _heap->decrease(source, (*_heap)[source] + (*_capacity)[it]); - break; - case Heap::POST_HEAP: - break; - } - } - return node; - } - - /// \brief Next node to be processed. - /// - /// Next node to be processed. - /// - /// \return The next node to be processed or INVALID if the - /// priority heap is empty. - Node nextNode() { - return !_heap->empty() ? _heap->top() : INVALID; - } - - /// \brief Returns \c false if there are nodes - /// to be processed in the priority heap - /// - /// Returns \c false if there are nodes - /// to be processed in the priority heap - bool emptyQueue() { return _heap->empty(); } - /// \brief Returns the number of the nodes to be processed - /// in the priority heap - /// - /// Returns the number of the nodes to be processed in the priority heap - int emptySize() { return _heap->size(); } - - /// \brief Executes the algorithm. - /// - /// Executes the algorithm. - /// - ///\pre init() must be called and at least one node should be added - /// with addSource() before using this function. - /// - /// This method runs the Maximum Cardinality Search algorithm from the - /// source node(s). - void start() { - while ( !_heap->empty() ) processNextNode(); - } - - /// \brief Executes the algorithm until \c dest is reached. - /// - /// Executes the algorithm until \c dest is reached. - /// - /// \pre init() must be called and at least one node should be added - /// with addSource() before using this function. - /// - /// This method runs the %MaxCardinalitySearch algorithm from the source - /// nodes. - void start(Node dest) { - while ( !_heap->empty() && _heap->top()!=dest ) processNextNode(); - if ( !_heap->empty() ) finalizeNodeData(_heap->top(), _heap->prio()); - } - - /// \brief Executes the algorithm until a condition is met. - /// - /// Executes the algorithm until a condition is met. - /// - /// \pre init() must be called and at least one node should be added - /// with addSource() before using this function. - /// - /// \param nm must be a bool (or convertible) node map. The algorithm - /// will stop when it reaches a node \c v with nm[v]==true. - template - void start(const NodeBoolMap &nm) { - while ( !_heap->empty() && !nm[_heap->top()] ) processNextNode(); - if ( !_heap->empty() ) finalizeNodeData(_heap->top(),_heap->prio()); - } - - /// \brief Runs the maximum cardinality search algorithm from node \c s. - /// - /// This method runs the %MaxCardinalitySearch algorithm from a root - /// node \c s. - /// - ///\note d.run(s) is just a shortcut of the following code. - ///\code - /// d.init(); - /// d.addSource(s); - /// d.start(); - ///\endcode - void run(Node s) { - init(); - addSource(s); - start(); - } - - /// \brief Runs the maximum cardinality search algorithm for the - /// whole digraph. - /// - /// This method runs the %MaxCardinalitySearch algorithm from all - /// unprocessed node of the digraph. - /// - ///\note d.run(s) is just a shortcut of the following code. - ///\code - /// d.init(); - /// for (NodeIt it(digraph); it != INVALID; ++it) { - /// if (!d.reached(it)) { - /// d.addSource(s); - /// d.start(); - /// } - /// } - ///\endcode - void run() { - init(); - for (NodeIt it(*_graph); it != INVALID; ++it) { - if (!reached(it)) { - addSource(it); - start(); - } - } - } - - ///@} - - /// \name Query Functions - /// The results of the maximum cardinality search algorithm can be - /// obtained using these functions. - /// \n - /// Before the use of these functions, either run() or start() must be - /// called. - - ///@{ - - /// \brief The cardinality of a node. - /// - /// Returns the cardinality of a node. - /// \pre \ref run() must be called before using this function. - /// \warning If node \c v in unreachable from the root the return value - /// of this funcion is undefined. - Value cardinality(Node node) const { return (*_cardinality)[node]; } - - /// \brief The current cardinality of a node. - /// - /// Returns the current cardinality of a node. - /// \pre the given node should be reached but not processed - Value currentCardinality(Node node) const { return (*_heap)[node]; } - - /// \brief Returns a reference to the NodeMap of cardinalities. - /// - /// Returns a reference to the NodeMap of cardinalities. \pre \ref run() - /// must be called before using this function. - const CardinalityMap &cardinalityMap() const { return *_cardinality;} - - /// \brief Checks if a node is reachable from the root. - /// - /// Returns \c true if \c v is reachable from the root. - /// \warning The source nodes are initated as unreached. - /// \pre \ref run() must be called before using this function. - bool reached(Node v) { return (*_heap_cross_ref)[v] != Heap::PRE_HEAP; } - - /// \brief Checks if a node is processed. - /// - /// Returns \c true if \c v is processed, i.e. the shortest - /// path to \c v has already found. - /// \pre \ref run() must be called before using this function. - bool processed(Node v) { return (*_heap_cross_ref)[v] == Heap::POST_HEAP; } - - ///@} - }; - -} - -#endif diff --git a/deps/lemon/lemon/min_cost_arborescence.h b/deps/lemon/lemon/min_cost_arborescence.h deleted file mode 100644 index 1d0a2b19d..000000000 --- a/deps/lemon/lemon/min_cost_arborescence.h +++ /dev/null @@ -1,808 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_MIN_COST_ARBORESCENCE_H -#define LEMON_MIN_COST_ARBORESCENCE_H - -///\ingroup spantree -///\file -///\brief Minimum Cost Arborescence algorithm. - -#include - -#include -#include -#include - -namespace lemon { - - - /// \brief Default traits class for MinCostArborescence class. - /// - /// Default traits class for MinCostArborescence class. - /// \param GR Digraph type. - /// \param CM Type of the cost map. - template - struct MinCostArborescenceDefaultTraits{ - - /// \brief The digraph type the algorithm runs on. - typedef GR Digraph; - - /// \brief The type of the map that stores the arc costs. - /// - /// The type of the map that stores the arc costs. - /// It must conform to the \ref concepts::ReadMap "ReadMap" concept. - typedef CM CostMap; - - /// \brief The value type of the costs. - /// - /// The value type of the costs. - typedef typename CostMap::Value Value; - - /// \brief The type of the map that stores which arcs are in the - /// arborescence. - /// - /// The type of the map that stores which arcs are in the - /// arborescence. It must conform to the \ref concepts::WriteMap - /// "WriteMap" concept, and its value type must be \c bool - /// (or convertible). Initially it will be set to \c false on each - /// arc, then it will be set on each arborescence arc once. - typedef typename Digraph::template ArcMap ArborescenceMap; - - /// \brief Instantiates a \c ArborescenceMap. - /// - /// This function instantiates a \c ArborescenceMap. - /// \param digraph The digraph to which we would like to calculate - /// the \c ArborescenceMap. - static ArborescenceMap *createArborescenceMap(const Digraph &digraph){ - return new ArborescenceMap(digraph); - } - - /// \brief The type of the \c PredMap - /// - /// The type of the \c PredMap. It must confrom to the - /// \ref concepts::WriteMap "WriteMap" concept, and its value type - /// must be the \c Arc type of the digraph. - typedef typename Digraph::template NodeMap PredMap; - - /// \brief Instantiates a \c PredMap. - /// - /// This function instantiates a \c PredMap. - /// \param digraph The digraph to which we would like to define the - /// \c PredMap. - static PredMap *createPredMap(const Digraph &digraph){ - return new PredMap(digraph); - } - - }; - - /// \ingroup spantree - /// - /// \brief Minimum Cost Arborescence algorithm class. - /// - /// This class provides an efficient implementation of the - /// Minimum Cost Arborescence algorithm. The arborescence is a tree - /// which is directed from a given source node of the digraph. One or - /// more sources should be given to the algorithm and it will calculate - /// the minimum cost subgraph that is the union of arborescences with the - /// given sources and spans all the nodes which are reachable from the - /// sources. The time complexity of the algorithm is O(n2+m). - /// - /// The algorithm also provides an optimal dual solution, therefore - /// the optimality of the solution can be checked. - /// - /// \param GR The digraph type the algorithm runs on. - /// \param CM A read-only arc map storing the costs of the - /// arcs. It is read once for each arc, so the map may involve in - /// relatively time consuming process to compute the arc costs if - /// it is necessary. The default map type is \ref - /// concepts::Digraph::ArcMap "Digraph::ArcMap". - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref MinCostArborescenceDefaultTraits - /// "MinCostArborescenceDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. -#ifndef DOXYGEN - template , - typename TR = - MinCostArborescenceDefaultTraits > -#else - template -#endif - class MinCostArborescence { - public: - - /// \brief The \ref lemon::MinCostArborescenceDefaultTraits "traits class" - /// of the algorithm. - typedef TR Traits; - /// The type of the underlying digraph. - typedef typename Traits::Digraph Digraph; - /// The type of the map that stores the arc costs. - typedef typename Traits::CostMap CostMap; - ///The type of the costs of the arcs. - typedef typename Traits::Value Value; - ///The type of the predecessor map. - typedef typename Traits::PredMap PredMap; - ///The type of the map that stores which arcs are in the arborescence. - typedef typename Traits::ArborescenceMap ArborescenceMap; - - typedef MinCostArborescence Create; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - struct CostArc { - - Arc arc; - Value value; - - CostArc() {} - CostArc(Arc _arc, Value _value) : arc(_arc), value(_value) {} - - }; - - const Digraph *_digraph; - const CostMap *_cost; - - PredMap *_pred; - bool local_pred; - - ArborescenceMap *_arborescence; - bool local_arborescence; - - typedef typename Digraph::template ArcMap ArcOrder; - ArcOrder *_arc_order; - - typedef typename Digraph::template NodeMap NodeOrder; - NodeOrder *_node_order; - - typedef typename Digraph::template NodeMap CostArcMap; - CostArcMap *_cost_arcs; - - struct StackLevel { - - std::vector arcs; - int node_level; - - }; - - std::vector level_stack; - std::vector queue; - - typedef std::vector DualNodeList; - - DualNodeList _dual_node_list; - - struct DualVariable { - int begin, end; - Value value; - - DualVariable(int _begin, int _end, Value _value) - : begin(_begin), end(_end), value(_value) {} - - }; - - typedef std::vector DualVariables; - - DualVariables _dual_variables; - - typedef typename Digraph::template NodeMap HeapCrossRef; - - HeapCrossRef *_heap_cross_ref; - - typedef BinHeap Heap; - - Heap *_heap; - - protected: - - MinCostArborescence() {} - - private: - - void createStructures() { - if (!_pred) { - local_pred = true; - _pred = Traits::createPredMap(*_digraph); - } - if (!_arborescence) { - local_arborescence = true; - _arborescence = Traits::createArborescenceMap(*_digraph); - } - if (!_arc_order) { - _arc_order = new ArcOrder(*_digraph); - } - if (!_node_order) { - _node_order = new NodeOrder(*_digraph); - } - if (!_cost_arcs) { - _cost_arcs = new CostArcMap(*_digraph); - } - if (!_heap_cross_ref) { - _heap_cross_ref = new HeapCrossRef(*_digraph, -1); - } - if (!_heap) { - _heap = new Heap(*_heap_cross_ref); - } - } - - void destroyStructures() { - if (local_arborescence) { - delete _arborescence; - } - if (local_pred) { - delete _pred; - } - if (_arc_order) { - delete _arc_order; - } - if (_node_order) { - delete _node_order; - } - if (_cost_arcs) { - delete _cost_arcs; - } - if (_heap) { - delete _heap; - } - if (_heap_cross_ref) { - delete _heap_cross_ref; - } - } - - Arc prepare(Node node) { - std::vector nodes; - (*_node_order)[node] = _dual_node_list.size(); - StackLevel level; - level.node_level = _dual_node_list.size(); - _dual_node_list.push_back(node); - for (InArcIt it(*_digraph, node); it != INVALID; ++it) { - Arc arc = it; - Node source = _digraph->source(arc); - Value value = (*_cost)[it]; - if (source == node || (*_node_order)[source] == -3) continue; - if ((*_cost_arcs)[source].arc == INVALID) { - (*_cost_arcs)[source].arc = arc; - (*_cost_arcs)[source].value = value; - nodes.push_back(source); - } else { - if ((*_cost_arcs)[source].value > value) { - (*_cost_arcs)[source].arc = arc; - (*_cost_arcs)[source].value = value; - } - } - } - CostArc minimum = (*_cost_arcs)[nodes[0]]; - for (int i = 1; i < int(nodes.size()); ++i) { - if ((*_cost_arcs)[nodes[i]].value < minimum.value) { - minimum = (*_cost_arcs)[nodes[i]]; - } - } - (*_arc_order)[minimum.arc] = _dual_variables.size(); - DualVariable var(_dual_node_list.size() - 1, - _dual_node_list.size(), minimum.value); - _dual_variables.push_back(var); - for (int i = 0; i < int(nodes.size()); ++i) { - (*_cost_arcs)[nodes[i]].value -= minimum.value; - level.arcs.push_back((*_cost_arcs)[nodes[i]]); - (*_cost_arcs)[nodes[i]].arc = INVALID; - } - level_stack.push_back(level); - return minimum.arc; - } - - Arc contract(Node node) { - int node_bottom = bottom(node); - std::vector nodes; - while (!level_stack.empty() && - level_stack.back().node_level >= node_bottom) { - for (int i = 0; i < int(level_stack.back().arcs.size()); ++i) { - Arc arc = level_stack.back().arcs[i].arc; - Node source = _digraph->source(arc); - Value value = level_stack.back().arcs[i].value; - if ((*_node_order)[source] >= node_bottom) continue; - if ((*_cost_arcs)[source].arc == INVALID) { - (*_cost_arcs)[source].arc = arc; - (*_cost_arcs)[source].value = value; - nodes.push_back(source); - } else { - if ((*_cost_arcs)[source].value > value) { - (*_cost_arcs)[source].arc = arc; - (*_cost_arcs)[source].value = value; - } - } - } - level_stack.pop_back(); - } - CostArc minimum = (*_cost_arcs)[nodes[0]]; - for (int i = 1; i < int(nodes.size()); ++i) { - if ((*_cost_arcs)[nodes[i]].value < minimum.value) { - minimum = (*_cost_arcs)[nodes[i]]; - } - } - (*_arc_order)[minimum.arc] = _dual_variables.size(); - DualVariable var(node_bottom, _dual_node_list.size(), minimum.value); - _dual_variables.push_back(var); - StackLevel level; - level.node_level = node_bottom; - for (int i = 0; i < int(nodes.size()); ++i) { - (*_cost_arcs)[nodes[i]].value -= minimum.value; - level.arcs.push_back((*_cost_arcs)[nodes[i]]); - (*_cost_arcs)[nodes[i]].arc = INVALID; - } - level_stack.push_back(level); - return minimum.arc; - } - - int bottom(Node node) { - int k = level_stack.size() - 1; - while (level_stack[k].node_level > (*_node_order)[node]) { - --k; - } - return level_stack[k].node_level; - } - - void finalize(Arc arc) { - Node node = _digraph->target(arc); - _heap->push(node, (*_arc_order)[arc]); - _pred->set(node, arc); - while (!_heap->empty()) { - Node source = _heap->top(); - _heap->pop(); - (*_node_order)[source] = -1; - for (OutArcIt it(*_digraph, source); it != INVALID; ++it) { - if ((*_arc_order)[it] < 0) continue; - Node target = _digraph->target(it); - switch(_heap->state(target)) { - case Heap::PRE_HEAP: - _heap->push(target, (*_arc_order)[it]); - _pred->set(target, it); - break; - case Heap::IN_HEAP: - if ((*_arc_order)[it] < (*_heap)[target]) { - _heap->decrease(target, (*_arc_order)[it]); - _pred->set(target, it); - } - break; - case Heap::POST_HEAP: - break; - } - } - _arborescence->set((*_pred)[source], true); - } - } - - - public: - - /// \name Named Template Parameters - - /// @{ - - template - struct SetArborescenceMapTraits : public Traits { - typedef T ArborescenceMap; - static ArborescenceMap *createArborescenceMap(const Digraph &) - { - LEMON_ASSERT(false, "ArborescenceMap is not initialized"); - return 0; // ignore warnings - } - }; - - /// \brief \ref named-templ-param "Named parameter" for - /// setting \c ArborescenceMap type - /// - /// \ref named-templ-param "Named parameter" for setting - /// \c ArborescenceMap type. - /// It must conform to the \ref concepts::WriteMap "WriteMap" concept, - /// and its value type must be \c bool (or convertible). - /// Initially it will be set to \c false on each arc, - /// then it will be set on each arborescence arc once. - template - struct SetArborescenceMap - : public MinCostArborescence > { - }; - - template - struct SetPredMapTraits : public Traits { - typedef T PredMap; - static PredMap *createPredMap(const Digraph &) - { - LEMON_ASSERT(false, "PredMap is not initialized"); - return 0; // ignore warnings - } - }; - - /// \brief \ref named-templ-param "Named parameter" for - /// setting \c PredMap type - /// - /// \ref named-templ-param "Named parameter" for setting - /// \c PredMap type. - /// It must meet the \ref concepts::WriteMap "WriteMap" concept, - /// and its value type must be the \c Arc type of the digraph. - template - struct SetPredMap - : public MinCostArborescence > { - }; - - /// @} - - /// \brief Constructor. - /// - /// \param digraph The digraph the algorithm will run on. - /// \param cost The cost map used by the algorithm. - MinCostArborescence(const Digraph& digraph, const CostMap& cost) - : _digraph(&digraph), _cost(&cost), _pred(0), local_pred(false), - _arborescence(0), local_arborescence(false), - _arc_order(0), _node_order(0), _cost_arcs(0), - _heap_cross_ref(0), _heap(0) {} - - /// \brief Destructor. - ~MinCostArborescence() { - destroyStructures(); - } - - /// \brief Sets the arborescence map. - /// - /// Sets the arborescence map. - /// \return (*this) - MinCostArborescence& arborescenceMap(ArborescenceMap& m) { - if (local_arborescence) { - delete _arborescence; - } - local_arborescence = false; - _arborescence = &m; - return *this; - } - - /// \brief Sets the predecessor map. - /// - /// Sets the predecessor map. - /// \return (*this) - MinCostArborescence& predMap(PredMap& m) { - if (local_pred) { - delete _pred; - } - local_pred = false; - _pred = &m; - return *this; - } - - /// \name Execution Control - /// The simplest way to execute the algorithm is to use - /// one of the member functions called \c run(...). \n - /// If you need better control on the execution, - /// you have to call \ref init() first, then you can add several - /// source nodes with \ref addSource(). - /// Finally \ref start() will perform the arborescence - /// computation. - - ///@{ - - /// \brief Initializes the internal data structures. - /// - /// Initializes the internal data structures. - /// - void init() { - createStructures(); - _heap->clear(); - for (NodeIt it(*_digraph); it != INVALID; ++it) { - (*_cost_arcs)[it].arc = INVALID; - (*_node_order)[it] = -3; - (*_heap_cross_ref)[it] = Heap::PRE_HEAP; - _pred->set(it, INVALID); - } - for (ArcIt it(*_digraph); it != INVALID; ++it) { - _arborescence->set(it, false); - (*_arc_order)[it] = -1; - } - _dual_node_list.clear(); - _dual_variables.clear(); - } - - /// \brief Adds a new source node. - /// - /// Adds a new source node to the algorithm. - void addSource(Node source) { - std::vector nodes; - nodes.push_back(source); - while (!nodes.empty()) { - Node node = nodes.back(); - nodes.pop_back(); - for (OutArcIt it(*_digraph, node); it != INVALID; ++it) { - Node target = _digraph->target(it); - if ((*_node_order)[target] == -3) { - (*_node_order)[target] = -2; - nodes.push_back(target); - queue.push_back(target); - } - } - } - (*_node_order)[source] = -1; - } - - /// \brief Processes the next node in the priority queue. - /// - /// Processes the next node in the priority queue. - /// - /// \return The processed node. - /// - /// \warning The queue must not be empty. - Node processNextNode() { - Node node = queue.back(); - queue.pop_back(); - if ((*_node_order)[node] == -2) { - Arc arc = prepare(node); - Node source = _digraph->source(arc); - while ((*_node_order)[source] != -1) { - if ((*_node_order)[source] >= 0) { - arc = contract(source); - } else { - arc = prepare(source); - } - source = _digraph->source(arc); - } - finalize(arc); - level_stack.clear(); - } - return node; - } - - /// \brief Returns the number of the nodes to be processed. - /// - /// Returns the number of the nodes to be processed in the priority - /// queue. - int queueSize() const { - return queue.size(); - } - - /// \brief Returns \c false if there are nodes to be processed. - /// - /// Returns \c false if there are nodes to be processed. - bool emptyQueue() const { - return queue.empty(); - } - - /// \brief Executes the algorithm. - /// - /// Executes the algorithm. - /// - /// \pre init() must be called and at least one node should be added - /// with addSource() before using this function. - /// - ///\note mca.start() is just a shortcut of the following code. - ///\code - ///while (!mca.emptyQueue()) { - /// mca.processNextNode(); - ///} - ///\endcode - void start() { - while (!emptyQueue()) { - processNextNode(); - } - } - - /// \brief Runs %MinCostArborescence algorithm from node \c s. - /// - /// This method runs the %MinCostArborescence algorithm from - /// a root node \c s. - /// - /// \note mca.run(s) is just a shortcut of the following code. - /// \code - /// mca.init(); - /// mca.addSource(s); - /// mca.start(); - /// \endcode - void run(Node s) { - init(); - addSource(s); - start(); - } - - ///@} - - /// \name Query Functions - /// The result of the %MinCostArborescence algorithm can be obtained - /// using these functions.\n - /// Either run() or start() must be called before using them. - - /// @{ - - /// \brief Returns the cost of the arborescence. - /// - /// Returns the cost of the arborescence. - Value arborescenceCost() const { - Value sum = 0; - for (ArcIt it(*_digraph); it != INVALID; ++it) { - if (arborescence(it)) { - sum += (*_cost)[it]; - } - } - return sum; - } - - /// \brief Returns \c true if the arc is in the arborescence. - /// - /// Returns \c true if the given arc is in the arborescence. - /// \param arc An arc of the digraph. - /// \pre \ref run() must be called before using this function. - bool arborescence(Arc arc) const { - return (*_pred)[_digraph->target(arc)] == arc; - } - - /// \brief Returns a const reference to the arborescence map. - /// - /// Returns a const reference to the arborescence map. - /// \pre \ref run() must be called before using this function. - const ArborescenceMap& arborescenceMap() const { - return *_arborescence; - } - - /// \brief Returns the predecessor arc of the given node. - /// - /// Returns the predecessor arc of the given node. - /// \pre \ref run() must be called before using this function. - Arc pred(Node node) const { - return (*_pred)[node]; - } - - /// \brief Returns a const reference to the pred map. - /// - /// Returns a const reference to the pred map. - /// \pre \ref run() must be called before using this function. - const PredMap& predMap() const { - return *_pred; - } - - /// \brief Indicates that a node is reachable from the sources. - /// - /// Indicates that a node is reachable from the sources. - bool reached(Node node) const { - return (*_node_order)[node] != -3; - } - - /// \brief Indicates that a node is processed. - /// - /// Indicates that a node is processed. The arborescence path exists - /// from the source to the given node. - bool processed(Node node) const { - return (*_node_order)[node] == -1; - } - - /// \brief Returns the number of the dual variables in basis. - /// - /// Returns the number of the dual variables in basis. - int dualNum() const { - return _dual_variables.size(); - } - - /// \brief Returns the value of the dual solution. - /// - /// Returns the value of the dual solution. It should be - /// equal to the arborescence value. - Value dualValue() const { - Value sum = 0; - for (int i = 0; i < int(_dual_variables.size()); ++i) { - sum += _dual_variables[i].value; - } - return sum; - } - - /// \brief Returns the number of the nodes in the dual variable. - /// - /// Returns the number of the nodes in the dual variable. - int dualSize(int k) const { - return _dual_variables[k].end - _dual_variables[k].begin; - } - - /// \brief Returns the value of the dual variable. - /// - /// Returns the the value of the dual variable. - Value dualValue(int k) const { - return _dual_variables[k].value; - } - - /// \brief LEMON iterator for getting a dual variable. - /// - /// This class provides a common style LEMON iterator for getting a - /// dual variable of \ref MinCostArborescence algorithm. - /// It iterates over a subset of the nodes. - class DualIt { - public: - - /// \brief Constructor. - /// - /// Constructor for getting the nodeset of the dual variable - /// of \ref MinCostArborescence algorithm. - DualIt(const MinCostArborescence& algorithm, int variable) - : _algorithm(&algorithm) - { - _index = _algorithm->_dual_variables[variable].begin; - _last = _algorithm->_dual_variables[variable].end; - } - - /// \brief Conversion to \c Node. - /// - /// Conversion to \c Node. - operator Node() const { - return _algorithm->_dual_node_list[_index]; - } - - /// \brief Increment operator. - /// - /// Increment operator. - DualIt& operator++() { - ++_index; - return *this; - } - - /// \brief Validity checking - /// - /// Checks whether the iterator is invalid. - bool operator==(Invalid) const { - return _index == _last; - } - - /// \brief Validity checking - /// - /// Checks whether the iterator is valid. - bool operator!=(Invalid) const { - return _index != _last; - } - - private: - const MinCostArborescence* _algorithm; - int _index, _last; - }; - - /// @} - - }; - - /// \ingroup spantree - /// - /// \brief Function type interface for MinCostArborescence algorithm. - /// - /// Function type interface for MinCostArborescence algorithm. - /// \param digraph The digraph the algorithm runs on. - /// \param cost An arc map storing the costs. - /// \param source The source node of the arborescence. - /// \retval arborescence An arc map with \c bool (or convertible) value - /// type that stores the arborescence. - /// \return The total cost of the arborescence. - /// - /// \sa MinCostArborescence - template - typename CostMap::Value minCostArborescence(const Digraph& digraph, - const CostMap& cost, - typename Digraph::Node source, - ArborescenceMap& arborescence) { - typename MinCostArborescence - ::template SetArborescenceMap - ::Create mca(digraph, cost); - mca.arborescenceMap(arborescence); - mca.run(source); - return mca.arborescenceCost(); - } - -} - -#endif diff --git a/deps/lemon/lemon/nagamochi_ibaraki.h b/deps/lemon/lemon/nagamochi_ibaraki.h deleted file mode 100644 index 57a6ba64d..000000000 --- a/deps/lemon/lemon/nagamochi_ibaraki.h +++ /dev/null @@ -1,702 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_NAGAMOCHI_IBARAKI_H -#define LEMON_NAGAMOCHI_IBARAKI_H - - -/// \ingroup min_cut -/// \file -/// \brief Implementation of the Nagamochi-Ibaraki algorithm. - -#include -#include -#include -#include -#include -#include - -#include - -namespace lemon { - - /// \brief Default traits class for NagamochiIbaraki class. - /// - /// Default traits class for NagamochiIbaraki class. - /// \param GR The undirected graph type. - /// \param CM Type of capacity map. - template - struct NagamochiIbarakiDefaultTraits { - /// The type of the capacity map. - typedef typename CM::Value Value; - - /// The undirected graph type the algorithm runs on. - typedef GR Graph; - - /// \brief The type of the map that stores the edge capacities. - /// - /// The type of the map that stores the edge capacities. - /// It must meet the \ref concepts::ReadMap "ReadMap" concept. - typedef CM CapacityMap; - - /// \brief Instantiates a CapacityMap. - /// - /// This function instantiates a \ref CapacityMap. -#ifdef DOXYGEN - static CapacityMap *createCapacityMap(const Graph& graph) -#else - static CapacityMap *createCapacityMap(const Graph&) -#endif - { - LEMON_ASSERT(false, "CapacityMap is not initialized"); - return 0; // ignore warnings - } - - /// \brief The cross reference type used by heap. - /// - /// The cross reference type used by heap. - /// Usually \c Graph::NodeMap. - typedef typename Graph::template NodeMap HeapCrossRef; - - /// \brief Instantiates a HeapCrossRef. - /// - /// This function instantiates a \ref HeapCrossRef. - /// \param g is the graph, to which we would like to define the - /// \ref HeapCrossRef. - static HeapCrossRef *createHeapCrossRef(const Graph& g) { - return new HeapCrossRef(g); - } - - /// \brief The heap type used by NagamochiIbaraki algorithm. - /// - /// The heap type used by NagamochiIbaraki algorithm. It has to - /// maximize the priorities. - /// - /// \sa BinHeap - /// \sa NagamochiIbaraki - typedef BinHeap > Heap; - - /// \brief Instantiates a Heap. - /// - /// This function instantiates a \ref Heap. - /// \param r is the cross reference of the heap. - static Heap *createHeap(HeapCrossRef& r) { - return new Heap(r); - } - }; - - /// \ingroup min_cut - /// - /// \brief Calculates the minimum cut in an undirected graph. - /// - /// Calculates the minimum cut in an undirected graph with the - /// Nagamochi-Ibaraki algorithm. The algorithm separates the graph's - /// nodes into two partitions with the minimum sum of edge capacities - /// between the two partitions. The algorithm can be used to test - /// the network reliability, especially to test how many links have - /// to be destroyed in the network to split it to at least two - /// distinict subnetworks. - /// - /// The complexity of the algorithm is \f$ O(nm\log(n)) \f$ but with - /// \ref FibHeap "Fibonacci heap" it can be decreased to - /// \f$ O(nm+n^2\log(n)) \f$. When the edges have unit capacities, - /// \c BucketHeap can be used which yields \f$ O(nm) \f$ time - /// complexity. - /// - /// \warning The value type of the capacity map should be able to - /// hold any cut value of the graph, otherwise the result can - /// overflow. - /// \note This capacity is supposed to be integer type. -#ifdef DOXYGEN - template -#else - template , - typename TR = NagamochiIbarakiDefaultTraits > -#endif - class NagamochiIbaraki { - public: - - typedef TR Traits; - /// The type of the underlying graph. - typedef typename Traits::Graph Graph; - - /// The type of the capacity map. - typedef typename Traits::CapacityMap CapacityMap; - /// The value type of the capacity map. - typedef typename Traits::CapacityMap::Value Value; - - /// The heap type used by the algorithm. - typedef typename Traits::Heap Heap; - /// The cross reference type used for the heap. - typedef typename Traits::HeapCrossRef HeapCrossRef; - - ///\name Named template parameters - - ///@{ - - struct SetUnitCapacityTraits : public Traits { - typedef ConstMap > CapacityMap; - static CapacityMap *createCapacityMap(const Graph&) { - return new CapacityMap(); - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// the capacity map to a constMap() instance - /// - /// \ref named-templ-param "Named parameter" for setting - /// the capacity map to a constMap() instance - struct SetUnitCapacity - : public NagamochiIbaraki { - typedef NagamochiIbaraki Create; - }; - - - template - struct SetHeapTraits : public Traits { - typedef CR HeapCrossRef; - typedef H Heap; - static HeapCrossRef *createHeapCrossRef(int num) { - LEMON_ASSERT(false, "HeapCrossRef is not initialized"); - return 0; // ignore warnings - } - static Heap *createHeap(HeapCrossRef &) { - LEMON_ASSERT(false, "Heap is not initialized"); - return 0; // ignore warnings - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// heap and cross reference type - /// - /// \ref named-templ-param "Named parameter" for setting heap and - /// cross reference type. The heap has to maximize the priorities. - template > - struct SetHeap - : public NagamochiIbaraki > { - typedef NagamochiIbaraki< Graph, CapacityMap, SetHeapTraits > - Create; - }; - - template - struct SetStandardHeapTraits : public Traits { - typedef CR HeapCrossRef; - typedef H Heap; - static HeapCrossRef *createHeapCrossRef(int size) { - return new HeapCrossRef(size); - } - static Heap *createHeap(HeapCrossRef &crossref) { - return new Heap(crossref); - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// heap and cross reference type with automatic allocation - /// - /// \ref named-templ-param "Named parameter" for setting heap and - /// cross reference type with automatic allocation. They should - /// have standard constructor interfaces to be able to - /// automatically created by the algorithm (i.e. the graph should - /// be passed to the constructor of the cross reference and the - /// cross reference should be passed to the constructor of the - /// heap). However, external heap and cross reference objects - /// could also be passed to the algorithm using the \ref heap() - /// function before calling \ref run() or \ref init(). The heap - /// has to maximize the priorities. - /// \sa SetHeap - template > - struct SetStandardHeap - : public NagamochiIbaraki > { - typedef NagamochiIbaraki > Create; - }; - - ///@} - - - private: - - const Graph &_graph; - const CapacityMap *_capacity; - bool _local_capacity; // unit capacity - - struct ArcData { - typename Graph::Node target; - int prev, next; - }; - struct EdgeData { - Value capacity; - Value cut; - }; - - struct NodeData { - int first_arc; - typename Graph::Node prev, next; - int curr_arc; - typename Graph::Node last_rep; - Value sum; - }; - - typename Graph::template NodeMap *_nodes; - std::vector _arcs; - std::vector _edges; - - typename Graph::Node _first_node; - int _node_num; - - Value _min_cut; - - HeapCrossRef *_heap_cross_ref; - bool _local_heap_cross_ref; - Heap *_heap; - bool _local_heap; - - typedef typename Graph::template NodeMap NodeList; - NodeList *_next_rep; - - typedef typename Graph::template NodeMap MinCutMap; - MinCutMap *_cut_map; - - void createStructures() { - if (!_nodes) { - _nodes = new (typename Graph::template NodeMap)(_graph); - } - if (!_capacity) { - _local_capacity = true; - _capacity = Traits::createCapacityMap(_graph); - } - if (!_heap_cross_ref) { - _local_heap_cross_ref = true; - _heap_cross_ref = Traits::createHeapCrossRef(_graph); - } - if (!_heap) { - _local_heap = true; - _heap = Traits::createHeap(*_heap_cross_ref); - } - if (!_next_rep) { - _next_rep = new NodeList(_graph); - } - if (!_cut_map) { - _cut_map = new MinCutMap(_graph); - } - } - - protected: - //This is here to avoid a gcc-3.3 compilation error. - //It should never be called. - NagamochiIbaraki() {} - - public: - - typedef NagamochiIbaraki Create; - - - /// \brief Constructor. - /// - /// \param graph The graph the algorithm runs on. - /// \param capacity The capacity map used by the algorithm. - NagamochiIbaraki(const Graph& graph, const CapacityMap& capacity) - : _graph(graph), _capacity(&capacity), _local_capacity(false), - _nodes(0), _arcs(), _edges(), _min_cut(), - _heap_cross_ref(0), _local_heap_cross_ref(false), - _heap(0), _local_heap(false), - _next_rep(0), _cut_map(0) {} - - /// \brief Constructor. - /// - /// This constructor can be used only when the Traits class - /// defines how can the local capacity map be instantiated. - /// If the SetUnitCapacity used the algorithm automatically - /// constructs the capacity map. - /// - ///\param graph The graph the algorithm runs on. - NagamochiIbaraki(const Graph& graph) - : _graph(graph), _capacity(0), _local_capacity(false), - _nodes(0), _arcs(), _edges(), _min_cut(), - _heap_cross_ref(0), _local_heap_cross_ref(false), - _heap(0), _local_heap(false), - _next_rep(0), _cut_map(0) {} - - /// \brief Destructor. - /// - /// Destructor. - ~NagamochiIbaraki() { - if (_local_capacity) delete _capacity; - if (_nodes) delete _nodes; - if (_local_heap) delete _heap; - if (_local_heap_cross_ref) delete _heap_cross_ref; - if (_next_rep) delete _next_rep; - if (_cut_map) delete _cut_map; - } - - /// \brief Sets the heap and the cross reference used by algorithm. - /// - /// Sets the heap and the cross reference used by algorithm. - /// If you don't use this function before calling \ref run(), - /// it will allocate one. The destuctor deallocates this - /// automatically allocated heap and cross reference, of course. - /// \return (*this) - NagamochiIbaraki &heap(Heap& hp, HeapCrossRef &cr) - { - if (_local_heap_cross_ref) { - delete _heap_cross_ref; - _local_heap_cross_ref = false; - } - _heap_cross_ref = &cr; - if (_local_heap) { - delete _heap; - _local_heap = false; - } - _heap = &hp; - return *this; - } - - /// \name Execution control - /// The simplest way to execute the algorithm is to use - /// one of the member functions called \c run(). - /// \n - /// If you need more control on the execution, - /// first you must call \ref init() and then call the start() - /// or proper times the processNextPhase() member functions. - - ///@{ - - /// \brief Initializes the internal data structures. - /// - /// Initializes the internal data structures. - void init() { - createStructures(); - - int edge_num = countEdges(_graph); - _edges.resize(edge_num); - _arcs.resize(2 * edge_num); - - typename Graph::Node prev = INVALID; - _node_num = 0; - for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { - (*_cut_map)[n] = false; - (*_next_rep)[n] = INVALID; - (*_nodes)[n].last_rep = n; - (*_nodes)[n].first_arc = -1; - (*_nodes)[n].curr_arc = -1; - (*_nodes)[n].prev = prev; - if (prev != INVALID) { - (*_nodes)[prev].next = n; - } - (*_nodes)[n].next = INVALID; - (*_nodes)[n].sum = 0; - prev = n; - ++_node_num; - } - - _first_node = typename Graph::NodeIt(_graph); - - int index = 0; - for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { - for (typename Graph::OutArcIt a(_graph, n); a != INVALID; ++a) { - typename Graph::Node m = _graph.target(a); - - if (!(n < m)) continue; - - (*_nodes)[n].sum += (*_capacity)[a]; - (*_nodes)[m].sum += (*_capacity)[a]; - - int c = (*_nodes)[m].curr_arc; - if (c != -1 && _arcs[c ^ 1].target == n) { - _edges[c >> 1].capacity += (*_capacity)[a]; - } else { - _edges[index].capacity = (*_capacity)[a]; - - _arcs[index << 1].prev = -1; - if ((*_nodes)[n].first_arc != -1) { - _arcs[(*_nodes)[n].first_arc].prev = (index << 1); - } - _arcs[index << 1].next = (*_nodes)[n].first_arc; - (*_nodes)[n].first_arc = (index << 1); - _arcs[index << 1].target = m; - - (*_nodes)[m].curr_arc = (index << 1); - - _arcs[(index << 1) | 1].prev = -1; - if ((*_nodes)[m].first_arc != -1) { - _arcs[(*_nodes)[m].first_arc].prev = ((index << 1) | 1); - } - _arcs[(index << 1) | 1].next = (*_nodes)[m].first_arc; - (*_nodes)[m].first_arc = ((index << 1) | 1); - _arcs[(index << 1) | 1].target = n; - - ++index; - } - } - } - - typename Graph::Node cut_node = INVALID; - _min_cut = std::numeric_limits::max(); - - for (typename Graph::Node n = _first_node; - n != INVALID; n = (*_nodes)[n].next) { - if ((*_nodes)[n].sum < _min_cut) { - cut_node = n; - _min_cut = (*_nodes)[n].sum; - } - } - (*_cut_map)[cut_node] = true; - if (_min_cut == 0) { - _first_node = INVALID; - } - } - - public: - - /// \brief Processes the next phase - /// - /// Processes the next phase in the algorithm. It must be called - /// at most one less the number of the nodes in the graph. - /// - ///\return %True when the algorithm finished. - bool processNextPhase() { - if (_first_node == INVALID) return true; - - _heap->clear(); - for (typename Graph::Node n = _first_node; - n != INVALID; n = (*_nodes)[n].next) { - (*_heap_cross_ref)[n] = Heap::PRE_HEAP; - } - - std::vector order; - order.reserve(_node_num); - int sep = 0; - - Value alpha = 0; - Value pmc = std::numeric_limits::max(); - - _heap->push(_first_node, static_cast(0)); - while (!_heap->empty()) { - typename Graph::Node n = _heap->top(); - Value v = _heap->prio(); - - _heap->pop(); - for (int a = (*_nodes)[n].first_arc; a != -1; a = _arcs[a].next) { - switch (_heap->state(_arcs[a].target)) { - case Heap::PRE_HEAP: - { - Value nv = _edges[a >> 1].capacity; - _heap->push(_arcs[a].target, nv); - _edges[a >> 1].cut = nv; - } break; - case Heap::IN_HEAP: - { - Value nv = _edges[a >> 1].capacity + (*_heap)[_arcs[a].target]; - _heap->decrease(_arcs[a].target, nv); - _edges[a >> 1].cut = nv; - } break; - case Heap::POST_HEAP: - break; - } - } - - alpha += (*_nodes)[n].sum; - alpha -= 2 * v; - - order.push_back(n); - if (!_heap->empty()) { - if (alpha < pmc) { - pmc = alpha; - sep = order.size(); - } - } - } - - if (static_cast(order.size()) < _node_num) { - _first_node = INVALID; - for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { - (*_cut_map)[n] = false; - } - for (int i = 0; i < static_cast(order.size()); ++i) { - typename Graph::Node n = order[i]; - while (n != INVALID) { - (*_cut_map)[n] = true; - n = (*_next_rep)[n]; - } - } - _min_cut = 0; - return true; - } - - if (pmc < _min_cut) { - for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { - (*_cut_map)[n] = false; - } - for (int i = 0; i < sep; ++i) { - typename Graph::Node n = order[i]; - while (n != INVALID) { - (*_cut_map)[n] = true; - n = (*_next_rep)[n]; - } - } - _min_cut = pmc; - } - - for (typename Graph::Node n = _first_node; - n != INVALID; n = (*_nodes)[n].next) { - bool merged = false; - for (int a = (*_nodes)[n].first_arc; a != -1; a = _arcs[a].next) { - if (!(_edges[a >> 1].cut < pmc)) { - if (!merged) { - for (int b = (*_nodes)[n].first_arc; b != -1; b = _arcs[b].next) { - (*_nodes)[_arcs[b].target].curr_arc = b; - } - merged = true; - } - typename Graph::Node m = _arcs[a].target; - int nb = 0; - for (int b = (*_nodes)[m].first_arc; b != -1; b = nb) { - nb = _arcs[b].next; - if ((b ^ a) == 1) continue; - typename Graph::Node o = _arcs[b].target; - int c = (*_nodes)[o].curr_arc; - if (c != -1 && _arcs[c ^ 1].target == n) { - _edges[c >> 1].capacity += _edges[b >> 1].capacity; - (*_nodes)[n].sum += _edges[b >> 1].capacity; - if (_edges[b >> 1].cut < _edges[c >> 1].cut) { - _edges[b >> 1].cut = _edges[c >> 1].cut; - } - if (_arcs[b ^ 1].prev != -1) { - _arcs[_arcs[b ^ 1].prev].next = _arcs[b ^ 1].next; - } else { - (*_nodes)[o].first_arc = _arcs[b ^ 1].next; - } - if (_arcs[b ^ 1].next != -1) { - _arcs[_arcs[b ^ 1].next].prev = _arcs[b ^ 1].prev; - } - } else { - if (_arcs[a].next != -1) { - _arcs[_arcs[a].next].prev = b; - } - _arcs[b].next = _arcs[a].next; - _arcs[b].prev = a; - _arcs[a].next = b; - _arcs[b ^ 1].target = n; - - (*_nodes)[n].sum += _edges[b >> 1].capacity; - (*_nodes)[o].curr_arc = b; - } - } - - if (_arcs[a].prev != -1) { - _arcs[_arcs[a].prev].next = _arcs[a].next; - } else { - (*_nodes)[n].first_arc = _arcs[a].next; - } - if (_arcs[a].next != -1) { - _arcs[_arcs[a].next].prev = _arcs[a].prev; - } - - (*_nodes)[n].sum -= _edges[a >> 1].capacity; - (*_next_rep)[(*_nodes)[n].last_rep] = m; - (*_nodes)[n].last_rep = (*_nodes)[m].last_rep; - - if ((*_nodes)[m].prev != INVALID) { - (*_nodes)[(*_nodes)[m].prev].next = (*_nodes)[m].next; - } else{ - _first_node = (*_nodes)[m].next; - } - if ((*_nodes)[m].next != INVALID) { - (*_nodes)[(*_nodes)[m].next].prev = (*_nodes)[m].prev; - } - --_node_num; - } - } - } - - if (_node_num == 1) { - _first_node = INVALID; - return true; - } - - return false; - } - - /// \brief Executes the algorithm. - /// - /// Executes the algorithm. - /// - /// \pre init() must be called - void start() { - while (!processNextPhase()) {} - } - - - /// \brief Runs %NagamochiIbaraki algorithm. - /// - /// This method runs the %Min cut algorithm - /// - /// \note mc.run(s) is just a shortcut of the following code. - ///\code - /// mc.init(); - /// mc.start(); - ///\endcode - void run() { - init(); - start(); - } - - ///@} - - /// \name Query Functions - /// - /// The result of the %NagamochiIbaraki - /// algorithm can be obtained using these functions.\n - /// Before the use of these functions, either run() or start() - /// must be called. - - ///@{ - - /// \brief Returns the min cut value. - /// - /// Returns the min cut value if the algorithm finished. - /// After the first processNextPhase() it is a value of a - /// valid cut in the graph. - Value minCutValue() const { - return _min_cut; - } - - /// \brief Returns a min cut in a NodeMap. - /// - /// It sets the nodes of one of the two partitions to true and - /// the other partition to false. - /// \param cutMap A \ref concepts::WriteMap "writable" node map with - /// \c bool (or convertible) value type. - template - Value minCutMap(CutMap& cutMap) const { - for (typename Graph::NodeIt n(_graph); n != INVALID; ++n) { - cutMap.set(n, (*_cut_map)[n]); - } - return minCutValue(); - } - - ///@} - - }; -} - -#endif diff --git a/deps/lemon/lemon/nauty_reader.h b/deps/lemon/lemon/nauty_reader.h deleted file mode 100644 index 896f2a606..000000000 --- a/deps/lemon/lemon/nauty_reader.h +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_NAUTY_READER_H -#define LEMON_NAUTY_READER_H - -#include -#include -#include - -/// \ingroup nauty_group -/// \file -/// \brief Nauty file reader. - -namespace lemon { - - /// \ingroup nauty_group - /// - /// \brief Nauty file reader - /// - /// The \e geng program is in the \e gtools suite of the nauty - /// package. This tool can generate all non-isomorphic undirected - /// graphs of several classes with given node number (e.g. - /// general, connected, biconnected, triangle-free, 4-cycle-free, - /// bipartite and graphs with given edge number and degree - /// constraints). This function reads a \e nauty \e graph6 \e format - /// line from the given stream and builds it in the given graph. - /// - /// The site of nauty package: http://cs.anu.edu.au/~bdm/nauty/ - /// - /// For example, the number of all non-isomorphic planar graphs - /// can be computed with the following code. - ///\code - /// int num = 0; - /// SmartGraph graph; - /// while (readNautyGraph(graph, std::cin)) { - /// PlanarityChecking pc(graph); - /// if (pc.run()) ++num; - /// } - /// std::cout << "Number of planar graphs: " << num << std::endl; - ///\endcode - /// - /// The nauty files are quite huge, therefore instead of the direct - /// file generation pipelining is recommended. For example, - ///\code - /// ./geng -c 10 | ./num_of_planar_graphs - ///\endcode - template - std::istream& readNautyGraph(Graph& graph, std::istream& is = std::cin) { - graph.clear(); - - std::string line; - if (getline(is, line)) { - int index = 0; - - int n; - - if (line[index] == '>') { - index += 10; - } - - char c = line[index++]; c -= 63; - if (c != 63) { - n = int(c); - } else { - c = line[index++]; c -= 63; - n = (int(c) << 12); - c = line[index++]; c -= 63; - n |= (int(c) << 6); - c = line[index++]; c -= 63; - n |= int(c); - } - - std::vector nodes; - for (int i = 0; i < n; ++i) { - nodes.push_back(graph.addNode()); - } - - int bit = -1; - for (int j = 0; j < n; ++j) { - for (int i = 0; i < j; ++i) { - if (bit == -1) { - c = line[index++]; c -= 63; - bit = 5; - } - bool b = (c & (1 << (bit--))) != 0; - - if (b) { - graph.addEdge(nodes[i], nodes[j]); - } - } - } - } - return is; - } -} - -#endif diff --git a/deps/lemon/lemon/nearest_neighbor_tsp.h b/deps/lemon/lemon/nearest_neighbor_tsp.h deleted file mode 100644 index 065e145df..000000000 --- a/deps/lemon/lemon/nearest_neighbor_tsp.h +++ /dev/null @@ -1,238 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_NEAREST_NEIGHBOUR_TSP_H -#define LEMON_NEAREST_NEIGHBOUR_TSP_H - -/// \ingroup tsp -/// \file -/// \brief Nearest neighbor algorithm for symmetric TSP - -#include -#include -#include -#include -#include - -namespace lemon { - - /// \ingroup tsp - /// - /// \brief Nearest neighbor algorithm for symmetric TSP. - /// - /// NearestNeighborTsp implements the nearest neighbor heuristic for solving - /// symmetric \ref tsp "TSP". - /// - /// This is probably the simplest TSP heuristic. - /// It starts with a minimum cost edge and at each step, it connects the - /// nearest unvisited node to the current path. - /// Finally, it connects the two end points of the path to form a tour. - /// - /// This method runs in O(n2) time. - /// It quickly finds a relatively short tour for most TSP instances, - /// but it could also yield a really bad (or even the worst) solution - /// in special cases. - /// - /// \tparam CM Type of the cost map. - template - class NearestNeighborTsp - { - public: - - /// Type of the cost map - typedef CM CostMap; - /// Type of the edge costs - typedef typename CM::Value Cost; - - private: - - GRAPH_TYPEDEFS(FullGraph); - - const FullGraph &_gr; - const CostMap &_cost; - Cost _sum; - std::vector _path; - - public: - - /// \brief Constructor - /// - /// Constructor. - /// \param gr The \ref FullGraph "full graph" the algorithm runs on. - /// \param cost The cost map. - NearestNeighborTsp(const FullGraph &gr, const CostMap &cost) - : _gr(gr), _cost(cost) {} - - /// \name Execution Control - /// @{ - - /// \brief Runs the algorithm. - /// - /// This function runs the algorithm. - /// - /// \return The total cost of the found tour. - Cost run() { - _path.clear(); - if (_gr.nodeNum() == 0) { - return _sum = 0; - } - else if (_gr.nodeNum() == 1) { - _path.push_back(_gr(0)); - return _sum = 0; - } - - std::deque path_dq; - Edge min_edge1 = INVALID, - min_edge2 = INVALID; - - min_edge1 = mapMin(_gr, _cost); - Node n1 = _gr.u(min_edge1), - n2 = _gr.v(min_edge1); - path_dq.push_back(n1); - path_dq.push_back(n2); - - FullGraph::NodeMap used(_gr, false); - used[n1] = true; - used[n2] = true; - - min_edge1 = INVALID; - while (int(path_dq.size()) != _gr.nodeNum()) { - if (min_edge1 == INVALID) { - for (IncEdgeIt e(_gr, n1); e != INVALID; ++e) { - if (!used[_gr.runningNode(e)] && - (min_edge1 == INVALID || _cost[e] < _cost[min_edge1])) { - min_edge1 = e; - } - } - } - - if (min_edge2 == INVALID) { - for (IncEdgeIt e(_gr, n2); e != INVALID; ++e) { - if (!used[_gr.runningNode(e)] && - (min_edge2 == INVALID||_cost[e] < _cost[min_edge2])) { - min_edge2 = e; - } - } - } - - if (_cost[min_edge1] < _cost[min_edge2]) { - n1 = _gr.oppositeNode(n1, min_edge1); - path_dq.push_front(n1); - - used[n1] = true; - min_edge1 = INVALID; - - if (_gr.u(min_edge2) == n1 || _gr.v(min_edge2) == n1) - min_edge2 = INVALID; - } else { - n2 = _gr.oppositeNode(n2, min_edge2); - path_dq.push_back(n2); - - used[n2] = true; - min_edge2 = INVALID; - - if (_gr.u(min_edge1) == n2 || _gr.v(min_edge1) == n2) - min_edge1 = INVALID; - } - } - - n1 = path_dq.back(); - n2 = path_dq.front(); - _path.push_back(n2); - _sum = _cost[_gr.edge(n1, n2)]; - for (int i = 1; i < int(path_dq.size()); ++i) { - n1 = n2; - n2 = path_dq[i]; - _path.push_back(n2); - _sum += _cost[_gr.edge(n1, n2)]; - } - - return _sum; - } - - /// @} - - /// \name Query Functions - /// @{ - - /// \brief The total cost of the found tour. - /// - /// This function returns the total cost of the found tour. - /// - /// \pre run() must be called before using this function. - Cost tourCost() const { - return _sum; - } - - /// \brief Returns a const reference to the node sequence of the - /// found tour. - /// - /// This function returns a const reference to a vector - /// that stores the node sequence of the found tour. - /// - /// \pre run() must be called before using this function. - const std::vector& tourNodes() const { - return _path; - } - - /// \brief Gives back the node sequence of the found tour. - /// - /// This function copies the node sequence of the found tour into - /// an STL container through the given output iterator. The - /// value_type of the container must be FullGraph::Node. - /// For example, - /// \code - /// std::vector nodes(countNodes(graph)); - /// tsp.tourNodes(nodes.begin()); - /// \endcode - /// or - /// \code - /// std::list nodes; - /// tsp.tourNodes(std::back_inserter(nodes)); - /// \endcode - /// - /// \pre run() must be called before using this function. - template - void tourNodes(Iterator out) const { - std::copy(_path.begin(), _path.end(), out); - } - - /// \brief Gives back the found tour as a path. - /// - /// This function copies the found tour as a list of arcs/edges into - /// the given \ref lemon::concepts::Path "path structure". - /// - /// \pre run() must be called before using this function. - template - void tour(Path &path) const { - path.clear(); - for (int i = 0; i < int(_path.size()) - 1; ++i) { - path.addBack(_gr.arc(_path[i], _path[i+1])); - } - if (int(_path.size()) >= 2) { - path.addBack(_gr.arc(_path.back(), _path.front())); - } - } - - /// @} - - }; - -}; // namespace lemon - -#endif diff --git a/deps/lemon/lemon/network_simplex.h b/deps/lemon/lemon/network_simplex.h deleted file mode 100644 index 6ccad33e6..000000000 --- a/deps/lemon/lemon/network_simplex.h +++ /dev/null @@ -1,1659 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_NETWORK_SIMPLEX_H -#define LEMON_NETWORK_SIMPLEX_H - -/// \ingroup min_cost_flow_algs -/// -/// \file -/// \brief Network Simplex algorithm for finding a minimum cost flow. - -#include -#include -#include - -#include -#include - -namespace lemon { - - /// \addtogroup min_cost_flow_algs - /// @{ - - /// \brief Implementation of the primal Network Simplex algorithm - /// for finding a \ref min_cost_flow "minimum cost flow". - /// - /// \ref NetworkSimplex implements the primal Network Simplex algorithm - /// for finding a \ref min_cost_flow "minimum cost flow" - /// \cite amo93networkflows, \cite dantzig63linearprog, - /// \cite kellyoneill91netsimplex. - /// This algorithm is a highly efficient specialized version of the - /// linear programming simplex method directly for the minimum cost - /// flow problem. - /// - /// In general, \ref NetworkSimplex and \ref CostScaling are the fastest - /// implementations available in LEMON for solving this problem. - /// (For more information, see \ref min_cost_flow_algs "the module page".) - /// Furthermore, this class supports both directions of the supply/demand - /// inequality constraints. For more information, see \ref SupplyType. - /// - /// Most of the parameters of the problem (except for the digraph) - /// can be given using separate functions, and the algorithm can be - /// executed using the \ref run() function. If some parameters are not - /// specified, then default values will be used. - /// - /// \tparam GR The digraph type the algorithm runs on. - /// \tparam V The number type used for flow amounts, capacity bounds - /// and supply values in the algorithm. By default, it is \c int. - /// \tparam C The number type used for costs and potentials in the - /// algorithm. By default, it is the same as \c V. - /// - /// \warning Both \c V and \c C must be signed number types. - /// \warning All input data (capacities, supply values, and costs) must - /// be integer. - /// - /// \note %NetworkSimplex provides five different pivot rule - /// implementations, from which the most efficient one is used - /// by default. For more information, see \ref PivotRule. - template - class NetworkSimplex - { - public: - - /// The type of the flow amounts, capacity bounds and supply values - typedef V Value; - /// The type of the arc costs - typedef C Cost; - - public: - - /// \brief Problem type constants for the \c run() function. - /// - /// Enum type containing the problem type constants that can be - /// returned by the \ref run() function of the algorithm. - enum ProblemType { - /// The problem has no feasible solution (flow). - INFEASIBLE, - /// The problem has optimal solution (i.e. it is feasible and - /// bounded), and the algorithm has found optimal flow and node - /// potentials (primal and dual solutions). - OPTIMAL, - /// The objective function of the problem is unbounded, i.e. - /// there is a directed cycle having negative total cost and - /// infinite upper bound. - UNBOUNDED - }; - - /// \brief Constants for selecting the type of the supply constraints. - /// - /// Enum type containing constants for selecting the supply type, - /// i.e. the direction of the inequalities in the supply/demand - /// constraints of the \ref min_cost_flow "minimum cost flow problem". - /// - /// The default supply type is \c GEQ, the \c LEQ type can be - /// selected using \ref supplyType(). - /// The equality form is a special case of both supply types. - enum SupplyType { - /// This option means that there are "greater or equal" - /// supply/demand constraints in the definition of the problem. - GEQ, - /// This option means that there are "less or equal" - /// supply/demand constraints in the definition of the problem. - LEQ - }; - - /// \brief Constants for selecting the pivot rule. - /// - /// Enum type containing constants for selecting the pivot rule for - /// the \ref run() function. - /// - /// \ref NetworkSimplex provides five different implementations for - /// the pivot strategy that significantly affects the running time - /// of the algorithm. - /// According to experimental tests conducted on various problem - /// instances, \ref BLOCK_SEARCH "Block Search" and - /// \ref ALTERING_LIST "Altering Candidate List" rules turned out - /// to be the most efficient. - /// Since \ref BLOCK_SEARCH "Block Search" is a simpler strategy that - /// seemed to be slightly more robust, it is used by default. - /// However, another pivot rule can easily be selected using the - /// \ref run() function with the proper parameter. - enum PivotRule { - - /// The \e First \e Eligible pivot rule. - /// The next eligible arc is selected in a wraparound fashion - /// in every iteration. - FIRST_ELIGIBLE, - - /// The \e Best \e Eligible pivot rule. - /// The best eligible arc is selected in every iteration. - BEST_ELIGIBLE, - - /// The \e Block \e Search pivot rule. - /// A specified number of arcs are examined in every iteration - /// in a wraparound fashion and the best eligible arc is selected - /// from this block. - BLOCK_SEARCH, - - /// The \e Candidate \e List pivot rule. - /// In a major iteration a candidate list is built from eligible arcs - /// in a wraparound fashion and in the following minor iterations - /// the best eligible arc is selected from this list. - CANDIDATE_LIST, - - /// The \e Altering \e Candidate \e List pivot rule. - /// It is a modified version of the Candidate List method. - /// It keeps only a few of the best eligible arcs from the former - /// candidate list and extends this list in every iteration. - ALTERING_LIST - }; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(GR); - - typedef std::vector IntVector; - typedef std::vector ValueVector; - typedef std::vector CostVector; - typedef std::vector CharVector; - // Note: vector is used instead of vector and - // vector for efficiency reasons - - // State constants for arcs - enum ArcState { - STATE_UPPER = -1, - STATE_TREE = 0, - STATE_LOWER = 1 - }; - - // Direction constants for tree arcs - enum ArcDirection { - DIR_DOWN = -1, - DIR_UP = 1 - }; - - private: - - // Data related to the underlying digraph - const GR &_graph; - int _node_num; - int _arc_num; - int _all_arc_num; - int _search_arc_num; - - // Parameters of the problem - bool _has_lower; - SupplyType _stype; - Value _sum_supply; - - // Data structures for storing the digraph - IntNodeMap _node_id; - IntArcMap _arc_id; - IntVector _source; - IntVector _target; - bool _arc_mixing; - - // Node and arc data - ValueVector _lower; - ValueVector _upper; - ValueVector _cap; - CostVector _cost; - ValueVector _supply; - ValueVector _flow; - CostVector _pi; - - // Data for storing the spanning tree structure - IntVector _parent; - IntVector _pred; - IntVector _thread; - IntVector _rev_thread; - IntVector _succ_num; - IntVector _last_succ; - CharVector _pred_dir; - CharVector _state; - IntVector _dirty_revs; - int _root; - - // Temporary data used in the current pivot iteration - int in_arc, join, u_in, v_in, u_out, v_out; - Value delta; - - const Value MAX; - - public: - - /// \brief Constant for infinite upper bounds (capacities). - /// - /// Constant for infinite upper bounds (capacities). - /// It is \c std::numeric_limits::infinity() if available, - /// \c std::numeric_limits::max() otherwise. - const Value INF; - - private: - - // Implementation of the First Eligible pivot rule - class FirstEligiblePivotRule - { - private: - - // References to the NetworkSimplex class - const IntVector &_source; - const IntVector &_target; - const CostVector &_cost; - const CharVector &_state; - const CostVector &_pi; - int &_in_arc; - int _search_arc_num; - - // Pivot rule data - int _next_arc; - - public: - - // Constructor - FirstEligiblePivotRule(NetworkSimplex &ns) : - _source(ns._source), _target(ns._target), - _cost(ns._cost), _state(ns._state), _pi(ns._pi), - _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num), - _next_arc(0) - {} - - // Find next entering arc - bool findEnteringArc() { - Cost c; - for (int e = _next_arc; e != _search_arc_num; ++e) { - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < 0) { - _in_arc = e; - _next_arc = e + 1; - return true; - } - } - for (int e = 0; e != _next_arc; ++e) { - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < 0) { - _in_arc = e; - _next_arc = e + 1; - return true; - } - } - return false; - } - - }; //class FirstEligiblePivotRule - - - // Implementation of the Best Eligible pivot rule - class BestEligiblePivotRule - { - private: - - // References to the NetworkSimplex class - const IntVector &_source; - const IntVector &_target; - const CostVector &_cost; - const CharVector &_state; - const CostVector &_pi; - int &_in_arc; - int _search_arc_num; - - public: - - // Constructor - BestEligiblePivotRule(NetworkSimplex &ns) : - _source(ns._source), _target(ns._target), - _cost(ns._cost), _state(ns._state), _pi(ns._pi), - _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num) - {} - - // Find next entering arc - bool findEnteringArc() { - Cost c, min = 0; - for (int e = 0; e != _search_arc_num; ++e) { - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < min) { - min = c; - _in_arc = e; - } - } - return min < 0; - } - - }; //class BestEligiblePivotRule - - - // Implementation of the Block Search pivot rule - class BlockSearchPivotRule - { - private: - - // References to the NetworkSimplex class - const IntVector &_source; - const IntVector &_target; - const CostVector &_cost; - const CharVector &_state; - const CostVector &_pi; - int &_in_arc; - int _search_arc_num; - - // Pivot rule data - int _block_size; - int _next_arc; - - public: - - // Constructor - BlockSearchPivotRule(NetworkSimplex &ns) : - _source(ns._source), _target(ns._target), - _cost(ns._cost), _state(ns._state), _pi(ns._pi), - _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num), - _next_arc(0) - { - // The main parameters of the pivot rule - const double BLOCK_SIZE_FACTOR = 1.0; - const int MIN_BLOCK_SIZE = 10; - - _block_size = std::max( int(BLOCK_SIZE_FACTOR * - std::sqrt(double(_search_arc_num))), - MIN_BLOCK_SIZE ); - } - - // Find next entering arc - bool findEnteringArc() { - Cost c, min = 0; - int cnt = _block_size; - int e; - for (e = _next_arc; e != _search_arc_num; ++e) { - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < min) { - min = c; - _in_arc = e; - } - if (--cnt == 0) { - if (min < 0) goto search_end; - cnt = _block_size; - } - } - for (e = 0; e != _next_arc; ++e) { - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < min) { - min = c; - _in_arc = e; - } - if (--cnt == 0) { - if (min < 0) goto search_end; - cnt = _block_size; - } - } - if (min >= 0) return false; - - search_end: - _next_arc = e; - return true; - } - - }; //class BlockSearchPivotRule - - - // Implementation of the Candidate List pivot rule - class CandidateListPivotRule - { - private: - - // References to the NetworkSimplex class - const IntVector &_source; - const IntVector &_target; - const CostVector &_cost; - const CharVector &_state; - const CostVector &_pi; - int &_in_arc; - int _search_arc_num; - - // Pivot rule data - IntVector _candidates; - int _list_length, _minor_limit; - int _curr_length, _minor_count; - int _next_arc; - - public: - - /// Constructor - CandidateListPivotRule(NetworkSimplex &ns) : - _source(ns._source), _target(ns._target), - _cost(ns._cost), _state(ns._state), _pi(ns._pi), - _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num), - _next_arc(0) - { - // The main parameters of the pivot rule - const double LIST_LENGTH_FACTOR = 0.25; - const int MIN_LIST_LENGTH = 10; - const double MINOR_LIMIT_FACTOR = 0.1; - const int MIN_MINOR_LIMIT = 3; - - _list_length = std::max( int(LIST_LENGTH_FACTOR * - std::sqrt(double(_search_arc_num))), - MIN_LIST_LENGTH ); - _minor_limit = std::max( int(MINOR_LIMIT_FACTOR * _list_length), - MIN_MINOR_LIMIT ); - _curr_length = _minor_count = 0; - _candidates.resize(_list_length); - } - - /// Find next entering arc - bool findEnteringArc() { - Cost min, c; - int e; - if (_curr_length > 0 && _minor_count < _minor_limit) { - // Minor iteration: select the best eligible arc from the - // current candidate list - ++_minor_count; - min = 0; - for (int i = 0; i < _curr_length; ++i) { - e = _candidates[i]; - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < min) { - min = c; - _in_arc = e; - } - else if (c >= 0) { - _candidates[i--] = _candidates[--_curr_length]; - } - } - if (min < 0) return true; - } - - // Major iteration: build a new candidate list - min = 0; - _curr_length = 0; - for (e = _next_arc; e != _search_arc_num; ++e) { - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < 0) { - _candidates[_curr_length++] = e; - if (c < min) { - min = c; - _in_arc = e; - } - if (_curr_length == _list_length) goto search_end; - } - } - for (e = 0; e != _next_arc; ++e) { - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < 0) { - _candidates[_curr_length++] = e; - if (c < min) { - min = c; - _in_arc = e; - } - if (_curr_length == _list_length) goto search_end; - } - } - if (_curr_length == 0) return false; - - search_end: - _minor_count = 1; - _next_arc = e; - return true; - } - - }; //class CandidateListPivotRule - - - // Implementation of the Altering Candidate List pivot rule - class AlteringListPivotRule - { - private: - - // References to the NetworkSimplex class - const IntVector &_source; - const IntVector &_target; - const CostVector &_cost; - const CharVector &_state; - const CostVector &_pi; - int &_in_arc; - int _search_arc_num; - - // Pivot rule data - int _block_size, _head_length, _curr_length; - int _next_arc; - IntVector _candidates; - CostVector _cand_cost; - - // Functor class to compare arcs during sort of the candidate list - class SortFunc - { - private: - const CostVector &_map; - public: - SortFunc(const CostVector &map) : _map(map) {} - bool operator()(int left, int right) { - return _map[left] < _map[right]; - } - }; - - SortFunc _sort_func; - - public: - - // Constructor - AlteringListPivotRule(NetworkSimplex &ns) : - _source(ns._source), _target(ns._target), - _cost(ns._cost), _state(ns._state), _pi(ns._pi), - _in_arc(ns.in_arc), _search_arc_num(ns._search_arc_num), - _next_arc(0), _cand_cost(ns._search_arc_num), _sort_func(_cand_cost) - { - // The main parameters of the pivot rule - const double BLOCK_SIZE_FACTOR = 1.0; - const int MIN_BLOCK_SIZE = 10; - const double HEAD_LENGTH_FACTOR = 0.01; - const int MIN_HEAD_LENGTH = 3; - - _block_size = std::max( int(BLOCK_SIZE_FACTOR * - std::sqrt(double(_search_arc_num))), - MIN_BLOCK_SIZE ); - _head_length = std::max( int(HEAD_LENGTH_FACTOR * _block_size), - MIN_HEAD_LENGTH ); - _candidates.resize(_head_length + _block_size); - _curr_length = 0; - } - - // Find next entering arc - bool findEnteringArc() { - // Check the current candidate list - int e; - Cost c; - for (int i = 0; i != _curr_length; ++i) { - e = _candidates[i]; - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < 0) { - _cand_cost[e] = c; - } else { - _candidates[i--] = _candidates[--_curr_length]; - } - } - - // Extend the list - int cnt = _block_size; - int limit = _head_length; - - for (e = _next_arc; e != _search_arc_num; ++e) { - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < 0) { - _cand_cost[e] = c; - _candidates[_curr_length++] = e; - } - if (--cnt == 0) { - if (_curr_length > limit) goto search_end; - limit = 0; - cnt = _block_size; - } - } - for (e = 0; e != _next_arc; ++e) { - c = _state[e] * (_cost[e] + _pi[_source[e]] - _pi[_target[e]]); - if (c < 0) { - _cand_cost[e] = c; - _candidates[_curr_length++] = e; - } - if (--cnt == 0) { - if (_curr_length > limit) goto search_end; - limit = 0; - cnt = _block_size; - } - } - if (_curr_length == 0) return false; - - search_end: - - // Perform partial sort operation on the candidate list - int new_length = std::min(_head_length + 1, _curr_length); - std::partial_sort(_candidates.begin(), _candidates.begin() + new_length, - _candidates.begin() + _curr_length, _sort_func); - - // Select the entering arc and remove it from the list - _in_arc = _candidates[0]; - _next_arc = e; - _candidates[0] = _candidates[new_length - 1]; - _curr_length = new_length - 1; - return true; - } - - }; //class AlteringListPivotRule - - public: - - /// \brief Constructor. - /// - /// The constructor of the class. - /// - /// \param graph The digraph the algorithm runs on. - /// \param arc_mixing Indicate if the arcs will be stored in a - /// mixed order in the internal data structure. - /// In general, it leads to similar performance as using the original - /// arc order, but it makes the algorithm more robust and in special - /// cases, even significantly faster. Therefore, it is enabled by default. - NetworkSimplex(const GR& graph, bool arc_mixing = true) : - _graph(graph), _node_id(graph), _arc_id(graph), - _arc_mixing(arc_mixing), - MAX(std::numeric_limits::max()), - INF(std::numeric_limits::has_infinity ? - std::numeric_limits::infinity() : MAX) - { - // Check the number types - LEMON_ASSERT(std::numeric_limits::is_signed, - "The flow type of NetworkSimplex must be signed"); - LEMON_ASSERT(std::numeric_limits::is_signed, - "The cost type of NetworkSimplex must be signed"); - - // Reset data structures - reset(); - } - - /// \name Parameters - /// The parameters of the algorithm can be specified using these - /// functions. - - /// @{ - - /// \brief Set the lower bounds on the arcs. - /// - /// This function sets the lower bounds on the arcs. - /// If it is not used before calling \ref run(), the lower bounds - /// will be set to zero on all arcs. - /// - /// \param map An arc map storing the lower bounds. - /// Its \c Value type must be convertible to the \c Value type - /// of the algorithm. - /// - /// \return (*this) - template - NetworkSimplex& lowerMap(const LowerMap& map) { - _has_lower = true; - for (ArcIt a(_graph); a != INVALID; ++a) { - _lower[_arc_id[a]] = map[a]; - } - return *this; - } - - /// \brief Set the upper bounds (capacities) on the arcs. - /// - /// This function sets the upper bounds (capacities) on the arcs. - /// If it is not used before calling \ref run(), the upper bounds - /// will be set to \ref INF on all arcs (i.e. the flow value will be - /// unbounded from above). - /// - /// \param map An arc map storing the upper bounds. - /// Its \c Value type must be convertible to the \c Value type - /// of the algorithm. - /// - /// \return (*this) - template - NetworkSimplex& upperMap(const UpperMap& map) { - for (ArcIt a(_graph); a != INVALID; ++a) { - _upper[_arc_id[a]] = map[a]; - } - return *this; - } - - /// \brief Set the costs of the arcs. - /// - /// This function sets the costs of the arcs. - /// If it is not used before calling \ref run(), the costs - /// will be set to \c 1 on all arcs. - /// - /// \param map An arc map storing the costs. - /// Its \c Value type must be convertible to the \c Cost type - /// of the algorithm. - /// - /// \return (*this) - template - NetworkSimplex& costMap(const CostMap& map) { - for (ArcIt a(_graph); a != INVALID; ++a) { - _cost[_arc_id[a]] = map[a]; - } - return *this; - } - - /// \brief Set the supply values of the nodes. - /// - /// This function sets the supply values of the nodes. - /// If neither this function nor \ref stSupply() is used before - /// calling \ref run(), the supply of each node will be set to zero. - /// - /// \param map A node map storing the supply values. - /// Its \c Value type must be convertible to the \c Value type - /// of the algorithm. - /// - /// \return (*this) - /// - /// \sa supplyType() - template - NetworkSimplex& supplyMap(const SupplyMap& map) { - for (NodeIt n(_graph); n != INVALID; ++n) { - _supply[_node_id[n]] = map[n]; - } - return *this; - } - - /// \brief Set single source and target nodes and a supply value. - /// - /// This function sets a single source node and a single target node - /// and the required flow value. - /// If neither this function nor \ref supplyMap() is used before - /// calling \ref run(), the supply of each node will be set to zero. - /// - /// Using this function has the same effect as using \ref supplyMap() - /// with a map in which \c k is assigned to \c s, \c -k is - /// assigned to \c t and all other nodes have zero supply value. - /// - /// \param s The source node. - /// \param t The target node. - /// \param k The required amount of flow from node \c s to node \c t - /// (i.e. the supply of \c s and the demand of \c t). - /// - /// \return (*this) - NetworkSimplex& stSupply(const Node& s, const Node& t, Value k) { - for (int i = 0; i != _node_num; ++i) { - _supply[i] = 0; - } - _supply[_node_id[s]] = k; - _supply[_node_id[t]] = -k; - return *this; - } - - /// \brief Set the type of the supply constraints. - /// - /// This function sets the type of the supply/demand constraints. - /// If it is not used before calling \ref run(), the \ref GEQ supply - /// type will be used. - /// - /// For more information, see \ref SupplyType. - /// - /// \return (*this) - NetworkSimplex& supplyType(SupplyType supply_type) { - _stype = supply_type; - return *this; - } - - /// @} - - /// \name Execution Control - /// The algorithm can be executed using \ref run(). - - /// @{ - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. - /// The paramters can be specified using functions \ref lowerMap(), - /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(), - /// \ref supplyType(). - /// For example, - /// \code - /// NetworkSimplex ns(graph); - /// ns.lowerMap(lower).upperMap(upper).costMap(cost) - /// .supplyMap(sup).run(); - /// \endcode - /// - /// This function can be called more than once. All the given parameters - /// are kept for the next call, unless \ref resetParams() or \ref reset() - /// is used, thus only the modified parameters have to be set again. - /// If the underlying digraph was also modified after the construction - /// of the class (or the last \ref reset() call), then the \ref reset() - /// function must be called. - /// - /// \param pivot_rule The pivot rule that will be used during the - /// algorithm. For more information, see \ref PivotRule. - /// - /// \return \c INFEASIBLE if no feasible flow exists, - /// \n \c OPTIMAL if the problem has optimal solution - /// (i.e. it is feasible and bounded), and the algorithm has found - /// optimal flow and node potentials (primal and dual solutions), - /// \n \c UNBOUNDED if the objective function of the problem is - /// unbounded, i.e. there is a directed cycle having negative total - /// cost and infinite upper bound. - /// - /// \see ProblemType, PivotRule - /// \see resetParams(), reset() - ProblemType run(PivotRule pivot_rule = BLOCK_SEARCH) { - if (!init()) return INFEASIBLE; - return start(pivot_rule); - } - - /// \brief Reset all the parameters that have been given before. - /// - /// This function resets all the paramaters that have been given - /// before using functions \ref lowerMap(), \ref upperMap(), - /// \ref costMap(), \ref supplyMap(), \ref stSupply(), \ref supplyType(). - /// - /// It is useful for multiple \ref run() calls. Basically, all the given - /// parameters are kept for the next \ref run() call, unless - /// \ref resetParams() or \ref reset() is used. - /// If the underlying digraph was also modified after the construction - /// of the class or the last \ref reset() call, then the \ref reset() - /// function must be used, otherwise \ref resetParams() is sufficient. - /// - /// For example, - /// \code - /// NetworkSimplex ns(graph); - /// - /// // First run - /// ns.lowerMap(lower).upperMap(upper).costMap(cost) - /// .supplyMap(sup).run(); - /// - /// // Run again with modified cost map (resetParams() is not called, - /// // so only the cost map have to be set again) - /// cost[e] += 100; - /// ns.costMap(cost).run(); - /// - /// // Run again from scratch using resetParams() - /// // (the lower bounds will be set to zero on all arcs) - /// ns.resetParams(); - /// ns.upperMap(capacity).costMap(cost) - /// .supplyMap(sup).run(); - /// \endcode - /// - /// \return (*this) - /// - /// \see reset(), run() - NetworkSimplex& resetParams() { - for (int i = 0; i != _node_num; ++i) { - _supply[i] = 0; - } - for (int i = 0; i != _arc_num; ++i) { - _lower[i] = 0; - _upper[i] = INF; - _cost[i] = 1; - } - _has_lower = false; - _stype = GEQ; - return *this; - } - - /// \brief Reset the internal data structures and all the parameters - /// that have been given before. - /// - /// This function resets the internal data structures and all the - /// paramaters that have been given before using functions \ref lowerMap(), - /// \ref upperMap(), \ref costMap(), \ref supplyMap(), \ref stSupply(), - /// \ref supplyType(). - /// - /// It is useful for multiple \ref run() calls. Basically, all the given - /// parameters are kept for the next \ref run() call, unless - /// \ref resetParams() or \ref reset() is used. - /// If the underlying digraph was also modified after the construction - /// of the class or the last \ref reset() call, then the \ref reset() - /// function must be used, otherwise \ref resetParams() is sufficient. - /// - /// See \ref resetParams() for examples. - /// - /// \return (*this) - /// - /// \see resetParams(), run() - NetworkSimplex& reset() { - // Resize vectors - _node_num = countNodes(_graph); - _arc_num = countArcs(_graph); - int all_node_num = _node_num + 1; - int max_arc_num = _arc_num + 2 * _node_num; - - _source.resize(max_arc_num); - _target.resize(max_arc_num); - - _lower.resize(_arc_num); - _upper.resize(_arc_num); - _cap.resize(max_arc_num); - _cost.resize(max_arc_num); - _supply.resize(all_node_num); - _flow.resize(max_arc_num); - _pi.resize(all_node_num); - - _parent.resize(all_node_num); - _pred.resize(all_node_num); - _pred_dir.resize(all_node_num); - _thread.resize(all_node_num); - _rev_thread.resize(all_node_num); - _succ_num.resize(all_node_num); - _last_succ.resize(all_node_num); - _state.resize(max_arc_num); - - // Copy the graph - int i = 0; - for (NodeIt n(_graph); n != INVALID; ++n, ++i) { - _node_id[n] = i; - } - if (_arc_mixing && _node_num > 1) { - // Store the arcs in a mixed order - const int skip = std::max(_arc_num / _node_num, 3); - int i = 0, j = 0; - for (ArcIt a(_graph); a != INVALID; ++a) { - _arc_id[a] = i; - _source[i] = _node_id[_graph.source(a)]; - _target[i] = _node_id[_graph.target(a)]; - if ((i += skip) >= _arc_num) i = ++j; - } - } else { - // Store the arcs in the original order - int i = 0; - for (ArcIt a(_graph); a != INVALID; ++a, ++i) { - _arc_id[a] = i; - _source[i] = _node_id[_graph.source(a)]; - _target[i] = _node_id[_graph.target(a)]; - } - } - - // Reset parameters - resetParams(); - return *this; - } - - /// @} - - /// \name Query Functions - /// The results of the algorithm can be obtained using these - /// functions.\n - /// The \ref run() function must be called before using them. - - /// @{ - - /// \brief Return the total cost of the found flow. - /// - /// This function returns the total cost of the found flow. - /// Its complexity is O(m). - /// - /// \note The return type of the function can be specified as a - /// template parameter. For example, - /// \code - /// ns.totalCost(); - /// \endcode - /// It is useful if the total cost cannot be stored in the \c Cost - /// type of the algorithm, which is the default return type of the - /// function. - /// - /// \pre \ref run() must be called before using this function. - template - Number totalCost() const { - Number c = 0; - for (ArcIt a(_graph); a != INVALID; ++a) { - int i = _arc_id[a]; - c += Number(_flow[i]) * Number(_cost[i]); - } - return c; - } - -#ifndef DOXYGEN - Cost totalCost() const { - return totalCost(); - } -#endif - - /// \brief Return the flow on the given arc. - /// - /// This function returns the flow on the given arc. - /// - /// \pre \ref run() must be called before using this function. - Value flow(const Arc& a) const { - return _flow[_arc_id[a]]; - } - - /// \brief Copy the flow values (the primal solution) into the - /// given map. - /// - /// This function copies the flow value on each arc into the given - /// map. The \c Value type of the algorithm must be convertible to - /// the \c Value type of the map. - /// - /// \pre \ref run() must be called before using this function. - template - void flowMap(FlowMap &map) const { - for (ArcIt a(_graph); a != INVALID; ++a) { - map.set(a, _flow[_arc_id[a]]); - } - } - - /// \brief Return the potential (dual value) of the given node. - /// - /// This function returns the potential (dual value) of the - /// given node. - /// - /// \pre \ref run() must be called before using this function. - Cost potential(const Node& n) const { - return _pi[_node_id[n]]; - } - - /// \brief Copy the potential values (the dual solution) into the - /// given map. - /// - /// This function copies the potential (dual value) of each node - /// into the given map. - /// The \c Cost type of the algorithm must be convertible to the - /// \c Value type of the map. - /// - /// \pre \ref run() must be called before using this function. - template - void potentialMap(PotentialMap &map) const { - for (NodeIt n(_graph); n != INVALID; ++n) { - map.set(n, _pi[_node_id[n]]); - } - } - - /// @} - - private: - - // Initialize internal data structures - bool init() { - if (_node_num == 0) return false; - - // Check the sum of supply values - _sum_supply = 0; - for (int i = 0; i != _node_num; ++i) { - _sum_supply += _supply[i]; - } - if ( !((_stype == GEQ && _sum_supply <= 0) || - (_stype == LEQ && _sum_supply >= 0)) ) return false; - - // Check lower and upper bounds - LEMON_DEBUG(checkBoundMaps(), - "Upper bounds must be greater or equal to the lower bounds"); - - // Remove non-zero lower bounds - if (_has_lower) { - for (int i = 0; i != _arc_num; ++i) { - Value c = _lower[i]; - if (c >= 0) { - _cap[i] = _upper[i] < MAX ? _upper[i] - c : INF; - } else { - _cap[i] = _upper[i] < MAX + c ? _upper[i] - c : INF; - } - _supply[_source[i]] -= c; - _supply[_target[i]] += c; - } - } else { - for (int i = 0; i != _arc_num; ++i) { - _cap[i] = _upper[i]; - } - } - - // Initialize artifical cost - Cost ART_COST; - if (std::numeric_limits::is_exact) { - ART_COST = std::numeric_limits::max() / 2 + 1; - } else { - ART_COST = 0; - for (int i = 0; i != _arc_num; ++i) { - if (_cost[i] > ART_COST) ART_COST = _cost[i]; - } - ART_COST = (ART_COST + 1) * _node_num; - } - - // Initialize arc maps - for (int i = 0; i != _arc_num; ++i) { - _flow[i] = 0; - _state[i] = STATE_LOWER; - } - - // Set data for the artificial root node - _root = _node_num; - _parent[_root] = -1; - _pred[_root] = -1; - _thread[_root] = 0; - _rev_thread[0] = _root; - _succ_num[_root] = _node_num + 1; - _last_succ[_root] = _root - 1; - _supply[_root] = -_sum_supply; - _pi[_root] = 0; - - // Add artificial arcs and initialize the spanning tree data structure - if (_sum_supply == 0) { - // EQ supply constraints - _search_arc_num = _arc_num; - _all_arc_num = _arc_num + _node_num; - for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) { - _parent[u] = _root; - _pred[u] = e; - _thread[u] = u + 1; - _rev_thread[u + 1] = u; - _succ_num[u] = 1; - _last_succ[u] = u; - _cap[e] = INF; - _state[e] = STATE_TREE; - if (_supply[u] >= 0) { - _pred_dir[u] = DIR_UP; - _pi[u] = 0; - _source[e] = u; - _target[e] = _root; - _flow[e] = _supply[u]; - _cost[e] = 0; - } else { - _pred_dir[u] = DIR_DOWN; - _pi[u] = ART_COST; - _source[e] = _root; - _target[e] = u; - _flow[e] = -_supply[u]; - _cost[e] = ART_COST; - } - } - } - else if (_sum_supply > 0) { - // LEQ supply constraints - _search_arc_num = _arc_num + _node_num; - int f = _arc_num + _node_num; - for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) { - _parent[u] = _root; - _thread[u] = u + 1; - _rev_thread[u + 1] = u; - _succ_num[u] = 1; - _last_succ[u] = u; - if (_supply[u] >= 0) { - _pred_dir[u] = DIR_UP; - _pi[u] = 0; - _pred[u] = e; - _source[e] = u; - _target[e] = _root; - _cap[e] = INF; - _flow[e] = _supply[u]; - _cost[e] = 0; - _state[e] = STATE_TREE; - } else { - _pred_dir[u] = DIR_DOWN; - _pi[u] = ART_COST; - _pred[u] = f; - _source[f] = _root; - _target[f] = u; - _cap[f] = INF; - _flow[f] = -_supply[u]; - _cost[f] = ART_COST; - _state[f] = STATE_TREE; - _source[e] = u; - _target[e] = _root; - _cap[e] = INF; - _flow[e] = 0; - _cost[e] = 0; - _state[e] = STATE_LOWER; - ++f; - } - } - _all_arc_num = f; - } - else { - // GEQ supply constraints - _search_arc_num = _arc_num + _node_num; - int f = _arc_num + _node_num; - for (int u = 0, e = _arc_num; u != _node_num; ++u, ++e) { - _parent[u] = _root; - _thread[u] = u + 1; - _rev_thread[u + 1] = u; - _succ_num[u] = 1; - _last_succ[u] = u; - if (_supply[u] <= 0) { - _pred_dir[u] = DIR_DOWN; - _pi[u] = 0; - _pred[u] = e; - _source[e] = _root; - _target[e] = u; - _cap[e] = INF; - _flow[e] = -_supply[u]; - _cost[e] = 0; - _state[e] = STATE_TREE; - } else { - _pred_dir[u] = DIR_UP; - _pi[u] = -ART_COST; - _pred[u] = f; - _source[f] = u; - _target[f] = _root; - _cap[f] = INF; - _flow[f] = _supply[u]; - _state[f] = STATE_TREE; - _cost[f] = ART_COST; - _source[e] = _root; - _target[e] = u; - _cap[e] = INF; - _flow[e] = 0; - _cost[e] = 0; - _state[e] = STATE_LOWER; - ++f; - } - } - _all_arc_num = f; - } - - return true; - } - - // Check if the upper bound is greater than or equal to the lower bound - // on each arc. - bool checkBoundMaps() { - for (int j = 0; j != _arc_num; ++j) { - if (_upper[j] < _lower[j]) return false; - } - return true; - } - - // Find the join node - void findJoinNode() { - int u = _source[in_arc]; - int v = _target[in_arc]; - while (u != v) { - if (_succ_num[u] < _succ_num[v]) { - u = _parent[u]; - } else { - v = _parent[v]; - } - } - join = u; - } - - // Find the leaving arc of the cycle and returns true if the - // leaving arc is not the same as the entering arc - bool findLeavingArc() { - // Initialize first and second nodes according to the direction - // of the cycle - int first, second; - if (_state[in_arc] == STATE_LOWER) { - first = _source[in_arc]; - second = _target[in_arc]; - } else { - first = _target[in_arc]; - second = _source[in_arc]; - } - delta = _cap[in_arc]; - int result = 0; - Value c, d; - int e; - - // Search the cycle form the first node to the join node - for (int u = first; u != join; u = _parent[u]) { - e = _pred[u]; - d = _flow[e]; - if (_pred_dir[u] == DIR_DOWN) { - c = _cap[e]; - d = c >= MAX ? INF : c - d; - } - if (d < delta) { - delta = d; - u_out = u; - result = 1; - } - } - - // Search the cycle form the second node to the join node - for (int u = second; u != join; u = _parent[u]) { - e = _pred[u]; - d = _flow[e]; - if (_pred_dir[u] == DIR_UP) { - c = _cap[e]; - d = c >= MAX ? INF : c - d; - } - if (d <= delta) { - delta = d; - u_out = u; - result = 2; - } - } - - if (result == 1) { - u_in = first; - v_in = second; - } else { - u_in = second; - v_in = first; - } - return result != 0; - } - - // Change _flow and _state vectors - void changeFlow(bool change) { - // Augment along the cycle - if (delta > 0) { - Value val = _state[in_arc] * delta; - _flow[in_arc] += val; - for (int u = _source[in_arc]; u != join; u = _parent[u]) { - _flow[_pred[u]] -= _pred_dir[u] * val; - } - for (int u = _target[in_arc]; u != join; u = _parent[u]) { - _flow[_pred[u]] += _pred_dir[u] * val; - } - } - // Update the state of the entering and leaving arcs - if (change) { - _state[in_arc] = STATE_TREE; - _state[_pred[u_out]] = - (_flow[_pred[u_out]] == 0) ? STATE_LOWER : STATE_UPPER; - } else { - _state[in_arc] = -_state[in_arc]; - } - } - - // Update the tree structure - void updateTreeStructure() { - int old_rev_thread = _rev_thread[u_out]; - int old_succ_num = _succ_num[u_out]; - int old_last_succ = _last_succ[u_out]; - v_out = _parent[u_out]; - - // Check if u_in and u_out coincide - if (u_in == u_out) { - // Update _parent, _pred, _pred_dir - _parent[u_in] = v_in; - _pred[u_in] = in_arc; - _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN; - - // Update _thread and _rev_thread - if (_thread[v_in] != u_out) { - int after = _thread[old_last_succ]; - _thread[old_rev_thread] = after; - _rev_thread[after] = old_rev_thread; - after = _thread[v_in]; - _thread[v_in] = u_out; - _rev_thread[u_out] = v_in; - _thread[old_last_succ] = after; - _rev_thread[after] = old_last_succ; - } - } else { - // Handle the case when old_rev_thread equals to v_in - // (it also means that join and v_out coincide) - int thread_continue = old_rev_thread == v_in ? - _thread[old_last_succ] : _thread[v_in]; - - // Update _thread and _parent along the stem nodes (i.e. the nodes - // between u_in and u_out, whose parent have to be changed) - int stem = u_in; // the current stem node - int par_stem = v_in; // the new parent of stem - int next_stem; // the next stem node - int last = _last_succ[u_in]; // the last successor of stem - int before, after = _thread[last]; - _thread[v_in] = u_in; - _dirty_revs.clear(); - _dirty_revs.push_back(v_in); - while (stem != u_out) { - // Insert the next stem node into the thread list - next_stem = _parent[stem]; - _thread[last] = next_stem; - _dirty_revs.push_back(last); - - // Remove the subtree of stem from the thread list - before = _rev_thread[stem]; - _thread[before] = after; - _rev_thread[after] = before; - - // Change the parent node and shift stem nodes - _parent[stem] = par_stem; - par_stem = stem; - stem = next_stem; - - // Update last and after - last = _last_succ[stem] == _last_succ[par_stem] ? - _rev_thread[par_stem] : _last_succ[stem]; - after = _thread[last]; - } - _parent[u_out] = par_stem; - _thread[last] = thread_continue; - _rev_thread[thread_continue] = last; - _last_succ[u_out] = last; - - // Remove the subtree of u_out from the thread list except for - // the case when old_rev_thread equals to v_in - if (old_rev_thread != v_in) { - _thread[old_rev_thread] = after; - _rev_thread[after] = old_rev_thread; - } - - // Update _rev_thread using the new _thread values - for (int i = 0; i != int(_dirty_revs.size()); ++i) { - int u = _dirty_revs[i]; - _rev_thread[_thread[u]] = u; - } - - // Update _pred, _pred_dir, _last_succ and _succ_num for the - // stem nodes from u_out to u_in - int tmp_sc = 0, tmp_ls = _last_succ[u_out]; - for (int u = u_out, p = _parent[u]; u != u_in; u = p, p = _parent[u]) { - _pred[u] = _pred[p]; - _pred_dir[u] = -_pred_dir[p]; - tmp_sc += _succ_num[u] - _succ_num[p]; - _succ_num[u] = tmp_sc; - _last_succ[p] = tmp_ls; - } - _pred[u_in] = in_arc; - _pred_dir[u_in] = u_in == _source[in_arc] ? DIR_UP : DIR_DOWN; - _succ_num[u_in] = old_succ_num; - } - - // Update _last_succ from v_in towards the root - int up_limit_out = _last_succ[join] == v_in ? join : -1; - int last_succ_out = _last_succ[u_out]; - for (int u = v_in; u != -1 && _last_succ[u] == v_in; u = _parent[u]) { - _last_succ[u] = last_succ_out; - } - - // Update _last_succ from v_out towards the root - if (join != old_rev_thread && v_in != old_rev_thread) { - for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; - u = _parent[u]) { - _last_succ[u] = old_rev_thread; - } - } - else if (last_succ_out != old_last_succ) { - for (int u = v_out; u != up_limit_out && _last_succ[u] == old_last_succ; - u = _parent[u]) { - _last_succ[u] = last_succ_out; - } - } - - // Update _succ_num from v_in to join - for (int u = v_in; u != join; u = _parent[u]) { - _succ_num[u] += old_succ_num; - } - // Update _succ_num from v_out to join - for (int u = v_out; u != join; u = _parent[u]) { - _succ_num[u] -= old_succ_num; - } - } - - // Update potentials in the subtree that has been moved - void updatePotential() { - Cost sigma = _pi[v_in] - _pi[u_in] - - _pred_dir[u_in] * _cost[in_arc]; - int end = _thread[_last_succ[u_in]]; - for (int u = u_in; u != end; u = _thread[u]) { - _pi[u] += sigma; - } - } - - // Heuristic initial pivots - bool initialPivots() { - Value curr, total = 0; - std::vector supply_nodes, demand_nodes; - for (NodeIt u(_graph); u != INVALID; ++u) { - curr = _supply[_node_id[u]]; - if (curr > 0) { - total += curr; - supply_nodes.push_back(u); - } - else if (curr < 0) { - demand_nodes.push_back(u); - } - } - if (_sum_supply > 0) total -= _sum_supply; - if (total <= 0) return true; - - IntVector arc_vector; - if (_sum_supply >= 0) { - if (supply_nodes.size() == 1 && demand_nodes.size() == 1) { - // Perform a reverse graph search from the sink to the source - typename GR::template NodeMap reached(_graph, false); - Node s = supply_nodes[0], t = demand_nodes[0]; - std::vector stack; - reached[t] = true; - stack.push_back(t); - while (!stack.empty()) { - Node u, v = stack.back(); - stack.pop_back(); - if (v == s) break; - for (InArcIt a(_graph, v); a != INVALID; ++a) { - if (reached[u = _graph.source(a)]) continue; - int j = _arc_id[a]; - if (_cap[j] >= total) { - arc_vector.push_back(j); - reached[u] = true; - stack.push_back(u); - } - } - } - } else { - // Find the min. cost incoming arc for each demand node - for (int i = 0; i != int(demand_nodes.size()); ++i) { - Node v = demand_nodes[i]; - Cost c, min_cost = std::numeric_limits::max(); - Arc min_arc = INVALID; - for (InArcIt a(_graph, v); a != INVALID; ++a) { - c = _cost[_arc_id[a]]; - if (c < min_cost) { - min_cost = c; - min_arc = a; - } - } - if (min_arc != INVALID) { - arc_vector.push_back(_arc_id[min_arc]); - } - } - } - } else { - // Find the min. cost outgoing arc for each supply node - for (int i = 0; i != int(supply_nodes.size()); ++i) { - Node u = supply_nodes[i]; - Cost c, min_cost = std::numeric_limits::max(); - Arc min_arc = INVALID; - for (OutArcIt a(_graph, u); a != INVALID; ++a) { - c = _cost[_arc_id[a]]; - if (c < min_cost) { - min_cost = c; - min_arc = a; - } - } - if (min_arc != INVALID) { - arc_vector.push_back(_arc_id[min_arc]); - } - } - } - - // Perform heuristic initial pivots - for (int i = 0; i != int(arc_vector.size()); ++i) { - in_arc = arc_vector[i]; - if (_state[in_arc] * (_cost[in_arc] + _pi[_source[in_arc]] - - _pi[_target[in_arc]]) >= 0) continue; - findJoinNode(); - bool change = findLeavingArc(); - if (delta >= MAX) return false; - changeFlow(change); - if (change) { - updateTreeStructure(); - updatePotential(); - } - } - return true; - } - - // Execute the algorithm - ProblemType start(PivotRule pivot_rule) { - // Select the pivot rule implementation - switch (pivot_rule) { - case FIRST_ELIGIBLE: - return start(); - case BEST_ELIGIBLE: - return start(); - case BLOCK_SEARCH: - return start(); - case CANDIDATE_LIST: - return start(); - case ALTERING_LIST: - return start(); - } - return INFEASIBLE; // avoid warning - } - - template - ProblemType start() { - PivotRuleImpl pivot(*this); - - // Perform heuristic initial pivots - if (!initialPivots()) return UNBOUNDED; - - // Execute the Network Simplex algorithm - while (pivot.findEnteringArc()) { - findJoinNode(); - bool change = findLeavingArc(); - if (delta >= MAX) return UNBOUNDED; - changeFlow(change); - if (change) { - updateTreeStructure(); - updatePotential(); - } - } - - // Check feasibility - for (int e = _search_arc_num; e != _all_arc_num; ++e) { - if (_flow[e] != 0) return INFEASIBLE; - } - - // Transform the solution and the supply map to the original form - if (_has_lower) { - for (int i = 0; i != _arc_num; ++i) { - Value c = _lower[i]; - if (c != 0) { - _flow[i] += c; - _supply[_source[i]] += c; - _supply[_target[i]] -= c; - } - } - } - - // Shift potentials to meet the requirements of the GEQ/LEQ type - // optimality conditions - if (_sum_supply == 0) { - if (_stype == GEQ) { - Cost max_pot = -std::numeric_limits::max(); - for (int i = 0; i != _node_num; ++i) { - if (_pi[i] > max_pot) max_pot = _pi[i]; - } - if (max_pot > 0) { - for (int i = 0; i != _node_num; ++i) - _pi[i] -= max_pot; - } - } else { - Cost min_pot = std::numeric_limits::max(); - for (int i = 0; i != _node_num; ++i) { - if (_pi[i] < min_pot) min_pot = _pi[i]; - } - if (min_pot < 0) { - for (int i = 0; i != _node_num; ++i) - _pi[i] -= min_pot; - } - } - } - - return OPTIMAL; - } - - }; //class NetworkSimplex - - ///@} - -} //namespace lemon - -#endif //LEMON_NETWORK_SIMPLEX_H diff --git a/deps/lemon/lemon/opt2_tsp.h b/deps/lemon/lemon/opt2_tsp.h deleted file mode 100644 index 686cc9cb8..000000000 --- a/deps/lemon/lemon/opt2_tsp.h +++ /dev/null @@ -1,367 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_OPT2_TSP_H -#define LEMON_OPT2_TSP_H - -/// \ingroup tsp -/// \file -/// \brief 2-opt algorithm for symmetric TSP. - -#include -#include - -namespace lemon { - - /// \ingroup tsp - /// - /// \brief 2-opt algorithm for symmetric TSP. - /// - /// Opt2Tsp implements the 2-opt heuristic for solving - /// symmetric \ref tsp "TSP". - /// - /// This algorithm starts with an initial tour and iteratively improves it. - /// At each step, it removes two edges and the reconnects the created two - /// paths in the other way if the resulting tour is shorter. - /// The algorithm finishes when no such 2-opt move can be applied, and so - /// the tour is 2-optimal. - /// - /// If no starting tour is given to the \ref run() function, then the - /// algorithm uses the node sequence determined by the node IDs. - /// Oherwise, it starts with the given tour. - /// - /// This is a rather slow but effective method. - /// Its typical usage is the improvement of the result of a fast tour - /// construction heuristic (e.g. the InsertionTsp algorithm). - /// - /// \tparam CM Type of the cost map. - template - class Opt2Tsp - { - public: - - /// Type of the cost map - typedef CM CostMap; - /// Type of the edge costs - typedef typename CM::Value Cost; - - private: - - GRAPH_TYPEDEFS(FullGraph); - - const FullGraph &_gr; - const CostMap &_cost; - Cost _sum; - std::vector _plist; - std::vector _path; - - public: - - /// \brief Constructor - /// - /// Constructor. - /// \param gr The \ref FullGraph "full graph" the algorithm runs on. - /// \param cost The cost map. - Opt2Tsp(const FullGraph &gr, const CostMap &cost) - : _gr(gr), _cost(cost) {} - - /// \name Execution Control - /// @{ - - /// \brief Runs the algorithm from scratch. - /// - /// This function runs the algorithm starting from the tour that is - /// determined by the node ID sequence. - /// - /// \return The total cost of the found tour. - Cost run() { - _path.clear(); - - if (_gr.nodeNum() == 0) return _sum = 0; - else if (_gr.nodeNum() == 1) { - _path.push_back(_gr(0)); - return _sum = 0; - } - else if (_gr.nodeNum() == 2) { - _path.push_back(_gr(0)); - _path.push_back(_gr(1)); - return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; - } - - _plist.resize(2*_gr.nodeNum()); - for (int i = 1; i < _gr.nodeNum()-1; ++i) { - _plist[2*i] = i-1; - _plist[2*i+1] = i+1; - } - _plist[0] = _gr.nodeNum()-1; - _plist[1] = 1; - _plist[2*_gr.nodeNum()-2] = _gr.nodeNum()-2; - _plist[2*_gr.nodeNum()-1] = 0; - - return start(); - } - - /// \brief Runs the algorithm starting from the given tour. - /// - /// This function runs the algorithm starting from the given tour. - /// - /// \param tour The tour as a path structure. It must be a - /// \ref checkPath() "valid path" containing excactly n arcs. - /// - /// \return The total cost of the found tour. - template - Cost run(const Path& tour) { - _path.clear(); - - if (_gr.nodeNum() == 0) return _sum = 0; - else if (_gr.nodeNum() == 1) { - _path.push_back(_gr(0)); - return _sum = 0; - } - else if (_gr.nodeNum() == 2) { - _path.push_back(_gr(0)); - _path.push_back(_gr(1)); - return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; - } - - _plist.resize(2*_gr.nodeNum()); - typename Path::ArcIt it(tour); - int first = _gr.id(_gr.source(it)), - prev = first, - curr = _gr.id(_gr.target(it)), - next = -1; - _plist[2*first+1] = curr; - for (++it; it != INVALID; ++it) { - next = _gr.id(_gr.target(it)); - _plist[2*curr] = prev; - _plist[2*curr+1] = next; - prev = curr; - curr = next; - } - _plist[2*first] = prev; - - return start(); - } - - /// \brief Runs the algorithm starting from the given tour. - /// - /// This function runs the algorithm starting from the given tour - /// (node sequence). - /// - /// \param tour A vector that stores all Nodes of the graph - /// in the desired order. - /// - /// \return The total cost of the found tour. - Cost run(const std::vector& tour) { - _path.clear(); - - if (_gr.nodeNum() == 0) return _sum = 0; - else if (_gr.nodeNum() == 1) { - _path.push_back(_gr(0)); - return _sum = 0; - } - else if (_gr.nodeNum() == 2) { - _path.push_back(_gr(0)); - _path.push_back(_gr(1)); - return _sum = 2 * _cost[_gr.edge(_gr(0), _gr(1))]; - } - - _plist.resize(2*_gr.nodeNum()); - typename std::vector::const_iterator it = tour.begin(); - int first = _gr.id(*it), - prev = first, - curr = _gr.id(*(++it)), - next = -1; - _plist[2*first+1] = curr; - for (++it; it != tour.end(); ++it) { - next = _gr.id(*it); - _plist[2*curr] = prev; - _plist[2*curr+1] = next; - prev = curr; - curr = next; - } - _plist[2*first] = curr; - _plist[2*curr] = prev; - _plist[2*curr+1] = first; - - return start(); - } - - /// @} - - /// \name Query Functions - /// @{ - - /// \brief The total cost of the found tour. - /// - /// This function returns the total cost of the found tour. - /// - /// \pre run() must be called before using this function. - Cost tourCost() const { - return _sum; - } - - /// \brief Returns a const reference to the node sequence of the - /// found tour. - /// - /// This function returns a const reference to a vector - /// that stores the node sequence of the found tour. - /// - /// \pre run() must be called before using this function. - const std::vector& tourNodes() const { - return _path; - } - - /// \brief Gives back the node sequence of the found tour. - /// - /// This function copies the node sequence of the found tour into - /// an STL container through the given output iterator. The - /// value_type of the container must be FullGraph::Node. - /// For example, - /// \code - /// std::vector nodes(countNodes(graph)); - /// tsp.tourNodes(nodes.begin()); - /// \endcode - /// or - /// \code - /// std::list nodes; - /// tsp.tourNodes(std::back_inserter(nodes)); - /// \endcode - /// - /// \pre run() must be called before using this function. - template - void tourNodes(Iterator out) const { - std::copy(_path.begin(), _path.end(), out); - } - - /// \brief Gives back the found tour as a path. - /// - /// This function copies the found tour as a list of arcs/edges into - /// the given \ref lemon::concepts::Path "path structure". - /// - /// \pre run() must be called before using this function. - template - void tour(Path &path) const { - path.clear(); - for (int i = 0; i < int(_path.size()) - 1; ++i) { - path.addBack(_gr.arc(_path[i], _path[i+1])); - } - if (int(_path.size()) >= 2) { - path.addBack(_gr.arc(_path.back(), _path.front())); - } - } - - /// @} - - private: - - // Iterator class for the linked list storage of the tour - class PathListIt { - public: - PathListIt(const std::vector &pl, int i=0) - : plist(&pl), act(i), last(pl[2*act]) {} - PathListIt(const std::vector &pl, int i, int l) - : plist(&pl), act(i), last(l) {} - - int nextIndex() const { - return (*plist)[2*act] == last ? 2*act+1 : 2*act; - } - - int prevIndex() const { - return (*plist)[2*act] == last ? 2*act : 2*act+1; - } - - int next() const { - int x = (*plist)[2*act]; - return x == last ? (*plist)[2*act+1] : x; - } - - int prev() const { - return last; - } - - PathListIt& operator++() { - int tmp = act; - act = next(); - last = tmp; - return *this; - } - - operator int() const { - return act; - } - - private: - const std::vector *plist; - int act; - int last; - }; - - // Checks and applies 2-opt move (if it improves the tour) - bool checkOpt2(const PathListIt& i, const PathListIt& j) { - Node u = _gr.nodeFromId(i), - un = _gr.nodeFromId(i.next()), - v = _gr.nodeFromId(j), - vn = _gr.nodeFromId(j.next()); - - if (_cost[_gr.edge(u, un)] + _cost[_gr.edge(v, vn)] > - _cost[_gr.edge(u, v)] + _cost[_gr.edge(un, vn)]) - { - _plist[PathListIt(_plist, i.next(), i).prevIndex()] = j.next(); - _plist[PathListIt(_plist, j.next(), j).prevIndex()] = i.next(); - - _plist[i.nextIndex()] = j; - _plist[j.nextIndex()] = i; - - return true; - } - - return false; - } - - // Executes the algorithm from the initial tour - Cost start() { - - restart_search: - for (PathListIt i(_plist); true; ++i) { - PathListIt j = i; - if (++j == 0 || ++j == 0) break; - for (; j != 0 && j != i.prev(); ++j) { - if (checkOpt2(i, j)) - goto restart_search; - } - } - - PathListIt i(_plist); - _path.push_back(_gr.nodeFromId(i)); - for (++i; i != 0; ++i) - _path.push_back(_gr.nodeFromId(i)); - - _sum = _cost[_gr.edge(_path.back(), _path.front())]; - for (int i = 0; i < int(_path.size())-1; ++i) { - _sum += _cost[_gr.edge(_path[i], _path[i+1])]; - } - - return _sum; - } - - }; - -}; // namespace lemon - -#endif diff --git a/deps/lemon/lemon/pairing_heap.h b/deps/lemon/lemon/pairing_heap.h deleted file mode 100644 index da6ebcb15..000000000 --- a/deps/lemon/lemon/pairing_heap.h +++ /dev/null @@ -1,474 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_PAIRING_HEAP_H -#define LEMON_PAIRING_HEAP_H - -///\file -///\ingroup heaps -///\brief Pairing heap implementation. - -#include -#include -#include -#include - -namespace lemon { - - /// \ingroup heaps - /// - ///\brief Pairing Heap. - /// - /// This class implements the \e pairing \e heap data structure. - /// It fully conforms to the \ref concepts::Heap "heap concept". - /// - /// The methods \ref increase() and \ref erase() are not efficient - /// in a pairing heap. In case of many calls of these operations, - /// it is better to use other heap structure, e.g. \ref BinHeap - /// "binary heap". - /// - /// \tparam PR Type of the priorities of the items. - /// \tparam IM A read-writable item map with \c int values, used - /// internally to handle the cross references. - /// \tparam CMP A functor class for comparing the priorities. - /// The default is \c std::less. -#ifdef DOXYGEN - template -#else - template > -#endif - class PairingHeap { - public: - /// Type of the item-int map. - typedef IM ItemIntMap; - /// Type of the priorities. - typedef PR Prio; - /// Type of the items stored in the heap. - typedef typename ItemIntMap::Key Item; - /// Functor type for comparing the priorities. - typedef CMP Compare; - - /// \brief Type to represent the states of the items. - /// - /// Each item has a state associated to it. It can be "in heap", - /// "pre-heap" or "post-heap". The latter two are indifferent from the - /// heap's point of view, but may be useful to the user. - /// - /// The item-int map must be initialized in such way that it assigns - /// \c PRE_HEAP (-1) to any element to be put in the heap. - enum State { - IN_HEAP = 0, ///< = 0. - PRE_HEAP = -1, ///< = -1. - POST_HEAP = -2 ///< = -2. - }; - - private: - class store; - - std::vector _data; - int _min; - ItemIntMap &_iim; - Compare _comp; - int _num_items; - - public: - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - explicit PairingHeap(ItemIntMap &map) - : _min(0), _iim(map), _num_items(0) {} - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - /// \param comp The function object used for comparing the priorities. - PairingHeap(ItemIntMap &map, const Compare &comp) - : _min(0), _iim(map), _comp(comp), _num_items(0) {} - - /// \brief The number of items stored in the heap. - /// - /// This function returns the number of items stored in the heap. - int size() const { return _num_items; } - - /// \brief Check if the heap is empty. - /// - /// This function returns \c true if the heap is empty. - bool empty() const { return _num_items==0; } - - /// \brief Make the heap empty. - /// - /// This functon makes the heap empty. - /// It does not change the cross reference map. If you want to reuse - /// a heap that is not surely empty, you should first clear it and - /// then you should set the cross reference map to \c PRE_HEAP - /// for each item. - void clear() { - _data.clear(); - _min = 0; - _num_items = 0; - } - - /// \brief Set the priority of an item or insert it, if it is - /// not stored in the heap. - /// - /// This method sets the priority of the given item if it is - /// already stored in the heap. Otherwise it inserts the given - /// item into the heap with the given priority. - /// \param item The item. - /// \param value The priority. - void set (const Item& item, const Prio& value) { - int i=_iim[item]; - if ( i>=0 && _data[i].in ) { - if ( _comp(value, _data[i].prio) ) decrease(item, value); - if ( _comp(_data[i].prio, value) ) increase(item, value); - } else push(item, value); - } - - /// \brief Insert an item into the heap with the given priority. - /// - /// This function inserts the given item into the heap with the - /// given priority. - /// \param item The item to insert. - /// \param value The priority of the item. - /// \pre \e item must not be stored in the heap. - void push (const Item& item, const Prio& value) { - int i=_iim[item]; - if( i<0 ) { - int s=_data.size(); - _iim.set(item, s); - store st; - st.name=item; - _data.push_back(st); - i=s; - } else { - _data[i].parent=_data[i].child=-1; - _data[i].left_child=false; - _data[i].degree=0; - _data[i].in=true; - } - - _data[i].prio=value; - - if ( _num_items!=0 ) { - if ( _comp( value, _data[_min].prio) ) { - fuse(i,_min); - _min=i; - } - else fuse(_min,i); - } - else _min=i; - - ++_num_items; - } - - /// \brief Return the item having minimum priority. - /// - /// This function returns the item having minimum priority. - /// \pre The heap must be non-empty. - Item top() const { return _data[_min].name; } - - /// \brief The minimum priority. - /// - /// This function returns the minimum priority. - /// \pre The heap must be non-empty. - const Prio& prio() const { return _data[_min].prio; } - - /// \brief The priority of the given item. - /// - /// This function returns the priority of the given item. - /// \param item The item. - /// \pre \e item must be in the heap. - const Prio& operator[](const Item& item) const { - return _data[_iim[item]].prio; - } - - /// \brief Remove the item having minimum priority. - /// - /// This function removes the item having minimum priority. - /// \pre The heap must be non-empty. - void pop() { - std::vector trees; - int i=0, child_right = 0; - _data[_min].in=false; - - if( -1!=_data[_min].child ) { - i=_data[_min].child; - trees.push_back(i); - _data[i].parent = -1; - _data[_min].child = -1; - - int ch=-1; - while( _data[i].child!=-1 ) { - ch=_data[i].child; - if( _data[ch].left_child && i==_data[ch].parent ) { - break; - } else { - if( _data[ch].left_child ) { - child_right=_data[ch].parent; - _data[ch].parent = i; - --_data[i].degree; - } - else { - child_right=ch; - _data[i].child=-1; - _data[i].degree=0; - } - _data[child_right].parent = -1; - trees.push_back(child_right); - i = child_right; - } - } - - int num_child = trees.size(); - int other; - for( i=0; i=2) { - if ( _comp(_data[trees[i]].prio, _data[trees[i-2]].prio) ) { - other=trees[i]; - trees[i]=trees[i-2]; - trees[i-2]=other; - } - fuse( trees[i-2], trees[i] ); - i-=2; - } - _min = trees[0]; - } - else { - _min = _data[_min].child; - } - - if (_min >= 0) _data[_min].left_child = false; - --_num_items; - } - - /// \brief Remove the given item from the heap. - /// - /// This function removes the given item from the heap if it is - /// already stored. - /// \param item The item to delete. - /// \pre \e item must be in the heap. - void erase (const Item& item) { - int i=_iim[item]; - if ( i>=0 && _data[i].in ) { - decrease( item, _data[_min].prio-1 ); - pop(); - } - } - - /// \brief Decrease the priority of an item to the given value. - /// - /// This function decreases the priority of an item to the given value. - /// \param item The item. - /// \param value The priority. - /// \pre \e item must be stored in the heap with priority at least \e value. - void decrease (Item item, const Prio& value) { - int i=_iim[item]; - _data[i].prio=value; - int p=_data[i].parent; - - if( _data[i].left_child && i!=_data[p].child ) { - p=_data[p].parent; - } - - if ( p!=-1 && _comp(value,_data[p].prio) ) { - cut(i,p); - if ( _comp(_data[_min].prio,value) ) { - fuse(_min,i); - } else { - fuse(i,_min); - _min=i; - } - } - } - - /// \brief Increase the priority of an item to the given value. - /// - /// This function increases the priority of an item to the given value. - /// \param item The item. - /// \param value The priority. - /// \pre \e item must be stored in the heap with priority at most \e value. - void increase (Item item, const Prio& value) { - erase(item); - push(item,value); - } - - /// \brief Return the state of an item. - /// - /// This method returns \c PRE_HEAP if the given item has never - /// been in the heap, \c IN_HEAP if it is in the heap at the moment, - /// and \c POST_HEAP otherwise. - /// In the latter case it is possible that the item will get back - /// to the heap again. - /// \param item The item. - State state(const Item &item) const { - int i=_iim[item]; - if( i>=0 ) { - if( _data[i].in ) i=0; - else i=-2; - } - return State(i); - } - - /// \brief Set the state of an item in the heap. - /// - /// This function sets the state of the given item in the heap. - /// It can be used to manually clear the heap when it is important - /// to achive better time complexity. - /// \param i The item. - /// \param st The state. It should not be \c IN_HEAP. - void state(const Item& i, State st) { - switch (st) { - case POST_HEAP: - case PRE_HEAP: - if (state(i) == IN_HEAP) erase(i); - _iim[i]=st; - break; - case IN_HEAP: - break; - } - } - - private: - - void cut(int a, int b) { - int child_a; - switch (_data[a].degree) { - case 2: - child_a = _data[_data[a].child].parent; - if( _data[a].left_child ) { - _data[child_a].left_child=true; - _data[b].child=child_a; - _data[child_a].parent=_data[a].parent; - } - else { - _data[child_a].left_child=false; - _data[child_a].parent=b; - if( a!=_data[b].child ) - _data[_data[b].child].parent=child_a; - else - _data[b].child=child_a; - } - --_data[a].degree; - _data[_data[a].child].parent=a; - break; - - case 1: - child_a = _data[a].child; - if( !_data[child_a].left_child ) { - --_data[a].degree; - if( _data[a].left_child ) { - _data[child_a].left_child=true; - _data[child_a].parent=_data[a].parent; - _data[b].child=child_a; - } - else { - _data[child_a].left_child=false; - _data[child_a].parent=b; - if( a!=_data[b].child ) - _data[_data[b].child].parent=child_a; - else - _data[b].child=child_a; - } - _data[a].child=-1; - } - else { - --_data[b].degree; - if( _data[a].left_child ) { - _data[b].child = - (1==_data[b].degree) ? _data[a].parent : -1; - } else { - if (1==_data[b].degree) - _data[_data[b].child].parent=b; - else - _data[b].child=-1; - } - } - break; - - case 0: - --_data[b].degree; - if( _data[a].left_child ) { - _data[b].child = - (0!=_data[b].degree) ? _data[a].parent : -1; - } else { - if( 0!=_data[b].degree ) - _data[_data[b].child].parent=b; - else - _data[b].child=-1; - } - break; - } - _data[a].parent=-1; - _data[a].left_child=false; - } - - void fuse(int a, int b) { - int child_a = _data[a].child; - int child_b = _data[b].child; - _data[a].child=b; - _data[b].parent=a; - _data[b].left_child=true; - - if( -1!=child_a ) { - _data[b].child=child_a; - _data[child_a].parent=b; - _data[child_a].left_child=false; - ++_data[b].degree; - - if( -1!=child_b ) { - _data[b].child=child_b; - _data[child_b].parent=child_a; - } - } - else { ++_data[a].degree; } - } - - class store { - friend class PairingHeap; - - Item name; - int parent; - int child; - bool left_child; - int degree; - bool in; - Prio prio; - - store() : parent(-1), child(-1), left_child(false), degree(0), in(true) {} - }; - }; - -} //namespace lemon - -#endif //LEMON_PAIRING_HEAP_H - diff --git a/deps/lemon/lemon/path.h b/deps/lemon/lemon/path.h deleted file mode 100644 index baa92c48b..000000000 --- a/deps/lemon/lemon/path.h +++ /dev/null @@ -1,1164 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\ingroup paths -///\file -///\brief Classes for representing paths in digraphs. -/// - -#ifndef LEMON_PATH_H -#define LEMON_PATH_H - -#include -#include - -#include -#include -#include - -namespace lemon { - - /// \addtogroup paths - /// @{ - - - /// \brief A structure for representing directed paths in a digraph. - /// - /// A structure for representing directed path in a digraph. - /// \tparam GR The digraph type in which the path is. - /// - /// In a sense, the path can be treated as a list of arcs. The - /// LEMON path type stores just this list. As a consequence, it - /// cannot enumerate the nodes of the path and the source node of - /// a zero length path is undefined. - /// - /// This implementation is a back and front insertable and erasable - /// path type. It can be indexed in O(1) time. The front and back - /// insertion and erase is done in O(1) (amortized) time. The - /// implementation uses two vectors for storing the front and back - /// insertions. - template - class Path { - public: - - typedef GR Digraph; - typedef typename Digraph::Arc Arc; - - /// \brief Default constructor - /// - /// Default constructor - Path() {} - - /// \brief Copy constructor - /// - Path(const Path& cpath) { - pathCopy(cpath, *this); - } - - /// \brief Template copy constructor - /// - /// This constuctor initializes the path from any other path type. - /// It simply makes a copy of the given path. - template - Path(const CPath& cpath) { - pathCopy(cpath, *this); - } - - /// \brief Copy assignment - /// - Path& operator=(const Path& cpath) { - pathCopy(cpath, *this); - return *this; - } - - /// \brief Template copy assignment - /// - /// This operator makes a copy of a path of any other type. - template - Path& operator=(const CPath& cpath) { - pathCopy(cpath, *this); - return *this; - } - - /// \brief LEMON style iterator for path arcs - /// - /// This class is used to iterate on the arcs of the paths. - class ArcIt { - friend class Path; - public: - /// \brief Default constructor - ArcIt() {} - /// \brief Invalid constructor - ArcIt(Invalid) : path(0), idx(-1) {} - /// \brief Initializate the iterator to the first arc of path - ArcIt(const Path &_path) - : path(&_path), idx(_path.empty() ? -1 : 0) {} - - private: - - ArcIt(const Path &_path, int _idx) - : path(&_path), idx(_idx) {} - - public: - - /// \brief Conversion to Arc - operator const Arc&() const { - return path->nth(idx); - } - - /// \brief Next arc - ArcIt& operator++() { - ++idx; - if (idx >= path->length()) idx = -1; - return *this; - } - - /// \brief Comparison operator - bool operator==(const ArcIt& e) const { return idx==e.idx; } - /// \brief Comparison operator - bool operator!=(const ArcIt& e) const { return idx!=e.idx; } - /// \brief Comparison operator - bool operator<(const ArcIt& e) const { return idx[0..length() - 1] range. - const Arc& nth(int n) const { - return n < int(head.size()) ? *(head.rbegin() + n) : - *(tail.begin() + (n - head.size())); - } - - /// \brief Initialize arc iterator to point to the n-th arc - /// - /// \pre \c n is in the [0..length() - 1] range. - ArcIt nthIt(int n) const { - return ArcIt(*this, n); - } - - /// \brief The first arc of the path - const Arc& front() const { - return head.empty() ? tail.front() : head.back(); - } - - /// \brief Add a new arc before the current path - void addFront(const Arc& arc) { - head.push_back(arc); - } - - /// \brief Erase the first arc of the path - void eraseFront() { - if (!head.empty()) { - head.pop_back(); - } else { - head.clear(); - int halfsize = tail.size() / 2; - head.resize(halfsize); - std::copy(tail.begin() + 1, tail.begin() + halfsize + 1, - head.rbegin()); - std::copy(tail.begin() + halfsize + 1, tail.end(), tail.begin()); - tail.resize(tail.size() - halfsize - 1); - } - } - - /// \brief The last arc of the path - const Arc& back() const { - return tail.empty() ? head.front() : tail.back(); - } - - /// \brief Add a new arc behind the current path - void addBack(const Arc& arc) { - tail.push_back(arc); - } - - /// \brief Erase the last arc of the path - void eraseBack() { - if (!tail.empty()) { - tail.pop_back(); - } else { - int halfsize = head.size() / 2; - tail.resize(halfsize); - std::copy(head.begin() + 1, head.begin() + halfsize + 1, - tail.rbegin()); - std::copy(head.begin() + halfsize + 1, head.end(), head.begin()); - head.resize(head.size() - halfsize - 1); - } - } - - typedef True BuildTag; - - template - void build(const CPath& path) { - int len = path.length(); - tail.reserve(len); - for (typename CPath::ArcIt it(path); it != INVALID; ++it) { - tail.push_back(it); - } - } - - template - void buildRev(const CPath& path) { - int len = path.length(); - head.reserve(len); - for (typename CPath::RevArcIt it(path); it != INVALID; ++it) { - head.push_back(it); - } - } - - protected: - typedef std::vector Container; - Container head, tail; - - }; - - /// \brief A structure for representing directed paths in a digraph. - /// - /// A structure for representing directed path in a digraph. - /// \tparam GR The digraph type in which the path is. - /// - /// In a sense, the path can be treated as a list of arcs. The - /// LEMON path type stores just this list. As a consequence it - /// cannot enumerate the nodes in the path and the zero length paths - /// cannot store the source. - /// - /// This implementation is a just back insertable and erasable path - /// type. It can be indexed in O(1) time. The back insertion and - /// erasure is amortized O(1) time. This implementation is faster - /// then the \c Path type because it use just one vector for the - /// arcs. - template - class SimplePath { - public: - - typedef GR Digraph; - typedef typename Digraph::Arc Arc; - - /// \brief Default constructor - /// - /// Default constructor - SimplePath() {} - - /// \brief Copy constructor - /// - SimplePath(const SimplePath& cpath) { - pathCopy(cpath, *this); - } - - /// \brief Template copy constructor - /// - /// This path can be initialized with any other path type. It just - /// makes a copy of the given path. - template - SimplePath(const CPath& cpath) { - pathCopy(cpath, *this); - } - - /// \brief Copy assignment - /// - SimplePath& operator=(const SimplePath& cpath) { - pathCopy(cpath, *this); - return *this; - } - - /// \brief Template copy assignment - /// - /// This path can be initialized with any other path type. It just - /// makes a copy of the given path. - template - SimplePath& operator=(const CPath& cpath) { - pathCopy(cpath, *this); - return *this; - } - - /// \brief Iterator class to iterate on the arcs of the paths - /// - /// This class is used to iterate on the arcs of the paths - /// - /// Of course it converts to Digraph::Arc - class ArcIt { - friend class SimplePath; - public: - /// Default constructor - ArcIt() {} - /// Invalid constructor - ArcIt(Invalid) : path(0), idx(-1) {} - /// \brief Initializate the constructor to the first arc of path - ArcIt(const SimplePath &_path) - : path(&_path), idx(_path.empty() ? -1 : 0) {} - - private: - - /// Constructor with starting point - ArcIt(const SimplePath &_path, int _idx) - : path(&_path), idx(_idx) {} - - public: - - ///Conversion to Digraph::Arc - operator const Arc&() const { - return path->nth(idx); - } - - /// Next arc - ArcIt& operator++() { - ++idx; - if (idx >= path->length()) idx = -1; - return *this; - } - - /// Comparison operator - bool operator==(const ArcIt& e) const { return idx==e.idx; } - /// Comparison operator - bool operator!=(const ArcIt& e) const { return idx!=e.idx; } - /// Comparison operator - bool operator<(const ArcIt& e) const { return idx[0..length() - 1] range. - const Arc& nth(int n) const { - return data[n]; - } - - /// \brief Initializes arc iterator to point to the n-th arc. - ArcIt nthIt(int n) const { - return ArcIt(*this, n); - } - - /// \brief The first arc of the path. - const Arc& front() const { - return data.front(); - } - - /// \brief The last arc of the path. - const Arc& back() const { - return data.back(); - } - - /// \brief Add a new arc behind the current path. - void addBack(const Arc& arc) { - data.push_back(arc); - } - - /// \brief Erase the last arc of the path - void eraseBack() { - data.pop_back(); - } - - typedef True BuildTag; - - template - void build(const CPath& path) { - int len = path.length(); - data.resize(len); - int index = 0; - for (typename CPath::ArcIt it(path); it != INVALID; ++it) { - data[index] = it;; - ++index; - } - } - - template - void buildRev(const CPath& path) { - int len = path.length(); - data.resize(len); - int index = len; - for (typename CPath::RevArcIt it(path); it != INVALID; ++it) { - --index; - data[index] = it;; - } - } - - protected: - typedef std::vector Container; - Container data; - - }; - - /// \brief A structure for representing directed paths in a digraph. - /// - /// A structure for representing directed path in a digraph. - /// \tparam GR The digraph type in which the path is. - /// - /// In a sense, the path can be treated as a list of arcs. The - /// LEMON path type stores just this list. As a consequence it - /// cannot enumerate the nodes in the path and the zero length paths - /// cannot store the source. - /// - /// This implementation is a back and front insertable and erasable - /// path type. It can be indexed in O(k) time, where k is the rank - /// of the arc in the path. The length can be computed in O(n) - /// time. The front and back insertion and erasure is O(1) time - /// and it can be splited and spliced in O(1) time. - template - class ListPath { - public: - - typedef GR Digraph; - typedef typename Digraph::Arc Arc; - - protected: - - // the std::list<> is incompatible - // hard to create invalid iterator - struct Node { - Arc arc; - Node *next, *prev; - }; - - Node *first, *last; - - std::allocator alloc; - - public: - - /// \brief Default constructor - /// - /// Default constructor - ListPath() : first(0), last(0) {} - - /// \brief Copy constructor - /// - ListPath(const ListPath& cpath) : first(0), last(0) { - pathCopy(cpath, *this); - } - - /// \brief Template copy constructor - /// - /// This path can be initialized with any other path type. It just - /// makes a copy of the given path. - template - ListPath(const CPath& cpath) : first(0), last(0) { - pathCopy(cpath, *this); - } - - /// \brief Destructor of the path - /// - /// Destructor of the path - ~ListPath() { - clear(); - } - - /// \brief Copy assignment - /// - ListPath& operator=(const ListPath& cpath) { - pathCopy(cpath, *this); - return *this; - } - - /// \brief Template copy assignment - /// - /// This path can be initialized with any other path type. It just - /// makes a copy of the given path. - template - ListPath& operator=(const CPath& cpath) { - pathCopy(cpath, *this); - return *this; - } - - /// \brief Iterator class to iterate on the arcs of the paths - /// - /// This class is used to iterate on the arcs of the paths - /// - /// Of course it converts to Digraph::Arc - class ArcIt { - friend class ListPath; - public: - /// Default constructor - ArcIt() {} - /// Invalid constructor - ArcIt(Invalid) : path(0), node(0) {} - /// \brief Initializate the constructor to the first arc of path - ArcIt(const ListPath &_path) - : path(&_path), node(_path.first) {} - - protected: - - ArcIt(const ListPath &_path, Node *_node) - : path(&_path), node(_node) {} - - - public: - - ///Conversion to Digraph::Arc - operator const Arc&() const { - return node->arc; - } - - /// Next arc - ArcIt& operator++() { - node = node->next; - return *this; - } - - /// Comparison operator - bool operator==(const ArcIt& e) const { return node==e.node; } - /// Comparison operator - bool operator!=(const ArcIt& e) const { return node!=e.node; } - /// Comparison operator - bool operator<(const ArcIt& e) const { return node[0..length() - 1] range. - const Arc& nth(int n) const { - Node *node = first; - for (int i = 0; i < n; ++i) { - node = node->next; - } - return node->arc; - } - - /// \brief Initializes arc iterator to point to the n-th arc. - ArcIt nthIt(int n) const { - Node *node = first; - for (int i = 0; i < n; ++i) { - node = node->next; - } - return ArcIt(*this, node); - } - - /// \brief Length of the path. - int length() const { - int len = 0; - Node *node = first; - while (node != 0) { - node = node->next; - ++len; - } - return len; - } - - /// \brief Return true if the path is empty. - bool empty() const { return first == 0; } - - /// \brief Reset the path to an empty one. - void clear() { - while (first != 0) { - last = first->next; - alloc.destroy(first); - alloc.deallocate(first, 1); - first = last; - } - } - - /// \brief The first arc of the path - const Arc& front() const { - return first->arc; - } - - /// \brief Add a new arc before the current path - void addFront(const Arc& arc) { - Node *node = alloc.allocate(1); - alloc.construct(node, Node()); - node->prev = 0; - node->next = first; - node->arc = arc; - if (first) { - first->prev = node; - first = node; - } else { - first = last = node; - } - } - - /// \brief Erase the first arc of the path - void eraseFront() { - Node *node = first; - first = first->next; - if (first) { - first->prev = 0; - } else { - last = 0; - } - alloc.destroy(node); - alloc.deallocate(node, 1); - } - - /// \brief The last arc of the path. - const Arc& back() const { - return last->arc; - } - - /// \brief Add a new arc behind the current path. - void addBack(const Arc& arc) { - Node *node = alloc.allocate(1); - alloc.construct(node, Node()); - node->next = 0; - node->prev = last; - node->arc = arc; - if (last) { - last->next = node; - last = node; - } else { - last = first = node; - } - } - - /// \brief Erase the last arc of the path - void eraseBack() { - Node *node = last; - last = last->prev; - if (last) { - last->next = 0; - } else { - first = 0; - } - alloc.destroy(node); - alloc.deallocate(node, 1); - } - - /// \brief Splice a path to the back of the current path. - /// - /// It splices \c tpath to the back of the current path and \c - /// tpath becomes empty. The time complexity of this function is - /// O(1). - void spliceBack(ListPath& tpath) { - if (first) { - if (tpath.first) { - last->next = tpath.first; - tpath.first->prev = last; - last = tpath.last; - } - } else { - first = tpath.first; - last = tpath.last; - } - tpath.first = tpath.last = 0; - } - - /// \brief Splice a path to the front of the current path. - /// - /// It splices \c tpath before the current path and \c tpath - /// becomes empty. The time complexity of this function - /// is O(1). - void spliceFront(ListPath& tpath) { - if (first) { - if (tpath.first) { - first->prev = tpath.last; - tpath.last->next = first; - first = tpath.first; - } - } else { - first = tpath.first; - last = tpath.last; - } - tpath.first = tpath.last = 0; - } - - /// \brief Splice a path into the current path. - /// - /// It splices the \c tpath into the current path before the - /// position of \c it iterator and \c tpath becomes empty. The - /// time complexity of this function is O(1). If the \c it is - /// \c INVALID then it will splice behind the current path. - void splice(ArcIt it, ListPath& tpath) { - if (it.node) { - if (tpath.first) { - tpath.first->prev = it.node->prev; - if (it.node->prev) { - it.node->prev->next = tpath.first; - } else { - first = tpath.first; - } - it.node->prev = tpath.last; - tpath.last->next = it.node; - } - } else { - if (first) { - if (tpath.first) { - last->next = tpath.first; - tpath.first->prev = last; - last = tpath.last; - } - } else { - first = tpath.first; - last = tpath.last; - } - } - tpath.first = tpath.last = 0; - } - - /// \brief Split the current path. - /// - /// It splits the current path into two parts. The part before - /// the iterator \c it will remain in the current path and the part - /// starting with - /// \c it will put into \c tpath. If \c tpath have arcs - /// before the operation they are removed first. The time - /// complexity of this function is O(1) plus the the time of emtying - /// \c tpath. If \c it is \c INVALID then it just clears \c tpath - void split(ArcIt it, ListPath& tpath) { - tpath.clear(); - if (it.node) { - tpath.first = it.node; - tpath.last = last; - if (it.node->prev) { - last = it.node->prev; - last->next = 0; - } else { - first = last = 0; - } - it.node->prev = 0; - } - } - - - typedef True BuildTag; - - template - void build(const CPath& path) { - for (typename CPath::ArcIt it(path); it != INVALID; ++it) { - addBack(it); - } - } - - template - void buildRev(const CPath& path) { - for (typename CPath::RevArcIt it(path); it != INVALID; ++it) { - addFront(it); - } - } - - }; - - /// \brief A structure for representing directed paths in a digraph. - /// - /// A structure for representing directed path in a digraph. - /// \tparam GR The digraph type in which the path is. - /// - /// In a sense, the path can be treated as a list of arcs. The - /// LEMON path type stores just this list. As a consequence it - /// cannot enumerate the nodes in the path and the source node of - /// a zero length path is undefined. - /// - /// This implementation is completly static, i.e. it can be copy constucted - /// or copy assigned from another path, but otherwise it cannot be - /// modified. - /// - /// Being the the most memory efficient path type in LEMON, - /// it is intented to be - /// used when you want to store a large number of paths. - template - class StaticPath { - public: - - typedef GR Digraph; - typedef typename Digraph::Arc Arc; - - /// \brief Default constructor - /// - /// Default constructor - StaticPath() : len(0), arcs(0) {} - - /// \brief Copy constructor - /// - StaticPath(const StaticPath& cpath) : arcs(0) { - pathCopy(cpath, *this); - } - - /// \brief Template copy constructor - /// - /// This path can be initialized from any other path type. - template - StaticPath(const CPath& cpath) : arcs(0) { - pathCopy(cpath, *this); - } - - /// \brief Destructor of the path - /// - /// Destructor of the path - ~StaticPath() { - if (arcs) delete[] arcs; - } - - /// \brief Copy assignment - /// - StaticPath& operator=(const StaticPath& cpath) { - pathCopy(cpath, *this); - return *this; - } - - /// \brief Template copy assignment - /// - /// This path can be made equal to any other path type. It simply - /// makes a copy of the given path. - template - StaticPath& operator=(const CPath& cpath) { - pathCopy(cpath, *this); - return *this; - } - - /// \brief Iterator class to iterate on the arcs of the paths - /// - /// This class is used to iterate on the arcs of the paths - /// - /// Of course it converts to Digraph::Arc - class ArcIt { - friend class StaticPath; - public: - /// Default constructor - ArcIt() {} - /// Invalid constructor - ArcIt(Invalid) : path(0), idx(-1) {} - /// Initializate the constructor to the first arc of path - ArcIt(const StaticPath &_path) - : path(&_path), idx(_path.empty() ? -1 : 0) {} - - private: - - /// Constructor with starting point - ArcIt(const StaticPath &_path, int _idx) - : idx(_idx), path(&_path) {} - - public: - - ///Conversion to Digraph::Arc - operator const Arc&() const { - return path->nth(idx); - } - - /// Next arc - ArcIt& operator++() { - ++idx; - if (idx >= path->length()) idx = -1; - return *this; - } - - /// Comparison operator - bool operator==(const ArcIt& e) const { return idx==e.idx; } - /// Comparison operator - bool operator!=(const ArcIt& e) const { return idx!=e.idx; } - /// Comparison operator - bool operator<(const ArcIt& e) const { return idx[0..length() - 1] range. - const Arc& nth(int n) const { - return arcs[n]; - } - - /// \brief The arc iterator pointing to the n-th arc. - ArcIt nthIt(int n) const { - return ArcIt(*this, n); - } - - /// \brief The length of the path. - int length() const { return len; } - - /// \brief Return true when the path is empty. - int empty() const { return len == 0; } - - /// \brief Erase all arcs in the digraph. - void clear() { - len = 0; - if (arcs) delete[] arcs; - arcs = 0; - } - - /// \brief The first arc of the path. - const Arc& front() const { - return arcs[0]; - } - - /// \brief The last arc of the path. - const Arc& back() const { - return arcs[len - 1]; - } - - - typedef True BuildTag; - - template - void build(const CPath& path) { - len = path.length(); - arcs = new Arc[len]; - int index = 0; - for (typename CPath::ArcIt it(path); it != INVALID; ++it) { - arcs[index] = it; - ++index; - } - } - - template - void buildRev(const CPath& path) { - len = path.length(); - arcs = new Arc[len]; - int index = len; - for (typename CPath::RevArcIt it(path); it != INVALID; ++it) { - --index; - arcs[index] = it; - } - } - - private: - int len; - Arc* arcs; - }; - - /////////////////////////////////////////////////////////////////////// - // Additional utilities - /////////////////////////////////////////////////////////////////////// - - namespace _path_bits { - - template - struct RevPathTagIndicator { - static const bool value = false; - }; - - template - struct RevPathTagIndicator< - Path, - typename enable_if::type - > { - static const bool value = true; - }; - - template - struct BuildTagIndicator { - static const bool value = false; - }; - - template - struct BuildTagIndicator< - Path, - typename enable_if::type - > { - static const bool value = true; - }; - - template ::value> - struct PathCopySelectorForward { - static void copy(const From& from, To& to) { - to.clear(); - for (typename From::ArcIt it(from); it != INVALID; ++it) { - to.addBack(it); - } - } - }; - - template - struct PathCopySelectorForward { - static void copy(const From& from, To& to) { - to.clear(); - to.build(from); - } - }; - - template ::value> - struct PathCopySelectorBackward { - static void copy(const From& from, To& to) { - to.clear(); - for (typename From::RevArcIt it(from); it != INVALID; ++it) { - to.addFront(it); - } - } - }; - - template - struct PathCopySelectorBackward { - static void copy(const From& from, To& to) { - to.clear(); - to.buildRev(from); - } - }; - - - template ::value> - struct PathCopySelector { - static void copy(const From& from, To& to) { - PathCopySelectorForward::copy(from, to); - } - }; - - template - struct PathCopySelector { - static void copy(const From& from, To& to) { - PathCopySelectorBackward::copy(from, to); - } - }; - - } - - - /// \brief Make a copy of a path. - /// - /// This function makes a copy of a path. - template - void pathCopy(const From& from, To& to) { - checkConcept, From>(); - _path_bits::PathCopySelector::copy(from, to); - } - - /// \brief Deprecated version of \ref pathCopy(). - /// - /// Deprecated version of \ref pathCopy() (only for reverse compatibility). - template - void copyPath(To& to, const From& from) { - pathCopy(from, to); - } - - /// \brief Check the consistency of a path. - /// - /// This function checks that the target of each arc is the same - /// as the source of the next one. - /// - template - bool checkPath(const Digraph& digraph, const Path& path) { - typename Path::ArcIt it(path); - if (it == INVALID) return true; - typename Digraph::Node node = digraph.target(it); - ++it; - while (it != INVALID) { - if (digraph.source(it) != node) return false; - node = digraph.target(it); - ++it; - } - return true; - } - - /// \brief The source of a path - /// - /// This function returns the source node of the given path. - /// If the path is empty, then it returns \c INVALID. - template - typename Digraph::Node pathSource(const Digraph& digraph, const Path& path) { - return path.empty() ? INVALID : digraph.source(path.front()); - } - - /// \brief The target of a path - /// - /// This function returns the target node of the given path. - /// If the path is empty, then it returns \c INVALID. - template - typename Digraph::Node pathTarget(const Digraph& digraph, const Path& path) { - return path.empty() ? INVALID : digraph.target(path.back()); - } - - /// \brief Class which helps to iterate through the nodes of a path - /// - /// In a sense, the path can be treated as a list of arcs. The - /// LEMON path type stores only this list. As a consequence, it - /// cannot enumerate the nodes in the path and the zero length paths - /// cannot have a source node. - /// - /// This class implements the node iterator of a path structure. To - /// provide this feature, the underlying digraph should be passed to - /// the constructor of the iterator. - template - class PathNodeIt { - private: - const typename Path::Digraph *_digraph; - typename Path::ArcIt _it; - typename Path::Digraph::Node _nd; - - public: - - typedef typename Path::Digraph Digraph; - typedef typename Digraph::Node Node; - - /// Default constructor - PathNodeIt() {} - /// Invalid constructor - PathNodeIt(Invalid) - : _digraph(0), _it(INVALID), _nd(INVALID) {} - /// Constructor - PathNodeIt(const Digraph& digraph, const Path& path) - : _digraph(&digraph), _it(path) { - _nd = (_it != INVALID ? _digraph->source(_it) : INVALID); - } - /// Constructor - PathNodeIt(const Digraph& digraph, const Path& path, const Node& src) - : _digraph(&digraph), _it(path), _nd(src) {} - - ///Conversion to Digraph::Node - operator Node() const { - return _nd; - } - - /// Next node - PathNodeIt& operator++() { - if (_it == INVALID) _nd = INVALID; - else { - _nd = _digraph->target(_it); - ++_it; - } - return *this; - } - - /// Comparison operator - bool operator==(const PathNodeIt& n) const { - return _it == n._it && _nd == n._nd; - } - /// Comparison operator - bool operator!=(const PathNodeIt& n) const { - return _it != n._it || _nd != n._nd; - } - /// Comparison operator - bool operator<(const PathNodeIt& n) const { - return (_it < n._it && _nd != INVALID); - } - - }; - - ///@} - -} // namespace lemon - -#endif // LEMON_PATH_H diff --git a/deps/lemon/lemon/planarity.h b/deps/lemon/lemon/planarity.h deleted file mode 100644 index bfe8e85dc..000000000 --- a/deps/lemon/lemon/planarity.h +++ /dev/null @@ -1,2754 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_PLANARITY_H -#define LEMON_PLANARITY_H - -/// \ingroup planar -/// \file -/// \brief Planarity checking, embedding, drawing and coloring - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace lemon { - - namespace _planarity_bits { - - template - struct PlanarityVisitor : DfsVisitor { - - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - typedef typename Graph::template NodeMap PredMap; - - typedef typename Graph::template EdgeMap TreeMap; - - typedef typename Graph::template NodeMap OrderMap; - typedef std::vector OrderList; - - typedef typename Graph::template NodeMap LowMap; - typedef typename Graph::template NodeMap AncestorMap; - - PlanarityVisitor(const Graph& graph, - PredMap& pred_map, TreeMap& tree_map, - OrderMap& order_map, OrderList& order_list, - AncestorMap& ancestor_map, LowMap& low_map) - : _graph(graph), _pred_map(pred_map), _tree_map(tree_map), - _order_map(order_map), _order_list(order_list), - _ancestor_map(ancestor_map), _low_map(low_map) {} - - void reach(const Node& node) { - _order_map[node] = _order_list.size(); - _low_map[node] = _order_list.size(); - _ancestor_map[node] = _order_list.size(); - _order_list.push_back(node); - } - - void discover(const Arc& arc) { - Node target = _graph.target(arc); - - _tree_map[arc] = true; - _pred_map[target] = arc; - } - - void examine(const Arc& arc) { - Node source = _graph.source(arc); - Node target = _graph.target(arc); - - if (_order_map[target] < _order_map[source] && !_tree_map[arc]) { - if (_low_map[source] > _order_map[target]) { - _low_map[source] = _order_map[target]; - } - if (_ancestor_map[source] > _order_map[target]) { - _ancestor_map[source] = _order_map[target]; - } - } - } - - void backtrack(const Arc& arc) { - Node source = _graph.source(arc); - Node target = _graph.target(arc); - - if (_low_map[source] > _low_map[target]) { - _low_map[source] = _low_map[target]; - } - } - - const Graph& _graph; - PredMap& _pred_map; - TreeMap& _tree_map; - OrderMap& _order_map; - OrderList& _order_list; - AncestorMap& _ancestor_map; - LowMap& _low_map; - }; - - template - struct NodeDataNode { - int prev, next; - int visited; - typename Graph::Arc first; - bool inverted; - }; - - template - struct NodeDataNode { - int prev, next; - int visited; - }; - - template - struct ChildListNode { - typedef typename Graph::Node Node; - Node first; - Node prev, next; - }; - - template - struct ArcListNode { - typename Graph::Arc prev, next; - }; - - template - class PlanarityChecking { - private: - - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - const Graph& _graph; - - private: - - typedef typename Graph::template NodeMap PredMap; - - typedef typename Graph::template EdgeMap TreeMap; - - typedef typename Graph::template NodeMap OrderMap; - typedef std::vector OrderList; - - typedef typename Graph::template NodeMap LowMap; - typedef typename Graph::template NodeMap AncestorMap; - - typedef _planarity_bits::NodeDataNode NodeDataNode; - typedef std::vector NodeData; - - typedef _planarity_bits::ChildListNode ChildListNode; - typedef typename Graph::template NodeMap ChildLists; - - typedef typename Graph::template NodeMap > MergeRoots; - - typedef typename Graph::template NodeMap EmbedArc; - - public: - - PlanarityChecking(const Graph& graph) : _graph(graph) {} - - bool run() { - typedef _planarity_bits::PlanarityVisitor Visitor; - - PredMap pred_map(_graph, INVALID); - TreeMap tree_map(_graph, false); - - OrderMap order_map(_graph, -1); - OrderList order_list; - - AncestorMap ancestor_map(_graph, -1); - LowMap low_map(_graph, -1); - - Visitor visitor(_graph, pred_map, tree_map, - order_map, order_list, ancestor_map, low_map); - DfsVisit visit(_graph, visitor); - visit.run(); - - ChildLists child_lists(_graph); - createChildLists(tree_map, order_map, low_map, child_lists); - - NodeData node_data(2 * order_list.size()); - - EmbedArc embed_arc(_graph, false); - - MergeRoots merge_roots(_graph); - - for (int i = order_list.size() - 1; i >= 0; --i) { - - Node node = order_list[i]; - - Node source = node; - for (OutArcIt e(_graph, node); e != INVALID; ++e) { - Node target = _graph.target(e); - - if (order_map[source] < order_map[target] && tree_map[e]) { - initFace(target, node_data, order_map, order_list); - } - } - - for (OutArcIt e(_graph, node); e != INVALID; ++e) { - Node target = _graph.target(e); - - if (order_map[source] < order_map[target] && !tree_map[e]) { - embed_arc[target] = true; - walkUp(target, source, i, pred_map, low_map, - order_map, order_list, node_data, merge_roots); - } - } - - for (typename MergeRoots::Value::iterator it = - merge_roots[node].begin(); - it != merge_roots[node].end(); ++it) { - int rn = *it; - walkDown(rn, i, node_data, order_list, child_lists, - ancestor_map, low_map, embed_arc, merge_roots); - } - merge_roots[node].clear(); - - for (OutArcIt e(_graph, node); e != INVALID; ++e) { - Node target = _graph.target(e); - - if (order_map[source] < order_map[target] && !tree_map[e]) { - if (embed_arc[target]) { - return false; - } - } - } - } - - return true; - } - - private: - - void createChildLists(const TreeMap& tree_map, const OrderMap& order_map, - const LowMap& low_map, ChildLists& child_lists) { - - for (NodeIt n(_graph); n != INVALID; ++n) { - Node source = n; - - std::vector targets; - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Node target = _graph.target(e); - - if (order_map[source] < order_map[target] && tree_map[e]) { - targets.push_back(target); - } - } - - if (targets.size() == 0) { - child_lists[source].first = INVALID; - } else if (targets.size() == 1) { - child_lists[source].first = targets[0]; - child_lists[targets[0]].prev = INVALID; - child_lists[targets[0]].next = INVALID; - } else { - radixSort(targets.begin(), targets.end(), mapToFunctor(low_map)); - for (int i = 1; i < int(targets.size()); ++i) { - child_lists[targets[i]].prev = targets[i - 1]; - child_lists[targets[i - 1]].next = targets[i]; - } - child_lists[targets.back()].next = INVALID; - child_lists[targets.front()].prev = INVALID; - child_lists[source].first = targets.front(); - } - } - } - - void walkUp(const Node& node, Node root, int rorder, - const PredMap& pred_map, const LowMap& low_map, - const OrderMap& order_map, const OrderList& order_list, - NodeData& node_data, MergeRoots& merge_roots) { - - int na, nb; - bool da, db; - - na = nb = order_map[node]; - da = true; db = false; - - while (true) { - - if (node_data[na].visited == rorder) break; - if (node_data[nb].visited == rorder) break; - - node_data[na].visited = rorder; - node_data[nb].visited = rorder; - - int rn = -1; - - if (na >= int(order_list.size())) { - rn = na; - } else if (nb >= int(order_list.size())) { - rn = nb; - } - - if (rn == -1) { - int nn; - - nn = da ? node_data[na].prev : node_data[na].next; - da = node_data[nn].prev != na; - na = nn; - - nn = db ? node_data[nb].prev : node_data[nb].next; - db = node_data[nn].prev != nb; - nb = nn; - - } else { - - Node rep = order_list[rn - order_list.size()]; - Node parent = _graph.source(pred_map[rep]); - - if (low_map[rep] < rorder) { - merge_roots[parent].push_back(rn); - } else { - merge_roots[parent].push_front(rn); - } - - if (parent != root) { - na = nb = order_map[parent]; - da = true; db = false; - } else { - break; - } - } - } - } - - void walkDown(int rn, int rorder, NodeData& node_data, - OrderList& order_list, ChildLists& child_lists, - AncestorMap& ancestor_map, LowMap& low_map, - EmbedArc& embed_arc, MergeRoots& merge_roots) { - - std::vector > merge_stack; - - for (int di = 0; di < 2; ++di) { - bool rd = di == 0; - int pn = rn; - int n = rd ? node_data[rn].next : node_data[rn].prev; - - while (n != rn) { - - Node node = order_list[n]; - - if (embed_arc[node]) { - - // Merging components on the critical path - while (!merge_stack.empty()) { - - // Component root - int cn = merge_stack.back().first; - bool cd = merge_stack.back().second; - merge_stack.pop_back(); - - // Parent of component - int dn = merge_stack.back().first; - bool dd = merge_stack.back().second; - merge_stack.pop_back(); - - Node parent = order_list[dn]; - - // Erasing from merge_roots - merge_roots[parent].pop_front(); - - Node child = order_list[cn - order_list.size()]; - - // Erasing from child_lists - if (child_lists[child].prev != INVALID) { - child_lists[child_lists[child].prev].next = - child_lists[child].next; - } else { - child_lists[parent].first = child_lists[child].next; - } - - if (child_lists[child].next != INVALID) { - child_lists[child_lists[child].next].prev = - child_lists[child].prev; - } - - // Merging external faces - { - int en = cn; - cn = cd ? node_data[cn].prev : node_data[cn].next; - cd = node_data[cn].next == en; - - } - - if (cd) node_data[cn].next = dn; else node_data[cn].prev = dn; - if (dd) node_data[dn].prev = cn; else node_data[dn].next = cn; - - } - - bool d = pn == node_data[n].prev; - - if (node_data[n].prev == node_data[n].next && - node_data[n].inverted) { - d = !d; - } - - // Embedding arc into external face - if (rd) node_data[rn].next = n; else node_data[rn].prev = n; - if (d) node_data[n].prev = rn; else node_data[n].next = rn; - pn = rn; - - embed_arc[order_list[n]] = false; - } - - if (!merge_roots[node].empty()) { - - bool d = pn == node_data[n].prev; - - merge_stack.push_back(std::make_pair(n, d)); - - int rn = merge_roots[node].front(); - - int xn = node_data[rn].next; - Node xnode = order_list[xn]; - - int yn = node_data[rn].prev; - Node ynode = order_list[yn]; - - bool rd; - if (!external(xnode, rorder, child_lists, - ancestor_map, low_map)) { - rd = true; - } else if (!external(ynode, rorder, child_lists, - ancestor_map, low_map)) { - rd = false; - } else if (pertinent(xnode, embed_arc, merge_roots)) { - rd = true; - } else { - rd = false; - } - - merge_stack.push_back(std::make_pair(rn, rd)); - - pn = rn; - n = rd ? xn : yn; - - } else if (!external(node, rorder, child_lists, - ancestor_map, low_map)) { - int nn = (node_data[n].next != pn ? - node_data[n].next : node_data[n].prev); - - bool nd = n == node_data[nn].prev; - - if (nd) node_data[nn].prev = pn; - else node_data[nn].next = pn; - - if (n == node_data[pn].prev) node_data[pn].prev = nn; - else node_data[pn].next = nn; - - node_data[nn].inverted = - (node_data[nn].prev == node_data[nn].next && nd != rd); - - n = nn; - } - else break; - - } - - if (!merge_stack.empty() || n == rn) { - break; - } - } - } - - void initFace(const Node& node, NodeData& node_data, - const OrderMap& order_map, const OrderList& order_list) { - int n = order_map[node]; - int rn = n + order_list.size(); - - node_data[n].next = node_data[n].prev = rn; - node_data[rn].next = node_data[rn].prev = n; - - node_data[n].visited = order_list.size(); - node_data[rn].visited = order_list.size(); - - } - - bool external(const Node& node, int rorder, - ChildLists& child_lists, AncestorMap& ancestor_map, - LowMap& low_map) { - Node child = child_lists[node].first; - - if (child != INVALID) { - if (low_map[child] < rorder) return true; - } - - if (ancestor_map[node] < rorder) return true; - - return false; - } - - bool pertinent(const Node& node, const EmbedArc& embed_arc, - const MergeRoots& merge_roots) { - return !merge_roots[node].empty() || embed_arc[node]; - } - - }; - - } - - /// \ingroup planar - /// - /// \brief Planarity checking of an undirected simple graph - /// - /// This function implements the Boyer-Myrvold algorithm for - /// planarity checking of an undirected simple graph. It is a simplified - /// version of the PlanarEmbedding algorithm class because neither - /// the embedding nor the Kuratowski subdivisons are computed. - template - bool checkPlanarity(const GR& graph) { - _planarity_bits::PlanarityChecking pc(graph); - return pc.run(); - } - - /// \ingroup planar - /// - /// \brief Planar embedding of an undirected simple graph - /// - /// This class implements the Boyer-Myrvold algorithm for planar - /// embedding of an undirected simple graph. The planar embedding is an - /// ordering of the outgoing edges of the nodes, which is a possible - /// configuration to draw the graph in the plane. If there is not - /// such ordering then the graph contains a K5 (full graph - /// with 5 nodes) or a K3,3 (complete bipartite graph on - /// 3 Red and 3 Blue nodes) subdivision. - /// - /// The current implementation calculates either an embedding or a - /// Kuratowski subdivision. The running time of the algorithm is O(n). - /// - /// \see PlanarDrawing, checkPlanarity() - template - class PlanarEmbedding { - private: - - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - const Graph& _graph; - typename Graph::template ArcMap _embedding; - - typename Graph::template EdgeMap _kuratowski; - - private: - - typedef typename Graph::template NodeMap PredMap; - - typedef typename Graph::template EdgeMap TreeMap; - - typedef typename Graph::template NodeMap OrderMap; - typedef std::vector OrderList; - - typedef typename Graph::template NodeMap LowMap; - typedef typename Graph::template NodeMap AncestorMap; - - typedef _planarity_bits::NodeDataNode NodeDataNode; - typedef std::vector NodeData; - - typedef _planarity_bits::ChildListNode ChildListNode; - typedef typename Graph::template NodeMap ChildLists; - - typedef typename Graph::template NodeMap > MergeRoots; - - typedef typename Graph::template NodeMap EmbedArc; - - typedef _planarity_bits::ArcListNode ArcListNode; - typedef typename Graph::template ArcMap ArcLists; - - typedef typename Graph::template NodeMap FlipMap; - - typedef typename Graph::template NodeMap TypeMap; - - enum IsolatorNodeType { - HIGHX = 6, LOWX = 7, - HIGHY = 8, LOWY = 9, - ROOT = 10, PERTINENT = 11, - INTERNAL = 12 - }; - - public: - - /// \brief The map type for storing the embedding - /// - /// The map type for storing the embedding. - /// \see embeddingMap() - typedef typename Graph::template ArcMap EmbeddingMap; - - /// \brief Constructor - /// - /// Constructor. - /// \pre The graph must be simple, i.e. it should not - /// contain parallel or loop arcs. - PlanarEmbedding(const Graph& graph) - : _graph(graph), _embedding(_graph), _kuratowski(graph, false) {} - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. - /// \param kuratowski If this parameter is set to \c false, then the - /// algorithm does not compute a Kuratowski subdivision. - /// \return \c true if the graph is planar. - bool run(bool kuratowski = true) { - typedef _planarity_bits::PlanarityVisitor Visitor; - - PredMap pred_map(_graph, INVALID); - TreeMap tree_map(_graph, false); - - OrderMap order_map(_graph, -1); - OrderList order_list; - - AncestorMap ancestor_map(_graph, -1); - LowMap low_map(_graph, -1); - - Visitor visitor(_graph, pred_map, tree_map, - order_map, order_list, ancestor_map, low_map); - DfsVisit visit(_graph, visitor); - visit.run(); - - ChildLists child_lists(_graph); - createChildLists(tree_map, order_map, low_map, child_lists); - - NodeData node_data(2 * order_list.size()); - - EmbedArc embed_arc(_graph, INVALID); - - MergeRoots merge_roots(_graph); - - ArcLists arc_lists(_graph); - - FlipMap flip_map(_graph, false); - - for (int i = order_list.size() - 1; i >= 0; --i) { - - Node node = order_list[i]; - - node_data[i].first = INVALID; - - Node source = node; - for (OutArcIt e(_graph, node); e != INVALID; ++e) { - Node target = _graph.target(e); - - if (order_map[source] < order_map[target] && tree_map[e]) { - initFace(target, arc_lists, node_data, - pred_map, order_map, order_list); - } - } - - for (OutArcIt e(_graph, node); e != INVALID; ++e) { - Node target = _graph.target(e); - - if (order_map[source] < order_map[target] && !tree_map[e]) { - embed_arc[target] = e; - walkUp(target, source, i, pred_map, low_map, - order_map, order_list, node_data, merge_roots); - } - } - - for (typename MergeRoots::Value::iterator it = - merge_roots[node].begin(); it != merge_roots[node].end(); ++it) { - int rn = *it; - walkDown(rn, i, node_data, arc_lists, flip_map, order_list, - child_lists, ancestor_map, low_map, embed_arc, merge_roots); - } - merge_roots[node].clear(); - - for (OutArcIt e(_graph, node); e != INVALID; ++e) { - Node target = _graph.target(e); - - if (order_map[source] < order_map[target] && !tree_map[e]) { - if (embed_arc[target] != INVALID) { - if (kuratowski) { - isolateKuratowski(e, node_data, arc_lists, flip_map, - order_map, order_list, pred_map, child_lists, - ancestor_map, low_map, - embed_arc, merge_roots); - } - return false; - } - } - } - } - - for (int i = 0; i < int(order_list.size()); ++i) { - - mergeRemainingFaces(order_list[i], node_data, order_list, order_map, - child_lists, arc_lists); - storeEmbedding(order_list[i], node_data, order_map, pred_map, - arc_lists, flip_map); - } - - return true; - } - - /// \brief Give back the successor of an arc - /// - /// This function gives back the successor of an arc. It makes - /// possible to query the cyclic order of the outgoing arcs from - /// a node. - Arc next(const Arc& arc) const { - return _embedding[arc]; - } - - /// \brief Give back the calculated embedding map - /// - /// This function gives back the calculated embedding map, which - /// contains the successor of each arc in the cyclic order of the - /// outgoing arcs of its source node. - const EmbeddingMap& embeddingMap() const { - return _embedding; - } - - /// \brief Give back \c true if the given edge is in the Kuratowski - /// subdivision - /// - /// This function gives back \c true if the given edge is in the found - /// Kuratowski subdivision. - /// \pre The \c run() function must be called with \c true parameter - /// before using this function. - bool kuratowski(const Edge& edge) const { - return _kuratowski[edge]; - } - - private: - - void createChildLists(const TreeMap& tree_map, const OrderMap& order_map, - const LowMap& low_map, ChildLists& child_lists) { - - for (NodeIt n(_graph); n != INVALID; ++n) { - Node source = n; - - std::vector targets; - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Node target = _graph.target(e); - - if (order_map[source] < order_map[target] && tree_map[e]) { - targets.push_back(target); - } - } - - if (targets.size() == 0) { - child_lists[source].first = INVALID; - } else if (targets.size() == 1) { - child_lists[source].first = targets[0]; - child_lists[targets[0]].prev = INVALID; - child_lists[targets[0]].next = INVALID; - } else { - radixSort(targets.begin(), targets.end(), mapToFunctor(low_map)); - for (int i = 1; i < int(targets.size()); ++i) { - child_lists[targets[i]].prev = targets[i - 1]; - child_lists[targets[i - 1]].next = targets[i]; - } - child_lists[targets.back()].next = INVALID; - child_lists[targets.front()].prev = INVALID; - child_lists[source].first = targets.front(); - } - } - } - - void walkUp(const Node& node, Node root, int rorder, - const PredMap& pred_map, const LowMap& low_map, - const OrderMap& order_map, const OrderList& order_list, - NodeData& node_data, MergeRoots& merge_roots) { - - int na, nb; - bool da, db; - - na = nb = order_map[node]; - da = true; db = false; - - while (true) { - - if (node_data[na].visited == rorder) break; - if (node_data[nb].visited == rorder) break; - - node_data[na].visited = rorder; - node_data[nb].visited = rorder; - - int rn = -1; - - if (na >= int(order_list.size())) { - rn = na; - } else if (nb >= int(order_list.size())) { - rn = nb; - } - - if (rn == -1) { - int nn; - - nn = da ? node_data[na].prev : node_data[na].next; - da = node_data[nn].prev != na; - na = nn; - - nn = db ? node_data[nb].prev : node_data[nb].next; - db = node_data[nn].prev != nb; - nb = nn; - - } else { - - Node rep = order_list[rn - order_list.size()]; - Node parent = _graph.source(pred_map[rep]); - - if (low_map[rep] < rorder) { - merge_roots[parent].push_back(rn); - } else { - merge_roots[parent].push_front(rn); - } - - if (parent != root) { - na = nb = order_map[parent]; - da = true; db = false; - } else { - break; - } - } - } - } - - void walkDown(int rn, int rorder, NodeData& node_data, - ArcLists& arc_lists, FlipMap& flip_map, - OrderList& order_list, ChildLists& child_lists, - AncestorMap& ancestor_map, LowMap& low_map, - EmbedArc& embed_arc, MergeRoots& merge_roots) { - - std::vector > merge_stack; - - for (int di = 0; di < 2; ++di) { - bool rd = di == 0; - int pn = rn; - int n = rd ? node_data[rn].next : node_data[rn].prev; - - while (n != rn) { - - Node node = order_list[n]; - - if (embed_arc[node] != INVALID) { - - // Merging components on the critical path - while (!merge_stack.empty()) { - - // Component root - int cn = merge_stack.back().first; - bool cd = merge_stack.back().second; - merge_stack.pop_back(); - - // Parent of component - int dn = merge_stack.back().first; - bool dd = merge_stack.back().second; - merge_stack.pop_back(); - - Node parent = order_list[dn]; - - // Erasing from merge_roots - merge_roots[parent].pop_front(); - - Node child = order_list[cn - order_list.size()]; - - // Erasing from child_lists - if (child_lists[child].prev != INVALID) { - child_lists[child_lists[child].prev].next = - child_lists[child].next; - } else { - child_lists[parent].first = child_lists[child].next; - } - - if (child_lists[child].next != INVALID) { - child_lists[child_lists[child].next].prev = - child_lists[child].prev; - } - - // Merging arcs + flipping - Arc de = node_data[dn].first; - Arc ce = node_data[cn].first; - - flip_map[order_list[cn - order_list.size()]] = cd != dd; - if (cd != dd) { - std::swap(arc_lists[ce].prev, arc_lists[ce].next); - ce = arc_lists[ce].prev; - std::swap(arc_lists[ce].prev, arc_lists[ce].next); - } - - { - Arc dne = arc_lists[de].next; - Arc cne = arc_lists[ce].next; - - arc_lists[de].next = cne; - arc_lists[ce].next = dne; - - arc_lists[dne].prev = ce; - arc_lists[cne].prev = de; - } - - if (dd) { - node_data[dn].first = ce; - } - - // Merging external faces - { - int en = cn; - cn = cd ? node_data[cn].prev : node_data[cn].next; - cd = node_data[cn].next == en; - - if (node_data[cn].prev == node_data[cn].next && - node_data[cn].inverted) { - cd = !cd; - } - } - - if (cd) node_data[cn].next = dn; else node_data[cn].prev = dn; - if (dd) node_data[dn].prev = cn; else node_data[dn].next = cn; - - } - - bool d = pn == node_data[n].prev; - - if (node_data[n].prev == node_data[n].next && - node_data[n].inverted) { - d = !d; - } - - // Add new arc - { - Arc arc = embed_arc[node]; - Arc re = node_data[rn].first; - - arc_lists[arc_lists[re].next].prev = arc; - arc_lists[arc].next = arc_lists[re].next; - arc_lists[arc].prev = re; - arc_lists[re].next = arc; - - if (!rd) { - node_data[rn].first = arc; - } - - Arc rev = _graph.oppositeArc(arc); - Arc e = node_data[n].first; - - arc_lists[arc_lists[e].next].prev = rev; - arc_lists[rev].next = arc_lists[e].next; - arc_lists[rev].prev = e; - arc_lists[e].next = rev; - - if (d) { - node_data[n].first = rev; - } - - } - - // Embedding arc into external face - if (rd) node_data[rn].next = n; else node_data[rn].prev = n; - if (d) node_data[n].prev = rn; else node_data[n].next = rn; - pn = rn; - - embed_arc[order_list[n]] = INVALID; - } - - if (!merge_roots[node].empty()) { - - bool d = pn == node_data[n].prev; - if (node_data[n].prev == node_data[n].next && - node_data[n].inverted) { - d = !d; - } - - merge_stack.push_back(std::make_pair(n, d)); - - int rn = merge_roots[node].front(); - - int xn = node_data[rn].next; - Node xnode = order_list[xn]; - - int yn = node_data[rn].prev; - Node ynode = order_list[yn]; - - bool rd; - if (!external(xnode, rorder, child_lists, ancestor_map, low_map)) { - rd = true; - } else if (!external(ynode, rorder, child_lists, - ancestor_map, low_map)) { - rd = false; - } else if (pertinent(xnode, embed_arc, merge_roots)) { - rd = true; - } else { - rd = false; - } - - merge_stack.push_back(std::make_pair(rn, rd)); - - pn = rn; - n = rd ? xn : yn; - - } else if (!external(node, rorder, child_lists, - ancestor_map, low_map)) { - int nn = (node_data[n].next != pn ? - node_data[n].next : node_data[n].prev); - - bool nd = n == node_data[nn].prev; - - if (nd) node_data[nn].prev = pn; - else node_data[nn].next = pn; - - if (n == node_data[pn].prev) node_data[pn].prev = nn; - else node_data[pn].next = nn; - - node_data[nn].inverted = - (node_data[nn].prev == node_data[nn].next && nd != rd); - - n = nn; - } - else break; - - } - - if (!merge_stack.empty() || n == rn) { - break; - } - } - } - - void initFace(const Node& node, ArcLists& arc_lists, - NodeData& node_data, const PredMap& pred_map, - const OrderMap& order_map, const OrderList& order_list) { - int n = order_map[node]; - int rn = n + order_list.size(); - - node_data[n].next = node_data[n].prev = rn; - node_data[rn].next = node_data[rn].prev = n; - - node_data[n].visited = order_list.size(); - node_data[rn].visited = order_list.size(); - - node_data[n].inverted = false; - node_data[rn].inverted = false; - - Arc arc = pred_map[node]; - Arc rev = _graph.oppositeArc(arc); - - node_data[rn].first = arc; - node_data[n].first = rev; - - arc_lists[arc].prev = arc; - arc_lists[arc].next = arc; - - arc_lists[rev].prev = rev; - arc_lists[rev].next = rev; - - } - - void mergeRemainingFaces(const Node& node, NodeData& node_data, - OrderList& order_list, OrderMap& order_map, - ChildLists& child_lists, ArcLists& arc_lists) { - while (child_lists[node].first != INVALID) { - int dd = order_map[node]; - Node child = child_lists[node].first; - int cd = order_map[child] + order_list.size(); - child_lists[node].first = child_lists[child].next; - - Arc de = node_data[dd].first; - Arc ce = node_data[cd].first; - - if (de != INVALID) { - Arc dne = arc_lists[de].next; - Arc cne = arc_lists[ce].next; - - arc_lists[de].next = cne; - arc_lists[ce].next = dne; - - arc_lists[dne].prev = ce; - arc_lists[cne].prev = de; - } - - node_data[dd].first = ce; - - } - } - - void storeEmbedding(const Node& node, NodeData& node_data, - OrderMap& order_map, PredMap& pred_map, - ArcLists& arc_lists, FlipMap& flip_map) { - - if (node_data[order_map[node]].first == INVALID) return; - - if (pred_map[node] != INVALID) { - Node source = _graph.source(pred_map[node]); - flip_map[node] = flip_map[node] != flip_map[source]; - } - - Arc first = node_data[order_map[node]].first; - Arc prev = first; - - Arc arc = flip_map[node] ? - arc_lists[prev].prev : arc_lists[prev].next; - - _embedding[prev] = arc; - - while (arc != first) { - Arc next = arc_lists[arc].prev == prev ? - arc_lists[arc].next : arc_lists[arc].prev; - prev = arc; arc = next; - _embedding[prev] = arc; - } - } - - - bool external(const Node& node, int rorder, - ChildLists& child_lists, AncestorMap& ancestor_map, - LowMap& low_map) { - Node child = child_lists[node].first; - - if (child != INVALID) { - if (low_map[child] < rorder) return true; - } - - if (ancestor_map[node] < rorder) return true; - - return false; - } - - bool pertinent(const Node& node, const EmbedArc& embed_arc, - const MergeRoots& merge_roots) { - return !merge_roots[node].empty() || embed_arc[node] != INVALID; - } - - int lowPoint(const Node& node, OrderMap& order_map, ChildLists& child_lists, - AncestorMap& ancestor_map, LowMap& low_map) { - int low_point; - - Node child = child_lists[node].first; - - if (child != INVALID) { - low_point = low_map[child]; - } else { - low_point = order_map[node]; - } - - if (low_point > ancestor_map[node]) { - low_point = ancestor_map[node]; - } - - return low_point; - } - - int findComponentRoot(Node root, Node node, ChildLists& child_lists, - OrderMap& order_map, OrderList& order_list) { - - int order = order_map[root]; - int norder = order_map[node]; - - Node child = child_lists[root].first; - while (child != INVALID) { - int corder = order_map[child]; - if (corder > order && corder < norder) { - order = corder; - } - child = child_lists[child].next; - } - return order + order_list.size(); - } - - Node findPertinent(Node node, OrderMap& order_map, NodeData& node_data, - EmbedArc& embed_arc, MergeRoots& merge_roots) { - Node wnode =_graph.target(node_data[order_map[node]].first); - while (!pertinent(wnode, embed_arc, merge_roots)) { - wnode = _graph.target(node_data[order_map[wnode]].first); - } - return wnode; - } - - - Node findExternal(Node node, int rorder, OrderMap& order_map, - ChildLists& child_lists, AncestorMap& ancestor_map, - LowMap& low_map, NodeData& node_data) { - Node wnode =_graph.target(node_data[order_map[node]].first); - while (!external(wnode, rorder, child_lists, ancestor_map, low_map)) { - wnode = _graph.target(node_data[order_map[wnode]].first); - } - return wnode; - } - - void markCommonPath(Node node, int rorder, Node& wnode, Node& znode, - OrderList& order_list, OrderMap& order_map, - NodeData& node_data, ArcLists& arc_lists, - EmbedArc& embed_arc, MergeRoots& merge_roots, - ChildLists& child_lists, AncestorMap& ancestor_map, - LowMap& low_map) { - - Node cnode = node; - Node pred = INVALID; - - while (true) { - - bool pert = pertinent(cnode, embed_arc, merge_roots); - bool ext = external(cnode, rorder, child_lists, ancestor_map, low_map); - - if (pert && ext) { - if (!merge_roots[cnode].empty()) { - int cn = merge_roots[cnode].back(); - - if (low_map[order_list[cn - order_list.size()]] < rorder) { - Arc arc = node_data[cn].first; - _kuratowski.set(arc, true); - - pred = cnode; - cnode = _graph.target(arc); - - continue; - } - } - wnode = znode = cnode; - return; - - } else if (pert) { - wnode = cnode; - - while (!external(cnode, rorder, child_lists, ancestor_map, low_map)) { - Arc arc = node_data[order_map[cnode]].first; - - if (_graph.target(arc) == pred) { - arc = arc_lists[arc].next; - } - _kuratowski.set(arc, true); - - Node next = _graph.target(arc); - pred = cnode; cnode = next; - } - - znode = cnode; - return; - - } else if (ext) { - znode = cnode; - - while (!pertinent(cnode, embed_arc, merge_roots)) { - Arc arc = node_data[order_map[cnode]].first; - - if (_graph.target(arc) == pred) { - arc = arc_lists[arc].next; - } - _kuratowski.set(arc, true); - - Node next = _graph.target(arc); - pred = cnode; cnode = next; - } - - wnode = cnode; - return; - - } else { - Arc arc = node_data[order_map[cnode]].first; - - if (_graph.target(arc) == pred) { - arc = arc_lists[arc].next; - } - _kuratowski.set(arc, true); - - Node next = _graph.target(arc); - pred = cnode; cnode = next; - } - - } - - } - - void orientComponent(Node root, int rn, OrderMap& order_map, - PredMap& pred_map, NodeData& node_data, - ArcLists& arc_lists, FlipMap& flip_map, - TypeMap& type_map) { - node_data[order_map[root]].first = node_data[rn].first; - type_map[root] = 1; - - std::vector st, qu; - - st.push_back(root); - while (!st.empty()) { - Node node = st.back(); - st.pop_back(); - qu.push_back(node); - - Arc arc = node_data[order_map[node]].first; - - if (type_map[_graph.target(arc)] == 0) { - st.push_back(_graph.target(arc)); - type_map[_graph.target(arc)] = 1; - } - - Arc last = arc, pred = arc; - arc = arc_lists[arc].next; - while (arc != last) { - - if (type_map[_graph.target(arc)] == 0) { - st.push_back(_graph.target(arc)); - type_map[_graph.target(arc)] = 1; - } - - Arc next = arc_lists[arc].next != pred ? - arc_lists[arc].next : arc_lists[arc].prev; - pred = arc; arc = next; - } - - } - - type_map[root] = 2; - flip_map[root] = false; - - for (int i = 1; i < int(qu.size()); ++i) { - - Node node = qu[i]; - - while (type_map[node] != 2) { - st.push_back(node); - type_map[node] = 2; - node = _graph.source(pred_map[node]); - } - - bool flip = flip_map[node]; - - while (!st.empty()) { - node = st.back(); - st.pop_back(); - - flip_map[node] = flip != flip_map[node]; - flip = flip_map[node]; - - if (flip) { - Arc arc = node_data[order_map[node]].first; - std::swap(arc_lists[arc].prev, arc_lists[arc].next); - arc = arc_lists[arc].prev; - std::swap(arc_lists[arc].prev, arc_lists[arc].next); - node_data[order_map[node]].first = arc; - } - } - } - - for (int i = 0; i < int(qu.size()); ++i) { - - Arc arc = node_data[order_map[qu[i]]].first; - Arc last = arc, pred = arc; - - arc = arc_lists[arc].next; - while (arc != last) { - - if (arc_lists[arc].next == pred) { - std::swap(arc_lists[arc].next, arc_lists[arc].prev); - } - pred = arc; arc = arc_lists[arc].next; - } - - } - } - - void setFaceFlags(Node root, Node wnode, Node ynode, Node xnode, - OrderMap& order_map, NodeData& node_data, - TypeMap& type_map) { - Node node = _graph.target(node_data[order_map[root]].first); - - while (node != ynode) { - type_map[node] = HIGHY; - node = _graph.target(node_data[order_map[node]].first); - } - - while (node != wnode) { - type_map[node] = LOWY; - node = _graph.target(node_data[order_map[node]].first); - } - - node = _graph.target(node_data[order_map[wnode]].first); - - while (node != xnode) { - type_map[node] = LOWX; - node = _graph.target(node_data[order_map[node]].first); - } - type_map[node] = LOWX; - - node = _graph.target(node_data[order_map[xnode]].first); - while (node != root) { - type_map[node] = HIGHX; - node = _graph.target(node_data[order_map[node]].first); - } - - type_map[wnode] = PERTINENT; - type_map[root] = ROOT; - } - - void findInternalPath(std::vector& ipath, - Node wnode, Node root, TypeMap& type_map, - OrderMap& order_map, NodeData& node_data, - ArcLists& arc_lists) { - std::vector st; - - Node node = wnode; - - while (node != root) { - Arc arc = arc_lists[node_data[order_map[node]].first].next; - st.push_back(arc); - node = _graph.target(arc); - } - - while (true) { - Arc arc = st.back(); - if (type_map[_graph.target(arc)] == LOWX || - type_map[_graph.target(arc)] == HIGHX) { - break; - } - if (type_map[_graph.target(arc)] == 2) { - type_map[_graph.target(arc)] = 3; - - arc = arc_lists[_graph.oppositeArc(arc)].next; - st.push_back(arc); - } else { - st.pop_back(); - arc = arc_lists[arc].next; - - while (_graph.oppositeArc(arc) == st.back()) { - arc = st.back(); - st.pop_back(); - arc = arc_lists[arc].next; - } - st.push_back(arc); - } - } - - for (int i = 0; i < int(st.size()); ++i) { - if (type_map[_graph.target(st[i])] != LOWY && - type_map[_graph.target(st[i])] != HIGHY) { - for (; i < int(st.size()); ++i) { - ipath.push_back(st[i]); - } - } - } - } - - void setInternalFlags(std::vector& ipath, TypeMap& type_map) { - for (int i = 1; i < int(ipath.size()); ++i) { - type_map[_graph.source(ipath[i])] = INTERNAL; - } - } - - void findPilePath(std::vector& ppath, - Node root, TypeMap& type_map, OrderMap& order_map, - NodeData& node_data, ArcLists& arc_lists) { - std::vector st; - - st.push_back(_graph.oppositeArc(node_data[order_map[root]].first)); - st.push_back(node_data[order_map[root]].first); - - while (st.size() > 1) { - Arc arc = st.back(); - if (type_map[_graph.target(arc)] == INTERNAL) { - break; - } - if (type_map[_graph.target(arc)] == 3) { - type_map[_graph.target(arc)] = 4; - - arc = arc_lists[_graph.oppositeArc(arc)].next; - st.push_back(arc); - } else { - st.pop_back(); - arc = arc_lists[arc].next; - - while (!st.empty() && _graph.oppositeArc(arc) == st.back()) { - arc = st.back(); - st.pop_back(); - arc = arc_lists[arc].next; - } - st.push_back(arc); - } - } - - for (int i = 1; i < int(st.size()); ++i) { - ppath.push_back(st[i]); - } - } - - - int markExternalPath(Node node, OrderMap& order_map, - ChildLists& child_lists, PredMap& pred_map, - AncestorMap& ancestor_map, LowMap& low_map) { - int lp = lowPoint(node, order_map, child_lists, - ancestor_map, low_map); - - if (ancestor_map[node] != lp) { - node = child_lists[node].first; - _kuratowski[pred_map[node]] = true; - - while (ancestor_map[node] != lp) { - for (OutArcIt e(_graph, node); e != INVALID; ++e) { - Node tnode = _graph.target(e); - if (order_map[tnode] > order_map[node] && low_map[tnode] == lp) { - node = tnode; - _kuratowski[e] = true; - break; - } - } - } - } - - for (OutArcIt e(_graph, node); e != INVALID; ++e) { - if (order_map[_graph.target(e)] == lp) { - _kuratowski[e] = true; - break; - } - } - - return lp; - } - - void markPertinentPath(Node node, OrderMap& order_map, - NodeData& node_data, ArcLists& arc_lists, - EmbedArc& embed_arc, MergeRoots& merge_roots) { - while (embed_arc[node] == INVALID) { - int n = merge_roots[node].front(); - Arc arc = node_data[n].first; - - _kuratowski.set(arc, true); - - Node pred = node; - node = _graph.target(arc); - while (!pertinent(node, embed_arc, merge_roots)) { - arc = node_data[order_map[node]].first; - if (_graph.target(arc) == pred) { - arc = arc_lists[arc].next; - } - _kuratowski.set(arc, true); - pred = node; - node = _graph.target(arc); - } - } - _kuratowski.set(embed_arc[node], true); - } - - void markPredPath(Node node, Node snode, PredMap& pred_map) { - while (node != snode) { - _kuratowski.set(pred_map[node], true); - node = _graph.source(pred_map[node]); - } - } - - void markFacePath(Node ynode, Node xnode, - OrderMap& order_map, NodeData& node_data) { - Arc arc = node_data[order_map[ynode]].first; - Node node = _graph.target(arc); - _kuratowski.set(arc, true); - - while (node != xnode) { - arc = node_data[order_map[node]].first; - _kuratowski.set(arc, true); - node = _graph.target(arc); - } - } - - void markInternalPath(std::vector& path) { - for (int i = 0; i < int(path.size()); ++i) { - _kuratowski.set(path[i], true); - } - } - - void markPilePath(std::vector& path) { - for (int i = 0; i < int(path.size()); ++i) { - _kuratowski.set(path[i], true); - } - } - - void isolateKuratowski(Arc arc, NodeData& node_data, - ArcLists& arc_lists, FlipMap& flip_map, - OrderMap& order_map, OrderList& order_list, - PredMap& pred_map, ChildLists& child_lists, - AncestorMap& ancestor_map, LowMap& low_map, - EmbedArc& embed_arc, MergeRoots& merge_roots) { - - Node root = _graph.source(arc); - Node enode = _graph.target(arc); - - int rorder = order_map[root]; - - TypeMap type_map(_graph, 0); - - int rn = findComponentRoot(root, enode, child_lists, - order_map, order_list); - - Node xnode = order_list[node_data[rn].next]; - Node ynode = order_list[node_data[rn].prev]; - - // Minor-A - { - while (!merge_roots[xnode].empty() || !merge_roots[ynode].empty()) { - - if (!merge_roots[xnode].empty()) { - root = xnode; - rn = merge_roots[xnode].front(); - } else { - root = ynode; - rn = merge_roots[ynode].front(); - } - - xnode = order_list[node_data[rn].next]; - ynode = order_list[node_data[rn].prev]; - } - - if (root != _graph.source(arc)) { - orientComponent(root, rn, order_map, pred_map, - node_data, arc_lists, flip_map, type_map); - markFacePath(root, root, order_map, node_data); - int xlp = markExternalPath(xnode, order_map, child_lists, - pred_map, ancestor_map, low_map); - int ylp = markExternalPath(ynode, order_map, child_lists, - pred_map, ancestor_map, low_map); - markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); - Node lwnode = findPertinent(ynode, order_map, node_data, - embed_arc, merge_roots); - - markPertinentPath(lwnode, order_map, node_data, arc_lists, - embed_arc, merge_roots); - - return; - } - } - - orientComponent(root, rn, order_map, pred_map, - node_data, arc_lists, flip_map, type_map); - - Node wnode = findPertinent(ynode, order_map, node_data, - embed_arc, merge_roots); - setFaceFlags(root, wnode, ynode, xnode, order_map, node_data, type_map); - - - //Minor-B - if (!merge_roots[wnode].empty()) { - int cn = merge_roots[wnode].back(); - Node rep = order_list[cn - order_list.size()]; - if (low_map[rep] < rorder) { - markFacePath(root, root, order_map, node_data); - int xlp = markExternalPath(xnode, order_map, child_lists, - pred_map, ancestor_map, low_map); - int ylp = markExternalPath(ynode, order_map, child_lists, - pred_map, ancestor_map, low_map); - - Node lwnode, lznode; - markCommonPath(wnode, rorder, lwnode, lznode, order_list, - order_map, node_data, arc_lists, embed_arc, - merge_roots, child_lists, ancestor_map, low_map); - - markPertinentPath(lwnode, order_map, node_data, arc_lists, - embed_arc, merge_roots); - int zlp = markExternalPath(lznode, order_map, child_lists, - pred_map, ancestor_map, low_map); - - int minlp = xlp < ylp ? xlp : ylp; - if (zlp < minlp) minlp = zlp; - - int maxlp = xlp > ylp ? xlp : ylp; - if (zlp > maxlp) maxlp = zlp; - - markPredPath(order_list[maxlp], order_list[minlp], pred_map); - - return; - } - } - - Node pxnode, pynode; - std::vector ipath; - findInternalPath(ipath, wnode, root, type_map, order_map, - node_data, arc_lists); - setInternalFlags(ipath, type_map); - pynode = _graph.source(ipath.front()); - pxnode = _graph.target(ipath.back()); - - wnode = findPertinent(pynode, order_map, node_data, - embed_arc, merge_roots); - - // Minor-C - { - if (type_map[_graph.source(ipath.front())] == HIGHY) { - if (type_map[_graph.target(ipath.back())] == HIGHX) { - markFacePath(xnode, pxnode, order_map, node_data); - } - markFacePath(root, xnode, order_map, node_data); - markPertinentPath(wnode, order_map, node_data, arc_lists, - embed_arc, merge_roots); - markInternalPath(ipath); - int xlp = markExternalPath(xnode, order_map, child_lists, - pred_map, ancestor_map, low_map); - int ylp = markExternalPath(ynode, order_map, child_lists, - pred_map, ancestor_map, low_map); - markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); - return; - } - - if (type_map[_graph.target(ipath.back())] == HIGHX) { - markFacePath(ynode, root, order_map, node_data); - markPertinentPath(wnode, order_map, node_data, arc_lists, - embed_arc, merge_roots); - markInternalPath(ipath); - int xlp = markExternalPath(xnode, order_map, child_lists, - pred_map, ancestor_map, low_map); - int ylp = markExternalPath(ynode, order_map, child_lists, - pred_map, ancestor_map, low_map); - markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); - return; - } - } - - std::vector ppath; - findPilePath(ppath, root, type_map, order_map, node_data, arc_lists); - - // Minor-D - if (!ppath.empty()) { - markFacePath(ynode, xnode, order_map, node_data); - markPertinentPath(wnode, order_map, node_data, arc_lists, - embed_arc, merge_roots); - markPilePath(ppath); - markInternalPath(ipath); - int xlp = markExternalPath(xnode, order_map, child_lists, - pred_map, ancestor_map, low_map); - int ylp = markExternalPath(ynode, order_map, child_lists, - pred_map, ancestor_map, low_map); - markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); - return; - } - - // Minor-E* - { - - if (!external(wnode, rorder, child_lists, ancestor_map, low_map)) { - Node znode = findExternal(pynode, rorder, order_map, - child_lists, ancestor_map, - low_map, node_data); - - if (type_map[znode] == LOWY) { - markFacePath(root, xnode, order_map, node_data); - markPertinentPath(wnode, order_map, node_data, arc_lists, - embed_arc, merge_roots); - markInternalPath(ipath); - int xlp = markExternalPath(xnode, order_map, child_lists, - pred_map, ancestor_map, low_map); - int zlp = markExternalPath(znode, order_map, child_lists, - pred_map, ancestor_map, low_map); - markPredPath(root, order_list[xlp < zlp ? xlp : zlp], pred_map); - } else { - markFacePath(ynode, root, order_map, node_data); - markPertinentPath(wnode, order_map, node_data, arc_lists, - embed_arc, merge_roots); - markInternalPath(ipath); - int ylp = markExternalPath(ynode, order_map, child_lists, - pred_map, ancestor_map, low_map); - int zlp = markExternalPath(znode, order_map, child_lists, - pred_map, ancestor_map, low_map); - markPredPath(root, order_list[ylp < zlp ? ylp : zlp], pred_map); - } - return; - } - - int xlp = markExternalPath(xnode, order_map, child_lists, - pred_map, ancestor_map, low_map); - int ylp = markExternalPath(ynode, order_map, child_lists, - pred_map, ancestor_map, low_map); - int wlp = markExternalPath(wnode, order_map, child_lists, - pred_map, ancestor_map, low_map); - - if (wlp > xlp && wlp > ylp) { - markFacePath(root, root, order_map, node_data); - markPredPath(root, order_list[xlp < ylp ? xlp : ylp], pred_map); - return; - } - - markInternalPath(ipath); - markPertinentPath(wnode, order_map, node_data, arc_lists, - embed_arc, merge_roots); - - if (xlp > ylp && xlp > wlp) { - markFacePath(root, pynode, order_map, node_data); - markFacePath(wnode, xnode, order_map, node_data); - markPredPath(root, order_list[ylp < wlp ? ylp : wlp], pred_map); - return; - } - - if (ylp > xlp && ylp > wlp) { - markFacePath(pxnode, root, order_map, node_data); - markFacePath(ynode, wnode, order_map, node_data); - markPredPath(root, order_list[xlp < wlp ? xlp : wlp], pred_map); - return; - } - - if (pynode != ynode) { - markFacePath(pxnode, wnode, order_map, node_data); - - int minlp = xlp < ylp ? xlp : ylp; - if (wlp < minlp) minlp = wlp; - - int maxlp = xlp > ylp ? xlp : ylp; - if (wlp > maxlp) maxlp = wlp; - - markPredPath(order_list[maxlp], order_list[minlp], pred_map); - return; - } - - if (pxnode != xnode) { - markFacePath(wnode, pynode, order_map, node_data); - - int minlp = xlp < ylp ? xlp : ylp; - if (wlp < minlp) minlp = wlp; - - int maxlp = xlp > ylp ? xlp : ylp; - if (wlp > maxlp) maxlp = wlp; - - markPredPath(order_list[maxlp], order_list[minlp], pred_map); - return; - } - - markFacePath(root, root, order_map, node_data); - int minlp = xlp < ylp ? xlp : ylp; - if (wlp < minlp) minlp = wlp; - markPredPath(root, order_list[minlp], pred_map); - return; - } - - } - - }; - - namespace _planarity_bits { - - template - void makeConnected(Graph& graph, EmbeddingMap& embedding) { - DfsVisitor null_visitor; - DfsVisit > dfs(graph, null_visitor); - dfs.init(); - - typename Graph::Node u = INVALID; - for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { - if (!dfs.reached(n)) { - dfs.addSource(n); - dfs.start(); - if (u == INVALID) { - u = n; - } else { - typename Graph::Node v = n; - - typename Graph::Arc ue = typename Graph::OutArcIt(graph, u); - typename Graph::Arc ve = typename Graph::OutArcIt(graph, v); - - typename Graph::Arc e = graph.direct(graph.addEdge(u, v), true); - - if (ue != INVALID) { - embedding[e] = embedding[ue]; - embedding[ue] = e; - } else { - embedding[e] = e; - } - - if (ve != INVALID) { - embedding[graph.oppositeArc(e)] = embedding[ve]; - embedding[ve] = graph.oppositeArc(e); - } else { - embedding[graph.oppositeArc(e)] = graph.oppositeArc(e); - } - } - } - } - } - - template - void makeBiNodeConnected(Graph& graph, EmbeddingMap& embedding) { - typename Graph::template ArcMap processed(graph); - - std::vector arcs; - for (typename Graph::ArcIt e(graph); e != INVALID; ++e) { - arcs.push_back(e); - } - - IterableBoolMap visited(graph, false); - - for (int i = 0; i < int(arcs.size()); ++i) { - typename Graph::Arc pp = arcs[i]; - if (processed[pp]) continue; - - typename Graph::Arc e = embedding[graph.oppositeArc(pp)]; - processed[e] = true; - visited.set(graph.source(e), true); - - typename Graph::Arc p = e, l = e; - e = embedding[graph.oppositeArc(e)]; - - while (e != l) { - processed[e] = true; - - if (visited[graph.source(e)]) { - - typename Graph::Arc n = - graph.direct(graph.addEdge(graph.source(p), - graph.target(e)), true); - embedding[n] = p; - embedding[graph.oppositeArc(pp)] = n; - - embedding[graph.oppositeArc(n)] = - embedding[graph.oppositeArc(e)]; - embedding[graph.oppositeArc(e)] = - graph.oppositeArc(n); - - p = n; - e = embedding[graph.oppositeArc(n)]; - } else { - visited.set(graph.source(e), true); - pp = p; - p = e; - e = embedding[graph.oppositeArc(e)]; - } - } - visited.setAll(false); - } - } - - - template - void makeMaxPlanar(Graph& graph, EmbeddingMap& embedding) { - - typename Graph::template NodeMap degree(graph); - - for (typename Graph::NodeIt n(graph); n != INVALID; ++n) { - degree[n] = countIncEdges(graph, n); - } - - typename Graph::template ArcMap processed(graph); - IterableBoolMap visited(graph, false); - - std::vector arcs; - for (typename Graph::ArcIt e(graph); e != INVALID; ++e) { - arcs.push_back(e); - } - - for (int i = 0; i < int(arcs.size()); ++i) { - typename Graph::Arc e = arcs[i]; - - if (processed[e]) continue; - processed[e] = true; - - typename Graph::Arc mine = e; - int mind = degree[graph.source(e)]; - - int face_size = 1; - - typename Graph::Arc l = e; - e = embedding[graph.oppositeArc(e)]; - while (l != e) { - processed[e] = true; - - ++face_size; - - if (degree[graph.source(e)] < mind) { - mine = e; - mind = degree[graph.source(e)]; - } - - e = embedding[graph.oppositeArc(e)]; - } - - if (face_size < 4) { - continue; - } - - typename Graph::Node s = graph.source(mine); - for (typename Graph::OutArcIt e(graph, s); e != INVALID; ++e) { - visited.set(graph.target(e), true); - } - - typename Graph::Arc oppe = INVALID; - - e = embedding[graph.oppositeArc(mine)]; - e = embedding[graph.oppositeArc(e)]; - while (graph.target(e) != s) { - if (visited[graph.source(e)]) { - oppe = e; - break; - } - e = embedding[graph.oppositeArc(e)]; - } - visited.setAll(false); - - if (oppe == INVALID) { - - e = embedding[graph.oppositeArc(mine)]; - typename Graph::Arc pn = mine, p = e; - - e = embedding[graph.oppositeArc(e)]; - while (graph.target(e) != s) { - typename Graph::Arc n = - graph.direct(graph.addEdge(s, graph.source(e)), true); - - embedding[n] = pn; - embedding[graph.oppositeArc(n)] = e; - embedding[graph.oppositeArc(p)] = graph.oppositeArc(n); - - pn = n; - - p = e; - e = embedding[graph.oppositeArc(e)]; - } - - embedding[graph.oppositeArc(e)] = pn; - - } else { - - mine = embedding[graph.oppositeArc(mine)]; - s = graph.source(mine); - oppe = embedding[graph.oppositeArc(oppe)]; - typename Graph::Node t = graph.source(oppe); - - typename Graph::Arc ce = graph.direct(graph.addEdge(s, t), true); - embedding[ce] = mine; - embedding[graph.oppositeArc(ce)] = oppe; - - typename Graph::Arc pn = ce, p = oppe; - e = embedding[graph.oppositeArc(oppe)]; - while (graph.target(e) != s) { - typename Graph::Arc n = - graph.direct(graph.addEdge(s, graph.source(e)), true); - - embedding[n] = pn; - embedding[graph.oppositeArc(n)] = e; - embedding[graph.oppositeArc(p)] = graph.oppositeArc(n); - - pn = n; - - p = e; - e = embedding[graph.oppositeArc(e)]; - - } - embedding[graph.oppositeArc(e)] = pn; - - pn = graph.oppositeArc(ce), p = mine; - e = embedding[graph.oppositeArc(mine)]; - while (graph.target(e) != t) { - typename Graph::Arc n = - graph.direct(graph.addEdge(t, graph.source(e)), true); - - embedding[n] = pn; - embedding[graph.oppositeArc(n)] = e; - embedding[graph.oppositeArc(p)] = graph.oppositeArc(n); - - pn = n; - - p = e; - e = embedding[graph.oppositeArc(e)]; - - } - embedding[graph.oppositeArc(e)] = pn; - } - } - } - - } - - /// \ingroup planar - /// - /// \brief Schnyder's planar drawing algorithm - /// - /// The planar drawing algorithm calculates positions for the nodes - /// in the plane. These coordinates satisfy that if the edges are - /// represented with straight lines, then they will not intersect - /// each other. - /// - /// Scnyder's algorithm embeds the graph on an \c (n-2)x(n-2) size grid, - /// i.e. each node will be located in the \c [0..n-2]x[0..n-2] square. - /// The time complexity of the algorithm is O(n). - /// - /// \see PlanarEmbedding - template - class PlanarDrawing { - public: - - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - /// \brief The point type for storing coordinates - typedef dim2::Point Point; - /// \brief The map type for storing the coordinates of the nodes - typedef typename Graph::template NodeMap PointMap; - - - /// \brief Constructor - /// - /// Constructor - /// \pre The graph must be simple, i.e. it should not - /// contain parallel or loop arcs. - PlanarDrawing(const Graph& graph) - : _graph(graph), _point_map(graph) {} - - private: - - template - void drawing(const AuxGraph& graph, - const AuxEmbeddingMap& next, - PointMap& point_map) { - TEMPLATE_GRAPH_TYPEDEFS(AuxGraph); - - typename AuxGraph::template ArcMap prev(graph); - - for (NodeIt n(graph); n != INVALID; ++n) { - Arc e = OutArcIt(graph, n); - - Arc p = e, l = e; - - e = next[e]; - while (e != l) { - prev[e] = p; - p = e; - e = next[e]; - } - prev[e] = p; - } - - Node anode, bnode, cnode; - - { - Arc e = ArcIt(graph); - anode = graph.source(e); - bnode = graph.target(e); - cnode = graph.target(next[graph.oppositeArc(e)]); - } - - IterableBoolMap proper(graph, false); - typename AuxGraph::template NodeMap conn(graph, -1); - - conn[anode] = conn[bnode] = -2; - { - for (OutArcIt e(graph, anode); e != INVALID; ++e) { - Node m = graph.target(e); - if (conn[m] == -1) { - conn[m] = 1; - } - } - conn[cnode] = 2; - - for (OutArcIt e(graph, bnode); e != INVALID; ++e) { - Node m = graph.target(e); - if (conn[m] == -1) { - conn[m] = 1; - } else if (conn[m] != -2) { - conn[m] += 1; - Arc pe = graph.oppositeArc(e); - if (conn[graph.target(next[pe])] == -2) { - conn[m] -= 1; - } - if (conn[graph.target(prev[pe])] == -2) { - conn[m] -= 1; - } - - proper.set(m, conn[m] == 1); - } - } - } - - - typename AuxGraph::template ArcMap angle(graph, -1); - - while (proper.trueNum() != 0) { - Node n = typename IterableBoolMap::TrueIt(proper); - proper.set(n, false); - conn[n] = -2; - - for (OutArcIt e(graph, n); e != INVALID; ++e) { - Node m = graph.target(e); - if (conn[m] == -1) { - conn[m] = 1; - } else if (conn[m] != -2) { - conn[m] += 1; - Arc pe = graph.oppositeArc(e); - if (conn[graph.target(next[pe])] == -2) { - conn[m] -= 1; - } - if (conn[graph.target(prev[pe])] == -2) { - conn[m] -= 1; - } - - proper.set(m, conn[m] == 1); - } - } - - { - Arc e = OutArcIt(graph, n); - Arc p = e, l = e; - - e = next[e]; - while (e != l) { - - if (conn[graph.target(e)] == -2 && conn[graph.target(p)] == -2) { - Arc f = e; - angle[f] = 0; - f = next[graph.oppositeArc(f)]; - angle[f] = 1; - f = next[graph.oppositeArc(f)]; - angle[f] = 2; - } - - p = e; - e = next[e]; - } - - if (conn[graph.target(e)] == -2 && conn[graph.target(p)] == -2) { - Arc f = e; - angle[f] = 0; - f = next[graph.oppositeArc(f)]; - angle[f] = 1; - f = next[graph.oppositeArc(f)]; - angle[f] = 2; - } - } - } - - typename AuxGraph::template NodeMap apred(graph, INVALID); - typename AuxGraph::template NodeMap bpred(graph, INVALID); - typename AuxGraph::template NodeMap cpred(graph, INVALID); - - typename AuxGraph::template NodeMap apredid(graph, -1); - typename AuxGraph::template NodeMap bpredid(graph, -1); - typename AuxGraph::template NodeMap cpredid(graph, -1); - - for (ArcIt e(graph); e != INVALID; ++e) { - if (angle[e] == angle[next[e]]) { - switch (angle[e]) { - case 2: - apred[graph.target(e)] = graph.source(e); - apredid[graph.target(e)] = graph.id(graph.source(e)); - break; - case 1: - bpred[graph.target(e)] = graph.source(e); - bpredid[graph.target(e)] = graph.id(graph.source(e)); - break; - case 0: - cpred[graph.target(e)] = graph.source(e); - cpredid[graph.target(e)] = graph.id(graph.source(e)); - break; - } - } - } - - cpred[anode] = INVALID; - cpred[bnode] = INVALID; - - std::vector aorder, border, corder; - - { - typename AuxGraph::template NodeMap processed(graph, false); - std::vector st; - for (NodeIt n(graph); n != INVALID; ++n) { - if (!processed[n] && n != bnode && n != cnode) { - st.push_back(n); - processed[n] = true; - Node m = apred[n]; - while (m != INVALID && !processed[m]) { - st.push_back(m); - processed[m] = true; - m = apred[m]; - } - while (!st.empty()) { - aorder.push_back(st.back()); - st.pop_back(); - } - } - } - } - - { - typename AuxGraph::template NodeMap processed(graph, false); - std::vector st; - for (NodeIt n(graph); n != INVALID; ++n) { - if (!processed[n] && n != cnode && n != anode) { - st.push_back(n); - processed[n] = true; - Node m = bpred[n]; - while (m != INVALID && !processed[m]) { - st.push_back(m); - processed[m] = true; - m = bpred[m]; - } - while (!st.empty()) { - border.push_back(st.back()); - st.pop_back(); - } - } - } - } - - { - typename AuxGraph::template NodeMap processed(graph, false); - std::vector st; - for (NodeIt n(graph); n != INVALID; ++n) { - if (!processed[n] && n != anode && n != bnode) { - st.push_back(n); - processed[n] = true; - Node m = cpred[n]; - while (m != INVALID && !processed[m]) { - st.push_back(m); - processed[m] = true; - m = cpred[m]; - } - while (!st.empty()) { - corder.push_back(st.back()); - st.pop_back(); - } - } - } - } - - typename AuxGraph::template NodeMap atree(graph, 0); - for (int i = aorder.size() - 1; i >= 0; --i) { - Node n = aorder[i]; - atree[n] = 1; - for (OutArcIt e(graph, n); e != INVALID; ++e) { - if (apred[graph.target(e)] == n) { - atree[n] += atree[graph.target(e)]; - } - } - } - - typename AuxGraph::template NodeMap btree(graph, 0); - for (int i = border.size() - 1; i >= 0; --i) { - Node n = border[i]; - btree[n] = 1; - for (OutArcIt e(graph, n); e != INVALID; ++e) { - if (bpred[graph.target(e)] == n) { - btree[n] += btree[graph.target(e)]; - } - } - } - - typename AuxGraph::template NodeMap apath(graph, 0); - apath[bnode] = apath[cnode] = 1; - typename AuxGraph::template NodeMap apath_btree(graph, 0); - apath_btree[bnode] = btree[bnode]; - for (int i = 1; i < int(aorder.size()); ++i) { - Node n = aorder[i]; - apath[n] = apath[apred[n]] + 1; - apath_btree[n] = btree[n] + apath_btree[apred[n]]; - } - - typename AuxGraph::template NodeMap bpath_atree(graph, 0); - bpath_atree[anode] = atree[anode]; - for (int i = 1; i < int(border.size()); ++i) { - Node n = border[i]; - bpath_atree[n] = atree[n] + bpath_atree[bpred[n]]; - } - - typename AuxGraph::template NodeMap cpath(graph, 0); - cpath[anode] = cpath[bnode] = 1; - typename AuxGraph::template NodeMap cpath_atree(graph, 0); - cpath_atree[anode] = atree[anode]; - typename AuxGraph::template NodeMap cpath_btree(graph, 0); - cpath_btree[bnode] = btree[bnode]; - for (int i = 1; i < int(corder.size()); ++i) { - Node n = corder[i]; - cpath[n] = cpath[cpred[n]] + 1; - cpath_atree[n] = atree[n] + cpath_atree[cpred[n]]; - cpath_btree[n] = btree[n] + cpath_btree[cpred[n]]; - } - - typename AuxGraph::template NodeMap third(graph); - for (NodeIt n(graph); n != INVALID; ++n) { - point_map[n].x = - bpath_atree[n] + cpath_atree[n] - atree[n] - cpath[n] + 1; - point_map[n].y = - cpath_btree[n] + apath_btree[n] - btree[n] - apath[n] + 1; - } - - } - - public: - - /// \brief Calculate the node positions - /// - /// This function calculates the node positions on the plane. - /// \return \c true if the graph is planar. - bool run() { - PlanarEmbedding pe(_graph); - if (!pe.run()) return false; - - run(pe); - return true; - } - - /// \brief Calculate the node positions according to a - /// combinatorical embedding - /// - /// This function calculates the node positions on the plane. - /// The given \c embedding map should contain a valid combinatorical - /// embedding, i.e. a valid cyclic order of the arcs. - /// It can be computed using PlanarEmbedding. - template - void run(const EmbeddingMap& embedding) { - typedef SmartEdgeSet AuxGraph; - - if (3 * countNodes(_graph) - 6 == countEdges(_graph)) { - drawing(_graph, embedding, _point_map); - return; - } - - AuxGraph aux_graph(_graph); - typename AuxGraph::template ArcMap - aux_embedding(aux_graph); - - { - - typename Graph::template EdgeMap - ref(_graph); - - for (EdgeIt e(_graph); e != INVALID; ++e) { - ref[e] = aux_graph.addEdge(_graph.u(e), _graph.v(e)); - } - - for (EdgeIt e(_graph); e != INVALID; ++e) { - Arc ee = embedding[_graph.direct(e, true)]; - aux_embedding[aux_graph.direct(ref[e], true)] = - aux_graph.direct(ref[ee], _graph.direction(ee)); - ee = embedding[_graph.direct(e, false)]; - aux_embedding[aux_graph.direct(ref[e], false)] = - aux_graph.direct(ref[ee], _graph.direction(ee)); - } - } - _planarity_bits::makeConnected(aux_graph, aux_embedding); - _planarity_bits::makeBiNodeConnected(aux_graph, aux_embedding); - _planarity_bits::makeMaxPlanar(aux_graph, aux_embedding); - drawing(aux_graph, aux_embedding, _point_map); - } - - /// \brief The coordinate of the given node - /// - /// This function returns the coordinate of the given node. - Point operator[](const Node& node) const { - return _point_map[node]; - } - - /// \brief Return the grid embedding in a node map - /// - /// This function returns the grid embedding in a node map of - /// \c dim2::Point coordinates. - const PointMap& coords() const { - return _point_map; - } - - private: - - const Graph& _graph; - PointMap _point_map; - - }; - - namespace _planarity_bits { - - template - class KempeFilter { - public: - typedef typename ColorMap::Key Key; - typedef bool Value; - - KempeFilter(const ColorMap& color_map, - const typename ColorMap::Value& first, - const typename ColorMap::Value& second) - : _color_map(color_map), _first(first), _second(second) {} - - Value operator[](const Key& key) const { - return _color_map[key] == _first || _color_map[key] == _second; - } - - private: - const ColorMap& _color_map; - typename ColorMap::Value _first, _second; - }; - } - - /// \ingroup planar - /// - /// \brief Coloring planar graphs - /// - /// The graph coloring problem is the coloring of the graph nodes - /// so that there are no adjacent nodes with the same color. The - /// planar graphs can always be colored with four colors, which is - /// proved by Appel and Haken. Their proofs provide a quadratic - /// time algorithm for four coloring, but it could not be used to - /// implement an efficient algorithm. The five and six coloring can be - /// made in linear time, but in this class, the five coloring has - /// quadratic worst case time complexity. The two coloring (if - /// possible) is solvable with a graph search algorithm and it is - /// implemented in \ref bipartitePartitions() function in LEMON. To - /// decide whether a planar graph is three colorable is NP-complete. - /// - /// This class contains member functions for calculate colorings - /// with five and six colors. The six coloring algorithm is a simple - /// greedy coloring on the backward minimum outgoing order of nodes. - /// This order can be computed by selecting the node with least - /// outgoing arcs to unprocessed nodes in each phase. This order - /// guarantees that when a node is chosen for coloring it has at - /// most five already colored adjacents. The five coloring algorithm - /// use the same method, but if the greedy approach fails to color - /// with five colors, i.e. the node has five already different - /// colored neighbours, it swaps the colors in one of the connected - /// two colored sets with the Kempe recoloring method. - template - class PlanarColoring { - public: - - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - /// \brief The map type for storing color indices - typedef typename Graph::template NodeMap IndexMap; - /// \brief The map type for storing colors - /// - /// The map type for storing colors. - /// \see Palette, Color - typedef ComposeMap ColorMap; - - /// \brief Constructor - /// - /// Constructor. - /// \pre The graph must be simple, i.e. it should not - /// contain parallel or loop arcs. - PlanarColoring(const Graph& graph) - : _graph(graph), _color_map(graph), _palette(0) { - _palette.add(Color(1,0,0)); - _palette.add(Color(0,1,0)); - _palette.add(Color(0,0,1)); - _palette.add(Color(1,1,0)); - _palette.add(Color(1,0,1)); - _palette.add(Color(0,1,1)); - } - - /// \brief Return the node map of color indices - /// - /// This function returns the node map of color indices. The values are - /// in the range \c [0..4] or \c [0..5] according to the coloring method. - IndexMap colorIndexMap() const { - return _color_map; - } - - /// \brief Return the node map of colors - /// - /// This function returns the node map of colors. The values are among - /// five or six distinct \ref lemon::Color "colors". - ColorMap colorMap() const { - return composeMap(_palette, _color_map); - } - - /// \brief Return the color index of the node - /// - /// This function returns the color index of the given node. The value is - /// in the range \c [0..4] or \c [0..5] according to the coloring method. - int colorIndex(const Node& node) const { - return _color_map[node]; - } - - /// \brief Return the color of the node - /// - /// This function returns the color of the given node. The value is among - /// five or six distinct \ref lemon::Color "colors". - Color color(const Node& node) const { - return _palette[_color_map[node]]; - } - - - /// \brief Calculate a coloring with at most six colors - /// - /// This function calculates a coloring with at most six colors. The time - /// complexity of this variant is linear in the size of the graph. - /// \return \c true if the algorithm could color the graph with six colors. - /// If the algorithm fails, then the graph is not planar. - /// \note This function can return \c true if the graph is not - /// planar, but it can be colored with at most six colors. - bool runSixColoring() { - - typename Graph::template NodeMap heap_index(_graph, -1); - BucketHeap > heap(heap_index); - - for (NodeIt n(_graph); n != INVALID; ++n) { - _color_map[n] = -2; - heap.push(n, countOutArcs(_graph, n)); - } - - std::vector order; - - while (!heap.empty()) { - Node n = heap.top(); - heap.pop(); - _color_map[n] = -1; - order.push_back(n); - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Node t = _graph.runningNode(e); - if (_color_map[t] == -2) { - heap.decrease(t, heap[t] - 1); - } - } - } - - for (int i = order.size() - 1; i >= 0; --i) { - std::vector forbidden(6, false); - for (OutArcIt e(_graph, order[i]); e != INVALID; ++e) { - Node t = _graph.runningNode(e); - if (_color_map[t] != -1) { - forbidden[_color_map[t]] = true; - } - } - for (int k = 0; k < 6; ++k) { - if (!forbidden[k]) { - _color_map[order[i]] = k; - break; - } - } - if (_color_map[order[i]] == -1) { - return false; - } - } - return true; - } - - private: - - bool recolor(const Node& u, const Node& v) { - int ucolor = _color_map[u]; - int vcolor = _color_map[v]; - typedef _planarity_bits::KempeFilter KempeFilter; - KempeFilter filter(_color_map, ucolor, vcolor); - - typedef FilterNodes KempeGraph; - KempeGraph kempe_graph(_graph, filter); - - std::vector comp; - Bfs bfs(kempe_graph); - bfs.init(); - bfs.addSource(u); - while (!bfs.emptyQueue()) { - Node n = bfs.nextNode(); - if (n == v) return false; - comp.push_back(n); - bfs.processNextNode(); - } - - int scolor = ucolor + vcolor; - for (int i = 0; i < static_cast(comp.size()); ++i) { - _color_map[comp[i]] = scolor - _color_map[comp[i]]; - } - - return true; - } - - template - void kempeRecoloring(const Node& node, const EmbeddingMap& embedding) { - std::vector nodes; - nodes.reserve(4); - - for (Arc e = OutArcIt(_graph, node); e != INVALID; e = embedding[e]) { - Node t = _graph.target(e); - if (_color_map[t] != -1) { - nodes.push_back(t); - if (nodes.size() == 4) break; - } - } - - int color = _color_map[nodes[0]]; - if (recolor(nodes[0], nodes[2])) { - _color_map[node] = color; - } else { - color = _color_map[nodes[1]]; - recolor(nodes[1], nodes[3]); - _color_map[node] = color; - } - } - - public: - - /// \brief Calculate a coloring with at most five colors - /// - /// This function calculates a coloring with at most five - /// colors. The worst case time complexity of this variant is - /// quadratic in the size of the graph. - /// \param embedding This map should contain a valid combinatorical - /// embedding, i.e. a valid cyclic order of the arcs. - /// It can be computed using PlanarEmbedding. - template - void runFiveColoring(const EmbeddingMap& embedding) { - - typename Graph::template NodeMap heap_index(_graph, -1); - BucketHeap > heap(heap_index); - - for (NodeIt n(_graph); n != INVALID; ++n) { - _color_map[n] = -2; - heap.push(n, countOutArcs(_graph, n)); - } - - std::vector order; - - while (!heap.empty()) { - Node n = heap.top(); - heap.pop(); - _color_map[n] = -1; - order.push_back(n); - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Node t = _graph.runningNode(e); - if (_color_map[t] == -2) { - heap.decrease(t, heap[t] - 1); - } - } - } - - for (int i = order.size() - 1; i >= 0; --i) { - std::vector forbidden(5, false); - for (OutArcIt e(_graph, order[i]); e != INVALID; ++e) { - Node t = _graph.runningNode(e); - if (_color_map[t] != -1) { - forbidden[_color_map[t]] = true; - } - } - for (int k = 0; k < 5; ++k) { - if (!forbidden[k]) { - _color_map[order[i]] = k; - break; - } - } - if (_color_map[order[i]] == -1) { - kempeRecoloring(order[i], embedding); - } - } - } - - /// \brief Calculate a coloring with at most five colors - /// - /// This function calculates a coloring with at most five - /// colors. The worst case time complexity of this variant is - /// quadratic in the size of the graph. - /// \return \c true if the graph is planar. - bool runFiveColoring() { - PlanarEmbedding pe(_graph); - if (!pe.run()) return false; - - runFiveColoring(pe.embeddingMap()); - return true; - } - - private: - - const Graph& _graph; - IndexMap _color_map; - Palette _palette; - }; - -} - -#endif diff --git a/deps/lemon/lemon/preflow.h b/deps/lemon/lemon/preflow.h deleted file mode 100644 index 28ccd67dc..000000000 --- a/deps/lemon/lemon/preflow.h +++ /dev/null @@ -1,985 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_PREFLOW_H -#define LEMON_PREFLOW_H - -#include -#include - -/// \file -/// \ingroup max_flow -/// \brief Implementation of the preflow algorithm. - -namespace lemon { - - /// \brief Default traits class of Preflow class. - /// - /// Default traits class of Preflow class. - /// \tparam GR Digraph type. - /// \tparam CAP Capacity map type. - template - struct PreflowDefaultTraits { - - /// \brief The type of the digraph the algorithm runs on. - typedef GR Digraph; - - /// \brief The type of the map that stores the arc capacities. - /// - /// The type of the map that stores the arc capacities. - /// It must meet the \ref concepts::ReadMap "ReadMap" concept. - typedef CAP CapacityMap; - - /// \brief The type of the flow values. - typedef typename CapacityMap::Value Value; - - /// \brief The type of the map that stores the flow values. - /// - /// The type of the map that stores the flow values. - /// It must meet the \ref concepts::ReadWriteMap "ReadWriteMap" concept. -#ifdef DOXYGEN - typedef GR::ArcMap FlowMap; -#else - typedef typename Digraph::template ArcMap FlowMap; -#endif - - /// \brief Instantiates a FlowMap. - /// - /// This function instantiates a \ref FlowMap. - /// \param digraph The digraph for which we would like to define - /// the flow map. - static FlowMap* createFlowMap(const Digraph& digraph) { - return new FlowMap(digraph); - } - - /// \brief The elevator type used by Preflow algorithm. - /// - /// The elevator type used by Preflow algorithm. - /// - /// \sa Elevator, LinkedElevator -#ifdef DOXYGEN - typedef lemon::Elevator Elevator; -#else - typedef lemon::Elevator Elevator; -#endif - - /// \brief Instantiates an Elevator. - /// - /// This function instantiates an \ref Elevator. - /// \param digraph The digraph for which we would like to define - /// the elevator. - /// \param max_level The maximum level of the elevator. - static Elevator* createElevator(const Digraph& digraph, int max_level) { - return new Elevator(digraph, max_level); - } - - /// \brief The tolerance used by the algorithm - /// - /// The tolerance used by the algorithm to handle inexact computation. - typedef lemon::Tolerance Tolerance; - - }; - - - /// \ingroup max_flow - /// - /// \brief %Preflow algorithm class. - /// - /// This class provides an implementation of Goldberg-Tarjan's \e preflow - /// \e push-relabel algorithm producing a \ref max_flow - /// "flow of maximum value" in a digraph \cite clrs01algorithms, - /// \cite amo93networkflows, \cite goldberg88newapproach. - /// The preflow algorithms are the fastest known maximum - /// flow algorithms. The current implementation uses a mixture of the - /// \e "highest label" and the \e "bound decrease" heuristics. - /// The worst case time complexity of the algorithm is \f$O(n^2\sqrt{m})\f$. - /// - /// The algorithm consists of two phases. After the first phase - /// the maximum flow value and the minimum cut is obtained. The - /// second phase constructs a feasible maximum flow on each arc. - /// - /// \warning This implementation cannot handle infinite or very large - /// capacities (e.g. the maximum value of \c CAP::Value). - /// - /// \tparam GR The type of the digraph the algorithm runs on. - /// \tparam CAP The type of the capacity map. The default map - /// type is \ref concepts::Digraph::ArcMap "GR::ArcMap". - /// \tparam TR The traits class that defines various types used by the - /// algorithm. By default, it is \ref PreflowDefaultTraits - /// "PreflowDefaultTraits". - /// In most cases, this parameter should not be set directly, - /// consider to use the named template parameters instead. -#ifdef DOXYGEN - template -#else - template , - typename TR = PreflowDefaultTraits > -#endif - class Preflow { - public: - - ///The \ref lemon::PreflowDefaultTraits "traits class" of the algorithm. - typedef TR Traits; - ///The type of the digraph the algorithm runs on. - typedef typename Traits::Digraph Digraph; - ///The type of the capacity map. - typedef typename Traits::CapacityMap CapacityMap; - ///The type of the flow values. - typedef typename Traits::Value Value; - - ///The type of the flow map. - typedef typename Traits::FlowMap FlowMap; - ///The type of the elevator. - typedef typename Traits::Elevator Elevator; - ///The type of the tolerance. - typedef typename Traits::Tolerance Tolerance; - - private: - - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - const Digraph& _graph; - const CapacityMap* _capacity; - - int _node_num; - - Node _source, _target; - - FlowMap* _flow; - bool _local_flow; - - Elevator* _level; - bool _local_level; - - typedef typename Digraph::template NodeMap ExcessMap; - ExcessMap* _excess; - - Tolerance _tolerance; - - bool _phase; - - - void createStructures() { - _node_num = countNodes(_graph); - - if (!_flow) { - _flow = Traits::createFlowMap(_graph); - _local_flow = true; - } - if (!_level) { - _level = Traits::createElevator(_graph, _node_num); - _local_level = true; - } - if (!_excess) { - _excess = new ExcessMap(_graph); - } - } - - void destroyStructures() { - if (_local_flow) { - delete _flow; - } - if (_local_level) { - delete _level; - } - if (_excess) { - delete _excess; - } - } - - public: - - typedef Preflow Create; - - ///\name Named Template Parameters - - ///@{ - - template - struct SetFlowMapTraits : public Traits { - typedef T FlowMap; - static FlowMap *createFlowMap(const Digraph&) { - LEMON_ASSERT(false, "FlowMap is not initialized"); - return 0; // ignore warnings - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// FlowMap type - /// - /// \ref named-templ-param "Named parameter" for setting FlowMap - /// type. - template - struct SetFlowMap - : public Preflow > { - typedef Preflow > Create; - }; - - template - struct SetElevatorTraits : public Traits { - typedef T Elevator; - static Elevator *createElevator(const Digraph&, int) { - LEMON_ASSERT(false, "Elevator is not initialized"); - return 0; // ignore warnings - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// Elevator type - /// - /// \ref named-templ-param "Named parameter" for setting Elevator - /// type. If this named parameter is used, then an external - /// elevator object must be passed to the algorithm using the - /// \ref elevator(Elevator&) "elevator()" function before calling - /// \ref run() or \ref init(). - /// \sa SetStandardElevator - template - struct SetElevator - : public Preflow > { - typedef Preflow > Create; - }; - - template - struct SetStandardElevatorTraits : public Traits { - typedef T Elevator; - static Elevator *createElevator(const Digraph& digraph, int max_level) { - return new Elevator(digraph, max_level); - } - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// Elevator type with automatic allocation - /// - /// \ref named-templ-param "Named parameter" for setting Elevator - /// type with automatic allocation. - /// The Elevator should have standard constructor interface to be - /// able to automatically created by the algorithm (i.e. the - /// digraph and the maximum level should be passed to it). - /// However, an external elevator object could also be passed to the - /// algorithm with the \ref elevator(Elevator&) "elevator()" function - /// before calling \ref run() or \ref init(). - /// \sa SetElevator - template - struct SetStandardElevator - : public Preflow > { - typedef Preflow > Create; - }; - - /// @} - - protected: - - Preflow() {} - - public: - - - /// \brief The constructor of the class. - /// - /// The constructor of the class. - /// \param digraph The digraph the algorithm runs on. - /// \param capacity The capacity of the arcs. - /// \param source The source node. - /// \param target The target node. - Preflow(const Digraph& digraph, const CapacityMap& capacity, - Node source, Node target) - : _graph(digraph), _capacity(&capacity), - _node_num(0), _source(source), _target(target), - _flow(0), _local_flow(false), - _level(0), _local_level(false), - _excess(0), _tolerance(), _phase() {} - - /// \brief Destructor. - /// - /// Destructor. - ~Preflow() { - destroyStructures(); - } - - /// \brief Sets the capacity map. - /// - /// Sets the capacity map. - /// \return (*this) - Preflow& capacityMap(const CapacityMap& map) { - _capacity = ↦ - return *this; - } - - /// \brief Sets the flow map. - /// - /// Sets the flow map. - /// If you don't use this function before calling \ref run() or - /// \ref init(), an instance will be allocated automatically. - /// The destructor deallocates this automatically allocated map, - /// of course. - /// \return (*this) - Preflow& flowMap(FlowMap& map) { - if (_local_flow) { - delete _flow; - _local_flow = false; - } - _flow = ↦ - return *this; - } - - /// \brief Sets the source node. - /// - /// Sets the source node. - /// \return (*this) - Preflow& source(const Node& node) { - _source = node; - return *this; - } - - /// \brief Sets the target node. - /// - /// Sets the target node. - /// \return (*this) - Preflow& target(const Node& node) { - _target = node; - return *this; - } - - /// \brief Sets the elevator used by algorithm. - /// - /// Sets the elevator used by algorithm. - /// If you don't use this function before calling \ref run() or - /// \ref init(), an instance will be allocated automatically. - /// The destructor deallocates this automatically allocated elevator, - /// of course. - /// \return (*this) - Preflow& elevator(Elevator& elevator) { - if (_local_level) { - delete _level; - _local_level = false; - } - _level = &elevator; - return *this; - } - - /// \brief Returns a const reference to the elevator. - /// - /// Returns a const reference to the elevator. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - const Elevator& elevator() const { - return *_level; - } - - /// \brief Sets the tolerance used by the algorithm. - /// - /// Sets the tolerance object used by the algorithm. - /// \return (*this) - Preflow& tolerance(const Tolerance& tolerance) { - _tolerance = tolerance; - return *this; - } - - /// \brief Returns a const reference to the tolerance. - /// - /// Returns a const reference to the tolerance object used by - /// the algorithm. - const Tolerance& tolerance() const { - return _tolerance; - } - - /// \name Execution Control - /// The simplest way to execute the preflow algorithm is to use - /// \ref run() or \ref runMinCut().\n - /// If you need better control on the initial solution or the execution, - /// you have to call one of the \ref init() functions first, then - /// \ref startFirstPhase() and if you need it \ref startSecondPhase(). - - ///@{ - - /// \brief Initializes the internal data structures. - /// - /// Initializes the internal data structures and sets the initial - /// flow to zero on each arc. - void init() { - createStructures(); - - _phase = true; - for (NodeIt n(_graph); n != INVALID; ++n) { - (*_excess)[n] = 0; - } - - for (ArcIt e(_graph); e != INVALID; ++e) { - _flow->set(e, 0); - } - - typename Digraph::template NodeMap reached(_graph, false); - - _level->initStart(); - _level->initAddItem(_target); - - std::vector queue; - reached[_source] = true; - - queue.push_back(_target); - reached[_target] = true; - while (!queue.empty()) { - _level->initNewLevel(); - std::vector nqueue; - for (int i = 0; i < int(queue.size()); ++i) { - Node n = queue[i]; - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Node u = _graph.source(e); - if (!reached[u] && _tolerance.positive((*_capacity)[e])) { - reached[u] = true; - _level->initAddItem(u); - nqueue.push_back(u); - } - } - } - queue.swap(nqueue); - } - _level->initFinish(); - - for (OutArcIt e(_graph, _source); e != INVALID; ++e) { - if (_tolerance.positive((*_capacity)[e])) { - Node u = _graph.target(e); - if ((*_level)[u] == _level->maxLevel()) continue; - _flow->set(e, (*_capacity)[e]); - (*_excess)[u] += (*_capacity)[e]; - if (u != _target && !_level->active(u)) { - _level->activate(u); - } - } - } - } - - /// \brief Initializes the internal data structures using the - /// given flow map. - /// - /// Initializes the internal data structures and sets the initial - /// flow to the given \c flowMap. The \c flowMap should contain a - /// flow or at least a preflow, i.e. at each node excluding the - /// source node the incoming flow should greater or equal to the - /// outgoing flow. - /// \return \c false if the given \c flowMap is not a preflow. - template - bool init(const FlowMap& flowMap) { - createStructures(); - - for (ArcIt e(_graph); e != INVALID; ++e) { - _flow->set(e, flowMap[e]); - } - - for (NodeIt n(_graph); n != INVALID; ++n) { - Value excess = 0; - for (InArcIt e(_graph, n); e != INVALID; ++e) { - excess += (*_flow)[e]; - } - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - excess -= (*_flow)[e]; - } - if (excess < 0 && n != _source) return false; - (*_excess)[n] = excess; - } - - typename Digraph::template NodeMap reached(_graph, false); - - _level->initStart(); - _level->initAddItem(_target); - - std::vector queue; - reached[_source] = true; - - queue.push_back(_target); - reached[_target] = true; - while (!queue.empty()) { - _level->initNewLevel(); - std::vector nqueue; - for (int i = 0; i < int(queue.size()); ++i) { - Node n = queue[i]; - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Node u = _graph.source(e); - if (!reached[u] && - _tolerance.positive((*_capacity)[e] - (*_flow)[e])) { - reached[u] = true; - _level->initAddItem(u); - nqueue.push_back(u); - } - } - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.target(e); - if (!reached[v] && _tolerance.positive((*_flow)[e])) { - reached[v] = true; - _level->initAddItem(v); - nqueue.push_back(v); - } - } - } - queue.swap(nqueue); - } - _level->initFinish(); - - for (OutArcIt e(_graph, _source); e != INVALID; ++e) { - Value rem = (*_capacity)[e] - (*_flow)[e]; - if (_tolerance.positive(rem)) { - Node u = _graph.target(e); - if ((*_level)[u] == _level->maxLevel()) continue; - _flow->set(e, (*_capacity)[e]); - (*_excess)[u] += rem; - } - } - for (InArcIt e(_graph, _source); e != INVALID; ++e) { - Value rem = (*_flow)[e]; - if (_tolerance.positive(rem)) { - Node v = _graph.source(e); - if ((*_level)[v] == _level->maxLevel()) continue; - _flow->set(e, 0); - (*_excess)[v] += rem; - } - } - for (NodeIt n(_graph); n != INVALID; ++n) - if(n!=_source && n!=_target && _tolerance.positive((*_excess)[n])) - _level->activate(n); - - return true; - } - - /// \brief Starts the first phase of the preflow algorithm. - /// - /// The preflow algorithm consists of two phases, this method runs - /// the first phase. After the first phase the maximum flow value - /// and a minimum value cut can already be computed, although a - /// maximum flow is not yet obtained. So after calling this method - /// \ref flowValue() returns the value of a maximum flow and \ref - /// minCut() returns a minimum cut. - /// \pre One of the \ref init() functions must be called before - /// using this function. - void startFirstPhase() { - _phase = true; - - while (true) { - int num = _node_num; - - Node n = INVALID; - int level = -1; - - while (num > 0) { - n = _level->highestActive(); - if (n == INVALID) goto first_phase_done; - level = _level->highestActiveLevel(); - --num; - - Value excess = (*_excess)[n]; - int new_level = _level->maxLevel(); - - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Value rem = (*_capacity)[e] - (*_flow)[e]; - if (!_tolerance.positive(rem)) continue; - Node v = _graph.target(e); - if ((*_level)[v] < level) { - if (!_level->active(v) && v != _target) { - _level->activate(v); - } - if (!_tolerance.less(rem, excess)) { - _flow->set(e, (*_flow)[e] + excess); - (*_excess)[v] += excess; - excess = 0; - goto no_more_push_1; - } else { - excess -= rem; - (*_excess)[v] += rem; - _flow->set(e, (*_capacity)[e]); - } - } else if (new_level > (*_level)[v]) { - new_level = (*_level)[v]; - } - } - - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Value rem = (*_flow)[e]; - if (!_tolerance.positive(rem)) continue; - Node v = _graph.source(e); - if ((*_level)[v] < level) { - if (!_level->active(v) && v != _target) { - _level->activate(v); - } - if (!_tolerance.less(rem, excess)) { - _flow->set(e, (*_flow)[e] - excess); - (*_excess)[v] += excess; - excess = 0; - goto no_more_push_1; - } else { - excess -= rem; - (*_excess)[v] += rem; - _flow->set(e, 0); - } - } else if (new_level > (*_level)[v]) { - new_level = (*_level)[v]; - } - } - - no_more_push_1: - - (*_excess)[n] = excess; - - if (excess != 0) { - if (new_level + 1 < _level->maxLevel()) { - _level->liftHighestActive(new_level + 1); - } else { - _level->liftHighestActiveToTop(); - } - if (_level->emptyLevel(level)) { - _level->liftToTop(level); - } - } else { - _level->deactivate(n); - } - } - - num = _node_num * 20; - while (num > 0) { - while (level >= 0 && _level->activeFree(level)) { - --level; - } - if (level == -1) { - n = _level->highestActive(); - level = _level->highestActiveLevel(); - if (n == INVALID) goto first_phase_done; - } else { - n = _level->activeOn(level); - } - --num; - - Value excess = (*_excess)[n]; - int new_level = _level->maxLevel(); - - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Value rem = (*_capacity)[e] - (*_flow)[e]; - if (!_tolerance.positive(rem)) continue; - Node v = _graph.target(e); - if ((*_level)[v] < level) { - if (!_level->active(v) && v != _target) { - _level->activate(v); - } - if (!_tolerance.less(rem, excess)) { - _flow->set(e, (*_flow)[e] + excess); - (*_excess)[v] += excess; - excess = 0; - goto no_more_push_2; - } else { - excess -= rem; - (*_excess)[v] += rem; - _flow->set(e, (*_capacity)[e]); - } - } else if (new_level > (*_level)[v]) { - new_level = (*_level)[v]; - } - } - - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Value rem = (*_flow)[e]; - if (!_tolerance.positive(rem)) continue; - Node v = _graph.source(e); - if ((*_level)[v] < level) { - if (!_level->active(v) && v != _target) { - _level->activate(v); - } - if (!_tolerance.less(rem, excess)) { - _flow->set(e, (*_flow)[e] - excess); - (*_excess)[v] += excess; - excess = 0; - goto no_more_push_2; - } else { - excess -= rem; - (*_excess)[v] += rem; - _flow->set(e, 0); - } - } else if (new_level > (*_level)[v]) { - new_level = (*_level)[v]; - } - } - - no_more_push_2: - - (*_excess)[n] = excess; - - if (excess != 0) { - if (new_level + 1 < _level->maxLevel()) { - _level->liftActiveOn(level, new_level + 1); - } else { - _level->liftActiveToTop(level); - } - if (_level->emptyLevel(level)) { - _level->liftToTop(level); - } - } else { - _level->deactivate(n); - } - } - } - first_phase_done:; - } - - /// \brief Starts the second phase of the preflow algorithm. - /// - /// The preflow algorithm consists of two phases, this method runs - /// the second phase. After calling one of the \ref init() functions - /// and \ref startFirstPhase() and then \ref startSecondPhase(), - /// \ref flowMap() returns a maximum flow, \ref flowValue() returns the - /// value of a maximum flow, \ref minCut() returns a minimum cut - /// \pre One of the \ref init() functions and \ref startFirstPhase() - /// must be called before using this function. - void startSecondPhase() { - _phase = false; - - typename Digraph::template NodeMap reached(_graph); - for (NodeIt n(_graph); n != INVALID; ++n) { - reached[n] = (*_level)[n] < _level->maxLevel(); - } - - _level->initStart(); - _level->initAddItem(_source); - - std::vector queue; - queue.push_back(_source); - reached[_source] = true; - - while (!queue.empty()) { - _level->initNewLevel(); - std::vector nqueue; - for (int i = 0; i < int(queue.size()); ++i) { - Node n = queue[i]; - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Node v = _graph.target(e); - if (!reached[v] && _tolerance.positive((*_flow)[e])) { - reached[v] = true; - _level->initAddItem(v); - nqueue.push_back(v); - } - } - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Node u = _graph.source(e); - if (!reached[u] && - _tolerance.positive((*_capacity)[e] - (*_flow)[e])) { - reached[u] = true; - _level->initAddItem(u); - nqueue.push_back(u); - } - } - } - queue.swap(nqueue); - } - _level->initFinish(); - - for (NodeIt n(_graph); n != INVALID; ++n) { - if (!reached[n]) { - _level->dirtyTopButOne(n); - } else if ((*_excess)[n] > 0 && _target != n) { - _level->activate(n); - } - } - - Node n; - while ((n = _level->highestActive()) != INVALID) { - Value excess = (*_excess)[n]; - int level = _level->highestActiveLevel(); - int new_level = _level->maxLevel(); - - for (OutArcIt e(_graph, n); e != INVALID; ++e) { - Value rem = (*_capacity)[e] - (*_flow)[e]; - if (!_tolerance.positive(rem)) continue; - Node v = _graph.target(e); - if ((*_level)[v] < level) { - if (!_level->active(v) && v != _source) { - _level->activate(v); - } - if (!_tolerance.less(rem, excess)) { - _flow->set(e, (*_flow)[e] + excess); - (*_excess)[v] += excess; - excess = 0; - goto no_more_push; - } else { - excess -= rem; - (*_excess)[v] += rem; - _flow->set(e, (*_capacity)[e]); - } - } else if (new_level > (*_level)[v]) { - new_level = (*_level)[v]; - } - } - - for (InArcIt e(_graph, n); e != INVALID; ++e) { - Value rem = (*_flow)[e]; - if (!_tolerance.positive(rem)) continue; - Node v = _graph.source(e); - if ((*_level)[v] < level) { - if (!_level->active(v) && v != _source) { - _level->activate(v); - } - if (!_tolerance.less(rem, excess)) { - _flow->set(e, (*_flow)[e] - excess); - (*_excess)[v] += excess; - excess = 0; - goto no_more_push; - } else { - excess -= rem; - (*_excess)[v] += rem; - _flow->set(e, 0); - } - } else if (new_level > (*_level)[v]) { - new_level = (*_level)[v]; - } - } - - no_more_push: - - (*_excess)[n] = excess; - - if (excess != 0) { - if (new_level + 1 < _level->maxLevel()) { - _level->liftHighestActive(new_level + 1); - } else { - // Calculation error - _level->liftHighestActiveToTop(); - } - if (_level->emptyLevel(level)) { - // Calculation error - _level->liftToTop(level); - } - } else { - _level->deactivate(n); - } - - } - } - - /// \brief Runs the preflow algorithm. - /// - /// Runs the preflow algorithm. - /// \note pf.run() is just a shortcut of the following code. - /// \code - /// pf.init(); - /// pf.startFirstPhase(); - /// pf.startSecondPhase(); - /// \endcode - void run() { - init(); - startFirstPhase(); - startSecondPhase(); - } - - /// \brief Runs the preflow algorithm to compute the minimum cut. - /// - /// Runs the preflow algorithm to compute the minimum cut. - /// \note pf.runMinCut() is just a shortcut of the following code. - /// \code - /// pf.init(); - /// pf.startFirstPhase(); - /// \endcode - void runMinCut() { - init(); - startFirstPhase(); - } - - /// @} - - /// \name Query Functions - /// The results of the preflow algorithm can be obtained using these - /// functions.\n - /// Either one of the \ref run() "run*()" functions or one of the - /// \ref startFirstPhase() "start*()" functions should be called - /// before using them. - - ///@{ - - /// \brief Returns the value of the maximum flow. - /// - /// Returns the value of the maximum flow by returning the excess - /// of the target node. This value equals to the value of - /// the maximum flow already after the first phase of the algorithm. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - Value flowValue() const { - return (*_excess)[_target]; - } - - /// \brief Returns the flow value on the given arc. - /// - /// Returns the flow value on the given arc. This method can - /// be called after the second phase of the algorithm. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - Value flow(const Arc& arc) const { - return (*_flow)[arc]; - } - - /// \brief Returns a const reference to the flow map. - /// - /// Returns a const reference to the arc map storing the found flow. - /// This method can be called after the second phase of the algorithm. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - const FlowMap& flowMap() const { - return *_flow; - } - - /// \brief Returns \c true when the node is on the source side of the - /// minimum cut. - /// - /// Returns true when the node is on the source side of the found - /// minimum cut. This method can be called both after running \ref - /// startFirstPhase() and \ref startSecondPhase(). - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - bool minCut(const Node& node) const { - return ((*_level)[node] == _level->maxLevel()) == _phase; - } - - /// \brief Gives back a minimum value cut. - /// - /// Sets \c cutMap to the characteristic vector of a minimum value - /// cut. \c cutMap should be a \ref concepts::WriteMap "writable" - /// node map with \c bool (or convertible) value type. - /// - /// This method can be called both after running \ref startFirstPhase() - /// and \ref startSecondPhase(). The result after the second phase - /// could be slightly different if inexact computation is used. - /// - /// \note This function calls \ref minCut() for each node, so it runs in - /// O(n) time. - /// - /// \pre Either \ref run() or \ref init() must be called before - /// using this function. - template - void minCutMap(CutMap& cutMap) const { - for (NodeIt n(_graph); n != INVALID; ++n) { - cutMap.set(n, minCut(n)); - } - } - - /// @} - }; -} - -#endif diff --git a/deps/lemon/lemon/quad_heap.h b/deps/lemon/lemon/quad_heap.h deleted file mode 100644 index 27c50fd3f..000000000 --- a/deps/lemon/lemon/quad_heap.h +++ /dev/null @@ -1,343 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_QUAD_HEAP_H -#define LEMON_QUAD_HEAP_H - -///\ingroup heaps -///\file -///\brief Fourary (quaternary) heap implementation. - -#include -#include -#include - -namespace lemon { - - /// \ingroup heaps - /// - ///\brief Fourary (quaternary) heap data structure. - /// - /// This class implements the \e Fourary (\e quaternary) \e heap - /// data structure. - /// It fully conforms to the \ref concepts::Heap "heap concept". - /// - /// The fourary heap is a specialization of the \ref DHeap "D-ary heap" - /// for D=4. It is similar to the \ref BinHeap "binary heap", - /// but its nodes have at most four children, instead of two. - /// - /// \tparam PR Type of the priorities of the items. - /// \tparam IM A read-writable item map with \c int values, used - /// internally to handle the cross references. - /// \tparam CMP A functor class for comparing the priorities. - /// The default is \c std::less. - /// - ///\sa BinHeap - ///\sa DHeap -#ifdef DOXYGEN - template -#else - template > -#endif - class QuadHeap { - public: - /// Type of the item-int map. - typedef IM ItemIntMap; - /// Type of the priorities. - typedef PR Prio; - /// Type of the items stored in the heap. - typedef typename ItemIntMap::Key Item; - /// Type of the item-priority pairs. - typedef std::pair Pair; - /// Functor type for comparing the priorities. - typedef CMP Compare; - - /// \brief Type to represent the states of the items. - /// - /// Each item has a state associated to it. It can be "in heap", - /// "pre-heap" or "post-heap". The latter two are indifferent from the - /// heap's point of view, but may be useful to the user. - /// - /// The item-int map must be initialized in such way that it assigns - /// \c PRE_HEAP (-1) to any element to be put in the heap. - enum State { - IN_HEAP = 0, ///< = 0. - PRE_HEAP = -1, ///< = -1. - POST_HEAP = -2 ///< = -2. - }; - - private: - std::vector _data; - Compare _comp; - ItemIntMap &_iim; - - public: - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - explicit QuadHeap(ItemIntMap &map) : _iim(map) {} - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - /// \param comp The function object used for comparing the priorities. - QuadHeap(ItemIntMap &map, const Compare &comp) - : _iim(map), _comp(comp) {} - - /// \brief The number of items stored in the heap. - /// - /// This function returns the number of items stored in the heap. - int size() const { return _data.size(); } - - /// \brief Check if the heap is empty. - /// - /// This function returns \c true if the heap is empty. - bool empty() const { return _data.empty(); } - - /// \brief Make the heap empty. - /// - /// This functon makes the heap empty. - /// It does not change the cross reference map. If you want to reuse - /// a heap that is not surely empty, you should first clear it and - /// then you should set the cross reference map to \c PRE_HEAP - /// for each item. - void clear() { _data.clear(); } - - private: - static int parent(int i) { return (i-1)/4; } - static int firstChild(int i) { return 4*i+1; } - - bool less(const Pair &p1, const Pair &p2) const { - return _comp(p1.second, p2.second); - } - - void bubbleUp(int hole, Pair p) { - int par = parent(hole); - while( hole>0 && less(p,_data[par]) ) { - move(_data[par],hole); - hole = par; - par = parent(hole); - } - move(p, hole); - } - - void bubbleDown(int hole, Pair p, int length) { - if( length>1 ) { - int child = firstChild(hole); - while( child+30) bubbleDown(0, _data[n], n); - _data.pop_back(); - } - - /// \brief Remove the given item from the heap. - /// - /// This function removes the given item from the heap if it is - /// already stored. - /// \param i The item to delete. - /// \pre \e i must be in the heap. - void erase(const Item &i) { - int h = _iim[i]; - int n = _data.size()-1; - _iim.set(_data[h].first, POST_HEAP); - if( h=0) s=0; - return State(s); - } - - /// \brief Set the state of an item in the heap. - /// - /// This function sets the state of the given item in the heap. - /// It can be used to manually clear the heap when it is important - /// to achive better time complexity. - /// \param i The item. - /// \param st The state. It should not be \c IN_HEAP. - void state(const Item& i, State st) { - switch (st) { - case POST_HEAP: - case PRE_HEAP: - if (state(i) == IN_HEAP) erase(i); - _iim[i] = st; - break; - case IN_HEAP: - break; - } - } - - /// \brief Replace an item in the heap. - /// - /// This function replaces item \c i with item \c j. - /// Item \c i must be in the heap, while \c j must be out of the heap. - /// After calling this method, item \c i will be out of the - /// heap and \c j will be in the heap with the same prioriority - /// as item \c i had before. - void replace(const Item& i, const Item& j) { - int idx = _iim[i]; - _iim.set(i, _iim[j]); - _iim.set(j, idx); - _data[idx].first = j; - } - - }; // class QuadHeap - -} // namespace lemon - -#endif // LEMON_FOURARY_HEAP_H diff --git a/deps/lemon/lemon/radix_heap.h b/deps/lemon/lemon/radix_heap.h deleted file mode 100644 index 8701ce747..000000000 --- a/deps/lemon/lemon/radix_heap.h +++ /dev/null @@ -1,438 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_RADIX_HEAP_H -#define LEMON_RADIX_HEAP_H - -///\ingroup heaps -///\file -///\brief Radix heap implementation. - -#include -#include - -namespace lemon { - - - /// \ingroup heaps - /// - /// \brief Radix heap data structure. - /// - /// This class implements the \e radix \e heap data structure. - /// It practically conforms to the \ref concepts::Heap "heap concept", - /// but it has some limitations due its special implementation. - /// The type of the priorities must be \c int and the priority of an - /// item cannot be decreased under the priority of the last removed item. - /// - /// \tparam IM A read-writable item map with \c int values, used - /// internally to handle the cross references. - template - class RadixHeap { - - public: - - /// Type of the item-int map. - typedef IM ItemIntMap; - /// Type of the priorities. - typedef int Prio; - /// Type of the items stored in the heap. - typedef typename ItemIntMap::Key Item; - - /// \brief Exception thrown by RadixHeap. - /// - /// This exception is thrown when an item is inserted into a - /// RadixHeap with a priority smaller than the last erased one. - /// \see RadixHeap - class PriorityUnderflowError : public Exception { - public: - virtual const char* what() const throw() { - return "lemon::RadixHeap::PriorityUnderflowError"; - } - }; - - /// \brief Type to represent the states of the items. - /// - /// Each item has a state associated to it. It can be "in heap", - /// "pre-heap" or "post-heap". The latter two are indifferent from the - /// heap's point of view, but may be useful to the user. - /// - /// The item-int map must be initialized in such way that it assigns - /// \c PRE_HEAP (-1) to any element to be put in the heap. - enum State { - IN_HEAP = 0, ///< = 0. - PRE_HEAP = -1, ///< = -1. - POST_HEAP = -2 ///< = -2. - }; - - private: - - struct RadixItem { - int prev, next, box; - Item item; - int prio; - RadixItem(Item _item, int _prio) : item(_item), prio(_prio) {} - }; - - struct RadixBox { - int first; - int min, size; - RadixBox(int _min, int _size) : first(-1), min(_min), size(_size) {} - }; - - std::vector _data; - std::vector _boxes; - - ItemIntMap &_iim; - - public: - - /// \brief Constructor. - /// - /// Constructor. - /// \param map A map that assigns \c int values to the items. - /// It is used internally to handle the cross references. - /// The assigned value must be \c PRE_HEAP (-1) for each item. - /// \param minimum The initial minimum value of the heap. - /// \param capacity The initial capacity of the heap. - RadixHeap(ItemIntMap &map, int minimum = 0, int capacity = 0) - : _iim(map) - { - _boxes.push_back(RadixBox(minimum, 1)); - _boxes.push_back(RadixBox(minimum + 1, 1)); - while (lower(_boxes.size() - 1, capacity + minimum - 1)) { - extend(); - } - } - - /// \brief The number of items stored in the heap. - /// - /// This function returns the number of items stored in the heap. - int size() const { return _data.size(); } - - /// \brief Check if the heap is empty. - /// - /// This function returns \c true if the heap is empty. - bool empty() const { return _data.empty(); } - - /// \brief Make the heap empty. - /// - /// This functon makes the heap empty. - /// It does not change the cross reference map. If you want to reuse - /// a heap that is not surely empty, you should first clear it and - /// then you should set the cross reference map to \c PRE_HEAP - /// for each item. - /// \param minimum The minimum value of the heap. - /// \param capacity The capacity of the heap. - void clear(int minimum = 0, int capacity = 0) { - _data.clear(); _boxes.clear(); - _boxes.push_back(RadixBox(minimum, 1)); - _boxes.push_back(RadixBox(minimum + 1, 1)); - while (lower(_boxes.size() - 1, capacity + minimum - 1)) { - extend(); - } - } - - private: - - bool upper(int box, Prio pr) { - return pr < _boxes[box].min; - } - - bool lower(int box, Prio pr) { - return pr >= _boxes[box].min + _boxes[box].size; - } - - // Remove item from the box list - void remove(int index) { - if (_data[index].prev >= 0) { - _data[_data[index].prev].next = _data[index].next; - } else { - _boxes[_data[index].box].first = _data[index].next; - } - if (_data[index].next >= 0) { - _data[_data[index].next].prev = _data[index].prev; - } - } - - // Insert item into the box list - void insert(int box, int index) { - if (_boxes[box].first == -1) { - _boxes[box].first = index; - _data[index].next = _data[index].prev = -1; - } else { - _data[index].next = _boxes[box].first; - _data[_boxes[box].first].prev = index; - _data[index].prev = -1; - _boxes[box].first = index; - } - _data[index].box = box; - } - - // Add a new box to the box list - void extend() { - int min = _boxes.back().min + _boxes.back().size; - int bs = 2 * _boxes.back().size; - _boxes.push_back(RadixBox(min, bs)); - } - - // Move an item up into the proper box. - void bubbleUp(int index) { - if (!lower(_data[index].box, _data[index].prio)) return; - remove(index); - int box = findUp(_data[index].box, _data[index].prio); - insert(box, index); - } - - // Find up the proper box for the item with the given priority - int findUp(int start, int pr) { - while (lower(start, pr)) { - if (++start == int(_boxes.size())) { - extend(); - } - } - return start; - } - - // Move an item down into the proper box - void bubbleDown(int index) { - if (!upper(_data[index].box, _data[index].prio)) return; - remove(index); - int box = findDown(_data[index].box, _data[index].prio); - insert(box, index); - } - - // Find down the proper box for the item with the given priority - int findDown(int start, int pr) { - while (upper(start, pr)) { - if (--start < 0) throw PriorityUnderflowError(); - } - return start; - } - - // Find the first non-empty box - int findFirst() { - int first = 0; - while (_boxes[first].first == -1) ++first; - return first; - } - - // Gives back the minimum priority of the given box - int minValue(int box) { - int min = _data[_boxes[box].first].prio; - for (int k = _boxes[box].first; k != -1; k = _data[k].next) { - if (_data[k].prio < min) min = _data[k].prio; - } - return min; - } - - // Rearrange the items of the heap and make the first box non-empty - void moveDown() { - int box = findFirst(); - if (box == 0) return; - int min = minValue(box); - for (int i = 0; i <= box; ++i) { - _boxes[i].min = min; - min += _boxes[i].size; - } - int curr = _boxes[box].first, next; - while (curr != -1) { - next = _data[curr].next; - bubbleDown(curr); - curr = next; - } - } - - void relocateLast(int index) { - if (index != int(_data.size()) - 1) { - _data[index] = _data.back(); - if (_data[index].prev != -1) { - _data[_data[index].prev].next = index; - } else { - _boxes[_data[index].box].first = index; - } - if (_data[index].next != -1) { - _data[_data[index].next].prev = index; - } - _iim[_data[index].item] = index; - } - _data.pop_back(); - } - - public: - - /// \brief Insert an item into the heap with the given priority. - /// - /// This function inserts the given item into the heap with the - /// given priority. - /// \param i The item to insert. - /// \param p The priority of the item. - /// \pre \e i must not be stored in the heap. - /// \warning This method may throw an \c UnderFlowPriorityException. - void push(const Item &i, const Prio &p) { - int n = _data.size(); - _iim.set(i, n); - _data.push_back(RadixItem(i, p)); - while (lower(_boxes.size() - 1, p)) { - extend(); - } - int box = findDown(_boxes.size() - 1, p); - insert(box, n); - } - - /// \brief Return the item having minimum priority. - /// - /// This function returns the item having minimum priority. - /// \pre The heap must be non-empty. - Item top() const { - const_cast&>(*this).moveDown(); - return _data[_boxes[0].first].item; - } - - /// \brief The minimum priority. - /// - /// This function returns the minimum priority. - /// \pre The heap must be non-empty. - Prio prio() const { - const_cast&>(*this).moveDown(); - return _data[_boxes[0].first].prio; - } - - /// \brief Remove the item having minimum priority. - /// - /// This function removes the item having minimum priority. - /// \pre The heap must be non-empty. - void pop() { - moveDown(); - int index = _boxes[0].first; - _iim[_data[index].item] = POST_HEAP; - remove(index); - relocateLast(index); - } - - /// \brief Remove the given item from the heap. - /// - /// This function removes the given item from the heap if it is - /// already stored. - /// \param i The item to delete. - /// \pre \e i must be in the heap. - void erase(const Item &i) { - int index = _iim[i]; - _iim[i] = POST_HEAP; - remove(index); - relocateLast(index); - } - - /// \brief The priority of the given item. - /// - /// This function returns the priority of the given item. - /// \param i The item. - /// \pre \e i must be in the heap. - Prio operator[](const Item &i) const { - int idx = _iim[i]; - return _data[idx].prio; - } - - /// \brief Set the priority of an item or insert it, if it is - /// not stored in the heap. - /// - /// This method sets the priority of the given item if it is - /// already stored in the heap. Otherwise it inserts the given - /// item into the heap with the given priority. - /// \param i The item. - /// \param p The priority. - /// \pre \e i must be in the heap. - /// \warning This method may throw an \c UnderFlowPriorityException. - void set(const Item &i, const Prio &p) { - int idx = _iim[i]; - if( idx < 0 ) { - push(i, p); - } - else if( p >= _data[idx].prio ) { - _data[idx].prio = p; - bubbleUp(idx); - } else { - _data[idx].prio = p; - bubbleDown(idx); - } - } - - /// \brief Decrease the priority of an item to the given value. - /// - /// This function decreases the priority of an item to the given value. - /// \param i The item. - /// \param p The priority. - /// \pre \e i must be stored in the heap with priority at least \e p. - /// \warning This method may throw an \c UnderFlowPriorityException. - void decrease(const Item &i, const Prio &p) { - int idx = _iim[i]; - _data[idx].prio = p; - bubbleDown(idx); - } - - /// \brief Increase the priority of an item to the given value. - /// - /// This function increases the priority of an item to the given value. - /// \param i The item. - /// \param p The priority. - /// \pre \e i must be stored in the heap with priority at most \e p. - void increase(const Item &i, const Prio &p) { - int idx = _iim[i]; - _data[idx].prio = p; - bubbleUp(idx); - } - - /// \brief Return the state of an item. - /// - /// This method returns \c PRE_HEAP if the given item has never - /// been in the heap, \c IN_HEAP if it is in the heap at the moment, - /// and \c POST_HEAP otherwise. - /// In the latter case it is possible that the item will get back - /// to the heap again. - /// \param i The item. - State state(const Item &i) const { - int s = _iim[i]; - if( s >= 0 ) s = 0; - return State(s); - } - - /// \brief Set the state of an item in the heap. - /// - /// This function sets the state of the given item in the heap. - /// It can be used to manually clear the heap when it is important - /// to achive better time complexity. - /// \param i The item. - /// \param st The state. It should not be \c IN_HEAP. - void state(const Item& i, State st) { - switch (st) { - case POST_HEAP: - case PRE_HEAP: - if (state(i) == IN_HEAP) { - erase(i); - } - _iim[i] = st; - break; - case IN_HEAP: - break; - } - } - - }; // class RadixHeap - -} // namespace lemon - -#endif // LEMON_RADIX_HEAP_H diff --git a/deps/lemon/lemon/radix_sort.h b/deps/lemon/lemon/radix_sort.h deleted file mode 100644 index d80875663..000000000 --- a/deps/lemon/lemon/radix_sort.h +++ /dev/null @@ -1,487 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef RADIX_SORT_H -#define RADIX_SORT_H - -/// \ingroup auxalg -/// \file -/// \brief Radix sort -/// -/// Linear time sorting algorithms - -#include -#include -#include -#include - -namespace lemon { - - namespace _radix_sort_bits { - - template - bool unitRange(Iterator first, Iterator last) { - ++first; - return first == last; - } - - template - struct Identity { - const Value& operator()(const Value& val) { - return val; - } - }; - - - template - Iterator radixSortPartition(Iterator first, Iterator last, - Functor functor, Value mask) { - while (first != last && !(functor(*first) & mask)) { - ++first; - } - if (first == last) { - return first; - } - --last; - while (first != last && (functor(*last) & mask)) { - --last; - } - if (first == last) { - return first; - } - std::iter_swap(first, last); - ++first; - while (true) { - while (!(functor(*first) & mask)) { - ++first; - } - --last; - while (functor(*last) & mask) { - --last; - } - if (unitRange(last, first)) { - return first; - } - std::iter_swap(first, last); - ++first; - } - } - - template - Iterator radixSortSignPartition(Iterator first, Iterator last, - Functor functor) { - while (first != last && functor(*first) < 0) { - ++first; - } - if (first == last) { - return first; - } - --last; - while (first != last && functor(*last) >= 0) { - --last; - } - if (first == last) { - return first; - } - std::iter_swap(first, last); - ++first; - while (true) { - while (functor(*first) < 0) { - ++first; - } - --last; - while (functor(*last) >= 0) { - --last; - } - if (unitRange(last, first)) { - return first; - } - std::iter_swap(first, last); - ++first; - } - } - - template - void radixIntroSort(Iterator first, Iterator last, - Functor functor, Value mask) { - while (mask != 0 && first != last && !unitRange(first, last)) { - Iterator cut = radixSortPartition(first, last, functor, mask); - mask >>= 1; - radixIntroSort(first, cut, functor, mask); - first = cut; - } - } - - template - void radixSignedSort(Iterator first, Iterator last, Functor functor) { - - Iterator cut = radixSortSignPartition(first, last, functor); - - Value mask; - int max_digit; - Iterator it; - - mask = ~0; max_digit = 0; - for (it = first; it != cut; ++it) { - while ((mask & functor(*it)) != mask) { - ++max_digit; - mask <<= 1; - } - } - radixIntroSort(first, cut, functor, 1 << max_digit); - - mask = 0; max_digit = 0; - for (it = cut; it != last; ++it) { - while ((mask | functor(*it)) != mask) { - ++max_digit; - mask <<= 1; mask |= 1; - } - } - radixIntroSort(cut, last, functor, 1 << max_digit); - } - - template - void radixUnsignedSort(Iterator first, Iterator last, Functor functor) { - - Value mask = 0; - int max_digit = 0; - - Iterator it; - for (it = first; it != last; ++it) { - while ((mask | functor(*it)) != mask) { - ++max_digit; - mask <<= 1; mask |= 1; - } - } - radixIntroSort(first, last, functor, 1 << max_digit); - } - - - template ::is_signed > - struct RadixSortSelector { - template - static void sort(Iterator first, Iterator last, Functor functor) { - radixSignedSort(first, last, functor); - } - }; - - template - struct RadixSortSelector { - template - static void sort(Iterator first, Iterator last, Functor functor) { - radixUnsignedSort(first, last, functor); - } - }; - - } - - /// \ingroup auxalg - /// - /// \brief Sorts the STL compatible range into ascending order. - /// - /// The \c radixSort sorts an STL compatible range into ascending - /// order. The radix sort algorithm can sort items which are mapped - /// to integers with an adaptable unary function \c functor and the - /// order will be ascending according to these mapped values. - /// - /// It is also possible to use a normal function instead - /// of the functor object. If the functor is not given it will use - /// the identity function instead. - /// - /// This is a special quick sort algorithm where the pivot - /// values to split the items are choosen to be 2k - /// for each \c k. - /// Therefore, the time complexity of the algorithm is O(log(c)*n) and - /// it uses O(log(c)) additional space, where \c c is the maximal value - /// and \c n is the number of the items in the container. - /// - /// \param first The begin of the given range. - /// \param last The end of the given range. - /// \param functor An adaptible unary function or a normal function - /// which maps the items to any integer type which can be either - /// signed or unsigned. - /// - /// \sa stableRadixSort() - template - void radixSort(Iterator first, Iterator last, Functor functor) { - using namespace _radix_sort_bits; - typedef typename Functor::result_type Value; - RadixSortSelector::sort(first, last, functor); - } - - template - void radixSort(Iterator first, Iterator last, Value (*functor)(Key)) { - using namespace _radix_sort_bits; - RadixSortSelector::sort(first, last, functor); - } - - template - void radixSort(Iterator first, Iterator last, Value& (*functor)(Key)) { - using namespace _radix_sort_bits; - RadixSortSelector::sort(first, last, functor); - } - - template - void radixSort(Iterator first, Iterator last, Value (*functor)(Key&)) { - using namespace _radix_sort_bits; - RadixSortSelector::sort(first, last, functor); - } - - template - void radixSort(Iterator first, Iterator last, Value& (*functor)(Key&)) { - using namespace _radix_sort_bits; - RadixSortSelector::sort(first, last, functor); - } - - template - void radixSort(Iterator first, Iterator last) { - using namespace _radix_sort_bits; - typedef typename std::iterator_traits::value_type Value; - RadixSortSelector::sort(first, last, Identity()); - } - - namespace _radix_sort_bits { - - template - unsigned char valueByte(Value value, int byte) { - return value >> (std::numeric_limits::digits * byte); - } - - template - void stableRadixIntroSort(Key *first, Key *last, Key *target, - int byte, Functor functor) { - const int size = - unsigned(std::numeric_limits::max()) + 1; - std::vector counter(size); - for (int i = 0; i < size; ++i) { - counter[i] = 0; - } - Key *it = first; - while (first != last) { - ++counter[valueByte(functor(*first), byte)]; - ++first; - } - int prev, num = 0; - for (int i = 0; i < size; ++i) { - prev = num; - num += counter[i]; - counter[i] = prev; - } - while (it != last) { - target[counter[valueByte(functor(*it), byte)]++] = *it; - ++it; - } - } - - template - void signedStableRadixIntroSort(Key *first, Key *last, Key *target, - int byte, Functor functor) { - const int size = - unsigned(std::numeric_limits::max()) + 1; - std::vector counter(size); - for (int i = 0; i < size; ++i) { - counter[i] = 0; - } - Key *it = first; - while (first != last) { - counter[valueByte(functor(*first), byte)]++; - ++first; - } - int prev, num = 0; - for (int i = size / 2; i < size; ++i) { - prev = num; - num += counter[i]; - counter[i] = prev; - } - for (int i = 0; i < size / 2; ++i) { - prev = num; - num += counter[i]; - counter[i] = prev; - } - while (it != last) { - target[counter[valueByte(functor(*it), byte)]++] = *it; - ++it; - } - } - - - template - void stableRadixSignedSort(Iterator first, Iterator last, Functor functor) { - if (first == last) return; - typedef typename std::iterator_traits::value_type Key; - typedef std::allocator Allocator; - Allocator allocator; - - int length = std::distance(first, last); - Key* buffer = allocator.allocate(2 * length); - try { - bool dir = true; - std::copy(first, last, buffer); - for (int i = 0; i < int(sizeof(Value)) - 1; ++i) { - if (dir) { - stableRadixIntroSort(buffer, buffer + length, buffer + length, - i, functor); - } else { - stableRadixIntroSort(buffer + length, buffer + 2 * length, buffer, - i, functor); - } - dir = !dir; - } - if (dir) { - signedStableRadixIntroSort(buffer, buffer + length, buffer + length, - sizeof(Value) - 1, functor); - std::copy(buffer + length, buffer + 2 * length, first); - } else { - signedStableRadixIntroSort(buffer + length, buffer + 2 * length, - buffer, sizeof(Value) - 1, functor); - std::copy(buffer, buffer + length, first); - } - } catch (...) { - allocator.deallocate(buffer, 2 * length); - throw; - } - allocator.deallocate(buffer, 2 * length); - } - - template - void stableRadixUnsignedSort(Iterator first, Iterator last, - Functor functor) { - if (first == last) return; - typedef typename std::iterator_traits::value_type Key; - typedef std::allocator Allocator; - Allocator allocator; - - int length = std::distance(first, last); - Key *buffer = allocator.allocate(2 * length); - try { - bool dir = true; - std::copy(first, last, buffer); - for (int i = 0; i < int(sizeof(Value)); ++i) { - if (dir) { - stableRadixIntroSort(buffer, buffer + length, - buffer + length, i, functor); - } else { - stableRadixIntroSort(buffer + length, buffer + 2 * length, - buffer, i, functor); - } - dir = !dir; - } - if (dir) { - std::copy(buffer, buffer + length, first); - } else { - std::copy(buffer + length, buffer + 2 * length, first); - } - } catch (...) { - allocator.deallocate(buffer, 2 * length); - throw; - } - allocator.deallocate(buffer, 2 * length); - } - - - - template ::is_signed > - struct StableRadixSortSelector { - template - static void sort(Iterator first, Iterator last, Functor functor) { - stableRadixSignedSort(first, last, functor); - } - }; - - template - struct StableRadixSortSelector { - template - static void sort(Iterator first, Iterator last, Functor functor) { - stableRadixUnsignedSort(first, last, functor); - } - }; - - } - - /// \ingroup auxalg - /// - /// \brief Sorts the STL compatible range into ascending order in a stable - /// way. - /// - /// This function sorts an STL compatible range into ascending - /// order according to an integer mapping in the same as radixSort() does. - /// - /// This sorting algorithm is stable, i.e. the order of two equal - /// elements remains the same after the sorting. - /// - /// This sort algorithm use a radix forward sort on the - /// bytes of the integer number. The algorithm sorts the items - /// byte-by-byte. First, it counts how many times a byte value occurs - /// in the container, then it copies the corresponding items to - /// another container in asceding order in O(n) time. - /// - /// The time complexity of the algorithm is O(log(c)*n) and - /// it uses O(n) additional space, where \c c is the - /// maximal value and \c n is the number of the items in the - /// container. - /// - - /// \param first The begin of the given range. - /// \param last The end of the given range. - /// \param functor An adaptible unary function or a normal function - /// which maps the items to any integer type which can be either - /// signed or unsigned. - /// \sa radixSort() - template - void stableRadixSort(Iterator first, Iterator last, Functor functor) { - using namespace _radix_sort_bits; - typedef typename Functor::result_type Value; - StableRadixSortSelector::sort(first, last, functor); - } - - template - void stableRadixSort(Iterator first, Iterator last, Value (*functor)(Key)) { - using namespace _radix_sort_bits; - StableRadixSortSelector::sort(first, last, functor); - } - - template - void stableRadixSort(Iterator first, Iterator last, Value& (*functor)(Key)) { - using namespace _radix_sort_bits; - StableRadixSortSelector::sort(first, last, functor); - } - - template - void stableRadixSort(Iterator first, Iterator last, Value (*functor)(Key&)) { - using namespace _radix_sort_bits; - StableRadixSortSelector::sort(first, last, functor); - } - - template - void stableRadixSort(Iterator first, Iterator last, Value& (*functor)(Key&)) { - using namespace _radix_sort_bits; - StableRadixSortSelector::sort(first, last, functor); - } - - template - void stableRadixSort(Iterator first, Iterator last) { - using namespace _radix_sort_bits; - typedef typename std::iterator_traits::value_type Value; - StableRadixSortSelector::sort(first, last, Identity()); - } - -} - -#endif diff --git a/deps/lemon/lemon/random.cc b/deps/lemon/lemon/random.cc deleted file mode 100644 index 02951210b..000000000 --- a/deps/lemon/lemon/random.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\file -///\brief Instantiation of the Random class. - -#include - -namespace lemon { - /// \brief Global random number generator instance - /// - /// A global Mersenne Twister random number generator instance. - Random rnd; -} diff --git a/deps/lemon/lemon/random.h b/deps/lemon/lemon/random.h deleted file mode 100644 index 8de74ede8..000000000 --- a/deps/lemon/lemon/random.h +++ /dev/null @@ -1,1005 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -/* - * This file contains the reimplemented version of the Mersenne Twister - * Generator of Matsumoto and Nishimura. - * - * See the appropriate copyright notice below. - * - * Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. The names of its contributors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Any feedback is very welcome. - * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html - * email: m-mat @ math.sci.hiroshima-u.ac.jp (remove space) - */ - -#ifndef LEMON_RANDOM_H -#define LEMON_RANDOM_H - -#include -#include -#include -#include -#include - -#include -#include - -#ifndef WIN32 -#include -#include -#include -#include -#else -#include -#endif - -///\ingroup misc -///\file -///\brief Mersenne Twister random number generator - -namespace lemon { - - namespace _random_bits { - - template ::digits> - struct RandomTraits {}; - - template - struct RandomTraits<_Word, 32> { - - typedef _Word Word; - static const int bits = 32; - - static const int length = 624; - static const int shift = 397; - - static const Word mul = 0x6c078965u; - static const Word arrayInit = 0x012BD6AAu; - static const Word arrayMul1 = 0x0019660Du; - static const Word arrayMul2 = 0x5D588B65u; - - static const Word mask = 0x9908B0DFu; - static const Word loMask = (1u << 31) - 1; - static const Word hiMask = ~loMask; - - - static Word tempering(Word rnd) { - rnd ^= (rnd >> 11); - rnd ^= (rnd << 7) & 0x9D2C5680u; - rnd ^= (rnd << 15) & 0xEFC60000u; - rnd ^= (rnd >> 18); - return rnd; - } - - }; - - template - struct RandomTraits<_Word, 64> { - - typedef _Word Word; - static const int bits = 64; - - static const int length = 312; - static const int shift = 156; - - static const Word mul = Word(0x5851F42Du) << 32 | Word(0x4C957F2Du); - static const Word arrayInit = Word(0x00000000u) << 32 |Word(0x012BD6AAu); - static const Word arrayMul1 = Word(0x369DEA0Fu) << 32 |Word(0x31A53F85u); - static const Word arrayMul2 = Word(0x27BB2EE6u) << 32 |Word(0x87B0B0FDu); - - static const Word mask = Word(0xB5026F5Au) << 32 | Word(0xA96619E9u); - static const Word loMask = (Word(1u) << 31) - 1; - static const Word hiMask = ~loMask; - - static Word tempering(Word rnd) { - rnd ^= (rnd >> 29) & (Word(0x55555555u) << 32 | Word(0x55555555u)); - rnd ^= (rnd << 17) & (Word(0x71D67FFFu) << 32 | Word(0xEDA60000u)); - rnd ^= (rnd << 37) & (Word(0xFFF7EEE0u) << 32 | Word(0x00000000u)); - rnd ^= (rnd >> 43); - return rnd; - } - - }; - - template - class RandomCore { - public: - - typedef _Word Word; - - private: - - static const int bits = RandomTraits::bits; - - static const int length = RandomTraits::length; - static const int shift = RandomTraits::shift; - - public: - - void initState() { - static const Word seedArray[4] = { - 0x12345u, 0x23456u, 0x34567u, 0x45678u - }; - - initState(seedArray, seedArray + 4); - } - - void initState(Word seed) { - - static const Word mul = RandomTraits::mul; - - current = state; - - Word *curr = state + length - 1; - curr[0] = seed; --curr; - for (int i = 1; i < length; ++i) { - curr[0] = (mul * ( curr[1] ^ (curr[1] >> (bits - 2)) ) + i); - --curr; - } - } - - template - void initState(Iterator begin, Iterator end) { - - static const Word init = RandomTraits::arrayInit; - static const Word mul1 = RandomTraits::arrayMul1; - static const Word mul2 = RandomTraits::arrayMul2; - - - Word *curr = state + length - 1; --curr; - Iterator it = begin; int cnt = 0; - int num; - - initState(init); - - num = length > end - begin ? length : end - begin; - while (num--) { - curr[0] = (curr[0] ^ ((curr[1] ^ (curr[1] >> (bits - 2))) * mul1)) - + *it + cnt; - ++it; ++cnt; - if (it == end) { - it = begin; cnt = 0; - } - if (curr == state) { - curr = state + length - 1; curr[0] = state[0]; - } - --curr; - } - - num = length - 1; cnt = length - (curr - state) - 1; - while (num--) { - curr[0] = (curr[0] ^ ((curr[1] ^ (curr[1] >> (bits - 2))) * mul2)) - - cnt; - --curr; ++cnt; - if (curr == state) { - curr = state + length - 1; curr[0] = state[0]; --curr; - cnt = 1; - } - } - - state[length - 1] = Word(1) << (bits - 1); - } - - void copyState(const RandomCore& other) { - std::copy(other.state, other.state + length, state); - current = state + (other.current - other.state); - } - - Word operator()() { - if (current == state) fillState(); - --current; - Word rnd = *current; - return RandomTraits::tempering(rnd); - } - - private: - - - void fillState() { - static const Word mask[2] = { 0x0ul, RandomTraits::mask }; - static const Word loMask = RandomTraits::loMask; - static const Word hiMask = RandomTraits::hiMask; - - current = state + length; - - register Word *curr = state + length - 1; - register long num; - - num = length - shift; - while (num--) { - curr[0] = (((curr[0] & hiMask) | (curr[-1] & loMask)) >> 1) ^ - curr[- shift] ^ mask[curr[-1] & 1ul]; - --curr; - } - num = shift - 1; - while (num--) { - curr[0] = (((curr[0] & hiMask) | (curr[-1] & loMask)) >> 1) ^ - curr[length - shift] ^ mask[curr[-1] & 1ul]; - --curr; - } - state[0] = (((state[0] & hiMask) | (curr[length - 1] & loMask)) >> 1) ^ - curr[length - shift] ^ mask[curr[length - 1] & 1ul]; - - } - - - Word *current; - Word state[length]; - - }; - - - template ::digits + 1) / 2> - struct Masker { - static Result mask(const Result& result) { - return Masker:: - mask(static_cast(result | (result >> shift))); - } - }; - - template - struct Masker { - static Result mask(const Result& result) { - return static_cast(result | (result >> 1)); - } - }; - - template ::digits, int shift = 0, - bool last = rest <= std::numeric_limits::digits> - struct IntConversion { - static const int bits = std::numeric_limits::digits; - - static Result convert(RandomCore& rnd) { - return static_cast(rnd() >> (bits - rest)) << shift; - } - - }; - - template - struct IntConversion { - static const int bits = std::numeric_limits::digits; - - static Result convert(RandomCore& rnd) { - return (static_cast(rnd()) << shift) | - IntConversion::convert(rnd); - } - }; - - - template ::digits < - std::numeric_limits::digits) > - struct Mapping { - static Result map(RandomCore& rnd, const Result& bound) { - Word max = Word(bound - 1); - Result mask = Masker::mask(bound - 1); - Result num; - do { - num = IntConversion::convert(rnd) & mask; - } while (num > max); - return num; - } - }; - - template - struct Mapping { - static Result map(RandomCore& rnd, const Result& bound) { - Word max = Word(bound - 1); - Word mask = Masker::digits + 1) / 2> - ::mask(max); - Word num; - do { - num = rnd() & mask; - } while (num > max); - return num; - } - }; - - template - struct ShiftMultiplier { - static const Result multiplier() { - Result res = ShiftMultiplier::multiplier(); - res *= res; - if ((exp & 1) == 1) res *= static_cast(0.5); - return res; - } - }; - - template - struct ShiftMultiplier { - static const Result multiplier() { - return static_cast(1.0); - } - }; - - template - struct ShiftMultiplier { - static const Result multiplier() { - return static_cast(1.0/1048576.0); - } - }; - - template - struct ShiftMultiplier { - static const Result multiplier() { - return static_cast(1.0/4294967296.0); - } - }; - - template - struct ShiftMultiplier { - static const Result multiplier() { - return static_cast(1.0/9007199254740992.0); - } - }; - - template - struct ShiftMultiplier { - static const Result multiplier() { - return static_cast(1.0/18446744073709551616.0); - } - }; - - template - struct Shifting { - static Result shift(const Result& result) { - return result * ShiftMultiplier::multiplier(); - } - }; - - template ::digits, int shift = 0, - bool last = rest <= std::numeric_limits::digits> - struct RealConversion{ - static const int bits = std::numeric_limits::digits; - - static Result convert(RandomCore& rnd) { - return Shifting:: - shift(static_cast(rnd() >> (bits - rest))); - } - }; - - template - struct RealConversion { - static const int bits = std::numeric_limits::digits; - - static Result convert(RandomCore& rnd) { - return Shifting:: - shift(static_cast(rnd())) + - RealConversion:: - convert(rnd); - } - }; - - template - struct Initializer { - - template - static void init(RandomCore& rnd, Iterator begin, Iterator end) { - std::vector ws; - for (Iterator it = begin; it != end; ++it) { - ws.push_back(Word(*it)); - } - rnd.initState(ws.begin(), ws.end()); - } - - static void init(RandomCore& rnd, Result seed) { - rnd.initState(seed); - } - }; - - template - struct BoolConversion { - static bool convert(RandomCore& rnd) { - return (rnd() & 1) == 1; - } - }; - - template - struct BoolProducer { - Word buffer; - int num; - - BoolProducer() : num(0) {} - - bool convert(RandomCore& rnd) { - if (num == 0) { - buffer = rnd(); - num = RandomTraits::bits; - } - bool r = (buffer & 1); - buffer >>= 1; - --num; - return r; - } - }; - - } - - /// \ingroup misc - /// - /// \brief Mersenne Twister random number generator - /// - /// The Mersenne Twister is a twisted generalized feedback - /// shift-register generator of Matsumoto and Nishimura. The period - /// of this generator is \f$ 2^{19937} - 1 \f$ and it is - /// equi-distributed in 623 dimensions for 32-bit numbers. The time - /// performance of this generator is comparable to the commonly used - /// generators. - /// - /// This implementation is specialized for both 32-bit and 64-bit - /// architectures. The generators differ sligthly in the - /// initialization and generation phase so they produce two - /// completly different sequences. - /// - /// The generator gives back random numbers of serveral types. To - /// get a random number from a range of a floating point type you - /// can use one form of the \c operator() or the \c real() member - /// function. If you want to get random number from the {0, 1, ..., - /// n-1} integer range use the \c operator[] or the \c integer() - /// method. And to get random number from the whole range of an - /// integer type you can use the argumentless \c integer() or \c - /// uinteger() functions. After all you can get random bool with - /// equal chance of true and false or given probability of true - /// result with the \c boolean() member functions. - /// - ///\code - /// // The commented code is identical to the other - /// double a = rnd(); // [0.0, 1.0) - /// // double a = rnd.real(); // [0.0, 1.0) - /// double b = rnd(100.0); // [0.0, 100.0) - /// // double b = rnd.real(100.0); // [0.0, 100.0) - /// double c = rnd(1.0, 2.0); // [1.0, 2.0) - /// // double c = rnd.real(1.0, 2.0); // [1.0, 2.0) - /// int d = rnd[100000]; // 0..99999 - /// // int d = rnd.integer(100000); // 0..99999 - /// int e = rnd[6] + 1; // 1..6 - /// // int e = rnd.integer(1, 1 + 6); // 1..6 - /// int b = rnd.uinteger(); // 0 .. 2^31 - 1 - /// int c = rnd.integer(); // - 2^31 .. 2^31 - 1 - /// bool g = rnd.boolean(); // P(g = true) = 0.5 - /// bool h = rnd.boolean(0.8); // P(h = true) = 0.8 - ///\endcode - /// - /// LEMON provides a global instance of the random number - /// generator which name is \ref lemon::rnd "rnd". Usually it is a - /// good programming convenience to use this global generator to get - /// random numbers. - class Random { - private: - - // Architecture word - typedef unsigned long Word; - - _random_bits::RandomCore core; - _random_bits::BoolProducer bool_producer; - - - public: - - ///\name Initialization - /// - /// @{ - - /// \brief Default constructor - /// - /// Constructor with constant seeding. - Random() { core.initState(); } - - /// \brief Constructor with seed - /// - /// Constructor with seed. The current number type will be converted - /// to the architecture word type. - template - Random(Number seed) { - _random_bits::Initializer::init(core, seed); - } - - /// \brief Constructor with array seeding - /// - /// Constructor with array seeding. The given range should contain - /// any number type and the numbers will be converted to the - /// architecture word type. - template - Random(Iterator begin, Iterator end) { - typedef typename std::iterator_traits::value_type Number; - _random_bits::Initializer::init(core, begin, end); - } - - /// \brief Copy constructor - /// - /// Copy constructor. The generated sequence will be identical to - /// the other sequence. It can be used to save the current state - /// of the generator and later use it to generate the same - /// sequence. - Random(const Random& other) { - core.copyState(other.core); - } - - /// \brief Assign operator - /// - /// Assign operator. The generated sequence will be identical to - /// the other sequence. It can be used to save the current state - /// of the generator and later use it to generate the same - /// sequence. - Random& operator=(const Random& other) { - if (&other != this) { - core.copyState(other.core); - } - return *this; - } - - /// \brief Seeding random sequence - /// - /// Seeding the random sequence. The current number type will be - /// converted to the architecture word type. - template - void seed(Number seed) { - _random_bits::Initializer::init(core, seed); - } - - /// \brief Seeding random sequence - /// - /// Seeding the random sequence. The given range should contain - /// any number type and the numbers will be converted to the - /// architecture word type. - template - void seed(Iterator begin, Iterator end) { - typedef typename std::iterator_traits::value_type Number; - _random_bits::Initializer::init(core, begin, end); - } - - /// \brief Seeding from file or from process id and time - /// - /// By default, this function calls the \c seedFromFile() member - /// function with the /dev/urandom file. If it does not success, - /// it uses the \c seedFromTime(). - /// \return Currently always \c true. - bool seed() { -#ifndef WIN32 - if (seedFromFile("/dev/urandom", 0)) return true; -#endif - if (seedFromTime()) return true; - return false; - } - - /// \brief Seeding from file - /// - /// Seeding the random sequence from file. The linux kernel has two - /// devices, /dev/random and /dev/urandom which - /// could give good seed values for pseudo random generators (The - /// difference between two devices is that the random may - /// block the reading operation while the kernel can give good - /// source of randomness, while the urandom does not - /// block the input, but it could give back bytes with worse - /// entropy). - /// \param file The source file - /// \param offset The offset, from the file read. - /// \return \c true when the seeding successes. -#ifndef WIN32 - bool seedFromFile(const std::string& file = "/dev/urandom", int offset = 0) -#else - bool seedFromFile(const std::string& file = "", int offset = 0) -#endif - { - std::ifstream rs(file.c_str()); - const int size = 4; - Word buf[size]; - if (offset != 0 && !rs.seekg(offset)) return false; - if (!rs.read(reinterpret_cast(buf), sizeof(buf))) return false; - seed(buf, buf + size); - return true; - } - - /// \brief Seding from process id and time - /// - /// Seding from process id and time. This function uses the - /// current process id and the current time for initialize the - /// random sequence. - /// \return Currently always \c true. - bool seedFromTime() { -#ifndef WIN32 - timeval tv; - gettimeofday(&tv, 0); - seed(getpid() + tv.tv_sec + tv.tv_usec); -#else - seed(bits::getWinRndSeed()); -#endif - return true; - } - - /// @} - - ///\name Uniform Distributions - /// - /// @{ - - /// \brief Returns a random real number from the range [0, 1) - /// - /// It returns a random real number from the range [0, 1). The - /// default Number type is \c double. - template - Number real() { - return _random_bits::RealConversion::convert(core); - } - - double real() { - return real(); - } - - /// \brief Returns a random real number from the range [0, 1) - /// - /// It returns a random double from the range [0, 1). - double operator()() { - return real(); - } - - /// \brief Returns a random real number from the range [0, b) - /// - /// It returns a random real number from the range [0, b). - double operator()(double b) { - return real() * b; - } - - /// \brief Returns a random real number from the range [a, b) - /// - /// It returns a random real number from the range [a, b). - double operator()(double a, double b) { - return real() * (b - a) + a; - } - - /// \brief Returns a random integer from a range - /// - /// It returns a random integer from the range {0, 1, ..., b - 1}. - template - Number integer(Number b) { - return _random_bits::Mapping::map(core, b); - } - - /// \brief Returns a random integer from a range - /// - /// It returns a random integer from the range {a, a + 1, ..., b - 1}. - template - Number integer(Number a, Number b) { - return _random_bits::Mapping::map(core, b - a) + a; - } - - /// \brief Returns a random integer from a range - /// - /// It returns a random integer from the range {0, 1, ..., b - 1}. - template - Number operator[](Number b) { - return _random_bits::Mapping::map(core, b); - } - - /// \brief Returns a random non-negative integer - /// - /// It returns a random non-negative integer uniformly from the - /// whole range of the current \c Number type. The default result - /// type of this function is unsigned int. - template - Number uinteger() { - return _random_bits::IntConversion::convert(core); - } - - unsigned int uinteger() { - return uinteger(); - } - - /// \brief Returns a random integer - /// - /// It returns a random integer uniformly from the whole range of - /// the current \c Number type. The default result type of this - /// function is \c int. - template - Number integer() { - static const int nb = std::numeric_limits::digits + - (std::numeric_limits::is_signed ? 1 : 0); - return _random_bits::IntConversion::convert(core); - } - - int integer() { - return integer(); - } - - /// \brief Returns a random bool - /// - /// It returns a random bool. The generator holds a buffer for - /// random bits. Every time when it become empty the generator makes - /// a new random word and fill the buffer up. - bool boolean() { - return bool_producer.convert(core); - } - - /// @} - - ///\name Non-uniform Distributions - /// - ///@{ - - /// \brief Returns a random bool with given probability of true result. - /// - /// It returns a random bool with given probability of true result. - bool boolean(double p) { - return operator()() < p; - } - - /// Standard normal (Gauss) distribution - - /// Standard normal (Gauss) distribution. - /// \note The Cartesian form of the Box-Muller - /// transformation is used to generate a random normal distribution. - double gauss() - { - double V1,V2,S; - do { - V1=2*real()-1; - V2=2*real()-1; - S=V1*V1+V2*V2; - } while(S>=1); - return std::sqrt(-2*std::log(S)/S)*V1; - } - /// Normal (Gauss) distribution with given mean and standard deviation - - /// Normal (Gauss) distribution with given mean and standard deviation. - /// \sa gauss() - double gauss(double mean,double std_dev) - { - return gauss()*std_dev+mean; - } - - /// Lognormal distribution - - /// Lognormal distribution. The parameters are the mean and the standard - /// deviation of exp(X). - /// - double lognormal(double n_mean,double n_std_dev) - { - return std::exp(gauss(n_mean,n_std_dev)); - } - /// Lognormal distribution - - /// Lognormal distribution. The parameter is an std::pair of - /// the mean and the standard deviation of exp(X). - /// - double lognormal(const std::pair ¶ms) - { - return std::exp(gauss(params.first,params.second)); - } - /// Compute the lognormal parameters from mean and standard deviation - - /// This function computes the lognormal parameters from mean and - /// standard deviation. The return value can direcly be passed to - /// lognormal(). - std::pair lognormalParamsFromMD(double mean, - double std_dev) - { - double fr=std_dev/mean; - fr*=fr; - double lg=std::log(1+fr); - return std::pair(std::log(mean)-lg/2.0,std::sqrt(lg)); - } - /// Lognormal distribution with given mean and standard deviation - - /// Lognormal distribution with given mean and standard deviation. - /// - double lognormalMD(double mean,double std_dev) - { - return lognormal(lognormalParamsFromMD(mean,std_dev)); - } - - /// Exponential distribution with given mean - - /// This function generates an exponential distribution random number - /// with mean 1/lambda. - /// - double exponential(double lambda=1.0) - { - return -std::log(1.0-real())/lambda; - } - - /// Gamma distribution with given integer shape - - /// This function generates a gamma distribution random number. - /// - ///\param k shape parameter (k>0 integer) - double gamma(int k) - { - double s = 0; - for(int i=0;i()); - return s; - } - - /// Gamma distribution with given shape and scale parameter - - /// This function generates a gamma distribution random number. - /// - ///\param k shape parameter (k>0) - ///\param theta scale parameter - /// - double gamma(double k,double theta=1.0) - { - double xi,nu; - const double delta = k-std::floor(k); - const double v0=E/(E-delta); - do { - double V0=1.0-real(); - double V1=1.0-real(); - double V2=1.0-real(); - if(V2<=v0) - { - xi=std::pow(V1,1.0/delta); - nu=V0*std::pow(xi,delta-1.0); - } - else - { - xi=1.0-std::log(V1); - nu=V0*std::exp(-xi); - } - } while(nu>std::pow(xi,delta-1.0)*std::exp(-xi)); - return theta*(xi+gamma(int(std::floor(k)))); - } - - /// Weibull distribution - - /// This function generates a Weibull distribution random number. - /// - ///\param k shape parameter (k>0) - ///\param lambda scale parameter (lambda>0) - /// - double weibull(double k,double lambda) - { - return lambda*pow(-std::log(1.0-real()),1.0/k); - } - - /// Pareto distribution - - /// This function generates a Pareto distribution random number. - /// - ///\param k shape parameter (k>0) - ///\param x_min location parameter (x_min>0) - /// - double pareto(double k,double x_min) - { - return exponential(gamma(k,1.0/x_min))+x_min; - } - - /// Poisson distribution - - /// This function generates a Poisson distribution random number with - /// parameter \c lambda. - /// - /// The probability mass function of this distribusion is - /// \f[ \frac{e^{-\lambda}\lambda^k}{k!} \f] - /// \note The algorithm is taken from the book of Donald E. Knuth titled - /// ''Seminumerical Algorithms'' (1969). Its running time is linear in the - /// return value. - - int poisson(double lambda) - { - const double l = std::exp(-lambda); - int k=0; - double p = 1.0; - do { - k++; - p*=real(); - } while (p>=l); - return k-1; - } - - ///@} - - ///\name Two Dimensional Distributions - /// - ///@{ - - /// Uniform distribution on the full unit circle - - /// Uniform distribution on the full unit circle. - /// - dim2::Point disc() - { - double V1,V2; - do { - V1=2*real()-1; - V2=2*real()-1; - - } while(V1*V1+V2*V2>=1); - return dim2::Point(V1,V2); - } - /// A kind of two dimensional normal (Gauss) distribution - - /// This function provides a turning symmetric two-dimensional distribution. - /// Both coordinates are of standard normal distribution, but they are not - /// independent. - /// - /// \note The coordinates are the two random variables provided by - /// the Box-Muller method. - dim2::Point gauss2() - { - double V1,V2,S; - do { - V1=2*real()-1; - V2=2*real()-1; - S=V1*V1+V2*V2; - } while(S>=1); - double W=std::sqrt(-2*std::log(S)/S); - return dim2::Point(W*V1,W*V2); - } - /// A kind of two dimensional exponential distribution - - /// This function provides a turning symmetric two-dimensional distribution. - /// The x-coordinate is of conditionally exponential distribution - /// with the condition that x is positive and y=0. If x is negative and - /// y=0 then, -x is of exponential distribution. The same is true for the - /// y-coordinate. - dim2::Point exponential2() - { - double V1,V2,S; - do { - V1=2*real()-1; - V2=2*real()-1; - S=V1*V1+V2*V2; - } while(S>=1); - double W=-std::log(S)/S; - return dim2::Point(W*V1,W*V2); - } - - ///@} - }; - - - extern Random rnd; - -} - -#endif diff --git a/deps/lemon/lemon/smart_graph.h b/deps/lemon/lemon/smart_graph.h deleted file mode 100644 index bdbe369a4..000000000 --- a/deps/lemon/lemon/smart_graph.h +++ /dev/null @@ -1,1344 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_SMART_GRAPH_H -#define LEMON_SMART_GRAPH_H - -///\ingroup graphs -///\file -///\brief SmartDigraph and SmartGraph classes. - -#include - -#include -#include -#include - -namespace lemon { - - class SmartDigraph; - - class SmartDigraphBase { - protected: - - struct NodeT - { - int first_in, first_out; - NodeT() {} - }; - struct ArcT - { - int target, source, next_in, next_out; - ArcT() {} - }; - - std::vector nodes; - std::vector arcs; - - public: - - typedef SmartDigraphBase Digraph; - - class Node; - class Arc; - - public: - - SmartDigraphBase() : nodes(), arcs() { } - SmartDigraphBase(const SmartDigraphBase &_g) - : nodes(_g.nodes), arcs(_g.arcs) { } - - typedef True NodeNumTag; - typedef True ArcNumTag; - - int nodeNum() const { return nodes.size(); } - int arcNum() const { return arcs.size(); } - - int maxNodeId() const { return nodes.size()-1; } - int maxArcId() const { return arcs.size()-1; } - - Node addNode() { - int n = nodes.size(); - nodes.push_back(NodeT()); - nodes[n].first_in = -1; - nodes[n].first_out = -1; - return Node(n); - } - - Arc addArc(Node u, Node v) { - int n = arcs.size(); - arcs.push_back(ArcT()); - arcs[n].source = u._id; - arcs[n].target = v._id; - arcs[n].next_out = nodes[u._id].first_out; - arcs[n].next_in = nodes[v._id].first_in; - nodes[u._id].first_out = nodes[v._id].first_in = n; - - return Arc(n); - } - - void clear() { - arcs.clear(); - nodes.clear(); - } - - Node source(Arc a) const { return Node(arcs[a._id].source); } - Node target(Arc a) const { return Node(arcs[a._id].target); } - - static int id(Node v) { return v._id; } - static int id(Arc a) { return a._id; } - - static Node nodeFromId(int id) { return Node(id);} - static Arc arcFromId(int id) { return Arc(id);} - - bool valid(Node n) const { - return n._id >= 0 && n._id < static_cast(nodes.size()); - } - bool valid(Arc a) const { - return a._id >= 0 && a._id < static_cast(arcs.size()); - } - - class Node { - friend class SmartDigraphBase; - friend class SmartDigraph; - - protected: - int _id; - explicit Node(int id) : _id(id) {} - public: - Node() {} - Node (Invalid) : _id(-1) {} - bool operator==(const Node i) const {return _id == i._id;} - bool operator!=(const Node i) const {return _id != i._id;} - bool operator<(const Node i) const {return _id < i._id;} - }; - - - class Arc { - friend class SmartDigraphBase; - friend class SmartDigraph; - - protected: - int _id; - explicit Arc(int id) : _id(id) {} - public: - Arc() { } - Arc (Invalid) : _id(-1) {} - bool operator==(const Arc i) const {return _id == i._id;} - bool operator!=(const Arc i) const {return _id != i._id;} - bool operator<(const Arc i) const {return _id < i._id;} - }; - - void first(Node& node) const { - node._id = nodes.size() - 1; - } - - static void next(Node& node) { - --node._id; - } - - void first(Arc& arc) const { - arc._id = arcs.size() - 1; - } - - static void next(Arc& arc) { - --arc._id; - } - - void firstOut(Arc& arc, const Node& node) const { - arc._id = nodes[node._id].first_out; - } - - void nextOut(Arc& arc) const { - arc._id = arcs[arc._id].next_out; - } - - void firstIn(Arc& arc, const Node& node) const { - arc._id = nodes[node._id].first_in; - } - - void nextIn(Arc& arc) const { - arc._id = arcs[arc._id].next_in; - } - - }; - - typedef DigraphExtender ExtendedSmartDigraphBase; - - ///\ingroup graphs - /// - ///\brief A smart directed graph class. - /// - ///\ref SmartDigraph is a simple and fast digraph implementation. - ///It is also quite memory efficient but at the price - ///that it does not support node and arc deletion - ///(except for the Snapshot feature). - /// - ///This type fully conforms to the \ref concepts::Digraph "Digraph concept" - ///and it also provides some additional functionalities. - ///Most of its member functions and nested classes are documented - ///only in the concept class. - /// - ///This class provides constant time counting for nodes and arcs. - /// - ///\sa concepts::Digraph - ///\sa SmartGraph - class SmartDigraph : public ExtendedSmartDigraphBase { - typedef ExtendedSmartDigraphBase Parent; - - private: - /// Digraphs are \e not copy constructible. Use DigraphCopy instead. - SmartDigraph(const SmartDigraph &) : ExtendedSmartDigraphBase() {}; - /// \brief Assignment of a digraph to another one is \e not allowed. - /// Use DigraphCopy instead. - void operator=(const SmartDigraph &) {} - - public: - - /// Constructor - - /// Constructor. - /// - SmartDigraph() {}; - - ///Add a new node to the digraph. - - ///This function adds a new node to the digraph. - ///\return The new node. - Node addNode() { return Parent::addNode(); } - - ///Add a new arc to the digraph. - - ///This function adds a new arc to the digraph with source node \c s - ///and target node \c t. - ///\return The new arc. - Arc addArc(Node s, Node t) { - return Parent::addArc(s, t); - } - - /// \brief Node validity check - /// - /// This function gives back \c true if the given node is valid, - /// i.e. it is a real node of the digraph. - /// - /// \warning A removed node (using Snapshot) could become valid again - /// if new nodes are added to the digraph. - bool valid(Node n) const { return Parent::valid(n); } - - /// \brief Arc validity check - /// - /// This function gives back \c true if the given arc is valid, - /// i.e. it is a real arc of the digraph. - /// - /// \warning A removed arc (using Snapshot) could become valid again - /// if new arcs are added to the graph. - bool valid(Arc a) const { return Parent::valid(a); } - - ///Split a node. - - ///This function splits the given node. First, a new node is added - ///to the digraph, then the source of each outgoing arc of node \c n - ///is moved to this new node. - ///If the second parameter \c connect is \c true (this is the default - ///value), then a new arc from node \c n to the newly created node - ///is also added. - ///\return The newly created node. - /// - ///\note All iterators remain valid. - /// - ///\warning This functionality cannot be used together with the Snapshot - ///feature. - Node split(Node n, bool connect = true) - { - Node b = addNode(); - nodes[b._id].first_out=nodes[n._id].first_out; - nodes[n._id].first_out=-1; - for(int i=nodes[b._id].first_out; i!=-1; i=arcs[i].next_out) { - arcs[i].source=b._id; - } - if(connect) addArc(n,b); - return b; - } - - ///Clear the digraph. - - ///This function erases all nodes and arcs from the digraph. - /// - void clear() { - Parent::clear(); - } - - /// Reserve memory for nodes. - - /// Using this function, it is possible to avoid superfluous memory - /// allocation: if you know that the digraph you want to build will - /// be large (e.g. it will contain millions of nodes and/or arcs), - /// then it is worth reserving space for this amount before starting - /// to build the digraph. - /// \sa reserveArc() - void reserveNode(int n) { nodes.reserve(n); }; - - /// Reserve memory for arcs. - - /// Using this function, it is possible to avoid superfluous memory - /// allocation: if you know that the digraph you want to build will - /// be large (e.g. it will contain millions of nodes and/or arcs), - /// then it is worth reserving space for this amount before starting - /// to build the digraph. - /// \sa reserveNode() - void reserveArc(int m) { arcs.reserve(m); }; - - public: - - class Snapshot; - - protected: - - void restoreSnapshot(const Snapshot &s) - { - while(s.arc_numnodes.size(); - arc_num=_graph->arcs.size(); - } - - ///Make a snapshot. - - ///This function makes a snapshot of the given digraph. - ///It can be called more than once. In case of a repeated - ///call, the previous snapshot gets lost. - void save(SmartDigraph &gr) { - _graph=&gr; - node_num=_graph->nodes.size(); - arc_num=_graph->arcs.size(); - } - - ///Undo the changes until a snapshot. - - ///This function undos the changes until the last snapshot - ///created by save() or Snapshot(SmartDigraph&). - void restore() - { - _graph->restoreSnapshot(*this); - } - }; - }; - - - class SmartGraphBase { - - protected: - - struct NodeT { - int first_out; - }; - - struct ArcT { - int target; - int next_out; - }; - - std::vector nodes; - std::vector arcs; - - public: - - typedef SmartGraphBase Graph; - - class Node; - class Arc; - class Edge; - - class Node { - friend class SmartGraphBase; - protected: - - int _id; - explicit Node(int id) { _id = id;} - - public: - Node() {} - Node (Invalid) { _id = -1; } - bool operator==(const Node& node) const {return _id == node._id;} - bool operator!=(const Node& node) const {return _id != node._id;} - bool operator<(const Node& node) const {return _id < node._id;} - }; - - class Edge { - friend class SmartGraphBase; - protected: - - int _id; - explicit Edge(int id) { _id = id;} - - public: - Edge() {} - Edge (Invalid) { _id = -1; } - bool operator==(const Edge& arc) const {return _id == arc._id;} - bool operator!=(const Edge& arc) const {return _id != arc._id;} - bool operator<(const Edge& arc) const {return _id < arc._id;} - }; - - class Arc { - friend class SmartGraphBase; - protected: - - int _id; - explicit Arc(int id) { _id = id;} - - public: - operator Edge() const { - return _id != -1 ? edgeFromId(_id / 2) : INVALID; - } - - Arc() {} - Arc (Invalid) { _id = -1; } - bool operator==(const Arc& arc) const {return _id == arc._id;} - bool operator!=(const Arc& arc) const {return _id != arc._id;} - bool operator<(const Arc& arc) const {return _id < arc._id;} - }; - - - - SmartGraphBase() - : nodes(), arcs() {} - - typedef True NodeNumTag; - typedef True EdgeNumTag; - typedef True ArcNumTag; - - int nodeNum() const { return nodes.size(); } - int edgeNum() const { return arcs.size() / 2; } - int arcNum() const { return arcs.size(); } - - int maxNodeId() const { return nodes.size()-1; } - int maxEdgeId() const { return arcs.size() / 2 - 1; } - int maxArcId() const { return arcs.size()-1; } - - Node source(Arc e) const { return Node(arcs[e._id ^ 1].target); } - Node target(Arc e) const { return Node(arcs[e._id].target); } - - Node u(Edge e) const { return Node(arcs[2 * e._id].target); } - Node v(Edge e) const { return Node(arcs[2 * e._id + 1].target); } - - static bool direction(Arc e) { - return (e._id & 1) == 1; - } - - static Arc direct(Edge e, bool d) { - return Arc(e._id * 2 + (d ? 1 : 0)); - } - - void first(Node& node) const { - node._id = nodes.size() - 1; - } - - static void next(Node& node) { - --node._id; - } - - void first(Arc& arc) const { - arc._id = arcs.size() - 1; - } - - static void next(Arc& arc) { - --arc._id; - } - - void first(Edge& arc) const { - arc._id = arcs.size() / 2 - 1; - } - - static void next(Edge& arc) { - --arc._id; - } - - void firstOut(Arc &arc, const Node& v) const { - arc._id = nodes[v._id].first_out; - } - void nextOut(Arc &arc) const { - arc._id = arcs[arc._id].next_out; - } - - void firstIn(Arc &arc, const Node& v) const { - arc._id = ((nodes[v._id].first_out) ^ 1); - if (arc._id == -2) arc._id = -1; - } - void nextIn(Arc &arc) const { - arc._id = ((arcs[arc._id ^ 1].next_out) ^ 1); - if (arc._id == -2) arc._id = -1; - } - - void firstInc(Edge &arc, bool& d, const Node& v) const { - int de = nodes[v._id].first_out; - if (de != -1) { - arc._id = de / 2; - d = ((de & 1) == 1); - } else { - arc._id = -1; - d = true; - } - } - void nextInc(Edge &arc, bool& d) const { - int de = (arcs[(arc._id * 2) | (d ? 1 : 0)].next_out); - if (de != -1) { - arc._id = de / 2; - d = ((de & 1) == 1); - } else { - arc._id = -1; - d = true; - } - } - - static int id(Node v) { return v._id; } - static int id(Arc e) { return e._id; } - static int id(Edge e) { return e._id; } - - static Node nodeFromId(int id) { return Node(id);} - static Arc arcFromId(int id) { return Arc(id);} - static Edge edgeFromId(int id) { return Edge(id);} - - bool valid(Node n) const { - return n._id >= 0 && n._id < static_cast(nodes.size()); - } - bool valid(Arc a) const { - return a._id >= 0 && a._id < static_cast(arcs.size()); - } - bool valid(Edge e) const { - return e._id >= 0 && 2 * e._id < static_cast(arcs.size()); - } - - Node addNode() { - int n = nodes.size(); - nodes.push_back(NodeT()); - nodes[n].first_out = -1; - - return Node(n); - } - - Edge addEdge(Node u, Node v) { - int n = arcs.size(); - arcs.push_back(ArcT()); - arcs.push_back(ArcT()); - - arcs[n].target = u._id; - arcs[n | 1].target = v._id; - - arcs[n].next_out = nodes[v._id].first_out; - nodes[v._id].first_out = n; - - arcs[n | 1].next_out = nodes[u._id].first_out; - nodes[u._id].first_out = (n | 1); - - return Edge(n / 2); - } - - void clear() { - arcs.clear(); - nodes.clear(); - } - - }; - - typedef GraphExtender ExtendedSmartGraphBase; - - /// \ingroup graphs - /// - /// \brief A smart undirected graph class. - /// - /// \ref SmartGraph is a simple and fast graph implementation. - /// It is also quite memory efficient but at the price - /// that it does not support node and edge deletion - /// (except for the Snapshot feature). - /// - /// This type fully conforms to the \ref concepts::Graph "Graph concept" - /// and it also provides some additional functionalities. - /// Most of its member functions and nested classes are documented - /// only in the concept class. - /// - /// This class provides constant time counting for nodes, edges and arcs. - /// - /// \sa concepts::Graph - /// \sa SmartDigraph - class SmartGraph : public ExtendedSmartGraphBase { - typedef ExtendedSmartGraphBase Parent; - - private: - /// Graphs are \e not copy constructible. Use GraphCopy instead. - SmartGraph(const SmartGraph &) : ExtendedSmartGraphBase() {}; - /// \brief Assignment of a graph to another one is \e not allowed. - /// Use GraphCopy instead. - void operator=(const SmartGraph &) {} - - public: - - /// Constructor - - /// Constructor. - /// - SmartGraph() {} - - /// \brief Add a new node to the graph. - /// - /// This function adds a new node to the graph. - /// \return The new node. - Node addNode() { return Parent::addNode(); } - - /// \brief Add a new edge to the graph. - /// - /// This function adds a new edge to the graph between nodes - /// \c u and \c v with inherent orientation from node \c u to - /// node \c v. - /// \return The new edge. - Edge addEdge(Node u, Node v) { - return Parent::addEdge(u, v); - } - - /// \brief Node validity check - /// - /// This function gives back \c true if the given node is valid, - /// i.e. it is a real node of the graph. - /// - /// \warning A removed node (using Snapshot) could become valid again - /// if new nodes are added to the graph. - bool valid(Node n) const { return Parent::valid(n); } - - /// \brief Edge validity check - /// - /// This function gives back \c true if the given edge is valid, - /// i.e. it is a real edge of the graph. - /// - /// \warning A removed edge (using Snapshot) could become valid again - /// if new edges are added to the graph. - bool valid(Edge e) const { return Parent::valid(e); } - - /// \brief Arc validity check - /// - /// This function gives back \c true if the given arc is valid, - /// i.e. it is a real arc of the graph. - /// - /// \warning A removed arc (using Snapshot) could become valid again - /// if new edges are added to the graph. - bool valid(Arc a) const { return Parent::valid(a); } - - ///Clear the graph. - - ///This function erases all nodes and arcs from the graph. - /// - void clear() { - Parent::clear(); - } - - /// Reserve memory for nodes. - - /// Using this function, it is possible to avoid superfluous memory - /// allocation: if you know that the graph you want to build will - /// be large (e.g. it will contain millions of nodes and/or edges), - /// then it is worth reserving space for this amount before starting - /// to build the graph. - /// \sa reserveEdge() - void reserveNode(int n) { nodes.reserve(n); }; - - /// Reserve memory for edges. - - /// Using this function, it is possible to avoid superfluous memory - /// allocation: if you know that the graph you want to build will - /// be large (e.g. it will contain millions of nodes and/or edges), - /// then it is worth reserving space for this amount before starting - /// to build the graph. - /// \sa reserveNode() - void reserveEdge(int m) { arcs.reserve(2 * m); }; - - public: - - class Snapshot; - - protected: - - void saveSnapshot(Snapshot &s) - { - s._graph = this; - s.node_num = nodes.size(); - s.arc_num = arcs.size(); - } - - void restoreSnapshot(const Snapshot &s) - { - while(s.arc_num dir; - dir.push_back(arcFromId(n)); - dir.push_back(arcFromId(n-1)); - Parent::notifier(Arc()).erase(dir); - nodes[arcs[n-1].target].first_out=arcs[n].next_out; - nodes[arcs[n].target].first_out=arcs[n-1].next_out; - arcs.pop_back(); - arcs.pop_back(); - } - while(s.node_numrestoreSnapshot(*this); - } - }; - }; - - class SmartBpGraphBase { - - protected: - - struct NodeT { - int first_out; - int partition_next; - int partition_index; - bool red; - }; - - struct ArcT { - int target; - int next_out; - }; - - std::vector nodes; - std::vector arcs; - - int first_red, first_blue; - int max_red, max_blue; - - public: - - typedef SmartBpGraphBase Graph; - - class Node; - class Arc; - class Edge; - - class Node { - friend class SmartBpGraphBase; - protected: - - int _id; - explicit Node(int id) { _id = id;} - - public: - Node() {} - Node (Invalid) { _id = -1; } - bool operator==(const Node& node) const {return _id == node._id;} - bool operator!=(const Node& node) const {return _id != node._id;} - bool operator<(const Node& node) const {return _id < node._id;} - }; - - class RedNode : public Node { - friend class SmartBpGraphBase; - protected: - - explicit RedNode(int pid) : Node(pid) {} - - public: - RedNode() {} - RedNode(const RedNode& node) : Node(node) {} - RedNode(Invalid) : Node(INVALID){} - }; - - class BlueNode : public Node { - friend class SmartBpGraphBase; - protected: - - explicit BlueNode(int pid) : Node(pid) {} - - public: - BlueNode() {} - BlueNode(const BlueNode& node) : Node(node) {} - BlueNode(Invalid) : Node(INVALID){} - }; - - class Edge { - friend class SmartBpGraphBase; - protected: - - int _id; - explicit Edge(int id) { _id = id;} - - public: - Edge() {} - Edge (Invalid) { _id = -1; } - bool operator==(const Edge& arc) const {return _id == arc._id;} - bool operator!=(const Edge& arc) const {return _id != arc._id;} - bool operator<(const Edge& arc) const {return _id < arc._id;} - }; - - class Arc { - friend class SmartBpGraphBase; - protected: - - int _id; - explicit Arc(int id) { _id = id;} - - public: - operator Edge() const { - return _id != -1 ? edgeFromId(_id / 2) : INVALID; - } - - Arc() {} - Arc (Invalid) { _id = -1; } - bool operator==(const Arc& arc) const {return _id == arc._id;} - bool operator!=(const Arc& arc) const {return _id != arc._id;} - bool operator<(const Arc& arc) const {return _id < arc._id;} - }; - - - - SmartBpGraphBase() - : nodes(), arcs(), first_red(-1), first_blue(-1), - max_red(-1), max_blue(-1) {} - - typedef True NodeNumTag; - typedef True EdgeNumTag; - typedef True ArcNumTag; - - int nodeNum() const { return nodes.size(); } - int redNum() const { return max_red + 1; } - int blueNum() const { return max_blue + 1; } - int edgeNum() const { return arcs.size() / 2; } - int arcNum() const { return arcs.size(); } - - int maxNodeId() const { return nodes.size()-1; } - int maxRedId() const { return max_red; } - int maxBlueId() const { return max_blue; } - int maxEdgeId() const { return arcs.size() / 2 - 1; } - int maxArcId() const { return arcs.size()-1; } - - bool red(Node n) const { return nodes[n._id].red; } - bool blue(Node n) const { return !nodes[n._id].red; } - - static RedNode asRedNodeUnsafe(Node n) { return RedNode(n._id); } - static BlueNode asBlueNodeUnsafe(Node n) { return BlueNode(n._id); } - - Node source(Arc a) const { return Node(arcs[a._id ^ 1].target); } - Node target(Arc a) const { return Node(arcs[a._id].target); } - - RedNode redNode(Edge e) const { - return RedNode(arcs[2 * e._id].target); - } - BlueNode blueNode(Edge e) const { - return BlueNode(arcs[2 * e._id + 1].target); - } - - static bool direction(Arc a) { - return (a._id & 1) == 1; - } - - static Arc direct(Edge e, bool d) { - return Arc(e._id * 2 + (d ? 1 : 0)); - } - - void first(Node& node) const { - node._id = nodes.size() - 1; - } - - static void next(Node& node) { - --node._id; - } - - void first(RedNode& node) const { - node._id = first_red; - } - - void next(RedNode& node) const { - node._id = nodes[node._id].partition_next; - } - - void first(BlueNode& node) const { - node._id = first_blue; - } - - void next(BlueNode& node) const { - node._id = nodes[node._id].partition_next; - } - - void first(Arc& arc) const { - arc._id = arcs.size() - 1; - } - - static void next(Arc& arc) { - --arc._id; - } - - void first(Edge& arc) const { - arc._id = arcs.size() / 2 - 1; - } - - static void next(Edge& arc) { - --arc._id; - } - - void firstOut(Arc &arc, const Node& v) const { - arc._id = nodes[v._id].first_out; - } - void nextOut(Arc &arc) const { - arc._id = arcs[arc._id].next_out; - } - - void firstIn(Arc &arc, const Node& v) const { - arc._id = ((nodes[v._id].first_out) ^ 1); - if (arc._id == -2) arc._id = -1; - } - void nextIn(Arc &arc) const { - arc._id = ((arcs[arc._id ^ 1].next_out) ^ 1); - if (arc._id == -2) arc._id = -1; - } - - void firstInc(Edge &arc, bool& d, const Node& v) const { - int de = nodes[v._id].first_out; - if (de != -1) { - arc._id = de / 2; - d = ((de & 1) == 1); - } else { - arc._id = -1; - d = true; - } - } - void nextInc(Edge &arc, bool& d) const { - int de = (arcs[(arc._id * 2) | (d ? 1 : 0)].next_out); - if (de != -1) { - arc._id = de / 2; - d = ((de & 1) == 1); - } else { - arc._id = -1; - d = true; - } - } - - static int id(Node v) { return v._id; } - int id(RedNode v) const { return nodes[v._id].partition_index; } - int id(BlueNode v) const { return nodes[v._id].partition_index; } - static int id(Arc e) { return e._id; } - static int id(Edge e) { return e._id; } - - static Node nodeFromId(int id) { return Node(id);} - static Arc arcFromId(int id) { return Arc(id);} - static Edge edgeFromId(int id) { return Edge(id);} - - bool valid(Node n) const { - return n._id >= 0 && n._id < static_cast(nodes.size()); - } - bool valid(Arc a) const { - return a._id >= 0 && a._id < static_cast(arcs.size()); - } - bool valid(Edge e) const { - return e._id >= 0 && 2 * e._id < static_cast(arcs.size()); - } - - RedNode addRedNode() { - int n = nodes.size(); - nodes.push_back(NodeT()); - nodes[n].first_out = -1; - nodes[n].red = true; - nodes[n].partition_index = ++max_red; - nodes[n].partition_next = first_red; - first_red = n; - - return RedNode(n); - } - - BlueNode addBlueNode() { - int n = nodes.size(); - nodes.push_back(NodeT()); - nodes[n].first_out = -1; - nodes[n].red = false; - nodes[n].partition_index = ++max_blue; - nodes[n].partition_next = first_blue; - first_blue = n; - - return BlueNode(n); - } - - Edge addEdge(RedNode u, BlueNode v) { - int n = arcs.size(); - arcs.push_back(ArcT()); - arcs.push_back(ArcT()); - - arcs[n].target = u._id; - arcs[n | 1].target = v._id; - - arcs[n].next_out = nodes[v._id].first_out; - nodes[v._id].first_out = n; - - arcs[n | 1].next_out = nodes[u._id].first_out; - nodes[u._id].first_out = (n | 1); - - return Edge(n / 2); - } - - void clear() { - arcs.clear(); - nodes.clear(); - first_red = -1; - first_blue = -1; - max_blue = -1; - max_red = -1; - } - - }; - - typedef BpGraphExtender ExtendedSmartBpGraphBase; - - /// \ingroup graphs - /// - /// \brief A smart undirected bipartite graph class. - /// - /// \ref SmartBpGraph is a simple and fast bipartite graph implementation. - /// It is also quite memory efficient but at the price - /// that it does not support node and edge deletion - /// (except for the Snapshot feature). - /// - /// This type fully conforms to the \ref concepts::BpGraph "BpGraph concept" - /// and it also provides some additional functionalities. - /// Most of its member functions and nested classes are documented - /// only in the concept class. - /// - /// This class provides constant time counting for nodes, edges and arcs. - /// - /// \sa concepts::BpGraph - /// \sa SmartGraph - class SmartBpGraph : public ExtendedSmartBpGraphBase { - typedef ExtendedSmartBpGraphBase Parent; - - private: - /// Graphs are \e not copy constructible. Use GraphCopy instead. - SmartBpGraph(const SmartBpGraph &) : ExtendedSmartBpGraphBase() {}; - /// \brief Assignment of a graph to another one is \e not allowed. - /// Use GraphCopy instead. - void operator=(const SmartBpGraph &) {} - - public: - - /// Constructor - - /// Constructor. - /// - SmartBpGraph() {} - - /// \brief Add a new red node to the graph. - /// - /// This function adds a red new node to the graph. - /// \return The new node. - RedNode addRedNode() { return Parent::addRedNode(); } - - /// \brief Add a new blue node to the graph. - /// - /// This function adds a blue new node to the graph. - /// \return The new node. - BlueNode addBlueNode() { return Parent::addBlueNode(); } - - /// \brief Add a new edge to the graph. - /// - /// This function adds a new edge to the graph between nodes - /// \c u and \c v with inherent orientation from node \c u to - /// node \c v. - /// \return The new edge. - Edge addEdge(RedNode u, BlueNode v) { - return Parent::addEdge(u, v); - } - Edge addEdge(BlueNode v, RedNode u) { - return Parent::addEdge(u, v); - } - - /// \brief Node validity check - /// - /// This function gives back \c true if the given node is valid, - /// i.e. it is a real node of the graph. - /// - /// \warning A removed node (using Snapshot) could become valid again - /// if new nodes are added to the graph. - bool valid(Node n) const { return Parent::valid(n); } - - /// \brief Edge validity check - /// - /// This function gives back \c true if the given edge is valid, - /// i.e. it is a real edge of the graph. - /// - /// \warning A removed edge (using Snapshot) could become valid again - /// if new edges are added to the graph. - bool valid(Edge e) const { return Parent::valid(e); } - - /// \brief Arc validity check - /// - /// This function gives back \c true if the given arc is valid, - /// i.e. it is a real arc of the graph. - /// - /// \warning A removed arc (using Snapshot) could become valid again - /// if new edges are added to the graph. - bool valid(Arc a) const { return Parent::valid(a); } - - ///Clear the graph. - - ///This function erases all nodes and arcs from the graph. - /// - void clear() { - Parent::clear(); - } - - /// Reserve memory for nodes. - - /// Using this function, it is possible to avoid superfluous memory - /// allocation: if you know that the graph you want to build will - /// be large (e.g. it will contain millions of nodes and/or edges), - /// then it is worth reserving space for this amount before starting - /// to build the graph. - /// \sa reserveEdge() - void reserveNode(int n) { nodes.reserve(n); }; - - /// Reserve memory for edges. - - /// Using this function, it is possible to avoid superfluous memory - /// allocation: if you know that the graph you want to build will - /// be large (e.g. it will contain millions of nodes and/or edges), - /// then it is worth reserving space for this amount before starting - /// to build the graph. - /// \sa reserveNode() - void reserveEdge(int m) { arcs.reserve(2 * m); }; - - public: - - class Snapshot; - - protected: - - void saveSnapshot(Snapshot &s) - { - s._graph = this; - s.node_num = nodes.size(); - s.arc_num = arcs.size(); - } - - void restoreSnapshot(const Snapshot &s) - { - while(s.arc_num dir; - dir.push_back(arcFromId(n)); - dir.push_back(arcFromId(n-1)); - Parent::notifier(Arc()).erase(dir); - nodes[arcs[n-1].target].first_out=arcs[n].next_out; - nodes[arcs[n].target].first_out=arcs[n-1].next_out; - arcs.pop_back(); - arcs.pop_back(); - } - while(s.node_numrestoreSnapshot(*this); - } - }; - }; - -} //namespace lemon - - -#endif //LEMON_SMART_GRAPH_H diff --git a/deps/lemon/lemon/soplex.cc b/deps/lemon/lemon/soplex.cc deleted file mode 100644 index d7517231c..000000000 --- a/deps/lemon/lemon/soplex.cc +++ /dev/null @@ -1,465 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include - -#include -#include - - -///\file -///\brief Implementation of the LEMON-SOPLEX lp solver interface. -namespace lemon { - - SoplexLp::SoplexLp() { - soplex = new soplex::SoPlex; - messageLevel(MESSAGE_NOTHING); - } - - SoplexLp::~SoplexLp() { - delete soplex; - } - - SoplexLp::SoplexLp(const SoplexLp& lp) { - rows = lp.rows; - cols = lp.cols; - - soplex = new soplex::SoPlex; - (*static_cast(soplex)) = *(lp.soplex); - - _col_names = lp._col_names; - _col_names_ref = lp._col_names_ref; - - _row_names = lp._row_names; - _row_names_ref = lp._row_names_ref; - - messageLevel(MESSAGE_NOTHING); - } - - void SoplexLp::_clear_temporals() { - _primal_values.clear(); - _dual_values.clear(); - } - - SoplexLp* SoplexLp::newSolver() const { - SoplexLp* newlp = new SoplexLp(); - return newlp; - } - - SoplexLp* SoplexLp::cloneSolver() const { - SoplexLp* newlp = new SoplexLp(*this); - return newlp; - } - - const char* SoplexLp::_solverName() const { return "SoplexLp"; } - - int SoplexLp::_addCol() { - soplex::LPCol c; - c.setLower(-soplex::infinity); - c.setUpper(soplex::infinity); - soplex->addCol(c); - - _col_names.push_back(std::string()); - - return soplex->nCols() - 1; - } - - int SoplexLp::_addRow() { - soplex::LPRow r; - r.setLhs(-soplex::infinity); - r.setRhs(soplex::infinity); - soplex->addRow(r); - - _row_names.push_back(std::string()); - - return soplex->nRows() - 1; - } - - int SoplexLp::_addRow(Value l, ExprIterator b, ExprIterator e, Value u) { - soplex::DSVector v; - for (ExprIterator it = b; it != e; ++it) { - v.add(it->first, it->second); - } - soplex::LPRow r(l, v, u); - soplex->addRow(r); - - _row_names.push_back(std::string()); - - return soplex->nRows() - 1; - } - - - void SoplexLp::_eraseCol(int i) { - soplex->removeCol(i); - _col_names_ref.erase(_col_names[i]); - _col_names[i] = _col_names.back(); - _col_names_ref[_col_names.back()] = i; - _col_names.pop_back(); - } - - void SoplexLp::_eraseRow(int i) { - soplex->removeRow(i); - _row_names_ref.erase(_row_names[i]); - _row_names[i] = _row_names.back(); - _row_names_ref[_row_names.back()] = i; - _row_names.pop_back(); - } - - void SoplexLp::_eraseColId(int i) { - cols.eraseIndex(i); - cols.relocateIndex(i, cols.maxIndex()); - } - void SoplexLp::_eraseRowId(int i) { - rows.eraseIndex(i); - rows.relocateIndex(i, rows.maxIndex()); - } - - void SoplexLp::_getColName(int c, std::string &name) const { - name = _col_names[c]; - } - - void SoplexLp::_setColName(int c, const std::string &name) { - _col_names_ref.erase(_col_names[c]); - _col_names[c] = name; - if (!name.empty()) { - _col_names_ref.insert(std::make_pair(name, c)); - } - } - - int SoplexLp::_colByName(const std::string& name) const { - std::map::const_iterator it = - _col_names_ref.find(name); - if (it != _col_names_ref.end()) { - return it->second; - } else { - return -1; - } - } - - void SoplexLp::_getRowName(int r, std::string &name) const { - name = _row_names[r]; - } - - void SoplexLp::_setRowName(int r, const std::string &name) { - _row_names_ref.erase(_row_names[r]); - _row_names[r] = name; - if (!name.empty()) { - _row_names_ref.insert(std::make_pair(name, r)); - } - } - - int SoplexLp::_rowByName(const std::string& name) const { - std::map::const_iterator it = - _row_names_ref.find(name); - if (it != _row_names_ref.end()) { - return it->second; - } else { - return -1; - } - } - - - void SoplexLp::_setRowCoeffs(int i, ExprIterator b, ExprIterator e) { - for (int j = 0; j < soplex->nCols(); ++j) { - soplex->changeElement(i, j, 0.0); - } - for(ExprIterator it = b; it != e; ++it) { - soplex->changeElement(i, it->first, it->second); - } - } - - void SoplexLp::_getRowCoeffs(int i, InsertIterator b) const { - const soplex::SVector& vec = soplex->rowVector(i); - for (int k = 0; k < vec.size(); ++k) { - *b = std::make_pair(vec.index(k), vec.value(k)); - ++b; - } - } - - void SoplexLp::_setColCoeffs(int j, ExprIterator b, ExprIterator e) { - for (int i = 0; i < soplex->nRows(); ++i) { - soplex->changeElement(i, j, 0.0); - } - for(ExprIterator it = b; it != e; ++it) { - soplex->changeElement(it->first, j, it->second); - } - } - - void SoplexLp::_getColCoeffs(int i, InsertIterator b) const { - const soplex::SVector& vec = soplex->colVector(i); - for (int k = 0; k < vec.size(); ++k) { - *b = std::make_pair(vec.index(k), vec.value(k)); - ++b; - } - } - - void SoplexLp::_setCoeff(int i, int j, Value value) { - soplex->changeElement(i, j, value); - } - - SoplexLp::Value SoplexLp::_getCoeff(int i, int j) const { - return soplex->rowVector(i)[j]; - } - - void SoplexLp::_setColLowerBound(int i, Value value) { - LEMON_ASSERT(value != INF, "Invalid bound"); - soplex->changeLower(i, value != -INF ? value : -soplex::infinity); - } - - SoplexLp::Value SoplexLp::_getColLowerBound(int i) const { - double value = soplex->lower(i); - return value != -soplex::infinity ? value : -INF; - } - - void SoplexLp::_setColUpperBound(int i, Value value) { - LEMON_ASSERT(value != -INF, "Invalid bound"); - soplex->changeUpper(i, value != INF ? value : soplex::infinity); - } - - SoplexLp::Value SoplexLp::_getColUpperBound(int i) const { - double value = soplex->upper(i); - return value != soplex::infinity ? value : INF; - } - - void SoplexLp::_setRowLowerBound(int i, Value lb) { - LEMON_ASSERT(lb != INF, "Invalid bound"); - soplex->changeRange(i, lb != -INF ? lb : -soplex::infinity, soplex->rhs(i)); - } - - SoplexLp::Value SoplexLp::_getRowLowerBound(int i) const { - double res = soplex->lhs(i); - return res == -soplex::infinity ? -INF : res; - } - - void SoplexLp::_setRowUpperBound(int i, Value ub) { - LEMON_ASSERT(ub != -INF, "Invalid bound"); - soplex->changeRange(i, soplex->lhs(i), ub != INF ? ub : soplex::infinity); - } - - SoplexLp::Value SoplexLp::_getRowUpperBound(int i) const { - double res = soplex->rhs(i); - return res == soplex::infinity ? INF : res; - } - - void SoplexLp::_setObjCoeffs(ExprIterator b, ExprIterator e) { - for (int j = 0; j < soplex->nCols(); ++j) { - soplex->changeObj(j, 0.0); - } - for (ExprIterator it = b; it != e; ++it) { - soplex->changeObj(it->first, it->second); - } - } - - void SoplexLp::_getObjCoeffs(InsertIterator b) const { - for (int j = 0; j < soplex->nCols(); ++j) { - Value coef = soplex->obj(j); - if (coef != 0.0) { - *b = std::make_pair(j, coef); - ++b; - } - } - } - - void SoplexLp::_setObjCoeff(int i, Value obj_coef) { - soplex->changeObj(i, obj_coef); - } - - SoplexLp::Value SoplexLp::_getObjCoeff(int i) const { - return soplex->obj(i); - } - - SoplexLp::SolveExitStatus SoplexLp::_solve() { - - _clear_temporals(); - - _applyMessageLevel(); - - soplex::SPxSolver::Status status = soplex->solve(); - - switch (status) { - case soplex::SPxSolver::OPTIMAL: - case soplex::SPxSolver::INFEASIBLE: - case soplex::SPxSolver::UNBOUNDED: - return SOLVED; - default: - return UNSOLVED; - } - } - - SoplexLp::Value SoplexLp::_getPrimal(int i) const { - if (_primal_values.empty()) { - _primal_values.resize(soplex->nCols()); - soplex::Vector pv(_primal_values.size(), &_primal_values.front()); - soplex->getPrimal(pv); - } - return _primal_values[i]; - } - - SoplexLp::Value SoplexLp::_getDual(int i) const { - if (_dual_values.empty()) { - _dual_values.resize(soplex->nRows()); - soplex::Vector dv(_dual_values.size(), &_dual_values.front()); - soplex->getDual(dv); - } - return _dual_values[i]; - } - - SoplexLp::Value SoplexLp::_getPrimalValue() const { - return soplex->objValue(); - } - - SoplexLp::VarStatus SoplexLp::_getColStatus(int i) const { - switch (soplex->getBasisColStatus(i)) { - case soplex::SPxSolver::BASIC: - return BASIC; - case soplex::SPxSolver::ON_UPPER: - return UPPER; - case soplex::SPxSolver::ON_LOWER: - return LOWER; - case soplex::SPxSolver::FIXED: - return FIXED; - case soplex::SPxSolver::ZERO: - return FREE; - default: - LEMON_ASSERT(false, "Wrong column status"); - return VarStatus(); - } - } - - SoplexLp::VarStatus SoplexLp::_getRowStatus(int i) const { - switch (soplex->getBasisRowStatus(i)) { - case soplex::SPxSolver::BASIC: - return BASIC; - case soplex::SPxSolver::ON_UPPER: - return UPPER; - case soplex::SPxSolver::ON_LOWER: - return LOWER; - case soplex::SPxSolver::FIXED: - return FIXED; - case soplex::SPxSolver::ZERO: - return FREE; - default: - LEMON_ASSERT(false, "Wrong row status"); - return VarStatus(); - } - } - - SoplexLp::Value SoplexLp::_getPrimalRay(int i) const { - if (_primal_ray.empty()) { - _primal_ray.resize(soplex->nCols()); - soplex::Vector pv(_primal_ray.size(), &_primal_ray.front()); - soplex->getDualfarkas(pv); - } - return _primal_ray[i]; - } - - SoplexLp::Value SoplexLp::_getDualRay(int i) const { - if (_dual_ray.empty()) { - _dual_ray.resize(soplex->nRows()); - soplex::Vector dv(_dual_ray.size(), &_dual_ray.front()); - soplex->getDualfarkas(dv); - } - return _dual_ray[i]; - } - - SoplexLp::ProblemType SoplexLp::_getPrimalType() const { - switch (soplex->status()) { - case soplex::SPxSolver::OPTIMAL: - return OPTIMAL; - case soplex::SPxSolver::UNBOUNDED: - return UNBOUNDED; - case soplex::SPxSolver::INFEASIBLE: - return INFEASIBLE; - default: - return UNDEFINED; - } - } - - SoplexLp::ProblemType SoplexLp::_getDualType() const { - switch (soplex->status()) { - case soplex::SPxSolver::OPTIMAL: - return OPTIMAL; - case soplex::SPxSolver::UNBOUNDED: - return UNBOUNDED; - case soplex::SPxSolver::INFEASIBLE: - return INFEASIBLE; - default: - return UNDEFINED; - } - } - - void SoplexLp::_setSense(Sense sense) { - switch (sense) { - case MIN: - soplex->changeSense(soplex::SPxSolver::MINIMIZE); - break; - case MAX: - soplex->changeSense(soplex::SPxSolver::MAXIMIZE); - } - } - - SoplexLp::Sense SoplexLp::_getSense() const { - switch (soplex->spxSense()) { - case soplex::SPxSolver::MAXIMIZE: - return MAX; - case soplex::SPxSolver::MINIMIZE: - return MIN; - default: - LEMON_ASSERT(false, "Wrong sense."); - return SoplexLp::Sense(); - } - } - - void SoplexLp::_clear() { - soplex->clear(); - _col_names.clear(); - _col_names_ref.clear(); - _row_names.clear(); - _row_names_ref.clear(); - cols.clear(); - rows.clear(); - _clear_temporals(); - } - - void SoplexLp::_messageLevel(MessageLevel level) { - switch (level) { - case MESSAGE_NOTHING: - _message_level = -1; - break; - case MESSAGE_ERROR: - _message_level = soplex::SPxOut::ERROR; - break; - case MESSAGE_WARNING: - _message_level = soplex::SPxOut::WARNING; - break; - case MESSAGE_NORMAL: - _message_level = soplex::SPxOut::INFO2; - break; - case MESSAGE_VERBOSE: - _message_level = soplex::SPxOut::DEBUG; - break; - } - } - - void SoplexLp::_applyMessageLevel() { - soplex::Param::setVerbose(_message_level); - } - -} //namespace lemon - diff --git a/deps/lemon/lemon/soplex.h b/deps/lemon/lemon/soplex.h deleted file mode 100644 index be73f3abe..000000000 --- a/deps/lemon/lemon/soplex.h +++ /dev/null @@ -1,158 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_SOPLEX_H -#define LEMON_SOPLEX_H - -///\file -///\brief Header of the LEMON-SOPLEX lp solver interface. - -#include -#include - -#include - -// Forward declaration -namespace soplex { - class SoPlex; -} - -namespace lemon { - - /// \ingroup lp_group - /// - /// \brief Interface for the SOPLEX solver - /// - /// This class implements an interface for the SoPlex LP solver. - /// The SoPlex library is an object oriented lp solver library - /// developed at the Konrad-Zuse-Zentrum für Informationstechnik - /// Berlin (ZIB). You can find detailed information about it at the - /// http://soplex.zib.de address. - class SoplexLp : public LpSolver { - private: - - soplex::SoPlex* soplex; - - std::vector _col_names; - std::map _col_names_ref; - - std::vector _row_names; - std::map _row_names_ref; - - private: - - // these values cannot be retrieved element by element - mutable std::vector _primal_values; - mutable std::vector _dual_values; - - mutable std::vector _primal_ray; - mutable std::vector _dual_ray; - - void _clear_temporals(); - - public: - - /// \e - SoplexLp(); - /// \e - SoplexLp(const SoplexLp&); - /// \e - ~SoplexLp(); - /// \e - virtual SoplexLp* newSolver() const; - /// \e - virtual SoplexLp* cloneSolver() const; - - protected: - - virtual const char* _solverName() const; - - virtual int _addCol(); - virtual int _addRow(); - virtual int _addRow(Value l, ExprIterator b, ExprIterator e, Value u); - - virtual void _eraseCol(int i); - virtual void _eraseRow(int i); - - virtual void _eraseColId(int i); - virtual void _eraseRowId(int i); - - virtual void _getColName(int col, std::string& name) const; - virtual void _setColName(int col, const std::string& name); - virtual int _colByName(const std::string& name) const; - - virtual void _getRowName(int row, std::string& name) const; - virtual void _setRowName(int row, const std::string& name); - virtual int _rowByName(const std::string& name) const; - - virtual void _setRowCoeffs(int i, ExprIterator b, ExprIterator e); - virtual void _getRowCoeffs(int i, InsertIterator b) const; - - virtual void _setColCoeffs(int i, ExprIterator b, ExprIterator e); - virtual void _getColCoeffs(int i, InsertIterator b) const; - - virtual void _setCoeff(int row, int col, Value value); - virtual Value _getCoeff(int row, int col) const; - - virtual void _setColLowerBound(int i, Value value); - virtual Value _getColLowerBound(int i) const; - virtual void _setColUpperBound(int i, Value value); - virtual Value _getColUpperBound(int i) const; - - virtual void _setRowLowerBound(int i, Value value); - virtual Value _getRowLowerBound(int i) const; - virtual void _setRowUpperBound(int i, Value value); - virtual Value _getRowUpperBound(int i) const; - - virtual void _setObjCoeffs(ExprIterator b, ExprIterator e); - virtual void _getObjCoeffs(InsertIterator b) const; - - virtual void _setObjCoeff(int i, Value obj_coef); - virtual Value _getObjCoeff(int i) const; - - virtual void _setSense(Sense sense); - virtual Sense _getSense() const; - - virtual SolveExitStatus _solve(); - virtual Value _getPrimal(int i) const; - virtual Value _getDual(int i) const; - - virtual Value _getPrimalValue() const; - - virtual Value _getPrimalRay(int i) const; - virtual Value _getDualRay(int i) const; - - virtual VarStatus _getColStatus(int i) const; - virtual VarStatus _getRowStatus(int i) const; - - virtual ProblemType _getPrimalType() const; - virtual ProblemType _getDualType() const; - - virtual void _clear(); - - void _messageLevel(MessageLevel m); - void _applyMessageLevel(); - - int _message_level; - - }; - -} //END OF NAMESPACE LEMON - -#endif //LEMON_SOPLEX_H - diff --git a/deps/lemon/lemon/static_graph.h b/deps/lemon/lemon/static_graph.h deleted file mode 100644 index 1f04e4084..000000000 --- a/deps/lemon/lemon/static_graph.h +++ /dev/null @@ -1,476 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2010 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_STATIC_GRAPH_H -#define LEMON_STATIC_GRAPH_H - -///\ingroup graphs -///\file -///\brief StaticDigraph class. - -#include -#include - -namespace lemon { - - class StaticDigraphBase { - public: - - StaticDigraphBase() - : built(false), node_num(0), arc_num(0), - node_first_out(NULL), node_first_in(NULL), - arc_source(NULL), arc_target(NULL), - arc_next_in(NULL), arc_next_out(NULL) {} - - ~StaticDigraphBase() { - if (built) { - delete[] node_first_out; - delete[] node_first_in; - delete[] arc_source; - delete[] arc_target; - delete[] arc_next_out; - delete[] arc_next_in; - } - } - - class Node { - friend class StaticDigraphBase; - protected: - int id; - Node(int _id) : id(_id) {} - public: - Node() {} - Node (Invalid) : id(-1) {} - bool operator==(const Node& node) const { return id == node.id; } - bool operator!=(const Node& node) const { return id != node.id; } - bool operator<(const Node& node) const { return id < node.id; } - }; - - class Arc { - friend class StaticDigraphBase; - protected: - int id; - Arc(int _id) : id(_id) {} - public: - Arc() { } - Arc (Invalid) : id(-1) {} - bool operator==(const Arc& arc) const { return id == arc.id; } - bool operator!=(const Arc& arc) const { return id != arc.id; } - bool operator<(const Arc& arc) const { return id < arc.id; } - }; - - Node source(const Arc& e) const { return Node(arc_source[e.id]); } - Node target(const Arc& e) const { return Node(arc_target[e.id]); } - - void first(Node& n) const { n.id = node_num - 1; } - static void next(Node& n) { --n.id; } - - void first(Arc& e) const { e.id = arc_num - 1; } - static void next(Arc& e) { --e.id; } - - void firstOut(Arc& e, const Node& n) const { - e.id = node_first_out[n.id] != node_first_out[n.id + 1] ? - node_first_out[n.id] : -1; - } - void nextOut(Arc& e) const { e.id = arc_next_out[e.id]; } - - void firstIn(Arc& e, const Node& n) const { e.id = node_first_in[n.id]; } - void nextIn(Arc& e) const { e.id = arc_next_in[e.id]; } - - static int id(const Node& n) { return n.id; } - static Node nodeFromId(int id) { return Node(id); } - int maxNodeId() const { return node_num - 1; } - - static int id(const Arc& e) { return e.id; } - static Arc arcFromId(int id) { return Arc(id); } - int maxArcId() const { return arc_num - 1; } - - typedef True NodeNumTag; - typedef True ArcNumTag; - - int nodeNum() const { return node_num; } - int arcNum() const { return arc_num; } - - private: - - template - class ArcLess { - public: - typedef typename Digraph::Arc Arc; - - ArcLess(const Digraph &_graph, const NodeRefMap& _nodeRef) - : digraph(_graph), nodeRef(_nodeRef) {} - - bool operator()(const Arc& left, const Arc& right) const { - return nodeRef[digraph.target(left)] < nodeRef[digraph.target(right)]; - } - private: - const Digraph& digraph; - const NodeRefMap& nodeRef; - }; - - public: - - typedef True BuildTag; - - void clear() { - if (built) { - delete[] node_first_out; - delete[] node_first_in; - delete[] arc_source; - delete[] arc_target; - delete[] arc_next_out; - delete[] arc_next_in; - } - built = false; - node_num = 0; - arc_num = 0; - } - - template - void build(const Digraph& digraph, NodeRefMap& nodeRef, ArcRefMap& arcRef) { - typedef typename Digraph::Node GNode; - typedef typename Digraph::Arc GArc; - - built = true; - - node_num = countNodes(digraph); - arc_num = countArcs(digraph); - - node_first_out = new int[node_num + 1]; - node_first_in = new int[node_num]; - - arc_source = new int[arc_num]; - arc_target = new int[arc_num]; - arc_next_out = new int[arc_num]; - arc_next_in = new int[arc_num]; - - int node_index = 0; - for (typename Digraph::NodeIt n(digraph); n != INVALID; ++n) { - nodeRef[n] = Node(node_index); - node_first_in[node_index] = -1; - ++node_index; - } - - ArcLess arcLess(digraph, nodeRef); - - int arc_index = 0; - for (typename Digraph::NodeIt n(digraph); n != INVALID; ++n) { - int source = nodeRef[n].id; - std::vector arcs; - for (typename Digraph::OutArcIt e(digraph, n); e != INVALID; ++e) { - arcs.push_back(e); - } - if (!arcs.empty()) { - node_first_out[source] = arc_index; - std::sort(arcs.begin(), arcs.end(), arcLess); - for (typename std::vector::iterator it = arcs.begin(); - it != arcs.end(); ++it) { - int target = nodeRef[digraph.target(*it)].id; - arcRef[*it] = Arc(arc_index); - arc_source[arc_index] = source; - arc_target[arc_index] = target; - arc_next_in[arc_index] = node_first_in[target]; - node_first_in[target] = arc_index; - arc_next_out[arc_index] = arc_index + 1; - ++arc_index; - } - arc_next_out[arc_index - 1] = -1; - } else { - node_first_out[source] = arc_index; - } - } - node_first_out[node_num] = arc_num; - } - - template - void build(int n, ArcListIterator first, ArcListIterator last) { - built = true; - - node_num = n; - arc_num = std::distance(first, last); - - node_first_out = new int[node_num + 1]; - node_first_in = new int[node_num]; - - arc_source = new int[arc_num]; - arc_target = new int[arc_num]; - arc_next_out = new int[arc_num]; - arc_next_in = new int[arc_num]; - - for (int i = 0; i != node_num; ++i) { - node_first_in[i] = -1; - } - - int arc_index = 0; - for (int i = 0; i != node_num; ++i) { - node_first_out[i] = arc_index; - for ( ; first != last && (*first).first == i; ++first) { - int j = (*first).second; - LEMON_ASSERT(j >= 0 && j < node_num, - "Wrong arc list for StaticDigraph::build()"); - arc_source[arc_index] = i; - arc_target[arc_index] = j; - arc_next_in[arc_index] = node_first_in[j]; - node_first_in[j] = arc_index; - arc_next_out[arc_index] = arc_index + 1; - ++arc_index; - } - if (arc_index > node_first_out[i]) - arc_next_out[arc_index - 1] = -1; - } - LEMON_ASSERT(first == last, - "Wrong arc list for StaticDigraph::build()"); - node_first_out[node_num] = arc_num; - } - - protected: - - void fastFirstOut(Arc& e, const Node& n) const { - e.id = node_first_out[n.id]; - } - - static void fastNextOut(Arc& e) { - ++e.id; - } - void fastLastOut(Arc& e, const Node& n) const { - e.id = node_first_out[n.id + 1]; - } - - protected: - bool built; - int node_num; - int arc_num; - int *node_first_out; - int *node_first_in; - int *arc_source; - int *arc_target; - int *arc_next_in; - int *arc_next_out; - }; - - typedef DigraphExtender ExtendedStaticDigraphBase; - - - /// \ingroup graphs - /// - /// \brief A static directed graph class. - /// - /// \ref StaticDigraph is a highly efficient digraph implementation, - /// but it is fully static. - /// It stores only two \c int values for each node and only four \c int - /// values for each arc. Moreover it provides faster item iteration than - /// \ref ListDigraph and \ref SmartDigraph, especially using \c OutArcIt - /// iterators, since its arcs are stored in an appropriate order. - /// However it only provides build() and clear() functions and does not - /// support any other modification of the digraph. - /// - /// Since this digraph structure is completely static, its nodes and arcs - /// can be indexed with integers from the ranges [0..nodeNum()-1] - /// and [0..arcNum()-1], respectively. - /// The index of an item is the same as its ID, it can be obtained - /// using the corresponding \ref index() or \ref concepts::Digraph::id() - /// "id()" function. A node or arc with a certain index can be obtained - /// using node() or arc(). - /// - /// This type fully conforms to the \ref concepts::Digraph "Digraph concept". - /// Most of its member functions and nested classes are documented - /// only in the concept class. - /// - /// This class provides constant time counting for nodes and arcs. - /// - /// \sa concepts::Digraph - class StaticDigraph : public ExtendedStaticDigraphBase { - public: - - typedef ExtendedStaticDigraphBase Parent; - - public: - - /// \brief Constructor - /// - /// Default constructor. - StaticDigraph() : Parent() {} - - /// \brief The node with the given index. - /// - /// This function returns the node with the given index. - /// \sa index() - static Node node(int ix) { return Parent::nodeFromId(ix); } - - /// \brief The arc with the given index. - /// - /// This function returns the arc with the given index. - /// \sa index() - static Arc arc(int ix) { return Parent::arcFromId(ix); } - - /// \brief The index of the given node. - /// - /// This function returns the index of the the given node. - /// \sa node() - static int index(Node node) { return Parent::id(node); } - - /// \brief The index of the given arc. - /// - /// This function returns the index of the the given arc. - /// \sa arc() - static int index(Arc arc) { return Parent::id(arc); } - - /// \brief Number of nodes. - /// - /// This function returns the number of nodes. - int nodeNum() const { return node_num; } - - /// \brief Number of arcs. - /// - /// This function returns the number of arcs. - int arcNum() const { return arc_num; } - - /// \brief Build the digraph copying another digraph. - /// - /// This function builds the digraph copying another digraph of any - /// kind. It can be called more than once, but in such case, the whole - /// structure and all maps will be cleared and rebuilt. - /// - /// This method also makes possible to copy a digraph to a StaticDigraph - /// structure using \ref DigraphCopy. - /// - /// \param digraph An existing digraph to be copied. - /// \param nodeRef The node references will be copied into this map. - /// Its key type must be \c Digraph::Node and its value type must be - /// \c StaticDigraph::Node. - /// It must conform to the \ref concepts::ReadWriteMap "ReadWriteMap" - /// concept. - /// \param arcRef The arc references will be copied into this map. - /// Its key type must be \c Digraph::Arc and its value type must be - /// \c StaticDigraph::Arc. - /// It must conform to the \ref concepts::WriteMap "WriteMap" concept. - /// - /// \note If you do not need the arc references, then you could use - /// \ref NullMap for the last parameter. However the node references - /// are required by the function itself, thus they must be readable - /// from the map. - template - void build(const Digraph& digraph, NodeRefMap& nodeRef, ArcRefMap& arcRef) { - if (built) Parent::clear(); - Parent::build(digraph, nodeRef, arcRef); - } - - /// \brief Build the digraph from an arc list. - /// - /// This function builds the digraph from the given arc list. - /// It can be called more than once, but in such case, the whole - /// structure and all maps will be cleared and rebuilt. - /// - /// The list of the arcs must be given in the range [begin, end) - /// specified by STL compatible itartors whose \c value_type must be - /// std::pair. - /// Each arc must be specified by a pair of integer indices - /// from the range [0..n-1]. The pairs must be in a - /// non-decreasing order with respect to their first values. - /// If the k-th pair in the list is (i,j), then - /// arc(k-1) will connect node(i) to node(j). - /// - /// \param n The number of nodes. - /// \param begin An iterator pointing to the beginning of the arc list. - /// \param end An iterator pointing to the end of the arc list. - /// - /// For example, a simple digraph can be constructed like this. - /// \code - /// std::vector > arcs; - /// arcs.push_back(std::make_pair(0,1)); - /// arcs.push_back(std::make_pair(0,2)); - /// arcs.push_back(std::make_pair(1,3)); - /// arcs.push_back(std::make_pair(1,2)); - /// arcs.push_back(std::make_pair(3,0)); - /// StaticDigraph gr; - /// gr.build(4, arcs.begin(), arcs.end()); - /// \endcode - template - void build(int n, ArcListIterator begin, ArcListIterator end) { - if (built) Parent::clear(); - StaticDigraphBase::build(n, begin, end); - notifier(Node()).build(); - notifier(Arc()).build(); - } - - /// \brief Clear the digraph. - /// - /// This function erases all nodes and arcs from the digraph. - void clear() { - Parent::clear(); - } - - protected: - - using Parent::fastFirstOut; - using Parent::fastNextOut; - using Parent::fastLastOut; - - public: - - class OutArcIt : public Arc { - public: - - OutArcIt() { } - - OutArcIt(Invalid i) : Arc(i) { } - - OutArcIt(const StaticDigraph& digraph, const Node& node) { - digraph.fastFirstOut(*this, node); - digraph.fastLastOut(last, node); - if (last == *this) *this = INVALID; - } - - OutArcIt(const StaticDigraph& digraph, const Arc& arc) : Arc(arc) { - if (arc != INVALID) { - digraph.fastLastOut(last, digraph.source(arc)); - } - } - - OutArcIt& operator++() { - StaticDigraph::fastNextOut(*this); - if (last == *this) *this = INVALID; - return *this; - } - - private: - Arc last; - }; - - Node baseNode(const OutArcIt &arc) const { - return Parent::source(static_cast(arc)); - } - - Node runningNode(const OutArcIt &arc) const { - return Parent::target(static_cast(arc)); - } - - Node baseNode(const InArcIt &arc) const { - return Parent::target(static_cast(arc)); - } - - Node runningNode(const InArcIt &arc) const { - return Parent::source(static_cast(arc)); - } - - }; - -} - -#endif diff --git a/deps/lemon/lemon/suurballe.h b/deps/lemon/lemon/suurballe.h deleted file mode 100644 index f1338a294..000000000 --- a/deps/lemon/lemon/suurballe.h +++ /dev/null @@ -1,776 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_SUURBALLE_H -#define LEMON_SUURBALLE_H - -///\ingroup shortest_path -///\file -///\brief An algorithm for finding arc-disjoint paths between two -/// nodes having minimum total length. - -#include -#include -#include -#include -#include -#include -#include - -namespace lemon { - - /// \brief Default traits class of Suurballe algorithm. - /// - /// Default traits class of Suurballe algorithm. - /// \tparam GR The digraph type the algorithm runs on. - /// \tparam LEN The type of the length map. - /// The default value is GR::ArcMap. -#ifdef DOXYGEN - template -#else - template < typename GR, - typename LEN = typename GR::template ArcMap > -#endif - struct SuurballeDefaultTraits - { - /// The type of the digraph. - typedef GR Digraph; - /// The type of the length map. - typedef LEN LengthMap; - /// The type of the lengths. - typedef typename LEN::Value Length; - /// The type of the flow map. - typedef typename GR::template ArcMap FlowMap; - /// The type of the potential map. - typedef typename GR::template NodeMap PotentialMap; - - /// \brief The path type - /// - /// The type used for storing the found arc-disjoint paths. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addBack() function. - typedef lemon::Path Path; - - /// The cross reference type used for the heap. - typedef typename GR::template NodeMap HeapCrossRef; - - /// \brief The heap type used for internal Dijkstra computations. - /// - /// The type of the heap used for internal Dijkstra computations. - /// It must conform to the \ref lemon::concepts::Heap "Heap" concept - /// and its priority type must be \c Length. - typedef BinHeap Heap; - }; - - /// \addtogroup shortest_path - /// @{ - - /// \brief Algorithm for finding arc-disjoint paths between two nodes - /// having minimum total length. - /// - /// \ref lemon::Suurballe "Suurballe" implements an algorithm for - /// finding arc-disjoint paths having minimum total length (cost) - /// from a given source node to a given target node in a digraph. - /// - /// Note that this problem is a special case of the \ref min_cost_flow - /// "minimum cost flow problem". This implementation is actually an - /// efficient specialized version of the \ref CapacityScaling - /// "successive shortest path" algorithm directly for this problem. - /// Therefore this class provides query functions for flow values and - /// node potentials (the dual solution) just like the minimum cost flow - /// algorithms. - /// - /// \tparam GR The digraph type the algorithm runs on. - /// \tparam LEN The type of the length map. - /// The default value is GR::ArcMap. - /// - /// \warning Length values should be \e non-negative. - /// - /// \note For finding \e node-disjoint paths, this algorithm can be used - /// along with the \ref SplitNodes adaptor. -#ifdef DOXYGEN - template -#else - template < typename GR, - typename LEN = typename GR::template ArcMap, - typename TR = SuurballeDefaultTraits > -#endif - class Suurballe - { - TEMPLATE_DIGRAPH_TYPEDEFS(GR); - - typedef ConstMap ConstArcMap; - typedef typename GR::template NodeMap PredMap; - - public: - - /// The type of the digraph. - typedef typename TR::Digraph Digraph; - /// The type of the length map. - typedef typename TR::LengthMap LengthMap; - /// The type of the lengths. - typedef typename TR::Length Length; - - /// The type of the flow map. - typedef typename TR::FlowMap FlowMap; - /// The type of the potential map. - typedef typename TR::PotentialMap PotentialMap; - /// The type of the path structures. - typedef typename TR::Path Path; - /// The cross reference type used for the heap. - typedef typename TR::HeapCrossRef HeapCrossRef; - /// The heap type used for internal Dijkstra computations. - typedef typename TR::Heap Heap; - - /// The \ref lemon::SuurballeDefaultTraits "traits class" of the algorithm. - typedef TR Traits; - - private: - - // ResidualDijkstra is a special implementation of the - // Dijkstra algorithm for finding shortest paths in the - // residual network with respect to the reduced arc lengths - // and modifying the node potentials according to the - // distance of the nodes. - class ResidualDijkstra - { - private: - - const Digraph &_graph; - const LengthMap &_length; - const FlowMap &_flow; - PotentialMap &_pi; - PredMap &_pred; - Node _s; - Node _t; - - PotentialMap _dist; - std::vector _proc_nodes; - - public: - - // Constructor - ResidualDijkstra(Suurballe &srb) : - _graph(srb._graph), _length(srb._length), - _flow(*srb._flow), _pi(*srb._potential), _pred(srb._pred), - _s(srb._s), _t(srb._t), _dist(_graph) {} - - // Run the algorithm and return true if a path is found - // from the source node to the target node. - bool run(int cnt) { - return cnt == 0 ? startFirst() : start(); - } - - private: - - // Execute the algorithm for the first time (the flow and potential - // functions have to be identically zero). - bool startFirst() { - HeapCrossRef heap_cross_ref(_graph, Heap::PRE_HEAP); - Heap heap(heap_cross_ref); - heap.push(_s, 0); - _pred[_s] = INVALID; - _proc_nodes.clear(); - - // Process nodes - while (!heap.empty() && heap.top() != _t) { - Node u = heap.top(), v; - Length d = heap.prio(), dn; - _dist[u] = heap.prio(); - _proc_nodes.push_back(u); - heap.pop(); - - // Traverse outgoing arcs - for (OutArcIt e(_graph, u); e != INVALID; ++e) { - v = _graph.target(e); - switch(heap.state(v)) { - case Heap::PRE_HEAP: - heap.push(v, d + _length[e]); - _pred[v] = e; - break; - case Heap::IN_HEAP: - dn = d + _length[e]; - if (dn < heap[v]) { - heap.decrease(v, dn); - _pred[v] = e; - } - break; - case Heap::POST_HEAP: - break; - } - } - } - if (heap.empty()) return false; - - // Update potentials of processed nodes - Length t_dist = heap.prio(); - for (int i = 0; i < int(_proc_nodes.size()); ++i) - _pi[_proc_nodes[i]] = _dist[_proc_nodes[i]] - t_dist; - return true; - } - - // Execute the algorithm. - bool start() { - HeapCrossRef heap_cross_ref(_graph, Heap::PRE_HEAP); - Heap heap(heap_cross_ref); - heap.push(_s, 0); - _pred[_s] = INVALID; - _proc_nodes.clear(); - - // Process nodes - while (!heap.empty() && heap.top() != _t) { - Node u = heap.top(), v; - Length d = heap.prio() + _pi[u], dn; - _dist[u] = heap.prio(); - _proc_nodes.push_back(u); - heap.pop(); - - // Traverse outgoing arcs - for (OutArcIt e(_graph, u); e != INVALID; ++e) { - if (_flow[e] == 0) { - v = _graph.target(e); - switch(heap.state(v)) { - case Heap::PRE_HEAP: - heap.push(v, d + _length[e] - _pi[v]); - _pred[v] = e; - break; - case Heap::IN_HEAP: - dn = d + _length[e] - _pi[v]; - if (dn < heap[v]) { - heap.decrease(v, dn); - _pred[v] = e; - } - break; - case Heap::POST_HEAP: - break; - } - } - } - - // Traverse incoming arcs - for (InArcIt e(_graph, u); e != INVALID; ++e) { - if (_flow[e] == 1) { - v = _graph.source(e); - switch(heap.state(v)) { - case Heap::PRE_HEAP: - heap.push(v, d - _length[e] - _pi[v]); - _pred[v] = e; - break; - case Heap::IN_HEAP: - dn = d - _length[e] - _pi[v]; - if (dn < heap[v]) { - heap.decrease(v, dn); - _pred[v] = e; - } - break; - case Heap::POST_HEAP: - break; - } - } - } - } - if (heap.empty()) return false; - - // Update potentials of processed nodes - Length t_dist = heap.prio(); - for (int i = 0; i < int(_proc_nodes.size()); ++i) - _pi[_proc_nodes[i]] += _dist[_proc_nodes[i]] - t_dist; - return true; - } - - }; //class ResidualDijkstra - - public: - - /// \name Named Template Parameters - /// @{ - - template - struct SetFlowMapTraits : public Traits { - typedef T FlowMap; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c FlowMap type. - /// - /// \ref named-templ-param "Named parameter" for setting - /// \c FlowMap type. - template - struct SetFlowMap - : public Suurballe > { - typedef Suurballe > Create; - }; - - template - struct SetPotentialMapTraits : public Traits { - typedef T PotentialMap; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c PotentialMap type. - /// - /// \ref named-templ-param "Named parameter" for setting - /// \c PotentialMap type. - template - struct SetPotentialMap - : public Suurballe > { - typedef Suurballe > Create; - }; - - template - struct SetPathTraits : public Traits { - typedef T Path; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c %Path type. - /// - /// \ref named-templ-param "Named parameter" for setting \c %Path type. - /// It must conform to the \ref lemon::concepts::Path "Path" concept - /// and it must have an \c addBack() function. - template - struct SetPath - : public Suurballe > { - typedef Suurballe > Create; - }; - - template - struct SetHeapTraits : public Traits { - typedef H Heap; - typedef CR HeapCrossRef; - }; - - /// \brief \ref named-templ-param "Named parameter" for setting - /// \c Heap and \c HeapCrossRef types. - /// - /// \ref named-templ-param "Named parameter" for setting \c Heap - /// and \c HeapCrossRef types with automatic allocation. - /// They will be used for internal Dijkstra computations. - /// The heap type must conform to the \ref lemon::concepts::Heap "Heap" - /// concept and its priority type must be \c Length. - template > - struct SetHeap - : public Suurballe > { - typedef Suurballe > Create; - }; - - /// @} - - private: - - // The digraph the algorithm runs on - const Digraph &_graph; - // The length map - const LengthMap &_length; - - // Arc map of the current flow - FlowMap *_flow; - bool _local_flow; - // Node map of the current potentials - PotentialMap *_potential; - bool _local_potential; - - // The source node - Node _s; - // The target node - Node _t; - - // Container to store the found paths - std::vector _paths; - int _path_num; - - // The pred arc map - PredMap _pred; - - // Data for full init - PotentialMap *_init_dist; - PredMap *_init_pred; - bool _full_init; - - protected: - - Suurballe() {} - - public: - - /// \brief Constructor. - /// - /// Constructor. - /// - /// \param graph The digraph the algorithm runs on. - /// \param length The length (cost) values of the arcs. - Suurballe( const Digraph &graph, - const LengthMap &length ) : - _graph(graph), _length(length), _flow(0), _local_flow(false), - _potential(0), _local_potential(false), _pred(graph), - _init_dist(0), _init_pred(0) - {} - - /// Destructor. - ~Suurballe() { - if (_local_flow) delete _flow; - if (_local_potential) delete _potential; - delete _init_dist; - delete _init_pred; - } - - /// \brief Set the flow map. - /// - /// This function sets the flow map. - /// If it is not used before calling \ref run() or \ref init(), - /// an instance will be allocated automatically. The destructor - /// deallocates this automatically allocated map, of course. - /// - /// The found flow contains only 0 and 1 values, since it is the - /// union of the found arc-disjoint paths. - /// - /// \return (*this) - Suurballe& flowMap(FlowMap &map) { - if (_local_flow) { - delete _flow; - _local_flow = false; - } - _flow = ↦ - return *this; - } - - /// \brief Set the potential map. - /// - /// This function sets the potential map. - /// If it is not used before calling \ref run() or \ref init(), - /// an instance will be allocated automatically. The destructor - /// deallocates this automatically allocated map, of course. - /// - /// The node potentials provide the dual solution of the underlying - /// \ref min_cost_flow "minimum cost flow problem". - /// - /// \return (*this) - Suurballe& potentialMap(PotentialMap &map) { - if (_local_potential) { - delete _potential; - _local_potential = false; - } - _potential = ↦ - return *this; - } - - /// \name Execution Control - /// The simplest way to execute the algorithm is to call the run() - /// function.\n - /// If you need to execute the algorithm many times using the same - /// source node, then you may call fullInit() once and start() - /// for each target node.\n - /// If you only need the flow that is the union of the found - /// arc-disjoint paths, then you may call findFlow() instead of - /// start(). - - /// @{ - - /// \brief Run the algorithm. - /// - /// This function runs the algorithm. - /// - /// \param s The source node. - /// \param t The target node. - /// \param k The number of paths to be found. - /// - /// \return \c k if there are at least \c k arc-disjoint paths from - /// \c s to \c t in the digraph. Otherwise it returns the number of - /// arc-disjoint paths found. - /// - /// \note Apart from the return value, s.run(s, t, k) is - /// just a shortcut of the following code. - /// \code - /// s.init(s); - /// s.start(t, k); - /// \endcode - int run(const Node& s, const Node& t, int k = 2) { - init(s); - start(t, k); - return _path_num; - } - - /// \brief Initialize the algorithm. - /// - /// This function initializes the algorithm with the given source node. - /// - /// \param s The source node. - void init(const Node& s) { - _s = s; - - // Initialize maps - if (!_flow) { - _flow = new FlowMap(_graph); - _local_flow = true; - } - if (!_potential) { - _potential = new PotentialMap(_graph); - _local_potential = true; - } - _full_init = false; - } - - /// \brief Initialize the algorithm and perform Dijkstra. - /// - /// This function initializes the algorithm and performs a full - /// Dijkstra search from the given source node. It makes consecutive - /// executions of \ref start() "start(t, k)" faster, since they - /// have to perform %Dijkstra only k-1 times. - /// - /// This initialization is usually worth using instead of \ref init() - /// if the algorithm is executed many times using the same source node. - /// - /// \param s The source node. - void fullInit(const Node& s) { - // Initialize maps - init(s); - if (!_init_dist) { - _init_dist = new PotentialMap(_graph); - } - if (!_init_pred) { - _init_pred = new PredMap(_graph); - } - - // Run a full Dijkstra - typename Dijkstra - ::template SetStandardHeap - ::template SetDistMap - ::template SetPredMap - ::Create dijk(_graph, _length); - dijk.distMap(*_init_dist).predMap(*_init_pred); - dijk.run(s); - - _full_init = true; - } - - /// \brief Execute the algorithm. - /// - /// This function executes the algorithm. - /// - /// \param t The target node. - /// \param k The number of paths to be found. - /// - /// \return \c k if there are at least \c k arc-disjoint paths from - /// \c s to \c t in the digraph. Otherwise it returns the number of - /// arc-disjoint paths found. - /// - /// \note Apart from the return value, s.start(t, k) is - /// just a shortcut of the following code. - /// \code - /// s.findFlow(t, k); - /// s.findPaths(); - /// \endcode - int start(const Node& t, int k = 2) { - findFlow(t, k); - findPaths(); - return _path_num; - } - - /// \brief Execute the algorithm to find an optimal flow. - /// - /// This function executes the successive shortest path algorithm to - /// find a minimum cost flow, which is the union of \c k (or less) - /// arc-disjoint paths. - /// - /// \param t The target node. - /// \param k The number of paths to be found. - /// - /// \return \c k if there are at least \c k arc-disjoint paths from - /// the source node to the given node \c t in the digraph. - /// Otherwise it returns the number of arc-disjoint paths found. - /// - /// \pre \ref init() must be called before using this function. - int findFlow(const Node& t, int k = 2) { - _t = t; - ResidualDijkstra dijkstra(*this); - - // Initialization - for (ArcIt e(_graph); e != INVALID; ++e) { - (*_flow)[e] = 0; - } - if (_full_init) { - for (NodeIt n(_graph); n != INVALID; ++n) { - (*_potential)[n] = (*_init_dist)[n]; - } - Node u = _t; - Arc e; - while ((e = (*_init_pred)[u]) != INVALID) { - (*_flow)[e] = 1; - u = _graph.source(e); - } - _path_num = 1; - } else { - for (NodeIt n(_graph); n != INVALID; ++n) { - (*_potential)[n] = 0; - } - _path_num = 0; - } - - // Find shortest paths - while (_path_num < k) { - // Run Dijkstra - if (!dijkstra.run(_path_num)) break; - ++_path_num; - - // Set the flow along the found shortest path - Node u = _t; - Arc e; - while ((e = _pred[u]) != INVALID) { - if (u == _graph.target(e)) { - (*_flow)[e] = 1; - u = _graph.source(e); - } else { - (*_flow)[e] = 0; - u = _graph.target(e); - } - } - } - return _path_num; - } - - /// \brief Compute the paths from the flow. - /// - /// This function computes arc-disjoint paths from the found minimum - /// cost flow, which is the union of them. - /// - /// \pre \ref init() and \ref findFlow() must be called before using - /// this function. - void findPaths() { - FlowMap res_flow(_graph); - for(ArcIt a(_graph); a != INVALID; ++a) res_flow[a] = (*_flow)[a]; - - _paths.clear(); - _paths.resize(_path_num); - for (int i = 0; i < _path_num; ++i) { - Node n = _s; - while (n != _t) { - OutArcIt e(_graph, n); - for ( ; res_flow[e] == 0; ++e) ; - n = _graph.target(e); - _paths[i].addBack(e); - res_flow[e] = 0; - } - } - } - - /// @} - - /// \name Query Functions - /// The results of the algorithm can be obtained using these - /// functions. - /// \n The algorithm should be executed before using them. - - /// @{ - - /// \brief Return the total length of the found paths. - /// - /// This function returns the total length of the found paths, i.e. - /// the total cost of the found flow. - /// The complexity of the function is O(m). - /// - /// \pre \ref run() or \ref findFlow() must be called before using - /// this function. - Length totalLength() const { - Length c = 0; - for (ArcIt e(_graph); e != INVALID; ++e) - c += (*_flow)[e] * _length[e]; - return c; - } - - /// \brief Return the flow value on the given arc. - /// - /// This function returns the flow value on the given arc. - /// It is \c 1 if the arc is involved in one of the found arc-disjoint - /// paths, otherwise it is \c 0. - /// - /// \pre \ref run() or \ref findFlow() must be called before using - /// this function. - int flow(const Arc& arc) const { - return (*_flow)[arc]; - } - - /// \brief Return a const reference to an arc map storing the - /// found flow. - /// - /// This function returns a const reference to an arc map storing - /// the flow that is the union of the found arc-disjoint paths. - /// - /// \pre \ref run() or \ref findFlow() must be called before using - /// this function. - const FlowMap& flowMap() const { - return *_flow; - } - - /// \brief Return the potential of the given node. - /// - /// This function returns the potential of the given node. - /// The node potentials provide the dual solution of the - /// underlying \ref min_cost_flow "minimum cost flow problem". - /// - /// \pre \ref run() or \ref findFlow() must be called before using - /// this function. - Length potential(const Node& node) const { - return (*_potential)[node]; - } - - /// \brief Return a const reference to a node map storing the - /// found potentials (the dual solution). - /// - /// This function returns a const reference to a node map storing - /// the found potentials that provide the dual solution of the - /// underlying \ref min_cost_flow "minimum cost flow problem". - /// - /// \pre \ref run() or \ref findFlow() must be called before using - /// this function. - const PotentialMap& potentialMap() const { - return *_potential; - } - - /// \brief Return the number of the found paths. - /// - /// This function returns the number of the found paths. - /// - /// \pre \ref run() or \ref findFlow() must be called before using - /// this function. - int pathNum() const { - return _path_num; - } - - /// \brief Return a const reference to the specified path. - /// - /// This function returns a const reference to the specified path. - /// - /// \param i The function returns the i-th path. - /// \c i must be between \c 0 and %pathNum()-1. - /// - /// \pre \ref run() or \ref findPaths() must be called before using - /// this function. - const Path& path(int i) const { - return _paths[i]; - } - - /// @} - - }; //class Suurballe - - ///@} - -} //namespace lemon - -#endif //LEMON_SUURBALLE_H diff --git a/deps/lemon/lemon/time_measure.h b/deps/lemon/lemon/time_measure.h deleted file mode 100644 index 3f7f07789..000000000 --- a/deps/lemon/lemon/time_measure.h +++ /dev/null @@ -1,610 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_TIME_MEASURE_H -#define LEMON_TIME_MEASURE_H - -///\ingroup timecount -///\file -///\brief Tools for measuring cpu usage - -#ifdef WIN32 -#include -#else -#include -#include -#include -#endif - -#include -#include -#include -#include - -namespace lemon { - - /// \addtogroup timecount - /// @{ - - /// A class to store (cpu)time instances. - - /// This class stores five time values. - /// - a real time - /// - a user cpu time - /// - a system cpu time - /// - a user cpu time of children - /// - a system cpu time of children - /// - /// TimeStamp's can be added to or substracted from each other and - /// they can be pushed to a stream. - /// - /// In most cases, perhaps the \ref Timer or the \ref TimeReport - /// class is what you want to use instead. - - class TimeStamp - { - double utime; - double stime; - double cutime; - double cstime; - double rtime; - - public: - ///Display format specifier - - ///\e - /// - enum Format { - /// Reports all measured values - NORMAL = 0, - /// Only real time and an error indicator is displayed - SHORT = 1 - }; - - private: - static Format _format; - - void _reset() { - utime = stime = cutime = cstime = rtime = 0; - } - - public: - - ///Set output format - - ///Set output format. - /// - ///The output format is global for all timestamp instances. - static void format(Format f) { _format = f; } - ///Retrieve the current output format - - ///Retrieve the current output format - /// - ///The output format is global for all timestamp instances. - static Format format() { return _format; } - - - ///Read the current time values of the process - void stamp() - { -#ifndef WIN32 - timeval tv; - gettimeofday(&tv, 0); - rtime=tv.tv_sec+double(tv.tv_usec)/1e6; - - tms ts; - double tck=sysconf(_SC_CLK_TCK); - times(&ts); - utime=ts.tms_utime/tck; - stime=ts.tms_stime/tck; - cutime=ts.tms_cutime/tck; - cstime=ts.tms_cstime/tck; -#else - bits::getWinProcTimes(rtime, utime, stime, cutime, cstime); -#endif - } - - /// Constructor initializing with zero - TimeStamp() - { _reset(); } - ///Constructor initializing with the current time values of the process - TimeStamp(void *) { stamp();} - - ///Set every time value to zero - TimeStamp &reset() {_reset();return *this;} - - ///\e - TimeStamp &operator+=(const TimeStamp &b) - { - utime+=b.utime; - stime+=b.stime; - cutime+=b.cutime; - cstime+=b.cstime; - rtime+=b.rtime; - return *this; - } - ///\e - TimeStamp operator+(const TimeStamp &b) const - { - TimeStamp t(*this); - return t+=b; - } - ///\e - TimeStamp &operator-=(const TimeStamp &b) - { - utime-=b.utime; - stime-=b.stime; - cutime-=b.cutime; - cstime-=b.cstime; - rtime-=b.rtime; - return *this; - } - ///\e - TimeStamp operator-(const TimeStamp &b) const - { - TimeStamp t(*this); - return t-=b; - } - ///\e - TimeStamp &operator*=(double b) - { - utime*=b; - stime*=b; - cutime*=b; - cstime*=b; - rtime*=b; - return *this; - } - ///\e - TimeStamp operator*(double b) const - { - TimeStamp t(*this); - return t*=b; - } - friend TimeStamp operator*(double b,const TimeStamp &t); - ///\e - TimeStamp &operator/=(double b) - { - utime/=b; - stime/=b; - cutime/=b; - cstime/=b; - rtime/=b; - return *this; - } - ///\e - TimeStamp operator/(double b) const - { - TimeStamp t(*this); - return t/=b; - } - ///The time ellapsed since the last call of stamp() - TimeStamp ellapsed() const - { - TimeStamp t(NULL); - return t-*this; - } - - friend std::ostream& operator<<(std::ostream& os,const TimeStamp &t); - - ///Gives back the user time of the process - double userTime() const - { - return utime; - } - ///Gives back the system time of the process - double systemTime() const - { - return stime; - } - ///Gives back the user time of the process' children - - ///\note On WIN32 platform this value is not calculated. - /// - double cUserTime() const - { - return cutime; - } - ///Gives back the user time of the process' children - - ///\note On WIN32 platform this value is not calculated. - /// - double cSystemTime() const - { - return cstime; - } - ///Gives back the real time - double realTime() const {return rtime;} - }; - - inline TimeStamp operator*(double b,const TimeStamp &t) - { - return t*b; - } - - ///Prints the time counters - - ///Prints the time counters in the following form: - /// - /// u: XX.XXs s: XX.XXs cu: XX.XXs cs: XX.XXs real: XX.XXs - /// - /// where the values are the - /// \li \c u: user cpu time, - /// \li \c s: system cpu time, - /// \li \c cu: user cpu time of children, - /// \li \c cs: system cpu time of children, - /// \li \c real: real time. - /// \relates TimeStamp - /// \note On WIN32 platform the cummulative values are not - /// calculated. - inline std::ostream& operator<<(std::ostream& os,const TimeStamp &t) - { - switch(t._format) - { - case TimeStamp::NORMAL: - os << "u: " << t.userTime() << - "s, s: " << t.systemTime() << - "s, cu: " << t.cUserTime() << - "s, cs: " << t.cSystemTime() << - "s, real: " << t.realTime() << "s"; - break; - case TimeStamp::SHORT: - double total = t.userTime()+t.systemTime()+ - t.cUserTime()+t.cSystemTime(); - os << t.realTime() - << "s (err: " << round((t.realTime()-total)/ - t.realTime()*10000)/100 - << "%)"; - break; - } - return os; - } - - ///Class for measuring the cpu time and real time usage of the process - - ///Class for measuring the cpu time and real time usage of the process. - ///It is quite easy-to-use, here is a short example. - ///\code - /// #include - /// #include - /// - /// int main() - /// { - /// - /// ... - /// - /// Timer t; - /// doSomething(); - /// std::cout << t << '\n'; - /// t.restart(); - /// doSomethingElse(); - /// std::cout << t << '\n'; - /// - /// ... - /// - /// } - ///\endcode - /// - ///The \ref Timer can also be \ref stop() "stopped" and - ///\ref start() "started" again, so it is possible to compute collected - ///running times. - /// - ///\warning Depending on the operation system and its actual configuration - ///the time counters have a certain (10ms on a typical Linux system) - ///granularity. - ///Therefore this tool is not appropriate to measure very short times. - ///Also, if you start and stop the timer very frequently, it could lead to - ///distorted results. - /// - ///\note If you want to measure the running time of the execution of a certain - ///function, consider the usage of \ref TimeReport instead. - /// - ///\sa TimeReport - class Timer - { - int _running; //Timer is running iff _running>0; (_running>=0 always holds) - TimeStamp start_time; //This is the relativ start-time if the timer - //is _running, the collected _running time otherwise. - - void _reset() {if(_running) start_time.stamp(); else start_time.reset();} - - public: - ///Constructor. - - ///\param run indicates whether or not the timer starts immediately. - /// - Timer(bool run=true) :_running(run) {_reset();} - - ///\name Control the State of the Timer - ///Basically a Timer can be either running or stopped, - ///but it provides a bit finer control on the execution. - ///The \ref lemon::Timer "Timer" also counts the number of - ///\ref lemon::Timer::start() "start()" executions, and it stops - ///only after the same amount (or more) \ref lemon::Timer::stop() - ///"stop()"s. This can be useful e.g. to compute the running time - ///of recursive functions. - - ///@{ - - ///Reset and stop the time counters - - ///This function resets and stops the time counters - ///\sa restart() - void reset() - { - _running=0; - _reset(); - } - - ///Start the time counters - - ///This function starts the time counters. - /// - ///If the timer is started more than ones, it will remain running - ///until the same amount of \ref stop() is called. - ///\sa stop() - void start() - { - if(_running) _running++; - else { - _running=1; - TimeStamp t; - t.stamp(); - start_time=t-start_time; - } - } - - - ///Stop the time counters - - ///This function stops the time counters. If start() was executed more than - ///once, then the same number of stop() execution is necessary the really - ///stop the timer. - /// - ///\sa halt() - ///\sa start() - ///\sa restart() - ///\sa reset() - - void stop() - { - if(_running && !--_running) { - TimeStamp t; - t.stamp(); - start_time=t-start_time; - } - } - - ///Halt (i.e stop immediately) the time counters - - ///This function stops immediately the time counters, i.e. t.halt() - ///is a faster - ///equivalent of the following. - ///\code - /// while(t.running()) t.stop() - ///\endcode - /// - /// - ///\sa stop() - ///\sa restart() - ///\sa reset() - - void halt() - { - if(_running) { - _running=0; - TimeStamp t; - t.stamp(); - start_time=t-start_time; - } - } - - ///Returns the running state of the timer - - ///This function returns the number of stop() exections that is - ///necessary to really stop the timer. - ///For example, the timer - ///is running if and only if the return value is \c true - ///(i.e. greater than - ///zero). - int running() { return _running; } - - - ///Restart the time counters - - ///This function is a shorthand for - ///a reset() and a start() calls. - /// - void restart() - { - reset(); - start(); - } - - ///@} - - ///\name Query Functions for the Ellapsed Time - - ///@{ - - ///Gives back the ellapsed user time of the process - double userTime() const - { - return operator TimeStamp().userTime(); - } - ///Gives back the ellapsed system time of the process - double systemTime() const - { - return operator TimeStamp().systemTime(); - } - ///Gives back the ellapsed user time of the process' children - - ///\note On WIN32 platform this value is not calculated. - /// - double cUserTime() const - { - return operator TimeStamp().cUserTime(); - } - ///Gives back the ellapsed user time of the process' children - - ///\note On WIN32 platform this value is not calculated. - /// - double cSystemTime() const - { - return operator TimeStamp().cSystemTime(); - } - ///Gives back the ellapsed real time - double realTime() const - { - return operator TimeStamp().realTime(); - } - ///Computes the ellapsed time - - ///This conversion computes the ellapsed time, therefore you can print - ///the ellapsed time like this. - ///\code - /// Timer t; - /// doSomething(); - /// std::cout << t << '\n'; - ///\endcode - operator TimeStamp () const - { - TimeStamp t; - t.stamp(); - return _running?t-start_time:start_time; - } - - - ///@} - }; - - ///Same as Timer but prints a report on destruction. - - ///Same as \ref Timer but prints a report on destruction. - ///This example shows its usage. - ///\code - /// void myAlg(ListGraph &g,int n) - /// { - /// TimeReport tr("Running time of myAlg: "); - /// ... //Here comes the algorithm - /// } - ///\endcode - /// - ///\sa Timer - ///\sa NoTimeReport - class TimeReport : public Timer - { - std::string _title; - std::ostream &_os; - bool _active; - public: - ///Constructor - - ///Constructor. - ///\param title This text will be printed before the ellapsed time. - ///\param os The stream to print the report to. - ///\param run Sets whether the timer should start immediately. - ///\param active Sets whether the report should actually be printed - /// on destruction. - TimeReport(std::string title,std::ostream &os=std::cerr,bool run=true, - bool active=true) - : Timer(run), _title(title), _os(os), _active(active) {} - ///Destructor that prints the ellapsed time - ~TimeReport() - { - if(_active) _os << _title << *this << std::endl; - } - - ///Retrieve the activity status - - ///\e - /// - bool active() const { return _active; } - ///Set the activity status - - /// This function set whether the time report should actually be printed - /// on destruction. - void active(bool a) { _active=a; } - }; - - ///'Do nothing' version of TimeReport - - ///\sa TimeReport - /// - class NoTimeReport - { - public: - ///\e - NoTimeReport(std::string,std::ostream &,bool) {} - ///\e - NoTimeReport(std::string,std::ostream &) {} - ///\e - NoTimeReport(std::string) {} - ///\e Do nothing. - ~NoTimeReport() {} - - operator TimeStamp () const { return TimeStamp(); } - void reset() {} - void start() {} - void stop() {} - void halt() {} - int running() { return 0; } - void restart() {} - double userTime() const { return 0; } - double systemTime() const { return 0; } - double cUserTime() const { return 0; } - double cSystemTime() const { return 0; } - double realTime() const { return 0; } - }; - - ///Tool to measure the running time more exactly. - - ///This function calls \c f several times and returns the average - ///running time. The number of the executions will be choosen in such a way - ///that the full real running time will be roughly between \c min_time - ///and 2*min_time. - ///\param f the function object to be measured. - ///\param min_time the minimum total running time. - ///\retval num if it is not \c NULL, then the actual - /// number of execution of \c f will be written into *num. - ///\retval full_time if it is not \c NULL, then the actual - /// total running time will be written into *full_time. - ///\return The average running time of \c f. - - template - TimeStamp runningTimeTest(F f,double min_time=10,unsigned int *num = NULL, - TimeStamp *full_time=NULL) - { - TimeStamp full; - unsigned int total=0; - Timer t; - for(unsigned int tn=1;tn <= 1U<<31 && full.realTime()<=min_time; tn*=2) { - for(;total may offer additional tuning parameters. - /// - ///\sa Tolerance - ///\sa Tolerance - ///\sa Tolerance - - template - class Tolerance - { - public: - typedef T Value; - - ///\name Comparisons - ///The concept is that these bool functions return \c true only if - ///the related comparisons hold even if some numerical error appeared - ///during the computations. - - ///@{ - - ///Returns \c true if \c a is \e surely strictly less than \c b - static bool less(Value a,Value b) {return a(0) < a;} - ///Returns \c true if \c a is \e surely negative - static bool negative(Value a) {return a < static_cast(0);} - ///Returns \c true if \c a is \e surely non-zero - static bool nonZero(Value a) {return a != static_cast(0);} - - ///@} - - ///Returns the zero value. - static Value zero() {return static_cast(0);} - - // static bool finite(Value a) {} - // static Value big() {} - // static Value negativeBig() {} - }; - - - ///Float specialization of Tolerance. - - ///Float specialization of Tolerance. - ///\sa Tolerance - ///\relates Tolerance - template<> - class Tolerance - { - static float def_epsilon; - float _epsilon; - public: - ///\e - typedef float Value; - - ///Constructor setting the epsilon tolerance to the default value. - Tolerance() : _epsilon(def_epsilon) {} - ///Constructor setting the epsilon tolerance to the given value. - Tolerance(float e) : _epsilon(e) {} - - ///Returns the epsilon value. - Value epsilon() const {return _epsilon;} - ///Sets the epsilon value. - void epsilon(Value e) {_epsilon=e;} - - ///Returns the default epsilon value. - static Value defaultEpsilon() {return def_epsilon;} - ///Sets the default epsilon value. - static void defaultEpsilon(Value e) {def_epsilon=e;} - - ///\name Comparisons - ///See \ref lemon::Tolerance "Tolerance" for more details. - - ///@{ - - ///Returns \c true if \c a is \e surely strictly less than \c b - bool less(Value a,Value b) const {return a+_epsilona; } - ///Returns \c true if \c a is \e surely non-zero - bool nonZero(Value a) const { return positive(a)||negative(a); } - - ///@} - - ///Returns zero - static Value zero() {return 0;} - }; - - ///Double specialization of Tolerance. - - ///Double specialization of Tolerance. - ///\sa Tolerance - ///\relates Tolerance - template<> - class Tolerance - { - static double def_epsilon; - double _epsilon; - public: - ///\e - typedef double Value; - - ///Constructor setting the epsilon tolerance to the default value. - Tolerance() : _epsilon(def_epsilon) {} - ///Constructor setting the epsilon tolerance to the given value. - Tolerance(double e) : _epsilon(e) {} - - ///Returns the epsilon value. - Value epsilon() const {return _epsilon;} - ///Sets the epsilon value. - void epsilon(Value e) {_epsilon=e;} - - ///Returns the default epsilon value. - static Value defaultEpsilon() {return def_epsilon;} - ///Sets the default epsilon value. - static void defaultEpsilon(Value e) {def_epsilon=e;} - - ///\name Comparisons - ///See \ref lemon::Tolerance "Tolerance" for more details. - - ///@{ - - ///Returns \c true if \c a is \e surely strictly less than \c b - bool less(Value a,Value b) const {return a+_epsilona; } - ///Returns \c true if \c a is \e surely non-zero - bool nonZero(Value a) const { return positive(a)||negative(a); } - - ///@} - - ///Returns zero - static Value zero() {return 0;} - }; - - ///Long double specialization of Tolerance. - - ///Long double specialization of Tolerance. - ///\sa Tolerance - ///\relates Tolerance - template<> - class Tolerance - { - static long double def_epsilon; - long double _epsilon; - public: - ///\e - typedef long double Value; - - ///Constructor setting the epsilon tolerance to the default value. - Tolerance() : _epsilon(def_epsilon) {} - ///Constructor setting the epsilon tolerance to the given value. - Tolerance(long double e) : _epsilon(e) {} - - ///Returns the epsilon value. - Value epsilon() const {return _epsilon;} - ///Sets the epsilon value. - void epsilon(Value e) {_epsilon=e;} - - ///Returns the default epsilon value. - static Value defaultEpsilon() {return def_epsilon;} - ///Sets the default epsilon value. - static void defaultEpsilon(Value e) {def_epsilon=e;} - - ///\name Comparisons - ///See \ref lemon::Tolerance "Tolerance" for more details. - - ///@{ - - ///Returns \c true if \c a is \e surely strictly less than \c b - bool less(Value a,Value b) const {return a+_epsilona; } - ///Returns \c true if \c a is \e surely non-zero - bool nonZero(Value a) const { return positive(a)||negative(a); } - - ///@} - - ///Returns zero - static Value zero() {return 0;} - }; - - /// @} - -} //namespace lemon - -#endif //LEMON_TOLERANCE_H diff --git a/deps/lemon/lemon/unionfind.h b/deps/lemon/lemon/unionfind.h deleted file mode 100644 index 3d96b372b..000000000 --- a/deps/lemon/lemon/unionfind.h +++ /dev/null @@ -1,1824 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_UNION_FIND_H -#define LEMON_UNION_FIND_H - -//!\ingroup auxdat -//!\file -//!\brief Union-Find data structures. -//! - -#include -#include -#include -#include -#include - -#include - -namespace lemon { - - /// \ingroup auxdat - /// - /// \brief A \e Union-Find data structure implementation - /// - /// The class implements the \e Union-Find data structure. - /// The union operation uses rank heuristic, while - /// the find operation uses path compression. - /// This is a very simple but efficient implementation, providing - /// only four methods: join (union), find, insert and size. - /// For more features, see the \ref UnionFindEnum class. - /// - /// It is primarily used in Kruskal algorithm for finding minimal - /// cost spanning tree in a graph. - /// \sa kruskal() - /// - /// \pre You need to add all the elements by the \ref insert() - /// method. - template - class UnionFind { - public: - - ///\e - typedef IM ItemIntMap; - ///\e - typedef typename ItemIntMap::Key Item; - - private: - // If the items vector stores negative value for an item then - // that item is root item and it has -items[it] component size. - // Else the items[it] contains the index of the parent. - std::vector items; - ItemIntMap& index; - - bool rep(int idx) const { - return items[idx] < 0; - } - - int repIndex(int idx) const { - int k = idx; - while (!rep(k)) { - k = items[k] ; - } - while (idx != k) { - int next = items[idx]; - const_cast(items[idx]) = k; - idx = next; - } - return k; - } - - public: - - /// \brief Constructor - /// - /// Constructor of the UnionFind class. You should give an item to - /// integer map which will be used from the data structure. If you - /// modify directly this map that may cause segmentation fault, - /// invalid data structure, or infinite loop when you use again - /// the union-find. - UnionFind(ItemIntMap& m) : index(m) {} - - /// \brief Returns the index of the element's component. - /// - /// The method returns the index of the element's component. - /// This is an integer between zero and the number of inserted elements. - /// - int find(const Item& a) { - return repIndex(index[a]); - } - - /// \brief Clears the union-find data structure - /// - /// Erase each item from the data structure. - void clear() { - items.clear(); - } - - /// \brief Inserts a new element into the structure. - /// - /// This method inserts a new element into the data structure. - /// - /// The method returns the index of the new component. - int insert(const Item& a) { - int n = items.size(); - items.push_back(-1); - index.set(a,n); - return n; - } - - /// \brief Joining the components of element \e a and element \e b. - /// - /// This is the \e union operation of the Union-Find structure. - /// Joins the component of element \e a and component of - /// element \e b. If \e a and \e b are in the same component then - /// it returns false otherwise it returns true. - bool join(const Item& a, const Item& b) { - int ka = repIndex(index[a]); - int kb = repIndex(index[b]); - - if ( ka == kb ) - return false; - - if (items[ka] < items[kb]) { - items[ka] += items[kb]; - items[kb] = ka; - } else { - items[kb] += items[ka]; - items[ka] = kb; - } - return true; - } - - /// \brief Returns the size of the component of element \e a. - /// - /// Returns the size of the component of element \e a. - int size(const Item& a) { - int k = repIndex(index[a]); - return - items[k]; - } - - }; - - /// \ingroup auxdat - /// - /// \brief A \e Union-Find data structure implementation which - /// is able to enumerate the components. - /// - /// The class implements a \e Union-Find data structure - /// which is able to enumerate the components and the items in - /// a component. If you don't need this feature then perhaps it's - /// better to use the \ref UnionFind class which is more efficient. - /// - /// The union operation uses rank heuristic, while - /// the find operation uses path compression. - /// - /// \pre You need to add all the elements by the \ref insert() - /// method. - /// - template - class UnionFindEnum { - public: - - ///\e - typedef IM ItemIntMap; - ///\e - typedef typename ItemIntMap::Key Item; - - private: - - ItemIntMap& index; - - // If the parent stores negative value for an item then that item - // is root item and it has ~(items[it].parent) component id. Else - // the items[it].parent contains the index of the parent. - // - // The \c next and \c prev provides the double-linked - // cyclic list of one component's items. - struct ItemT { - int parent; - Item item; - - int next, prev; - }; - - std::vector items; - int firstFreeItem; - - struct ClassT { - int size; - int firstItem; - int next, prev; - }; - - std::vector classes; - int firstClass, firstFreeClass; - - int newClass() { - if (firstFreeClass == -1) { - int cdx = classes.size(); - classes.push_back(ClassT()); - return cdx; - } else { - int cdx = firstFreeClass; - firstFreeClass = classes[firstFreeClass].next; - return cdx; - } - } - - int newItem() { - if (firstFreeItem == -1) { - int idx = items.size(); - items.push_back(ItemT()); - return idx; - } else { - int idx = firstFreeItem; - firstFreeItem = items[firstFreeItem].next; - return idx; - } - } - - - bool rep(int idx) const { - return items[idx].parent < 0; - } - - int repIndex(int idx) const { - int k = idx; - while (!rep(k)) { - k = items[k].parent; - } - while (idx != k) { - int next = items[idx].parent; - const_cast(items[idx].parent) = k; - idx = next; - } - return k; - } - - int classIndex(int idx) const { - return ~(items[repIndex(idx)].parent); - } - - void singletonItem(int idx) { - items[idx].next = idx; - items[idx].prev = idx; - } - - void laceItem(int idx, int rdx) { - items[idx].prev = rdx; - items[idx].next = items[rdx].next; - items[items[rdx].next].prev = idx; - items[rdx].next = idx; - } - - void unlaceItem(int idx) { - items[items[idx].prev].next = items[idx].next; - items[items[idx].next].prev = items[idx].prev; - - items[idx].next = firstFreeItem; - firstFreeItem = idx; - } - - void spliceItems(int ak, int bk) { - items[items[ak].prev].next = bk; - items[items[bk].prev].next = ak; - int tmp = items[ak].prev; - items[ak].prev = items[bk].prev; - items[bk].prev = tmp; - - } - - void laceClass(int cls) { - if (firstClass != -1) { - classes[firstClass].prev = cls; - } - classes[cls].next = firstClass; - classes[cls].prev = -1; - firstClass = cls; - } - - void unlaceClass(int cls) { - if (classes[cls].prev != -1) { - classes[classes[cls].prev].next = classes[cls].next; - } else { - firstClass = classes[cls].next; - } - if (classes[cls].next != -1) { - classes[classes[cls].next].prev = classes[cls].prev; - } - - classes[cls].next = firstFreeClass; - firstFreeClass = cls; - } - - public: - - UnionFindEnum(ItemIntMap& _index) - : index(_index), items(), firstFreeItem(-1), - firstClass(-1), firstFreeClass(-1) {} - - /// \brief Inserts the given element into a new component. - /// - /// This method creates a new component consisting only of the - /// given element. - /// - int insert(const Item& item) { - int idx = newItem(); - - index.set(item, idx); - - singletonItem(idx); - items[idx].item = item; - - int cdx = newClass(); - - items[idx].parent = ~cdx; - - laceClass(cdx); - classes[cdx].size = 1; - classes[cdx].firstItem = idx; - - firstClass = cdx; - - return cdx; - } - - /// \brief Inserts the given element into the component of the others. - /// - /// This methods inserts the element \e a into the component of the - /// element \e comp. - void insert(const Item& item, int cls) { - int rdx = classes[cls].firstItem; - int idx = newItem(); - - index.set(item, idx); - - laceItem(idx, rdx); - - items[idx].item = item; - items[idx].parent = rdx; - - ++classes[~(items[rdx].parent)].size; - } - - /// \brief Clears the union-find data structure - /// - /// Erase each item from the data structure. - void clear() { - items.clear(); - firstClass = -1; - firstFreeItem = -1; - } - - /// \brief Finds the component of the given element. - /// - /// The method returns the component id of the given element. - int find(const Item &item) const { - return ~(items[repIndex(index[item])].parent); - } - - /// \brief Joining the component of element \e a and element \e b. - /// - /// This is the \e union operation of the Union-Find structure. - /// Joins the component of element \e a and component of - /// element \e b. If \e a and \e b are in the same component then - /// returns -1 else returns the remaining class. - int join(const Item& a, const Item& b) { - - int ak = repIndex(index[a]); - int bk = repIndex(index[b]); - - if (ak == bk) { - return -1; - } - - int acx = ~(items[ak].parent); - int bcx = ~(items[bk].parent); - - int rcx; - - if (classes[acx].size > classes[bcx].size) { - classes[acx].size += classes[bcx].size; - items[bk].parent = ak; - unlaceClass(bcx); - rcx = acx; - } else { - classes[bcx].size += classes[acx].size; - items[ak].parent = bk; - unlaceClass(acx); - rcx = bcx; - } - spliceItems(ak, bk); - - return rcx; - } - - /// \brief Returns the size of the class. - /// - /// Returns the size of the class. - int size(int cls) const { - return classes[cls].size; - } - - /// \brief Splits up the component. - /// - /// Splitting the component into singleton components (component - /// of size one). - void split(int cls) { - int fdx = classes[cls].firstItem; - int idx = items[fdx].next; - while (idx != fdx) { - int next = items[idx].next; - - singletonItem(idx); - - int cdx = newClass(); - items[idx].parent = ~cdx; - - laceClass(cdx); - classes[cdx].size = 1; - classes[cdx].firstItem = idx; - - idx = next; - } - - items[idx].prev = idx; - items[idx].next = idx; - - classes[~(items[idx].parent)].size = 1; - - } - - /// \brief Removes the given element from the structure. - /// - /// Removes the element from its component and if the component becomes - /// empty then removes that component from the component list. - /// - /// \warning It is an error to remove an element which is not in - /// the structure. - /// \warning This running time of this operation is proportional to the - /// number of the items in this class. - void erase(const Item& item) { - int idx = index[item]; - int fdx = items[idx].next; - - int cdx = classIndex(idx); - if (idx == fdx) { - unlaceClass(cdx); - items[idx].next = firstFreeItem; - firstFreeItem = idx; - return; - } else { - classes[cdx].firstItem = fdx; - --classes[cdx].size; - items[fdx].parent = ~cdx; - - unlaceItem(idx); - idx = items[fdx].next; - while (idx != fdx) { - items[idx].parent = fdx; - idx = items[idx].next; - } - - } - - } - - /// \brief Gives back a representant item of the component. - /// - /// Gives back a representant item of the component. - Item item(int cls) const { - return items[classes[cls].firstItem].item; - } - - /// \brief Removes the component of the given element from the structure. - /// - /// Removes the component of the given element from the structure. - /// - /// \warning It is an error to give an element which is not in the - /// structure. - void eraseClass(int cls) { - int fdx = classes[cls].firstItem; - unlaceClass(cls); - items[items[fdx].prev].next = firstFreeItem; - firstFreeItem = fdx; - } - - /// \brief LEMON style iterator for the representant items. - /// - /// ClassIt is a lemon style iterator for the components. It iterates - /// on the ids of the classes. - class ClassIt { - public: - /// \brief Constructor of the iterator - /// - /// Constructor of the iterator - ClassIt(const UnionFindEnum& ufe) : unionFind(&ufe) { - cdx = unionFind->firstClass; - } - - /// \brief Constructor to get invalid iterator - /// - /// Constructor to get invalid iterator - ClassIt(Invalid) : unionFind(0), cdx(-1) {} - - /// \brief Increment operator - /// - /// It steps to the next representant item. - ClassIt& operator++() { - cdx = unionFind->classes[cdx].next; - return *this; - } - - /// \brief Conversion operator - /// - /// It converts the iterator to the current representant item. - operator int() const { - return cdx; - } - - /// \brief Equality operator - /// - /// Equality operator - bool operator==(const ClassIt& i) { - return i.cdx == cdx; - } - - /// \brief Inequality operator - /// - /// Inequality operator - bool operator!=(const ClassIt& i) { - return i.cdx != cdx; - } - - private: - const UnionFindEnum* unionFind; - int cdx; - }; - - /// \brief LEMON style iterator for the items of a component. - /// - /// ClassIt is a lemon style iterator for the components. It iterates - /// on the items of a class. By example if you want to iterate on - /// each items of each classes then you may write the next code. - ///\code - /// for (ClassIt cit(ufe); cit != INVALID; ++cit) { - /// std::cout << "Class: "; - /// for (ItemIt iit(ufe, cit); iit != INVALID; ++iit) { - /// std::cout << toString(iit) << ' ' << std::endl; - /// } - /// std::cout << std::endl; - /// } - ///\endcode - class ItemIt { - public: - /// \brief Constructor of the iterator - /// - /// Constructor of the iterator. The iterator iterates - /// on the class of the \c item. - ItemIt(const UnionFindEnum& ufe, int cls) : unionFind(&ufe) { - fdx = idx = unionFind->classes[cls].firstItem; - } - - /// \brief Constructor to get invalid iterator - /// - /// Constructor to get invalid iterator - ItemIt(Invalid) : unionFind(0), idx(-1) {} - - /// \brief Increment operator - /// - /// It steps to the next item in the class. - ItemIt& operator++() { - idx = unionFind->items[idx].next; - if (idx == fdx) idx = -1; - return *this; - } - - /// \brief Conversion operator - /// - /// It converts the iterator to the current item. - operator const Item&() const { - return unionFind->items[idx].item; - } - - /// \brief Equality operator - /// - /// Equality operator - bool operator==(const ItemIt& i) { - return i.idx == idx; - } - - /// \brief Inequality operator - /// - /// Inequality operator - bool operator!=(const ItemIt& i) { - return i.idx != idx; - } - - private: - const UnionFindEnum* unionFind; - int idx, fdx; - }; - - }; - - /// \ingroup auxdat - /// - /// \brief A \e Extend-Find data structure implementation which - /// is able to enumerate the components. - /// - /// The class implements an \e Extend-Find data structure which is - /// able to enumerate the components and the items in a - /// component. The data structure is a simplification of the - /// Union-Find structure, and it does not allow to merge two components. - /// - /// \pre You need to add all the elements by the \ref insert() - /// method. - template - class ExtendFindEnum { - public: - - ///\e - typedef IM ItemIntMap; - ///\e - typedef typename ItemIntMap::Key Item; - - private: - - ItemIntMap& index; - - struct ItemT { - int cls; - Item item; - int next, prev; - }; - - std::vector items; - int firstFreeItem; - - struct ClassT { - int firstItem; - int next, prev; - }; - - std::vector classes; - - int firstClass, firstFreeClass; - - int newClass() { - if (firstFreeClass != -1) { - int cdx = firstFreeClass; - firstFreeClass = classes[cdx].next; - return cdx; - } else { - classes.push_back(ClassT()); - return classes.size() - 1; - } - } - - int newItem() { - if (firstFreeItem != -1) { - int idx = firstFreeItem; - firstFreeItem = items[idx].next; - return idx; - } else { - items.push_back(ItemT()); - return items.size() - 1; - } - } - - public: - - /// \brief Constructor - ExtendFindEnum(ItemIntMap& _index) - : index(_index), items(), firstFreeItem(-1), - classes(), firstClass(-1), firstFreeClass(-1) {} - - /// \brief Inserts the given element into a new component. - /// - /// This method creates a new component consisting only of the - /// given element. - int insert(const Item& item) { - int cdx = newClass(); - classes[cdx].prev = -1; - classes[cdx].next = firstClass; - if (firstClass != -1) { - classes[firstClass].prev = cdx; - } - firstClass = cdx; - - int idx = newItem(); - items[idx].item = item; - items[idx].cls = cdx; - items[idx].prev = idx; - items[idx].next = idx; - - classes[cdx].firstItem = idx; - - index.set(item, idx); - - return cdx; - } - - /// \brief Inserts the given element into the given component. - /// - /// This methods inserts the element \e item a into the \e cls class. - void insert(const Item& item, int cls) { - int idx = newItem(); - int rdx = classes[cls].firstItem; - items[idx].item = item; - items[idx].cls = cls; - - items[idx].prev = rdx; - items[idx].next = items[rdx].next; - items[items[rdx].next].prev = idx; - items[rdx].next = idx; - - index.set(item, idx); - } - - /// \brief Clears the union-find data structure - /// - /// Erase each item from the data structure. - void clear() { - items.clear(); - classes.clear(); - firstClass = firstFreeClass = firstFreeItem = -1; - } - - /// \brief Gives back the class of the \e item. - /// - /// Gives back the class of the \e item. - int find(const Item &item) const { - return items[index[item]].cls; - } - - /// \brief Gives back a representant item of the component. - /// - /// Gives back a representant item of the component. - Item item(int cls) const { - return items[classes[cls].firstItem].item; - } - - /// \brief Removes the given element from the structure. - /// - /// Removes the element from its component and if the component becomes - /// empty then removes that component from the component list. - /// - /// \warning It is an error to remove an element which is not in - /// the structure. - void erase(const Item &item) { - int idx = index[item]; - int cdx = items[idx].cls; - - if (idx == items[idx].next) { - if (classes[cdx].prev != -1) { - classes[classes[cdx].prev].next = classes[cdx].next; - } else { - firstClass = classes[cdx].next; - } - if (classes[cdx].next != -1) { - classes[classes[cdx].next].prev = classes[cdx].prev; - } - classes[cdx].next = firstFreeClass; - firstFreeClass = cdx; - } else { - classes[cdx].firstItem = items[idx].next; - items[items[idx].next].prev = items[idx].prev; - items[items[idx].prev].next = items[idx].next; - } - items[idx].next = firstFreeItem; - firstFreeItem = idx; - - } - - - /// \brief Removes the component of the given element from the structure. - /// - /// Removes the component of the given element from the structure. - /// - /// \warning It is an error to give an element which is not in the - /// structure. - void eraseClass(int cdx) { - int idx = classes[cdx].firstItem; - items[items[idx].prev].next = firstFreeItem; - firstFreeItem = idx; - - if (classes[cdx].prev != -1) { - classes[classes[cdx].prev].next = classes[cdx].next; - } else { - firstClass = classes[cdx].next; - } - if (classes[cdx].next != -1) { - classes[classes[cdx].next].prev = classes[cdx].prev; - } - classes[cdx].next = firstFreeClass; - firstFreeClass = cdx; - } - - /// \brief LEMON style iterator for the classes. - /// - /// ClassIt is a lemon style iterator for the components. It iterates - /// on the ids of classes. - class ClassIt { - public: - /// \brief Constructor of the iterator - /// - /// Constructor of the iterator - ClassIt(const ExtendFindEnum& ufe) : extendFind(&ufe) { - cdx = extendFind->firstClass; - } - - /// \brief Constructor to get invalid iterator - /// - /// Constructor to get invalid iterator - ClassIt(Invalid) : extendFind(0), cdx(-1) {} - - /// \brief Increment operator - /// - /// It steps to the next representant item. - ClassIt& operator++() { - cdx = extendFind->classes[cdx].next; - return *this; - } - - /// \brief Conversion operator - /// - /// It converts the iterator to the current class id. - operator int() const { - return cdx; - } - - /// \brief Equality operator - /// - /// Equality operator - bool operator==(const ClassIt& i) { - return i.cdx == cdx; - } - - /// \brief Inequality operator - /// - /// Inequality operator - bool operator!=(const ClassIt& i) { - return i.cdx != cdx; - } - - private: - const ExtendFindEnum* extendFind; - int cdx; - }; - - /// \brief LEMON style iterator for the items of a component. - /// - /// ClassIt is a lemon style iterator for the components. It iterates - /// on the items of a class. By example if you want to iterate on - /// each items of each classes then you may write the next code. - ///\code - /// for (ClassIt cit(ufe); cit != INVALID; ++cit) { - /// std::cout << "Class: "; - /// for (ItemIt iit(ufe, cit); iit != INVALID; ++iit) { - /// std::cout << toString(iit) << ' ' << std::endl; - /// } - /// std::cout << std::endl; - /// } - ///\endcode - class ItemIt { - public: - /// \brief Constructor of the iterator - /// - /// Constructor of the iterator. The iterator iterates - /// on the class of the \c item. - ItemIt(const ExtendFindEnum& ufe, int cls) : extendFind(&ufe) { - fdx = idx = extendFind->classes[cls].firstItem; - } - - /// \brief Constructor to get invalid iterator - /// - /// Constructor to get invalid iterator - ItemIt(Invalid) : extendFind(0), idx(-1) {} - - /// \brief Increment operator - /// - /// It steps to the next item in the class. - ItemIt& operator++() { - idx = extendFind->items[idx].next; - if (fdx == idx) idx = -1; - return *this; - } - - /// \brief Conversion operator - /// - /// It converts the iterator to the current item. - operator const Item&() const { - return extendFind->items[idx].item; - } - - /// \brief Equality operator - /// - /// Equality operator - bool operator==(const ItemIt& i) { - return i.idx == idx; - } - - /// \brief Inequality operator - /// - /// Inequality operator - bool operator!=(const ItemIt& i) { - return i.idx != idx; - } - - private: - const ExtendFindEnum* extendFind; - int idx, fdx; - }; - - }; - - /// \ingroup auxdat - /// - /// \brief A \e Union-Find data structure implementation which - /// is able to store a priority for each item and retrieve the minimum of - /// each class. - /// - /// A \e Union-Find data structure implementation which is able to - /// store a priority for each item and retrieve the minimum of each - /// class. In addition, it supports the joining and splitting the - /// components. If you don't need this feature then you makes - /// better to use the \ref UnionFind class which is more efficient. - /// - /// The union-find data strcuture based on a (2, 16)-tree with a - /// tournament minimum selection on the internal nodes. The insert - /// operation takes O(1), the find, set, decrease and increase takes - /// O(log(n)), where n is the number of nodes in the current - /// component. The complexity of join and split is O(log(n)*k), - /// where n is the sum of the number of the nodes and k is the - /// number of joined components or the number of the components - /// after the split. - /// - /// \pre You need to add all the elements by the \ref insert() - /// method. - template > - class HeapUnionFind { - public: - - ///\e - typedef V Value; - ///\e - typedef typename IM::Key Item; - ///\e - typedef IM ItemIntMap; - ///\e - typedef Comp Compare; - - private: - - static const int cmax = 16; - - ItemIntMap& index; - - struct ClassNode { - int parent; - int depth; - - int left, right; - int next, prev; - }; - - int first_class; - int first_free_class; - std::vector classes; - - int newClass() { - if (first_free_class < 0) { - int id = classes.size(); - classes.push_back(ClassNode()); - return id; - } else { - int id = first_free_class; - first_free_class = classes[id].next; - return id; - } - } - - void deleteClass(int id) { - classes[id].next = first_free_class; - first_free_class = id; - } - - struct ItemNode { - int parent; - Item item; - Value prio; - int next, prev; - int left, right; - int size; - }; - - int first_free_node; - std::vector nodes; - - int newNode() { - if (first_free_node < 0) { - int id = nodes.size(); - nodes.push_back(ItemNode()); - return id; - } else { - int id = first_free_node; - first_free_node = nodes[id].next; - return id; - } - } - - void deleteNode(int id) { - nodes[id].next = first_free_node; - first_free_node = id; - } - - Comp comp; - - int findClass(int id) const { - int kd = id; - while (kd >= 0) { - kd = nodes[kd].parent; - } - return ~kd; - } - - int leftNode(int id) const { - int kd = ~(classes[id].parent); - for (int i = 0; i < classes[id].depth; ++i) { - kd = nodes[kd].left; - } - return kd; - } - - int nextNode(int id) const { - int depth = 0; - while (id >= 0 && nodes[id].next == -1) { - id = nodes[id].parent; - ++depth; - } - if (id < 0) { - return -1; - } - id = nodes[id].next; - while (depth--) { - id = nodes[id].left; - } - return id; - } - - - void setPrio(int id) { - int jd = nodes[id].left; - nodes[id].prio = nodes[jd].prio; - nodes[id].item = nodes[jd].item; - jd = nodes[jd].next; - while (jd != -1) { - if (comp(nodes[jd].prio, nodes[id].prio)) { - nodes[id].prio = nodes[jd].prio; - nodes[id].item = nodes[jd].item; - } - jd = nodes[jd].next; - } - } - - void push(int id, int jd) { - nodes[id].size = 1; - nodes[id].left = nodes[id].right = jd; - nodes[jd].next = nodes[jd].prev = -1; - nodes[jd].parent = id; - } - - void pushAfter(int id, int jd) { - int kd = nodes[id].parent; - if (nodes[id].next != -1) { - nodes[nodes[id].next].prev = jd; - if (kd >= 0) { - nodes[kd].size += 1; - } - } else { - if (kd >= 0) { - nodes[kd].right = jd; - nodes[kd].size += 1; - } - } - nodes[jd].next = nodes[id].next; - nodes[jd].prev = id; - nodes[id].next = jd; - nodes[jd].parent = kd; - } - - void pushRight(int id, int jd) { - nodes[id].size += 1; - nodes[jd].prev = nodes[id].right; - nodes[jd].next = -1; - nodes[nodes[id].right].next = jd; - nodes[id].right = jd; - nodes[jd].parent = id; - } - - void popRight(int id) { - nodes[id].size -= 1; - int jd = nodes[id].right; - nodes[nodes[jd].prev].next = -1; - nodes[id].right = nodes[jd].prev; - } - - void splice(int id, int jd) { - nodes[id].size += nodes[jd].size; - nodes[nodes[id].right].next = nodes[jd].left; - nodes[nodes[jd].left].prev = nodes[id].right; - int kd = nodes[jd].left; - while (kd != -1) { - nodes[kd].parent = id; - kd = nodes[kd].next; - } - nodes[id].right = nodes[jd].right; - } - - void split(int id, int jd) { - int kd = nodes[id].parent; - nodes[kd].right = nodes[id].prev; - nodes[nodes[id].prev].next = -1; - - nodes[jd].left = id; - nodes[id].prev = -1; - int num = 0; - while (id != -1) { - nodes[id].parent = jd; - nodes[jd].right = id; - id = nodes[id].next; - ++num; - } - nodes[kd].size -= num; - nodes[jd].size = num; - } - - void pushLeft(int id, int jd) { - nodes[id].size += 1; - nodes[jd].next = nodes[id].left; - nodes[jd].prev = -1; - nodes[nodes[id].left].prev = jd; - nodes[id].left = jd; - nodes[jd].parent = id; - } - - void popLeft(int id) { - nodes[id].size -= 1; - int jd = nodes[id].left; - nodes[nodes[jd].next].prev = -1; - nodes[id].left = nodes[jd].next; - } - - void repairLeft(int id) { - int jd = ~(classes[id].parent); - while (nodes[jd].left != -1) { - int kd = nodes[jd].left; - if (nodes[jd].size == 1) { - if (nodes[jd].parent < 0) { - classes[id].parent = ~kd; - classes[id].depth -= 1; - nodes[kd].parent = ~id; - deleteNode(jd); - jd = kd; - } else { - int pd = nodes[jd].parent; - if (nodes[nodes[jd].next].size < cmax) { - pushLeft(nodes[jd].next, nodes[jd].left); - if (less(jd, nodes[jd].next) || - nodes[jd].item == nodes[pd].item) { - nodes[nodes[jd].next].prio = nodes[jd].prio; - nodes[nodes[jd].next].item = nodes[jd].item; - } - popLeft(pd); - deleteNode(jd); - jd = pd; - } else { - int ld = nodes[nodes[jd].next].left; - popLeft(nodes[jd].next); - pushRight(jd, ld); - if (less(ld, nodes[jd].left) || - nodes[ld].item == nodes[pd].item) { - nodes[jd].item = nodes[ld].item; - nodes[jd].prio = nodes[ld].prio; - } - if (nodes[nodes[jd].next].item == nodes[ld].item) { - setPrio(nodes[jd].next); - } - jd = nodes[jd].left; - } - } - } else { - jd = nodes[jd].left; - } - } - } - - void repairRight(int id) { - int jd = ~(classes[id].parent); - while (nodes[jd].right != -1) { - int kd = nodes[jd].right; - if (nodes[jd].size == 1) { - if (nodes[jd].parent < 0) { - classes[id].parent = ~kd; - classes[id].depth -= 1; - nodes[kd].parent = ~id; - deleteNode(jd); - jd = kd; - } else { - int pd = nodes[jd].parent; - if (nodes[nodes[jd].prev].size < cmax) { - pushRight(nodes[jd].prev, nodes[jd].right); - if (less(jd, nodes[jd].prev) || - nodes[jd].item == nodes[pd].item) { - nodes[nodes[jd].prev].prio = nodes[jd].prio; - nodes[nodes[jd].prev].item = nodes[jd].item; - } - popRight(pd); - deleteNode(jd); - jd = pd; - } else { - int ld = nodes[nodes[jd].prev].right; - popRight(nodes[jd].prev); - pushLeft(jd, ld); - if (less(ld, nodes[jd].right) || - nodes[ld].item == nodes[pd].item) { - nodes[jd].item = nodes[ld].item; - nodes[jd].prio = nodes[ld].prio; - } - if (nodes[nodes[jd].prev].item == nodes[ld].item) { - setPrio(nodes[jd].prev); - } - jd = nodes[jd].right; - } - } - } else { - jd = nodes[jd].right; - } - } - } - - - bool less(int id, int jd) const { - return comp(nodes[id].prio, nodes[jd].prio); - } - - public: - - /// \brief Returns true when the given class is alive. - /// - /// Returns true when the given class is alive, ie. the class is - /// not nested into other class. - bool alive(int cls) const { - return classes[cls].parent < 0; - } - - /// \brief Returns true when the given class is trivial. - /// - /// Returns true when the given class is trivial, ie. the class - /// contains just one item directly. - bool trivial(int cls) const { - return classes[cls].left == -1; - } - - /// \brief Constructs the union-find. - /// - /// Constructs the union-find. - /// \brief _index The index map of the union-find. The data - /// structure uses internally for store references. - HeapUnionFind(ItemIntMap& _index) - : index(_index), first_class(-1), - first_free_class(-1), first_free_node(-1) {} - - /// \brief Clears the union-find data structure - /// - /// Erase each item from the data structure. - void clear() { - nodes.clear(); - classes.clear(); - first_free_node = first_free_class = first_class = -1; - } - - /// \brief Insert a new node into a new component. - /// - /// Insert a new node into a new component. - /// \param item The item of the new node. - /// \param prio The priority of the new node. - /// \return The class id of the one-item-heap. - int insert(const Item& item, const Value& prio) { - int id = newNode(); - nodes[id].item = item; - nodes[id].prio = prio; - nodes[id].size = 0; - - nodes[id].prev = -1; - nodes[id].next = -1; - - nodes[id].left = -1; - nodes[id].right = -1; - - nodes[id].item = item; - index[item] = id; - - int class_id = newClass(); - classes[class_id].parent = ~id; - classes[class_id].depth = 0; - - classes[class_id].left = -1; - classes[class_id].right = -1; - - if (first_class != -1) { - classes[first_class].prev = class_id; - } - classes[class_id].next = first_class; - classes[class_id].prev = -1; - first_class = class_id; - - nodes[id].parent = ~class_id; - - return class_id; - } - - /// \brief The class of the item. - /// - /// \return The alive class id of the item, which is not nested into - /// other classes. - /// - /// The time complexity is O(log(n)). - int find(const Item& item) const { - return findClass(index[item]); - } - - /// \brief Joins the classes. - /// - /// The current function joins the given classes. The parameter is - /// an STL range which should be contains valid class ids. The - /// time complexity is O(log(n)*k) where n is the overall number - /// of the joined nodes and k is the number of classes. - /// \return The class of the joined classes. - /// \pre The range should contain at least two class ids. - template - int join(Iterator begin, Iterator end) { - std::vector cs; - for (Iterator it = begin; it != end; ++it) { - cs.push_back(*it); - } - - int class_id = newClass(); - { // creation union-find - - if (first_class != -1) { - classes[first_class].prev = class_id; - } - classes[class_id].next = first_class; - classes[class_id].prev = -1; - first_class = class_id; - - classes[class_id].depth = classes[cs[0]].depth; - classes[class_id].parent = classes[cs[0]].parent; - nodes[~(classes[class_id].parent)].parent = ~class_id; - - int l = cs[0]; - - classes[class_id].left = l; - classes[class_id].right = l; - - if (classes[l].next != -1) { - classes[classes[l].next].prev = classes[l].prev; - } - classes[classes[l].prev].next = classes[l].next; - - classes[l].prev = -1; - classes[l].next = -1; - - classes[l].depth = leftNode(l); - classes[l].parent = class_id; - - } - - { // merging of heap - int l = class_id; - for (int ci = 1; ci < int(cs.size()); ++ci) { - int r = cs[ci]; - int rln = leftNode(r); - if (classes[l].depth > classes[r].depth) { - int id = ~(classes[l].parent); - for (int i = classes[r].depth + 1; i < classes[l].depth; ++i) { - id = nodes[id].right; - } - while (id >= 0 && nodes[id].size == cmax) { - int new_id = newNode(); - int right_id = nodes[id].right; - - popRight(id); - if (nodes[id].item == nodes[right_id].item) { - setPrio(id); - } - push(new_id, right_id); - pushRight(new_id, ~(classes[r].parent)); - - if (less(~classes[r].parent, right_id)) { - nodes[new_id].item = nodes[~classes[r].parent].item; - nodes[new_id].prio = nodes[~classes[r].parent].prio; - } else { - nodes[new_id].item = nodes[right_id].item; - nodes[new_id].prio = nodes[right_id].prio; - } - - id = nodes[id].parent; - classes[r].parent = ~new_id; - } - if (id < 0) { - int new_parent = newNode(); - nodes[new_parent].next = -1; - nodes[new_parent].prev = -1; - nodes[new_parent].parent = ~l; - - push(new_parent, ~(classes[l].parent)); - pushRight(new_parent, ~(classes[r].parent)); - setPrio(new_parent); - - classes[l].parent = ~new_parent; - classes[l].depth += 1; - } else { - pushRight(id, ~(classes[r].parent)); - while (id >= 0 && less(~(classes[r].parent), id)) { - nodes[id].prio = nodes[~(classes[r].parent)].prio; - nodes[id].item = nodes[~(classes[r].parent)].item; - id = nodes[id].parent; - } - } - } else if (classes[r].depth > classes[l].depth) { - int id = ~(classes[r].parent); - for (int i = classes[l].depth + 1; i < classes[r].depth; ++i) { - id = nodes[id].left; - } - while (id >= 0 && nodes[id].size == cmax) { - int new_id = newNode(); - int left_id = nodes[id].left; - - popLeft(id); - if (nodes[id].prio == nodes[left_id].prio) { - setPrio(id); - } - push(new_id, left_id); - pushLeft(new_id, ~(classes[l].parent)); - - if (less(~classes[l].parent, left_id)) { - nodes[new_id].item = nodes[~classes[l].parent].item; - nodes[new_id].prio = nodes[~classes[l].parent].prio; - } else { - nodes[new_id].item = nodes[left_id].item; - nodes[new_id].prio = nodes[left_id].prio; - } - - id = nodes[id].parent; - classes[l].parent = ~new_id; - - } - if (id < 0) { - int new_parent = newNode(); - nodes[new_parent].next = -1; - nodes[new_parent].prev = -1; - nodes[new_parent].parent = ~l; - - push(new_parent, ~(classes[r].parent)); - pushLeft(new_parent, ~(classes[l].parent)); - setPrio(new_parent); - - classes[r].parent = ~new_parent; - classes[r].depth += 1; - } else { - pushLeft(id, ~(classes[l].parent)); - while (id >= 0 && less(~(classes[l].parent), id)) { - nodes[id].prio = nodes[~(classes[l].parent)].prio; - nodes[id].item = nodes[~(classes[l].parent)].item; - id = nodes[id].parent; - } - } - nodes[~(classes[r].parent)].parent = ~l; - classes[l].parent = classes[r].parent; - classes[l].depth = classes[r].depth; - } else { - if (classes[l].depth != 0 && - nodes[~(classes[l].parent)].size + - nodes[~(classes[r].parent)].size <= cmax) { - splice(~(classes[l].parent), ~(classes[r].parent)); - deleteNode(~(classes[r].parent)); - if (less(~(classes[r].parent), ~(classes[l].parent))) { - nodes[~(classes[l].parent)].prio = - nodes[~(classes[r].parent)].prio; - nodes[~(classes[l].parent)].item = - nodes[~(classes[r].parent)].item; - } - } else { - int new_parent = newNode(); - nodes[new_parent].next = nodes[new_parent].prev = -1; - push(new_parent, ~(classes[l].parent)); - pushRight(new_parent, ~(classes[r].parent)); - setPrio(new_parent); - - classes[l].parent = ~new_parent; - classes[l].depth += 1; - nodes[new_parent].parent = ~l; - } - } - if (classes[r].next != -1) { - classes[classes[r].next].prev = classes[r].prev; - } - classes[classes[r].prev].next = classes[r].next; - - classes[r].prev = classes[l].right; - classes[classes[l].right].next = r; - classes[l].right = r; - classes[r].parent = l; - - classes[r].next = -1; - classes[r].depth = rln; - } - } - return class_id; - } - - /// \brief Split the class to subclasses. - /// - /// The current function splits the given class. The join, which - /// made the current class, stored a reference to the - /// subclasses. The \c splitClass() member restores the classes - /// and creates the heaps. The parameter is an STL output iterator - /// which will be filled with the subclass ids. The time - /// complexity is O(log(n)*k) where n is the overall number of - /// nodes in the splitted classes and k is the number of the - /// classes. - template - void split(int cls, Iterator out) { - std::vector cs; - { // splitting union-find - int id = cls; - int l = classes[id].left; - - classes[l].parent = classes[id].parent; - classes[l].depth = classes[id].depth; - - nodes[~(classes[l].parent)].parent = ~l; - - *out++ = l; - - while (l != -1) { - cs.push_back(l); - l = classes[l].next; - } - - classes[classes[id].right].next = first_class; - classes[first_class].prev = classes[id].right; - first_class = classes[id].left; - - if (classes[id].next != -1) { - classes[classes[id].next].prev = classes[id].prev; - } - classes[classes[id].prev].next = classes[id].next; - - deleteClass(id); - } - - { - for (int i = 1; i < int(cs.size()); ++i) { - int l = classes[cs[i]].depth; - while (nodes[nodes[l].parent].left == l) { - l = nodes[l].parent; - } - int r = l; - while (nodes[l].parent >= 0) { - l = nodes[l].parent; - int new_node = newNode(); - - nodes[new_node].prev = -1; - nodes[new_node].next = -1; - - split(r, new_node); - pushAfter(l, new_node); - setPrio(l); - setPrio(new_node); - r = new_node; - } - classes[cs[i]].parent = ~r; - classes[cs[i]].depth = classes[~(nodes[l].parent)].depth; - nodes[r].parent = ~cs[i]; - - nodes[l].next = -1; - nodes[r].prev = -1; - - repairRight(~(nodes[l].parent)); - repairLeft(cs[i]); - - *out++ = cs[i]; - } - } - } - - /// \brief Gives back the priority of the current item. - /// - /// Gives back the priority of the current item. - const Value& operator[](const Item& item) const { - return nodes[index[item]].prio; - } - - /// \brief Sets the priority of the current item. - /// - /// Sets the priority of the current item. - void set(const Item& item, const Value& prio) { - if (comp(prio, nodes[index[item]].prio)) { - decrease(item, prio); - } else if (!comp(prio, nodes[index[item]].prio)) { - increase(item, prio); - } - } - - /// \brief Increase the priority of the current item. - /// - /// Increase the priority of the current item. - void increase(const Item& item, const Value& prio) { - int id = index[item]; - int kd = nodes[id].parent; - nodes[id].prio = prio; - while (kd >= 0 && nodes[kd].item == item) { - setPrio(kd); - kd = nodes[kd].parent; - } - } - - /// \brief Increase the priority of the current item. - /// - /// Increase the priority of the current item. - void decrease(const Item& item, const Value& prio) { - int id = index[item]; - int kd = nodes[id].parent; - nodes[id].prio = prio; - while (kd >= 0 && less(id, kd)) { - nodes[kd].prio = prio; - nodes[kd].item = item; - kd = nodes[kd].parent; - } - } - - /// \brief Gives back the minimum priority of the class. - /// - /// Gives back the minimum priority of the class. - const Value& classPrio(int cls) const { - return nodes[~(classes[cls].parent)].prio; - } - - /// \brief Gives back the minimum priority item of the class. - /// - /// \return Gives back the minimum priority item of the class. - const Item& classTop(int cls) const { - return nodes[~(classes[cls].parent)].item; - } - - /// \brief Gives back a representant item of the class. - /// - /// Gives back a representant item of the class. - /// The representant is indpendent from the priorities of the - /// items. - const Item& classRep(int id) const { - int parent = classes[id].parent; - return nodes[parent >= 0 ? classes[id].depth : leftNode(id)].item; - } - - /// \brief LEMON style iterator for the items of a class. - /// - /// ClassIt is a lemon style iterator for the components. It iterates - /// on the items of a class. By example if you want to iterate on - /// each items of each classes then you may write the next code. - ///\code - /// for (ClassIt cit(huf); cit != INVALID; ++cit) { - /// std::cout << "Class: "; - /// for (ItemIt iit(huf, cit); iit != INVALID; ++iit) { - /// std::cout << toString(iit) << ' ' << std::endl; - /// } - /// std::cout << std::endl; - /// } - ///\endcode - class ItemIt { - private: - - const HeapUnionFind* _huf; - int _id, _lid; - - public: - - /// \brief Default constructor - /// - /// Default constructor - ItemIt() {} - - ItemIt(const HeapUnionFind& huf, int cls) : _huf(&huf) { - int id = cls; - int parent = _huf->classes[id].parent; - if (parent >= 0) { - _id = _huf->classes[id].depth; - if (_huf->classes[id].next != -1) { - _lid = _huf->classes[_huf->classes[id].next].depth; - } else { - _lid = -1; - } - } else { - _id = _huf->leftNode(id); - _lid = -1; - } - } - - /// \brief Increment operator - /// - /// It steps to the next item in the class. - ItemIt& operator++() { - _id = _huf->nextNode(_id); - return *this; - } - - /// \brief Conversion operator - /// - /// It converts the iterator to the current item. - operator const Item&() const { - return _huf->nodes[_id].item; - } - - /// \brief Equality operator - /// - /// Equality operator - bool operator==(const ItemIt& i) { - return i._id == _id; - } - - /// \brief Inequality operator - /// - /// Inequality operator - bool operator!=(const ItemIt& i) { - return i._id != _id; - } - - /// \brief Equality operator - /// - /// Equality operator - bool operator==(Invalid) { - return _id == _lid; - } - - /// \brief Inequality operator - /// - /// Inequality operator - bool operator!=(Invalid) { - return _id != _lid; - } - - }; - - /// \brief Class iterator - /// - /// The iterator stores - class ClassIt { - private: - - const HeapUnionFind* _huf; - int _id; - - public: - - ClassIt(const HeapUnionFind& huf) - : _huf(&huf), _id(huf.first_class) {} - - ClassIt(const HeapUnionFind& huf, int cls) - : _huf(&huf), _id(huf.classes[cls].left) {} - - ClassIt(Invalid) : _huf(0), _id(-1) {} - - const ClassIt& operator++() { - _id = _huf->classes[_id].next; - return *this; - } - - /// \brief Equality operator - /// - /// Equality operator - bool operator==(const ClassIt& i) { - return i._id == _id; - } - - /// \brief Inequality operator - /// - /// Inequality operator - bool operator!=(const ClassIt& i) { - return i._id != _id; - } - - operator int() const { - return _id; - } - - }; - - }; - - //! @} - -} //namespace lemon - -#endif //LEMON_UNION_FIND_H diff --git a/deps/lemon/scripts/unify-sources.sh b/deps/lemon/scripts/unify-sources.sh deleted file mode 100755 index 6aae63ab6..000000000 --- a/deps/lemon/scripts/unify-sources.sh +++ /dev/null @@ -1,390 +0,0 @@ -#!/bin/bash -# -# This file is a part of LEMON, a generic C++ optimization library. -# -# Copyright (C) 2003-2009 -# Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport -# (Egervary Research Group on Combinatorial Optimization, EGRES). -# -# Permission to use, modify and distribute this software is granted -# provided that this copyright notice appears in all copies. For -# precise terms see the accompanying LICENSE file. -# -# This software is provided "AS IS" with no warranty of any kind, -# express or implied, and with no claim as to its suitability for any -# purpose. - -YEAR=`date +%Y` -HGROOT=`hg root` - -function hg_year() { - if [ -n "$(hg st $1)" ]; then - echo $YEAR - else - hg log -l 1 --template='{date|isodate}\n' $1 | - cut -d '-' -f 1 - fi -} - -# file enumaration modes - -function all_files() { - hg status -a -m -c | - cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' | - while read file; do echo $HGROOT/$file; done -} - -function modified_files() { - hg status -a -m | - cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' | - while read file; do echo $HGROOT/$file; done -} - -function changed_files() { - { - if [ -n "$HG_PARENT1" ] - then - hg status --rev $HG_PARENT1:$HG_NODE -a -m - fi - if [ -n "$HG_PARENT2" ] - then - hg status --rev $HG_PARENT2:$HG_NODE -a -m - fi - } | cut -d ' ' -f 2 | grep -E '(\.(cc|h|dox)$|Makefile\.am$)' | - sort | uniq | - while read file; do echo $HGROOT/$file; done -} - -function given_files() { - for file in $GIVEN_FILES - do - echo $file - done -} - -# actions - -function update_action() { - if ! diff -q $1 $2 >/dev/null - then - echo -n " [$3 updated]" - rm $2 - mv $1 $2 - CHANGED=YES - fi -} - -function update_warning() { - echo -n " [$2 warning]" - WARNED=YES -} - -function update_init() { - echo Update source files... - TOTAL_FILES=0 - CHANGED_FILES=0 - WARNED_FILES=0 -} - -function update_done() { - echo $CHANGED_FILES out of $TOTAL_FILES files has been changed. - echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings. -} - -function update_begin() { - ((TOTAL_FILES++)) - CHANGED=NO - WARNED=NO -} - -function update_end() { - if [ $CHANGED == YES ] - then - ((++CHANGED_FILES)) - fi - if [ $WARNED == YES ] - then - ((++WARNED_FILES)) - fi -} - -function check_action() { - if [ "$3" == 'tabs' ] - then - if echo $2 | grep -q -v -E 'Makefile\.am$' - then - PATTERN=$(echo -e '\t') - else - PATTERN=' ' - fi - elif [ "$3" == 'trailing spaces' ] - then - PATTERN='\ +$' - else - PATTERN='*' - fi - - if ! diff -q $1 $2 >/dev/null - then - if [ "$PATTERN" == '*' ] - then - diff $1 $2 | grep '^[0-9]' | sed "s|^\(.*\)c.*$|$2:\1: check failed: $3|g" | - sed "s/:\([0-9]*\),\([0-9]*\):\(.*\)$/:\1:\3 (until line \2)/g" - else - grep -n -E "$PATTERN" $2 | sed "s|^\([0-9]*\):.*$|$2:\1: check failed: $3|g" - fi - FAILED=YES - fi -} - -function check_warning() { - if [ "$2" == 'long lines' ] - then - grep -n -E '.{81,}' $1 | sed "s|^\([0-9]*\):.*$|$1:\1: warning: $2|g" - else - echo "$1: warning: $2" - fi - WARNED=YES -} - -function check_init() { - echo Check source files... - FAILED_FILES=0 - WARNED_FILES=0 - TOTAL_FILES=0 -} - -function check_done() { - echo $FAILED_FILES out of $TOTAL_FILES files has been failed. - echo $WARNED_FILES out of $TOTAL_FILES files triggered warnings. - - if [ $WARNED_FILES -gt 0 -o $FAILED_FILES -gt 0 ] - then - if [ "$WARNING" == 'INTERACTIVE' ] - then - echo -n "Are the files with errors/warnings acceptable? (yes/no) " - while read answer - do - if [ "$answer" == 'yes' ] - then - return 0 - elif [ "$answer" == 'no' ] - then - return 1 - fi - echo -n "Are the files with errors/warnings acceptable? (yes/no) " - done - elif [ "$WARNING" == 'WERROR' ] - then - return 1 - fi - fi -} - -function check_begin() { - ((TOTAL_FILES++)) - FAILED=NO - WARNED=NO -} - -function check_end() { - if [ $FAILED == YES ] - then - ((++FAILED_FILES)) - fi - if [ $WARNED == YES ] - then - ((++WARNED_FILES)) - fi -} - - - -# checks - -function header_check() { - if echo $1 | grep -q -E 'Makefile\.am$' - then - return - fi - - TMP_FILE=`mktemp` - - (echo "/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-"$(hg_year $1)" - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided \"AS IS\" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ -" - awk 'BEGIN { pm=0; } - pm==3 { print } - /\/\* / && pm==0 { pm=1;} - /[^:blank:]/ && (pm==0 || pm==2) { pm=3; print;} - /\*\// && pm==1 { pm=2;} - ' $1 - ) >$TMP_FILE - - "$ACTION"_action "$TMP_FILE" "$1" header -} - -function tabs_check() { - if echo $1 | grep -q -v -E 'Makefile\.am$' - then - OLD_PATTERN=$(echo -e '\t') - NEW_PATTERN=' ' - else - OLD_PATTERN=' ' - NEW_PATTERN=$(echo -e '\t') - fi - TMP_FILE=`mktemp` - cat $1 | sed -e "s/$OLD_PATTERN/$NEW_PATTERN/g" >$TMP_FILE - - "$ACTION"_action "$TMP_FILE" "$1" 'tabs' -} - -function spaces_check() { - TMP_FILE=`mktemp` - cat $1 | sed -e 's/ \+$//g' >$TMP_FILE - - "$ACTION"_action "$TMP_FILE" "$1" 'trailing spaces' -} - -function long_lines_check() { - if cat $1 | grep -q -E '.{81,}' - then - "$ACTION"_warning $1 'long lines' - fi -} - -# process the file - -function process_file() { - if [ "$ACTION" == 'update' ] - then - echo -n " $ACTION $1..." - else - echo " $ACTION $1..." - fi - - CHECKING="header tabs spaces long_lines" - - "$ACTION"_begin $1 - for check in $CHECKING - do - "$check"_check $1 - done - "$ACTION"_end $1 - if [ "$ACTION" == 'update' ] - then - echo - fi -} - -function process_all { - "$ACTION"_init - while read file - do - process_file $file - done < <($FILES) - "$ACTION"_done -} - -while [ $# -gt 0 ] -do - - if [ "$1" == '--help' ] || [ "$1" == '-h' ] - then - echo -n \ -"Usage: - $0 [OPTIONS] [files] -Options: - --dry-run|-n - Check the files, but do not modify them. - --interactive|-i - If --dry-run is specified and the checker emits warnings, - then the user is asked if the warnings should be considered - errors. - --werror|-w - Make all warnings into errors. - --all|-a - Check all source files in the repository. - --modified|-m - Check only the modified (and new) source files. This option is - useful to check the modification before making a commit. - --changed|-c - Check only the changed source files compared to the parent(s) of - the current hg node. This option is useful as hg hook script. - To automatically check all your changes before making a commit, - add the following section to the appropriate .hg/hgrc file. - - [hooks] - pretxncommit.checksources = scripts/unify-sources.sh -c -n -i - - --help|-h - Print this help message. - files - The files to check/unify. If no file names are given, the modified - source files will be checked/unified (just like using the - --modified|-m option). -" - exit 0 - elif [ "$1" == '--dry-run' ] || [ "$1" == '-n' ] - then - [ -n "$ACTION" ] && echo "Conflicting action options" >&2 && exit 1 - ACTION=check - elif [ "$1" == "--all" ] || [ "$1" == '-a' ] - then - [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1 - FILES=all_files - elif [ "$1" == "--changed" ] || [ "$1" == '-c' ] - then - [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1 - FILES=changed_files - elif [ "$1" == "--modified" ] || [ "$1" == '-m' ] - then - [ -n "$FILES" ] && echo "Conflicting target options" >&2 && exit 1 - FILES=modified_files - elif [ "$1" == "--interactive" ] || [ "$1" == "-i" ] - then - [ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1 - WARNING='INTERACTIVE' - elif [ "$1" == "--werror" ] || [ "$1" == "-w" ] - then - [ -n "$WARNING" ] && echo "Conflicting warning options" >&2 && exit 1 - WARNING='WERROR' - elif [ $(echo x$1 | cut -c 2) == '-' ] - then - echo "Invalid option $1" >&2 && exit 1 - else - [ -n "$FILES" ] && echo "Invalid option $1" >&2 && exit 1 - GIVEN_FILES=$@ - FILES=given_files - break - fi - - shift -done - -if [ -z $FILES ] -then - FILES=modified_files -fi - -if [ -z $ACTION ] -then - ACTION=update -fi - -process_all diff --git a/deps/lemon/scripts/valgrind-wrapper.sh b/deps/lemon/scripts/valgrind-wrapper.sh deleted file mode 100755 index bbb122290..000000000 --- a/deps/lemon/scripts/valgrind-wrapper.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -# Run in valgrind, with leak checking enabled - -valgrind -q --leak-check=full "$@" 2> .valgrind-log - -# Save the test result - -result="$?" - -# Valgrind should generate no error messages - -log_contents="`cat .valgrind-log`" - -if [ "$log_contents" != "" ]; then - cat .valgrind-log >&2 - result=1 -fi - -rm -f .valgrind-log - -exit $result diff --git a/deps/lemon/test/CMakeLists.txt b/deps/lemon/test/CMakeLists.txt deleted file mode 100644 index 96fc5dd48..000000000 --- a/deps/lemon/test/CMakeLists.txt +++ /dev/null @@ -1,161 +0,0 @@ -INCLUDE_DIRECTORIES( - ${PROJECT_SOURCE_DIR} - ${PROJECT_BINARY_DIR} -) - -LINK_DIRECTORIES( - ${PROJECT_BINARY_DIR}/lemon -) - -SET(TEST_WITH_VALGRIND "NO" CACHE STRING - "Run the test with valgrind (YES/NO).") -SET(VALGRIND_FLAGS "" CACHE STRING "Valgrind flags used by the tests.") - -SET(TESTS - adaptors_test - arc_look_up_test - bellman_ford_test - bfs_test - bpgraph_test - circulation_test - connectivity_test - counter_test - dfs_test - digraph_test - dijkstra_test - dim_test - edge_set_test - error_test - euler_test - fractional_matching_test - gomory_hu_test - graph_copy_test - graph_test - graph_utils_test - hao_orlin_test - heap_test - kruskal_test - lgf_reader_writer_test - lgf_test - maps_test - matching_test - max_cardinality_search_test - max_clique_test - max_flow_test - min_cost_arborescence_test - min_cost_flow_test - min_mean_cycle_test - nagamochi_ibaraki_test - path_test - planarity_test - radix_sort_test - random_test - suurballe_test - time_measure_test - tsp_test - unionfind_test -) - -IF(LEMON_HAVE_LP) - IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer") - ADD_EXECUTABLE(lp_test lp_test.cc) - ELSE() - ADD_EXECUTABLE(lp_test EXCLUDE_FROM_ALL lp_test.cc) - ENDIF() - - SET(LP_TEST_LIBS lemon) - - IF(LEMON_HAVE_GLPK) - SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${GLPK_LIBRARIES}) - ENDIF() - IF(LEMON_HAVE_CPLEX) - SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${ILOG_LIBRARIES}) - ENDIF() - IF(LEMON_HAVE_CLP) - SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${COIN_CLP_LIBRARIES}) - ENDIF() - IF(LEMON_HAVE_SOPLEX) - SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${SOPLEX_LIBRARIES}) - ENDIF() - - TARGET_LINK_LIBRARIES(lp_test ${LP_TEST_LIBS}) - ADD_TEST(lp_test lp_test) - ADD_DEPENDENCIES(check lp_test) - - IF(WIN32 AND LEMON_HAVE_GLPK) - GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION) - GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH) - ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/glpk.dll ${TARGET_PATH} - COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/libltdl3.dll ${TARGET_PATH} - COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/zlib1.dll ${TARGET_PATH} - ) - ENDIF() - - IF(WIN32 AND LEMON_HAVE_CPLEX) - GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION) - GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH) - ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${ILOG_CPLEX_DLL} ${TARGET_PATH} - ) - ENDIF() -ENDIF() - -IF(LEMON_HAVE_MIP) - IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer") - ADD_EXECUTABLE(mip_test mip_test.cc) - ELSE() - ADD_EXECUTABLE(mip_test EXCLUDE_FROM_ALL mip_test.cc) - ENDIF() - - SET(MIP_TEST_LIBS lemon) - - IF(LEMON_HAVE_GLPK) - SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${GLPK_LIBRARIES}) - ENDIF() - IF(LEMON_HAVE_CPLEX) - SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${ILOG_LIBRARIES}) - ENDIF() - IF(LEMON_HAVE_CBC) - SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${COIN_CBC_LIBRARIES}) - ENDIF() - - TARGET_LINK_LIBRARIES(mip_test ${MIP_TEST_LIBS}) - ADD_TEST(mip_test mip_test) - ADD_DEPENDENCIES(check mip_test) - - IF(WIN32 AND LEMON_HAVE_GLPK) - GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION) - GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH) - ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/glpk.dll ${TARGET_PATH} - COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/libltdl3.dll ${TARGET_PATH} - COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/zlib1.dll ${TARGET_PATH} - ) - ENDIF() - - IF(WIN32 AND LEMON_HAVE_CPLEX) - GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION) - GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH) - ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${ILOG_CPLEX_DLL} ${TARGET_PATH} - ) - ENDIF() -ENDIF() - -FOREACH(TEST_NAME ${TESTS}) - IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer") - ADD_EXECUTABLE(${TEST_NAME} ${TEST_NAME}.cc) - ELSE() - ADD_EXECUTABLE(${TEST_NAME} EXCLUDE_FROM_ALL ${TEST_NAME}.cc) - ENDIF() - TARGET_LINK_LIBRARIES(${TEST_NAME} lemon) - IF(TEST_WITH_VALGRIND) - ADD_TEST(${TEST_NAME} - valgrind --error-exitcode=1 ${VALGRIND_FLAGS} - ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME} ) - ELSE() - ADD_TEST(${TEST_NAME} ${TEST_NAME}) - ENDIF() - ADD_DEPENDENCIES(check ${TEST_NAME}) -ENDFOREACH() diff --git a/deps/lemon/test/adaptors_test.cc b/deps/lemon/test/adaptors_test.cc deleted file mode 100644 index 9077db96e..000000000 --- a/deps/lemon/test/adaptors_test.cc +++ /dev/null @@ -1,1468 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "test/test_tools.h" -#include "test/graph_test.h" - -using namespace lemon; - -void checkReverseDigraph() { - // Check concepts - checkConcept >(); - checkConcept >(); - checkConcept, - ReverseDigraph >(); - checkConcept, - ReverseDigraph >(); - checkConcept, - ReverseDigraph >(); - checkConcept, - ReverseDigraph >(); - - // Create a digraph and an adaptor - typedef ListDigraph Digraph; - typedef ReverseDigraph Adaptor; - - Digraph digraph; - Adaptor adaptor(digraph); - - // Add nodes and arcs to the original digraph - Digraph::Node n1 = digraph.addNode(); - Digraph::Node n2 = digraph.addNode(); - Digraph::Node n3 = digraph.addNode(); - - Digraph::Arc a1 = digraph.addArc(n1, n2); - Digraph::Arc a2 = digraph.addArc(n1, n3); - Digraph::Arc a3 = digraph.addArc(n2, n3); - ::lemon::ignore_unused_variable_warning(a3); - - // Check the adaptor - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 3); - checkGraphConArcList(adaptor, 3); - - checkGraphOutArcList(adaptor, n1, 0); - checkGraphOutArcList(adaptor, n2, 1); - checkGraphOutArcList(adaptor, n3, 2); - - checkGraphInArcList(adaptor, n1, 2); - checkGraphInArcList(adaptor, n2, 1); - checkGraphInArcList(adaptor, n3, 0); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Check the orientation of the arcs - for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) { - check(adaptor.source(a) == digraph.target(a), "Wrong reverse"); - check(adaptor.target(a) == digraph.source(a), "Wrong reverse"); - } - - // Add and erase nodes and arcs in the digraph through the adaptor - Adaptor::Node n4 = adaptor.addNode(); - - Adaptor::Arc a4 = adaptor.addArc(n4, n3); - Adaptor::Arc a5 = adaptor.addArc(n2, n4); - Adaptor::Arc a6 = adaptor.addArc(n2, n4); - Adaptor::Arc a7 = adaptor.addArc(n1, n4); - Adaptor::Arc a8 = adaptor.addArc(n1, n2); - ::lemon::ignore_unused_variable_warning(a6,a7,a8); - - adaptor.erase(a1); - adaptor.erase(n3); - - // Check the adaptor - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 4); - checkGraphConArcList(adaptor, 4); - - checkGraphOutArcList(adaptor, n1, 2); - checkGraphOutArcList(adaptor, n2, 2); - checkGraphOutArcList(adaptor, n4, 0); - - checkGraphInArcList(adaptor, n1, 0); - checkGraphInArcList(adaptor, n2, 1); - checkGraphInArcList(adaptor, n4, 3); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Check the digraph - checkGraphNodeList(digraph, 3); - checkGraphArcList(digraph, 4); - checkGraphConArcList(digraph, 4); - - checkGraphOutArcList(digraph, n1, 0); - checkGraphOutArcList(digraph, n2, 1); - checkGraphOutArcList(digraph, n4, 3); - - checkGraphInArcList(digraph, n1, 2); - checkGraphInArcList(digraph, n2, 2); - checkGraphInArcList(digraph, n4, 0); - - checkNodeIds(digraph); - checkArcIds(digraph); - - checkGraphNodeMap(digraph); - checkGraphArcMap(digraph); - - // Check the conversion of nodes and arcs - Digraph::Node nd = n4; - nd = n4; - Adaptor::Node na = n1; - na = n2; - Digraph::Arc ad = a4; - ad = a5; - Adaptor::Arc aa = a1; - aa = a2; -} - -void checkSubDigraph() { - // Check concepts - checkConcept >(); - checkConcept >(); - checkConcept, - SubDigraph >(); - checkConcept, - SubDigraph >(); - checkConcept, - SubDigraph >(); - checkConcept, - SubDigraph >(); - - // Create a digraph and an adaptor - typedef ListDigraph Digraph; - typedef Digraph::NodeMap NodeFilter; - typedef Digraph::ArcMap ArcFilter; - typedef SubDigraph Adaptor; - - Digraph digraph; - NodeFilter node_filter(digraph); - ArcFilter arc_filter(digraph); - Adaptor adaptor(digraph, node_filter, arc_filter); - - // Add nodes and arcs to the original digraph and the adaptor - Digraph::Node n1 = digraph.addNode(); - Digraph::Node n2 = digraph.addNode(); - Adaptor::Node n3 = adaptor.addNode(); - - node_filter[n1] = node_filter[n2] = node_filter[n3] = true; - - Digraph::Arc a1 = digraph.addArc(n1, n2); - Digraph::Arc a2 = digraph.addArc(n1, n3); - Adaptor::Arc a3 = adaptor.addArc(n2, n3); - - arc_filter[a1] = arc_filter[a2] = arc_filter[a3] = true; - - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 3); - checkGraphConArcList(adaptor, 3); - - checkGraphOutArcList(adaptor, n1, 2); - checkGraphOutArcList(adaptor, n2, 1); - checkGraphOutArcList(adaptor, n3, 0); - - checkGraphInArcList(adaptor, n1, 0); - checkGraphInArcList(adaptor, n2, 1); - checkGraphInArcList(adaptor, n3, 2); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Hide an arc - adaptor.status(a2, false); - adaptor.disable(a3); - if (!adaptor.status(a3)) adaptor.enable(a3); - - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 2); - checkGraphConArcList(adaptor, 2); - - checkGraphOutArcList(adaptor, n1, 1); - checkGraphOutArcList(adaptor, n2, 1); - checkGraphOutArcList(adaptor, n3, 0); - - checkGraphInArcList(adaptor, n1, 0); - checkGraphInArcList(adaptor, n2, 1); - checkGraphInArcList(adaptor, n3, 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Hide a node - adaptor.status(n1, false); - adaptor.disable(n3); - if (!adaptor.status(n3)) adaptor.enable(n3); - - checkGraphNodeList(adaptor, 2); - checkGraphArcList(adaptor, 1); - checkGraphConArcList(adaptor, 1); - - checkGraphOutArcList(adaptor, n2, 1); - checkGraphOutArcList(adaptor, n3, 0); - - checkGraphInArcList(adaptor, n2, 0); - checkGraphInArcList(adaptor, n3, 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Hide all nodes and arcs - node_filter[n1] = node_filter[n2] = node_filter[n3] = false; - arc_filter[a1] = arc_filter[a2] = arc_filter[a3] = false; - - checkGraphNodeList(adaptor, 0); - checkGraphArcList(adaptor, 0); - checkGraphConArcList(adaptor, 0); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Check the conversion of nodes and arcs - Digraph::Node nd = n3; - nd = n3; - Adaptor::Node na = n1; - na = n2; - Digraph::Arc ad = a3; - ad = a3; - Adaptor::Arc aa = a1; - aa = a2; -} - -void checkFilterNodes1() { - // Check concepts - checkConcept >(); - checkConcept >(); - checkConcept, - FilterNodes >(); - checkConcept, - FilterNodes >(); - checkConcept, - FilterNodes >(); - checkConcept, - FilterNodes >(); - - // Create a digraph and an adaptor - typedef ListDigraph Digraph; - typedef Digraph::NodeMap NodeFilter; - typedef FilterNodes Adaptor; - - Digraph digraph; - NodeFilter node_filter(digraph); - Adaptor adaptor(digraph, node_filter); - - // Add nodes and arcs to the original digraph and the adaptor - Digraph::Node n1 = digraph.addNode(); - Digraph::Node n2 = digraph.addNode(); - Adaptor::Node n3 = adaptor.addNode(); - - node_filter[n1] = node_filter[n2] = node_filter[n3] = true; - - Digraph::Arc a1 = digraph.addArc(n1, n2); - Digraph::Arc a2 = digraph.addArc(n1, n3); - Adaptor::Arc a3 = adaptor.addArc(n2, n3); - - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 3); - checkGraphConArcList(adaptor, 3); - - checkGraphOutArcList(adaptor, n1, 2); - checkGraphOutArcList(adaptor, n2, 1); - checkGraphOutArcList(adaptor, n3, 0); - - checkGraphInArcList(adaptor, n1, 0); - checkGraphInArcList(adaptor, n2, 1); - checkGraphInArcList(adaptor, n3, 2); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Hide a node - adaptor.status(n1, false); - adaptor.disable(n3); - if (!adaptor.status(n3)) adaptor.enable(n3); - - checkGraphNodeList(adaptor, 2); - checkGraphArcList(adaptor, 1); - checkGraphConArcList(adaptor, 1); - - checkGraphOutArcList(adaptor, n2, 1); - checkGraphOutArcList(adaptor, n3, 0); - - checkGraphInArcList(adaptor, n2, 0); - checkGraphInArcList(adaptor, n3, 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Hide all nodes - node_filter[n1] = node_filter[n2] = node_filter[n3] = false; - - checkGraphNodeList(adaptor, 0); - checkGraphArcList(adaptor, 0); - checkGraphConArcList(adaptor, 0); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Check the conversion of nodes and arcs - Digraph::Node nd = n3; - nd = n3; - Adaptor::Node na = n1; - na = n2; - Digraph::Arc ad = a3; - ad = a3; - Adaptor::Arc aa = a1; - aa = a2; -} - -void checkFilterArcs() { - // Check concepts - checkConcept >(); - checkConcept >(); - checkConcept, - FilterArcs >(); - checkConcept, - FilterArcs >(); - checkConcept, - FilterArcs >(); - checkConcept, - FilterArcs >(); - - // Create a digraph and an adaptor - typedef ListDigraph Digraph; - typedef Digraph::ArcMap ArcFilter; - typedef FilterArcs Adaptor; - - Digraph digraph; - ArcFilter arc_filter(digraph); - Adaptor adaptor(digraph, arc_filter); - - // Add nodes and arcs to the original digraph and the adaptor - Digraph::Node n1 = digraph.addNode(); - Digraph::Node n2 = digraph.addNode(); - Adaptor::Node n3 = adaptor.addNode(); - - Digraph::Arc a1 = digraph.addArc(n1, n2); - Digraph::Arc a2 = digraph.addArc(n1, n3); - Adaptor::Arc a3 = adaptor.addArc(n2, n3); - - arc_filter[a1] = arc_filter[a2] = arc_filter[a3] = true; - - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 3); - checkGraphConArcList(adaptor, 3); - - checkGraphOutArcList(adaptor, n1, 2); - checkGraphOutArcList(adaptor, n2, 1); - checkGraphOutArcList(adaptor, n3, 0); - - checkGraphInArcList(adaptor, n1, 0); - checkGraphInArcList(adaptor, n2, 1); - checkGraphInArcList(adaptor, n3, 2); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Hide an arc - adaptor.status(a2, false); - adaptor.disable(a3); - if (!adaptor.status(a3)) adaptor.enable(a3); - - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 2); - checkGraphConArcList(adaptor, 2); - - checkGraphOutArcList(adaptor, n1, 1); - checkGraphOutArcList(adaptor, n2, 1); - checkGraphOutArcList(adaptor, n3, 0); - - checkGraphInArcList(adaptor, n1, 0); - checkGraphInArcList(adaptor, n2, 1); - checkGraphInArcList(adaptor, n3, 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Hide all arcs - arc_filter[a1] = arc_filter[a2] = arc_filter[a3] = false; - - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 0); - checkGraphConArcList(adaptor, 0); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Check the conversion of nodes and arcs - Digraph::Node nd = n3; - nd = n3; - Adaptor::Node na = n1; - na = n2; - Digraph::Arc ad = a3; - ad = a3; - Adaptor::Arc aa = a1; - aa = a2; -} - -void checkUndirector() { - // Check concepts - checkConcept >(); - checkConcept >(); - checkConcept, - Undirector >(); - checkConcept, - Undirector >(); - checkConcept, - Undirector >(); - checkConcept, - Undirector >(); - - - // Create a digraph and an adaptor - typedef ListDigraph Digraph; - typedef Undirector Adaptor; - - Digraph digraph; - Adaptor adaptor(digraph); - - // Add nodes and arcs/edges to the original digraph and the adaptor - Digraph::Node n1 = digraph.addNode(); - Digraph::Node n2 = digraph.addNode(); - Adaptor::Node n3 = adaptor.addNode(); - - Digraph::Arc a1 = digraph.addArc(n1, n2); - Digraph::Arc a2 = digraph.addArc(n1, n3); - Adaptor::Edge e3 = adaptor.addEdge(n2, n3); - - // Check the original digraph - checkGraphNodeList(digraph, 3); - checkGraphArcList(digraph, 3); - checkGraphConArcList(digraph, 3); - - checkGraphOutArcList(digraph, n1, 2); - checkGraphOutArcList(digraph, n2, 1); - checkGraphOutArcList(digraph, n3, 0); - - checkGraphInArcList(digraph, n1, 0); - checkGraphInArcList(digraph, n2, 1); - checkGraphInArcList(digraph, n3, 2); - - checkNodeIds(digraph); - checkArcIds(digraph); - - checkGraphNodeMap(digraph); - checkGraphArcMap(digraph); - - // Check the adaptor - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 6); - checkGraphEdgeList(adaptor, 3); - checkGraphConArcList(adaptor, 6); - checkGraphConEdgeList(adaptor, 3); - - checkGraphIncEdgeArcLists(adaptor, n1, 2); - checkGraphIncEdgeArcLists(adaptor, n2, 2); - checkGraphIncEdgeArcLists(adaptor, n3, 2); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - checkEdgeIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - checkGraphEdgeMap(adaptor); - - // Check the edges of the adaptor - for (Adaptor::EdgeIt e(adaptor); e != INVALID; ++e) { - check(adaptor.u(e) == digraph.source(e), "Wrong undir"); - check(adaptor.v(e) == digraph.target(e), "Wrong undir"); - } - - // Check CombinedArcMap - typedef Adaptor::CombinedArcMap - , Digraph::ArcMap > IntCombinedMap; - typedef Adaptor::CombinedArcMap - , Digraph::ArcMap > BoolCombinedMap; - checkConcept, - IntCombinedMap>(); - checkConcept, - BoolCombinedMap>(); - - Digraph::ArcMap fw_map(digraph), bk_map(digraph); - for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { - fw_map[a] = digraph.id(a); - bk_map[a] = -digraph.id(a); - } - - Adaptor::CombinedArcMap, Digraph::ArcMap > - comb_map(fw_map, bk_map); - for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) { - if (adaptor.source(a) == digraph.source(a)) { - check(comb_map[a] == fw_map[a], "Wrong combined map"); - } else { - check(comb_map[a] == bk_map[a], "Wrong combined map"); - } - } - - // Check the conversion of nodes and arcs/edges - Digraph::Node nd = n3; - nd = n3; - Adaptor::Node na = n1; - na = n2; - Digraph::Arc ad = e3; - ad = e3; - Adaptor::Edge ea = a1; - ea = a2; -} - -void checkResidualDigraph() { - // Check concepts - checkConcept >(); - checkConcept >(); - - // Create a digraph and an adaptor - typedef ListDigraph Digraph; - typedef Digraph::ArcMap IntArcMap; - typedef ResidualDigraph Adaptor; - - Digraph digraph; - IntArcMap capacity(digraph), flow(digraph); - Adaptor adaptor(digraph, capacity, flow); - - Digraph::Node n1 = digraph.addNode(); - Digraph::Node n2 = digraph.addNode(); - Digraph::Node n3 = digraph.addNode(); - Digraph::Node n4 = digraph.addNode(); - - Digraph::Arc a1 = digraph.addArc(n1, n2); - Digraph::Arc a2 = digraph.addArc(n1, n3); - Digraph::Arc a3 = digraph.addArc(n1, n4); - Digraph::Arc a4 = digraph.addArc(n2, n3); - Digraph::Arc a5 = digraph.addArc(n2, n4); - Digraph::Arc a6 = digraph.addArc(n3, n4); - - capacity[a1] = 8; - capacity[a2] = 6; - capacity[a3] = 4; - capacity[a4] = 4; - capacity[a5] = 6; - capacity[a6] = 10; - - // Check the adaptor with various flow values - for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { - flow[a] = 0; - } - - checkGraphNodeList(adaptor, 4); - checkGraphArcList(adaptor, 6); - checkGraphConArcList(adaptor, 6); - - checkGraphOutArcList(adaptor, n1, 3); - checkGraphOutArcList(adaptor, n2, 2); - checkGraphOutArcList(adaptor, n3, 1); - checkGraphOutArcList(adaptor, n4, 0); - - checkGraphInArcList(adaptor, n1, 0); - checkGraphInArcList(adaptor, n2, 1); - checkGraphInArcList(adaptor, n3, 2); - checkGraphInArcList(adaptor, n4, 3); - - for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { - flow[a] = capacity[a] / 2; - } - - checkGraphNodeList(adaptor, 4); - checkGraphArcList(adaptor, 12); - checkGraphConArcList(adaptor, 12); - - checkGraphOutArcList(adaptor, n1, 3); - checkGraphOutArcList(adaptor, n2, 3); - checkGraphOutArcList(adaptor, n3, 3); - checkGraphOutArcList(adaptor, n4, 3); - - checkGraphInArcList(adaptor, n1, 3); - checkGraphInArcList(adaptor, n2, 3); - checkGraphInArcList(adaptor, n3, 3); - checkGraphInArcList(adaptor, n4, 3); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { - flow[a] = capacity[a]; - } - - checkGraphNodeList(adaptor, 4); - checkGraphArcList(adaptor, 6); - checkGraphConArcList(adaptor, 6); - - checkGraphOutArcList(adaptor, n1, 0); - checkGraphOutArcList(adaptor, n2, 1); - checkGraphOutArcList(adaptor, n3, 2); - checkGraphOutArcList(adaptor, n4, 3); - - checkGraphInArcList(adaptor, n1, 3); - checkGraphInArcList(adaptor, n2, 2); - checkGraphInArcList(adaptor, n3, 1); - checkGraphInArcList(adaptor, n4, 0); - - // Saturate all backward arcs - // (set the flow to zero on all forward arcs) - for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) { - if (adaptor.backward(a)) - adaptor.augment(a, adaptor.residualCapacity(a)); - } - - checkGraphNodeList(adaptor, 4); - checkGraphArcList(adaptor, 6); - checkGraphConArcList(adaptor, 6); - - checkGraphOutArcList(adaptor, n1, 3); - checkGraphOutArcList(adaptor, n2, 2); - checkGraphOutArcList(adaptor, n3, 1); - checkGraphOutArcList(adaptor, n4, 0); - - checkGraphInArcList(adaptor, n1, 0); - checkGraphInArcList(adaptor, n2, 1); - checkGraphInArcList(adaptor, n3, 2); - checkGraphInArcList(adaptor, n4, 3); - - // Find maximum flow by augmenting along shortest paths - int flow_value = 0; - Adaptor::ResidualCapacity res_cap(adaptor); - while (true) { - - Bfs bfs(adaptor); - bfs.run(n1, n4); - - if (!bfs.reached(n4)) break; - - Path p = bfs.path(n4); - - int min = std::numeric_limits::max(); - for (Path::ArcIt a(p); a != INVALID; ++a) { - if (res_cap[a] < min) min = res_cap[a]; - } - - for (Path::ArcIt a(p); a != INVALID; ++a) { - adaptor.augment(a, min); - } - flow_value += min; - } - - check(flow_value == 18, "Wrong flow with res graph adaptor"); - - // Check forward() and backward() - for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) { - check(adaptor.forward(a) != adaptor.backward(a), - "Wrong forward() or backward()"); - check((adaptor.forward(a) && adaptor.forward(Digraph::Arc(a)) == a) || - (adaptor.backward(a) && adaptor.backward(Digraph::Arc(a)) == a), - "Wrong forward() or backward()"); - } - - // Check the conversion of nodes and arcs - Digraph::Node nd = Adaptor::NodeIt(adaptor); - nd = ++Adaptor::NodeIt(adaptor); - Adaptor::Node na = n1; - na = n2; - Digraph::Arc ad = Adaptor::ArcIt(adaptor); - ad = ++Adaptor::ArcIt(adaptor); -} - -void checkSplitNodes() { - // Check concepts - checkConcept >(); - checkConcept >(); - - // Create a digraph and an adaptor - typedef ListDigraph Digraph; - typedef SplitNodes Adaptor; - - Digraph digraph; - Adaptor adaptor(digraph); - - Digraph::Node n1 = digraph.addNode(); - Digraph::Node n2 = digraph.addNode(); - Digraph::Node n3 = digraph.addNode(); - - Digraph::Arc a1 = digraph.addArc(n1, n2); - Digraph::Arc a2 = digraph.addArc(n1, n3); - Digraph::Arc a3 = digraph.addArc(n2, n3); - ::lemon::ignore_unused_variable_warning(a1,a2,a3); - - checkGraphNodeList(adaptor, 6); - checkGraphArcList(adaptor, 6); - checkGraphConArcList(adaptor, 6); - - checkGraphOutArcList(adaptor, adaptor.inNode(n1), 1); - checkGraphOutArcList(adaptor, adaptor.outNode(n1), 2); - checkGraphOutArcList(adaptor, adaptor.inNode(n2), 1); - checkGraphOutArcList(adaptor, adaptor.outNode(n2), 1); - checkGraphOutArcList(adaptor, adaptor.inNode(n3), 1); - checkGraphOutArcList(adaptor, adaptor.outNode(n3), 0); - - checkGraphInArcList(adaptor, adaptor.inNode(n1), 0); - checkGraphInArcList(adaptor, adaptor.outNode(n1), 1); - checkGraphInArcList(adaptor, adaptor.inNode(n2), 1); - checkGraphInArcList(adaptor, adaptor.outNode(n2), 1); - checkGraphInArcList(adaptor, adaptor.inNode(n3), 2); - checkGraphInArcList(adaptor, adaptor.outNode(n3), 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Check split - for (Adaptor::ArcIt a(adaptor); a != INVALID; ++a) { - if (adaptor.origArc(a)) { - Digraph::Arc oa = a; - check(adaptor.source(a) == adaptor.outNode(digraph.source(oa)), - "Wrong split"); - check(adaptor.target(a) == adaptor.inNode(digraph.target(oa)), - "Wrong split"); - } else { - Digraph::Node on = a; - check(adaptor.source(a) == adaptor.inNode(on), "Wrong split"); - check(adaptor.target(a) == adaptor.outNode(on), "Wrong split"); - } - } - - // Check combined node map - typedef Adaptor::CombinedNodeMap - , Digraph::NodeMap > IntCombinedNodeMap; - typedef Adaptor::CombinedNodeMap - , Digraph::NodeMap > BoolCombinedNodeMap; - checkConcept, - IntCombinedNodeMap>(); -//checkConcept, -// BoolCombinedNodeMap>(); - checkConcept, - BoolCombinedNodeMap>(); - - Digraph::NodeMap in_map(digraph), out_map(digraph); - for (Digraph::NodeIt n(digraph); n != INVALID; ++n) { - in_map[n] = digraph.id(n); - out_map[n] = -digraph.id(n); - } - - Adaptor::CombinedNodeMap, Digraph::NodeMap > - node_map(in_map, out_map); - for (Adaptor::NodeIt n(adaptor); n != INVALID; ++n) { - if (adaptor.inNode(n)) { - check(node_map[n] == in_map[n], "Wrong combined node map"); - } else { - check(node_map[n] == out_map[n], "Wrong combined node map"); - } - } - - // Check combined arc map - typedef Adaptor::CombinedArcMap - , Digraph::NodeMap > IntCombinedArcMap; - typedef Adaptor::CombinedArcMap - , Digraph::NodeMap > BoolCombinedArcMap; - checkConcept, - IntCombinedArcMap>(); -//checkConcept, -// BoolCombinedArcMap>(); - checkConcept, - BoolCombinedArcMap>(); - - Digraph::ArcMap a_map(digraph); - for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { - a_map[a] = digraph.id(a); - } - - Adaptor::CombinedArcMap, Digraph::NodeMap > - arc_map(a_map, out_map); - for (Digraph::ArcIt a(digraph); a != INVALID; ++a) { - check(arc_map[adaptor.arc(a)] == a_map[a], "Wrong combined arc map"); - } - for (Digraph::NodeIt n(digraph); n != INVALID; ++n) { - check(arc_map[adaptor.arc(n)] == out_map[n], "Wrong combined arc map"); - } - - // Check the conversion of nodes - Digraph::Node nd = adaptor.inNode(n1); - check (nd == n1, "Wrong node conversion"); - nd = adaptor.outNode(n2); - check (nd == n2, "Wrong node conversion"); -} - -void checkSubGraph() { - // Check concepts - checkConcept >(); - checkConcept >(); - checkConcept, - SubGraph >(); - checkConcept, - SubGraph >(); - checkConcept, - SubGraph >(); - checkConcept, - SubGraph >(); - - // Create a graph and an adaptor - typedef ListGraph Graph; - typedef Graph::NodeMap NodeFilter; - typedef Graph::EdgeMap EdgeFilter; - typedef SubGraph Adaptor; - - Graph graph; - NodeFilter node_filter(graph); - EdgeFilter edge_filter(graph); - Adaptor adaptor(graph, node_filter, edge_filter); - - // Add nodes and edges to the original graph and the adaptor - Graph::Node n1 = graph.addNode(); - Graph::Node n2 = graph.addNode(); - Adaptor::Node n3 = adaptor.addNode(); - Adaptor::Node n4 = adaptor.addNode(); - - node_filter[n1] = node_filter[n2] = node_filter[n3] = node_filter[n4] = true; - - Graph::Edge e1 = graph.addEdge(n1, n2); - Graph::Edge e2 = graph.addEdge(n1, n3); - Adaptor::Edge e3 = adaptor.addEdge(n2, n3); - Adaptor::Edge e4 = adaptor.addEdge(n3, n4); - - edge_filter[e1] = edge_filter[e2] = edge_filter[e3] = edge_filter[e4] = true; - - checkGraphNodeList(adaptor, 4); - checkGraphArcList(adaptor, 8); - checkGraphEdgeList(adaptor, 4); - checkGraphConArcList(adaptor, 8); - checkGraphConEdgeList(adaptor, 4); - - checkGraphIncEdgeArcLists(adaptor, n1, 2); - checkGraphIncEdgeArcLists(adaptor, n2, 2); - checkGraphIncEdgeArcLists(adaptor, n3, 3); - checkGraphIncEdgeArcLists(adaptor, n4, 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - checkEdgeIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - checkGraphEdgeMap(adaptor); - - // Hide an edge - adaptor.status(e2, false); - adaptor.disable(e3); - if (!adaptor.status(e3)) adaptor.enable(e3); - - checkGraphNodeList(adaptor, 4); - checkGraphArcList(adaptor, 6); - checkGraphEdgeList(adaptor, 3); - checkGraphConArcList(adaptor, 6); - checkGraphConEdgeList(adaptor, 3); - - checkGraphIncEdgeArcLists(adaptor, n1, 1); - checkGraphIncEdgeArcLists(adaptor, n2, 2); - checkGraphIncEdgeArcLists(adaptor, n3, 2); - checkGraphIncEdgeArcLists(adaptor, n4, 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - checkEdgeIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - checkGraphEdgeMap(adaptor); - - // Hide a node - adaptor.status(n1, false); - adaptor.disable(n3); - if (!adaptor.status(n3)) adaptor.enable(n3); - - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 4); - checkGraphEdgeList(adaptor, 2); - checkGraphConArcList(adaptor, 4); - checkGraphConEdgeList(adaptor, 2); - - checkGraphIncEdgeArcLists(adaptor, n2, 1); - checkGraphIncEdgeArcLists(adaptor, n3, 2); - checkGraphIncEdgeArcLists(adaptor, n4, 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - checkEdgeIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - checkGraphEdgeMap(adaptor); - - // Hide all nodes and edges - node_filter[n1] = node_filter[n2] = node_filter[n3] = node_filter[n4] = false; - edge_filter[e1] = edge_filter[e2] = edge_filter[e3] = edge_filter[e4] = false; - - checkGraphNodeList(adaptor, 0); - checkGraphArcList(adaptor, 0); - checkGraphEdgeList(adaptor, 0); - checkGraphConArcList(adaptor, 0); - checkGraphConEdgeList(adaptor, 0); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - checkEdgeIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - checkGraphEdgeMap(adaptor); - - // Check the conversion of nodes and edges - Graph::Node ng = n3; - ng = n4; - Adaptor::Node na = n1; - na = n2; - Graph::Edge eg = e3; - eg = e4; - Adaptor::Edge ea = e1; - ea = e2; -} - -void checkFilterNodes2() { - // Check concepts - checkConcept >(); - checkConcept >(); - checkConcept, - FilterNodes >(); - checkConcept, - FilterNodes >(); - checkConcept, - FilterNodes >(); - checkConcept, - FilterNodes >(); - - // Create a graph and an adaptor - typedef ListGraph Graph; - typedef Graph::NodeMap NodeFilter; - typedef FilterNodes Adaptor; - - // Add nodes and edges to the original graph and the adaptor - Graph graph; - NodeFilter node_filter(graph); - Adaptor adaptor(graph, node_filter); - - Graph::Node n1 = graph.addNode(); - Graph::Node n2 = graph.addNode(); - Adaptor::Node n3 = adaptor.addNode(); - Adaptor::Node n4 = adaptor.addNode(); - - node_filter[n1] = node_filter[n2] = node_filter[n3] = node_filter[n4] = true; - - Graph::Edge e1 = graph.addEdge(n1, n2); - Graph::Edge e2 = graph.addEdge(n1, n3); - Adaptor::Edge e3 = adaptor.addEdge(n2, n3); - Adaptor::Edge e4 = adaptor.addEdge(n3, n4); - - checkGraphNodeList(adaptor, 4); - checkGraphArcList(adaptor, 8); - checkGraphEdgeList(adaptor, 4); - checkGraphConArcList(adaptor, 8); - checkGraphConEdgeList(adaptor, 4); - - checkGraphIncEdgeArcLists(adaptor, n1, 2); - checkGraphIncEdgeArcLists(adaptor, n2, 2); - checkGraphIncEdgeArcLists(adaptor, n3, 3); - checkGraphIncEdgeArcLists(adaptor, n4, 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - checkEdgeIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - checkGraphEdgeMap(adaptor); - - // Hide a node - adaptor.status(n1, false); - adaptor.disable(n3); - if (!adaptor.status(n3)) adaptor.enable(n3); - - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 4); - checkGraphEdgeList(adaptor, 2); - checkGraphConArcList(adaptor, 4); - checkGraphConEdgeList(adaptor, 2); - - checkGraphIncEdgeArcLists(adaptor, n2, 1); - checkGraphIncEdgeArcLists(adaptor, n3, 2); - checkGraphIncEdgeArcLists(adaptor, n4, 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - checkEdgeIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - checkGraphEdgeMap(adaptor); - - // Hide all nodes - node_filter[n1] = node_filter[n2] = node_filter[n3] = node_filter[n4] = false; - - checkGraphNodeList(adaptor, 0); - checkGraphArcList(adaptor, 0); - checkGraphEdgeList(adaptor, 0); - checkGraphConArcList(adaptor, 0); - checkGraphConEdgeList(adaptor, 0); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - checkEdgeIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - checkGraphEdgeMap(adaptor); - - // Check the conversion of nodes and edges - Graph::Node ng = n3; - ng = n4; - Adaptor::Node na = n1; - na = n2; - Graph::Edge eg = e3; - eg = e4; - Adaptor::Edge ea = e1; - ea = e2; -} - -void checkFilterEdges() { - // Check concepts - checkConcept >(); - checkConcept >(); - checkConcept, - FilterEdges >(); - checkConcept, - FilterEdges >(); - checkConcept, - FilterEdges >(); - checkConcept, - FilterEdges >(); - - // Create a graph and an adaptor - typedef ListGraph Graph; - typedef Graph::EdgeMap EdgeFilter; - typedef FilterEdges Adaptor; - - Graph graph; - EdgeFilter edge_filter(graph); - Adaptor adaptor(graph, edge_filter); - - // Add nodes and edges to the original graph and the adaptor - Graph::Node n1 = graph.addNode(); - Graph::Node n2 = graph.addNode(); - Adaptor::Node n3 = adaptor.addNode(); - Adaptor::Node n4 = adaptor.addNode(); - - Graph::Edge e1 = graph.addEdge(n1, n2); - Graph::Edge e2 = graph.addEdge(n1, n3); - Adaptor::Edge e3 = adaptor.addEdge(n2, n3); - Adaptor::Edge e4 = adaptor.addEdge(n3, n4); - - edge_filter[e1] = edge_filter[e2] = edge_filter[e3] = edge_filter[e4] = true; - - checkGraphNodeList(adaptor, 4); - checkGraphArcList(adaptor, 8); - checkGraphEdgeList(adaptor, 4); - checkGraphConArcList(adaptor, 8); - checkGraphConEdgeList(adaptor, 4); - - checkGraphIncEdgeArcLists(adaptor, n1, 2); - checkGraphIncEdgeArcLists(adaptor, n2, 2); - checkGraphIncEdgeArcLists(adaptor, n3, 3); - checkGraphIncEdgeArcLists(adaptor, n4, 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - checkEdgeIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - checkGraphEdgeMap(adaptor); - - // Hide an edge - adaptor.status(e2, false); - adaptor.disable(e3); - if (!adaptor.status(e3)) adaptor.enable(e3); - - checkGraphNodeList(adaptor, 4); - checkGraphArcList(adaptor, 6); - checkGraphEdgeList(adaptor, 3); - checkGraphConArcList(adaptor, 6); - checkGraphConEdgeList(adaptor, 3); - - checkGraphIncEdgeArcLists(adaptor, n1, 1); - checkGraphIncEdgeArcLists(adaptor, n2, 2); - checkGraphIncEdgeArcLists(adaptor, n3, 2); - checkGraphIncEdgeArcLists(adaptor, n4, 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - checkEdgeIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - checkGraphEdgeMap(adaptor); - - // Hide all edges - edge_filter[e1] = edge_filter[e2] = edge_filter[e3] = edge_filter[e4] = false; - - checkGraphNodeList(adaptor, 4); - checkGraphArcList(adaptor, 0); - checkGraphEdgeList(adaptor, 0); - checkGraphConArcList(adaptor, 0); - checkGraphConEdgeList(adaptor, 0); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - checkEdgeIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - checkGraphEdgeMap(adaptor); - - // Check the conversion of nodes and edges - Graph::Node ng = n3; - ng = n4; - Adaptor::Node na = n1; - na = n2; - Graph::Edge eg = e3; - eg = e4; - Adaptor::Edge ea = e1; - ea = e2; -} - -void checkOrienter() { - // Check concepts - checkConcept >(); - checkConcept >(); - checkConcept, - Orienter >(); - checkConcept, - Orienter >(); - checkConcept, - Orienter >(); - checkConcept, - Orienter >(); - - // Create a graph and an adaptor - typedef ListGraph Graph; - typedef ListGraph::EdgeMap DirMap; - typedef Orienter Adaptor; - - Graph graph; - DirMap dir(graph); - Adaptor adaptor(graph, dir); - - // Add nodes and edges to the original graph and the adaptor - Graph::Node n1 = graph.addNode(); - Graph::Node n2 = graph.addNode(); - Adaptor::Node n3 = adaptor.addNode(); - - Graph::Edge e1 = graph.addEdge(n1, n2); - Graph::Edge e2 = graph.addEdge(n1, n3); - Adaptor::Arc e3 = adaptor.addArc(n2, n3); - - dir[e1] = dir[e2] = dir[e3] = true; - - // Check the original graph - checkGraphNodeList(graph, 3); - checkGraphArcList(graph, 6); - checkGraphConArcList(graph, 6); - checkGraphEdgeList(graph, 3); - checkGraphConEdgeList(graph, 3); - - checkGraphIncEdgeArcLists(graph, n1, 2); - checkGraphIncEdgeArcLists(graph, n2, 2); - checkGraphIncEdgeArcLists(graph, n3, 2); - - checkNodeIds(graph); - checkArcIds(graph); - checkEdgeIds(graph); - - checkGraphNodeMap(graph); - checkGraphArcMap(graph); - checkGraphEdgeMap(graph); - - // Check the adaptor - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 3); - checkGraphConArcList(adaptor, 3); - - checkGraphOutArcList(adaptor, n1, 2); - checkGraphOutArcList(adaptor, n2, 1); - checkGraphOutArcList(adaptor, n3, 0); - - checkGraphInArcList(adaptor, n1, 0); - checkGraphInArcList(adaptor, n2, 1); - checkGraphInArcList(adaptor, n3, 2); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Check direction changing - { - dir[e1] = true; - Adaptor::Node u = adaptor.source(e1); - Adaptor::Node v = adaptor.target(e1); - - dir[e1] = false; - check (u == adaptor.target(e1), "Wrong dir"); - check (v == adaptor.source(e1), "Wrong dir"); - - check ((u == n1 && v == n2) || (u == n2 && v == n1), "Wrong dir"); - dir[e1] = n1 == u; - } - - { - dir[e2] = true; - Adaptor::Node u = adaptor.source(e2); - Adaptor::Node v = adaptor.target(e2); - - dir[e2] = false; - check (u == adaptor.target(e2), "Wrong dir"); - check (v == adaptor.source(e2), "Wrong dir"); - - check ((u == n1 && v == n3) || (u == n3 && v == n1), "Wrong dir"); - dir[e2] = n3 == u; - } - - { - dir[e3] = true; - Adaptor::Node u = adaptor.source(e3); - Adaptor::Node v = adaptor.target(e3); - - dir[e3] = false; - check (u == adaptor.target(e3), "Wrong dir"); - check (v == adaptor.source(e3), "Wrong dir"); - - check ((u == n2 && v == n3) || (u == n3 && v == n2), "Wrong dir"); - dir[e3] = n2 == u; - } - - // Check the adaptor again - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 3); - checkGraphConArcList(adaptor, 3); - - checkGraphOutArcList(adaptor, n1, 1); - checkGraphOutArcList(adaptor, n2, 1); - checkGraphOutArcList(adaptor, n3, 1); - - checkGraphInArcList(adaptor, n1, 1); - checkGraphInArcList(adaptor, n2, 1); - checkGraphInArcList(adaptor, n3, 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Check reverseArc() - adaptor.reverseArc(e2); - adaptor.reverseArc(e3); - adaptor.reverseArc(e2); - - checkGraphNodeList(adaptor, 3); - checkGraphArcList(adaptor, 3); - checkGraphConArcList(adaptor, 3); - - checkGraphOutArcList(adaptor, n1, 1); - checkGraphOutArcList(adaptor, n2, 0); - checkGraphOutArcList(adaptor, n3, 2); - - checkGraphInArcList(adaptor, n1, 1); - checkGraphInArcList(adaptor, n2, 2); - checkGraphInArcList(adaptor, n3, 0); - - // Check the conversion of nodes and arcs/edges - Graph::Node ng = n3; - ng = n3; - Adaptor::Node na = n1; - na = n2; - Graph::Edge eg = e3; - eg = e3; - Adaptor::Arc aa = e1; - aa = e2; -} - -void checkCombiningAdaptors() { - // Create a grid graph - GridGraph graph(2,2); - GridGraph::Node n1 = graph(0,0); - GridGraph::Node n2 = graph(0,1); - GridGraph::Node n3 = graph(1,0); - GridGraph::Node n4 = graph(1,1); - - GridGraph::EdgeMap dir_map(graph); - dir_map[graph.right(n1)] = graph.u(graph.right(n1)) != n1; - dir_map[graph.up(n1)] = graph.u(graph.up(n1)) == n1; - dir_map[graph.left(n4)] = graph.u(graph.left(n4)) == n4; - dir_map[graph.down(n4)] = graph.u(graph.down(n4)) == n4; - - // Apply several adaptors on the grid graph - typedef Orienter< const GridGraph, GridGraph::EdgeMap > - OrientedGridGraph; - typedef SplitNodes SplitGridGraph; - typedef Undirector USplitGridGraph; - checkConcept(); - checkConcept(); - - OrientedGridGraph oadaptor = orienter(graph, dir_map); - SplitGridGraph adaptor = splitNodes(oadaptor); - USplitGridGraph uadaptor = undirector(adaptor); - - // Check adaptor - checkGraphNodeList(adaptor, 8); - checkGraphArcList(adaptor, 8); - checkGraphConArcList(adaptor, 8); - - checkGraphOutArcList(adaptor, adaptor.inNode(n1), 1); - checkGraphOutArcList(adaptor, adaptor.outNode(n1), 1); - checkGraphOutArcList(adaptor, adaptor.inNode(n2), 1); - checkGraphOutArcList(adaptor, adaptor.outNode(n2), 0); - checkGraphOutArcList(adaptor, adaptor.inNode(n3), 1); - checkGraphOutArcList(adaptor, adaptor.outNode(n3), 1); - checkGraphOutArcList(adaptor, adaptor.inNode(n4), 1); - checkGraphOutArcList(adaptor, adaptor.outNode(n4), 2); - - checkGraphInArcList(adaptor, adaptor.inNode(n1), 1); - checkGraphInArcList(adaptor, adaptor.outNode(n1), 1); - checkGraphInArcList(adaptor, adaptor.inNode(n2), 2); - checkGraphInArcList(adaptor, adaptor.outNode(n2), 1); - checkGraphInArcList(adaptor, adaptor.inNode(n3), 1); - checkGraphInArcList(adaptor, adaptor.outNode(n3), 1); - checkGraphInArcList(adaptor, adaptor.inNode(n4), 0); - checkGraphInArcList(adaptor, adaptor.outNode(n4), 1); - - checkNodeIds(adaptor); - checkArcIds(adaptor); - - checkGraphNodeMap(adaptor); - checkGraphArcMap(adaptor); - - // Check uadaptor - checkGraphNodeList(uadaptor, 8); - checkGraphEdgeList(uadaptor, 8); - checkGraphArcList(uadaptor, 16); - checkGraphConEdgeList(uadaptor, 8); - checkGraphConArcList(uadaptor, 16); - - checkNodeIds(uadaptor); - checkEdgeIds(uadaptor); - checkArcIds(uadaptor); - - checkGraphNodeMap(uadaptor); - checkGraphEdgeMap(uadaptor); - checkGraphArcMap(uadaptor); - - checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n1), 2); - checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n1), 2); - checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n2), 3); - checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n2), 1); - checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n3), 2); - checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n3), 2); - checkGraphIncEdgeArcLists(uadaptor, adaptor.inNode(n4), 1); - checkGraphIncEdgeArcLists(uadaptor, adaptor.outNode(n4), 3); -} - -int main(int, const char **) { - // Check the digraph adaptors (using ListDigraph) - checkReverseDigraph(); - checkSubDigraph(); - checkFilterNodes1(); - checkFilterArcs(); - checkUndirector(); - checkResidualDigraph(); - checkSplitNodes(); - - // Check the graph adaptors (using ListGraph) - checkSubGraph(); - checkFilterNodes2(); - checkFilterEdges(); - checkOrienter(); - - // Combine adaptors (using GridGraph) - checkCombiningAdaptors(); - - return 0; -} diff --git a/deps/lemon/test/arc_look_up_test.cc b/deps/lemon/test/arc_look_up_test.cc deleted file mode 100644 index 2f4edf52d..000000000 --- a/deps/lemon/test/arc_look_up_test.cc +++ /dev/null @@ -1,84 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include "lemon/list_graph.h" -#include "lemon/lgf_reader.h" - -#include "test_tools.h" - -using namespace lemon; - -const std::string lgf = - "@nodes\n" -"label\n" -"0\n" -"1\n" -"2\n" -"3\n" -"4\n" -"5\n" -"6\n" -"@arcs\n" -"label\n" -"5 6 0\n" -"5 4 1\n" -"4 6 2\n" -"3 4 3\n" -"3 4 4\n" -"3 2 5\n" -"3 5 6\n" -"3 5 7\n" -"3 5 8\n" -"3 5 9\n" -"2 4 10\n" -"2 4 11\n" -"2 4 12\n" -"2 4 13\n" -"1 2 14\n" -"1 2 15\n" -"1 0 16\n" -"1 3 17\n" -"1 3 18\n" -"1 3 19\n" -"1 3 20\n" -"0 2 21\n" -"0 2 22\n" -"0 2 23\n" -"0 2 24\n"; - - -int main() { - ListDigraph graph; - std::istringstream lgfs(lgf); - DigraphReader(graph, lgfs).run(); - - AllArcLookUp lookup(graph); - - int numArcs = countArcs(graph); - - int arcCnt = 0; - for(ListDigraph::NodeIt n1(graph); n1 != INVALID; ++n1) - for(ListDigraph::NodeIt n2(graph); n2 != INVALID; ++n2) - for(ListDigraph::Arc a = lookup(n1, n2); a != INVALID; - a = lookup(n1, n2, a)) - ++arcCnt; - check(arcCnt==numArcs, "Wrong total number of arcs"); - - return 0; -} diff --git a/deps/lemon/test/bellman_ford_test.cc b/deps/lemon/test/bellman_ford_test.cc deleted file mode 100644 index 14faa07c9..000000000 --- a/deps/lemon/test/bellman_ford_test.cc +++ /dev/null @@ -1,289 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "graph_test.h" -#include "test_tools.h" - -using namespace lemon; - -char test_lgf[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "@arcs\n" - " length\n" - "0 1 3\n" - "1 2 -3\n" - "1 2 -5\n" - "1 3 -2\n" - "0 2 -1\n" - "1 2 -4\n" - "0 3 2\n" - "4 2 -5\n" - "2 3 1\n" - "@attributes\n" - "source 0\n" - "target 3\n"; - - -void checkBellmanFordCompile() -{ - typedef int Value; - typedef concepts::Digraph Digraph; - typedef concepts::ReadMap LengthMap; - typedef BellmanFord BF; - typedef Digraph::Node Node; - typedef Digraph::Arc Arc; - - Digraph gr; - Node s, t, n; - Arc e; - Value l; - ::lemon::ignore_unused_variable_warning(l); - int k=3; - bool b; - ::lemon::ignore_unused_variable_warning(b); - BF::DistMap d(gr); - BF::PredMap p(gr); - LengthMap length; - concepts::Path pp; - - { - BF bf_test(gr,length); - const BF& const_bf_test = bf_test; - - bf_test.run(s); - bf_test.run(s,k); - - bf_test.init(); - bf_test.addSource(s); - bf_test.addSource(s, 1); - b = bf_test.processNextRound(); - b = bf_test.processNextWeakRound(); - - bf_test.start(); - bf_test.checkedStart(); - bf_test.limitedStart(k); - - l = const_bf_test.dist(t); - e = const_bf_test.predArc(t); - s = const_bf_test.predNode(t); - b = const_bf_test.reached(t); - d = const_bf_test.distMap(); - p = const_bf_test.predMap(); - pp = const_bf_test.path(t); - pp = const_bf_test.negativeCycle(); - - for (BF::ActiveIt it(const_bf_test); it != INVALID; ++it) {} - } - { - BF::SetPredMap > - ::SetDistMap > - ::SetOperationTraits > - ::Create bf_test(gr,length); - - LengthMap length_map; - concepts::ReadWriteMap pred_map; - concepts::ReadWriteMap dist_map; - - bf_test - .lengthMap(length_map) - .predMap(pred_map) - .distMap(dist_map); - - bf_test.run(s); - bf_test.run(s,k); - - bf_test.init(); - bf_test.addSource(s); - bf_test.addSource(s, 1); - b = bf_test.processNextRound(); - b = bf_test.processNextWeakRound(); - - bf_test.start(); - bf_test.checkedStart(); - bf_test.limitedStart(k); - - l = bf_test.dist(t); - e = bf_test.predArc(t); - s = bf_test.predNode(t); - b = bf_test.reached(t); - pp = bf_test.path(t); - pp = bf_test.negativeCycle(); - } -} - -void checkBellmanFordFunctionCompile() -{ - typedef int Value; - typedef concepts::Digraph Digraph; - typedef Digraph::Arc Arc; - typedef Digraph::Node Node; - typedef concepts::ReadMap LengthMap; - - Digraph g; - bool b; - ::lemon::ignore_unused_variable_warning(b); - - bellmanFord(g,LengthMap()).run(Node()); - b = bellmanFord(g,LengthMap()).run(Node(),Node()); - bellmanFord(g,LengthMap()) - .predMap(concepts::ReadWriteMap()) - .distMap(concepts::ReadWriteMap()) - .run(Node()); - b=bellmanFord(g,LengthMap()) - .predMap(concepts::ReadWriteMap()) - .distMap(concepts::ReadWriteMap()) - .path(concepts::Path()) - .dist(Value()) - .run(Node(),Node()); -} - - -template -void checkBellmanFord() { - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - typedef typename Digraph::template ArcMap LengthMap; - - Digraph gr; - Node s, t; - LengthMap length(gr); - - std::istringstream input(test_lgf); - digraphReader(gr, input). - arcMap("length", length). - node("source", s). - node("target", t). - run(); - - BellmanFord - bf(gr, length); - bf.run(s); - Path p = bf.path(t); - - check(bf.reached(t) && bf.dist(t) == -1, "Bellman-Ford found a wrong path."); - check(p.length() == 3, "path() found a wrong path."); - check(checkPath(gr, p), "path() found a wrong path."); - check(pathSource(gr, p) == s, "path() found a wrong path."); - check(pathTarget(gr, p) == t, "path() found a wrong path."); - - ListPath path; - Value dist = 0; - bool reached = bellmanFord(gr,length).path(path).dist(dist).run(s,t); - - check(reached && dist == -1, "Bellman-Ford found a wrong path."); - check(path.length() == 3, "path() found a wrong path."); - check(checkPath(gr, path), "path() found a wrong path."); - check(pathSource(gr, path) == s, "path() found a wrong path."); - check(pathTarget(gr, path) == t, "path() found a wrong path."); - - for(ArcIt e(gr); e!=INVALID; ++e) { - Node u=gr.source(e); - Node v=gr.target(e); - check(!bf.reached(u) || (bf.dist(v) - bf.dist(u) <= length[e]), - "Wrong output. dist(target)-dist(source)-arc_length=" << - bf.dist(v) - bf.dist(u) - length[e]); - } - - for(NodeIt v(gr); v!=INVALID; ++v) { - if (bf.reached(v)) { - check(v==s || bf.predArc(v)!=INVALID, "Wrong tree."); - if (bf.predArc(v)!=INVALID ) { - Arc e=bf.predArc(v); - Node u=gr.source(e); - check(u==bf.predNode(v),"Wrong tree."); - check(bf.dist(v) - bf.dist(u) == length[e], - "Wrong distance! Difference: " << - bf.dist(v) - bf.dist(u) - length[e]); - } - } - } -} - -void checkBellmanFordNegativeCycle() { - DIGRAPH_TYPEDEFS(SmartDigraph); - - SmartDigraph gr; - IntArcMap length(gr); - - Node n1 = gr.addNode(); - Node n2 = gr.addNode(); - Node n3 = gr.addNode(); - Node n4 = gr.addNode(); - - Arc a1 = gr.addArc(n1, n2); - Arc a2 = gr.addArc(n2, n2); - - length[a1] = 2; - length[a2] = -1; - - { - BellmanFord bf(gr, length); - bf.run(n1); - StaticPath p = bf.negativeCycle(); - check(p.length() == 1 && p.front() == p.back() && p.front() == a2, - "Wrong negative cycle."); - } - - length[a2] = 0; - - { - BellmanFord bf(gr, length); - bf.run(n1); - check(bf.negativeCycle().empty(), - "Negative cycle should not be found."); - } - - length[gr.addArc(n1, n3)] = 5; - length[gr.addArc(n4, n3)] = 1; - length[gr.addArc(n2, n4)] = 2; - length[gr.addArc(n3, n2)] = -4; - - { - BellmanFord bf(gr, length); - bf.init(); - bf.addSource(n1); - for (int i = 0; i < 4; ++i) { - check(bf.negativeCycle().empty(), - "Negative cycle should not be found."); - bf.processNextRound(); - } - StaticPath p = bf.negativeCycle(); - check(p.length() == 3, "Wrong negative cycle."); - check(length[p.nth(0)] + length[p.nth(1)] + length[p.nth(2)] == -1, - "Wrong negative cycle."); - } -} - -int main() { - checkBellmanFord(); - checkBellmanFord(); - checkBellmanFordNegativeCycle(); - return 0; -} diff --git a/deps/lemon/test/bfs_test.cc b/deps/lemon/test/bfs_test.cc deleted file mode 100644 index 976fa88b6..000000000 --- a/deps/lemon/test/bfs_test.cc +++ /dev/null @@ -1,239 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "graph_test.h" -#include "test_tools.h" - -using namespace lemon; - -char test_lgf[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "@arcs\n" - " label\n" - "0 1 0\n" - "1 2 1\n" - "2 3 2\n" - "3 4 3\n" - "0 3 4\n" - "0 3 5\n" - "5 2 6\n" - "@attributes\n" - "source 0\n" - "target 4\n"; - -void checkBfsCompile() -{ - typedef concepts::Digraph Digraph; - typedef Bfs BType; - typedef Digraph::Node Node; - typedef Digraph::Arc Arc; - - Digraph G; - Node s, t, n; - Arc e; - int l, i; - ::lemon::ignore_unused_variable_warning(l,i); - bool b; - BType::DistMap d(G); - BType::PredMap p(G); - Path pp; - concepts::ReadMap nm; - - { - BType bfs_test(G); - const BType& const_bfs_test = bfs_test; - - bfs_test.run(s); - bfs_test.run(s,t); - bfs_test.run(); - - bfs_test.init(); - bfs_test.addSource(s); - n = bfs_test.processNextNode(); - n = bfs_test.processNextNode(t, b); - n = bfs_test.processNextNode(nm, n); - n = const_bfs_test.nextNode(); - b = const_bfs_test.emptyQueue(); - i = const_bfs_test.queueSize(); - - bfs_test.start(); - bfs_test.start(t); - bfs_test.start(nm); - - l = const_bfs_test.dist(t); - e = const_bfs_test.predArc(t); - s = const_bfs_test.predNode(t); - b = const_bfs_test.reached(t); - d = const_bfs_test.distMap(); - p = const_bfs_test.predMap(); - pp = const_bfs_test.path(t); - } - { - BType - ::SetPredMap > - ::SetDistMap > - ::SetReachedMap > - ::SetStandardProcessedMap - ::SetProcessedMap > - ::Create bfs_test(G); - - concepts::ReadWriteMap pred_map; - concepts::ReadWriteMap dist_map; - concepts::ReadWriteMap reached_map; - concepts::WriteMap processed_map; - - bfs_test - .predMap(pred_map) - .distMap(dist_map) - .reachedMap(reached_map) - .processedMap(processed_map); - - bfs_test.run(s); - bfs_test.run(s,t); - bfs_test.run(); - - bfs_test.init(); - bfs_test.addSource(s); - n = bfs_test.processNextNode(); - n = bfs_test.processNextNode(t, b); - n = bfs_test.processNextNode(nm, n); - n = bfs_test.nextNode(); - b = bfs_test.emptyQueue(); - i = bfs_test.queueSize(); - - bfs_test.start(); - bfs_test.start(t); - bfs_test.start(nm); - - l = bfs_test.dist(t); - e = bfs_test.predArc(t); - s = bfs_test.predNode(t); - b = bfs_test.reached(t); - pp = bfs_test.path(t); - } -} - -void checkBfsFunctionCompile() -{ - typedef int VType; - typedef concepts::Digraph Digraph; - typedef Digraph::Arc Arc; - typedef Digraph::Node Node; - - Digraph g; - bool b; - ::lemon::ignore_unused_variable_warning(b); - - bfs(g).run(Node()); - b=bfs(g).run(Node(),Node()); - bfs(g).run(); - bfs(g) - .predMap(concepts::ReadWriteMap()) - .distMap(concepts::ReadWriteMap()) - .reachedMap(concepts::ReadWriteMap()) - .processedMap(concepts::WriteMap()) - .run(Node()); - b=bfs(g) - .predMap(concepts::ReadWriteMap()) - .distMap(concepts::ReadWriteMap()) - .reachedMap(concepts::ReadWriteMap()) - .processedMap(concepts::WriteMap()) - .path(concepts::Path()) - .dist(VType()) - .run(Node(),Node()); - bfs(g) - .predMap(concepts::ReadWriteMap()) - .distMap(concepts::ReadWriteMap()) - .reachedMap(concepts::ReadWriteMap()) - .processedMap(concepts::WriteMap()) - .run(); -} - -template -void checkBfs() { - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - Digraph G; - Node s, t; - - std::istringstream input(test_lgf); - digraphReader(G, input). - node("source", s). - node("target", t). - run(); - - Bfs bfs_test(G); - bfs_test.run(s); - - check(bfs_test.dist(t)==2,"Bfs found a wrong path."); - - Path p = bfs_test.path(t); - check(p.length()==2,"path() found a wrong path."); - check(checkPath(G, p),"path() found a wrong path."); - check(pathSource(G, p) == s,"path() found a wrong path."); - check(pathTarget(G, p) == t,"path() found a wrong path."); - - - for(ArcIt a(G); a!=INVALID; ++a) { - Node u=G.source(a); - Node v=G.target(a); - check( !bfs_test.reached(u) || - (bfs_test.dist(v) <= bfs_test.dist(u)+1), - "Wrong output. " << G.id(u) << "->" << G.id(v)); - } - - for(NodeIt v(G); v!=INVALID; ++v) { - if (bfs_test.reached(v)) { - check(v==s || bfs_test.predArc(v)!=INVALID, "Wrong tree."); - if (bfs_test.predArc(v)!=INVALID ) { - Arc a=bfs_test.predArc(v); - Node u=G.source(a); - check(u==bfs_test.predNode(v),"Wrong tree."); - check(bfs_test.dist(v) - bfs_test.dist(u) == 1, - "Wrong distance. Difference: " - << std::abs(bfs_test.dist(v) - bfs_test.dist(u) - 1)); - } - } - } - - { - NullMap myPredMap; - bfs(G).predMap(myPredMap).run(s); - } -} - -int main() -{ - checkBfs(); - checkBfs(); - return 0; -} diff --git a/deps/lemon/test/bpgraph_test.cc b/deps/lemon/test/bpgraph_test.cc deleted file mode 100644 index 45fc5b855..000000000 --- a/deps/lemon/test/bpgraph_test.cc +++ /dev/null @@ -1,456 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include - -#include "test_tools.h" -#include "graph_test.h" - -using namespace lemon; -using namespace lemon::concepts; - -template -void checkBpGraphBuild() { - TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); - - BpGraph G; - checkGraphNodeList(G, 0); - checkGraphRedNodeList(G, 0); - checkGraphBlueNodeList(G, 0); - checkGraphEdgeList(G, 0); - checkGraphArcList(G, 0); - - G.reserveNode(3); - G.reserveEdge(3); - - RedNode - rn1 = G.addRedNode(); - checkGraphNodeList(G, 1); - checkGraphRedNodeList(G, 1); - checkGraphBlueNodeList(G, 0); - checkGraphEdgeList(G, 0); - checkGraphArcList(G, 0); - - BlueNode - bn1 = G.addBlueNode(), - bn2 = G.addBlueNode(); - checkGraphNodeList(G, 3); - checkGraphRedNodeList(G, 1); - checkGraphBlueNodeList(G, 2); - checkGraphEdgeList(G, 0); - checkGraphArcList(G, 0); - - Edge e1 = G.addEdge(rn1, bn2); - check(G.redNode(e1) == rn1 && G.blueNode(e1) == bn2, "Wrong edge"); - check(G.u(e1) == rn1 && G.v(e1) == bn2, "Wrong edge"); - - checkGraphNodeList(G, 3); - checkGraphRedNodeList(G, 1); - checkGraphBlueNodeList(G, 2); - checkGraphEdgeList(G, 1); - checkGraphArcList(G, 2); - - checkGraphIncEdgeArcLists(G, rn1, 1); - checkGraphIncEdgeArcLists(G, bn1, 0); - checkGraphIncEdgeArcLists(G, bn2, 1); - - checkGraphConEdgeList(G, 1); - checkGraphConArcList(G, 2); - - Edge - e2 = G.addEdge(bn1, rn1), - e3 = G.addEdge(rn1, bn2); - ::lemon::ignore_unused_variable_warning(e2,e3); - - checkGraphNodeList(G, 3); - checkGraphRedNodeList(G, 1); - checkGraphBlueNodeList(G, 2); - checkGraphEdgeList(G, 3); - checkGraphArcList(G, 6); - - checkGraphIncEdgeArcLists(G, rn1, 3); - checkGraphIncEdgeArcLists(G, bn1, 1); - checkGraphIncEdgeArcLists(G, bn2, 2); - - checkGraphConEdgeList(G, 3); - checkGraphConArcList(G, 6); - - checkArcDirections(G); - - checkNodeIds(G); - checkRedNodeIds(G); - checkBlueNodeIds(G); - checkArcIds(G); - checkEdgeIds(G); - - checkGraphNodeMap(G); - checkGraphRedNodeMap(G); - checkGraphBlueNodeMap(G); - checkGraphArcMap(G); - checkGraphEdgeMap(G); -} - -template -void checkBpGraphErase() { - TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); - - BpGraph G; - RedNode - n1 = G.addRedNode(), n4 = G.addRedNode(); - BlueNode - n2 = G.addBlueNode(), n3 = G.addBlueNode(); - Edge - e1 = G.addEdge(n1, n2), e2 = G.addEdge(n1, n3), - e3 = G.addEdge(n4, n2), e4 = G.addEdge(n4, n3); - ::lemon::ignore_unused_variable_warning(e1,e3,e4); - - // Check edge deletion - G.erase(e2); - - checkGraphNodeList(G, 4); - checkGraphRedNodeList(G, 2); - checkGraphBlueNodeList(G, 2); - checkGraphEdgeList(G, 3); - checkGraphArcList(G, 6); - - checkGraphIncEdgeArcLists(G, n1, 1); - checkGraphIncEdgeArcLists(G, n2, 2); - checkGraphIncEdgeArcLists(G, n3, 1); - checkGraphIncEdgeArcLists(G, n4, 2); - - checkGraphConEdgeList(G, 3); - checkGraphConArcList(G, 6); - - // Check node deletion - G.erase(n3); - - checkGraphNodeList(G, 3); - checkGraphRedNodeList(G, 2); - checkGraphBlueNodeList(G, 1); - checkGraphEdgeList(G, 2); - checkGraphArcList(G, 4); - - checkGraphIncEdgeArcLists(G, n1, 1); - checkGraphIncEdgeArcLists(G, n2, 2); - checkGraphIncEdgeArcLists(G, n4, 1); - - checkGraphConEdgeList(G, 2); - checkGraphConArcList(G, 4); - -} - -template -void checkBpGraphAlter() { - TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); - - BpGraph G; - RedNode - n1 = G.addRedNode(), n4 = G.addRedNode(); - BlueNode - n2 = G.addBlueNode(), n3 = G.addBlueNode(); - Edge - e1 = G.addEdge(n1, n2), e2 = G.addEdge(n1, n3), - e3 = G.addEdge(n4, n2), e4 = G.addEdge(n4, n3); - ::lemon::ignore_unused_variable_warning(e1,e3,e4); - - G.changeRed(e2, n4); - check(G.redNode(e2) == n4, "Wrong red node"); - check(G.blueNode(e2) == n3, "Wrong blue node"); - - checkGraphNodeList(G, 4); - checkGraphRedNodeList(G, 2); - checkGraphBlueNodeList(G, 2); - checkGraphEdgeList(G, 4); - checkGraphArcList(G, 8); - - checkGraphIncEdgeArcLists(G, n1, 1); - checkGraphIncEdgeArcLists(G, n2, 2); - checkGraphIncEdgeArcLists(G, n3, 2); - checkGraphIncEdgeArcLists(G, n4, 3); - - checkGraphConEdgeList(G, 4); - checkGraphConArcList(G, 8); - - G.changeBlue(e2, n2); - check(G.redNode(e2) == n4, "Wrong red node"); - check(G.blueNode(e2) == n2, "Wrong blue node"); - - checkGraphNodeList(G, 4); - checkGraphRedNodeList(G, 2); - checkGraphBlueNodeList(G, 2); - checkGraphEdgeList(G, 4); - checkGraphArcList(G, 8); - - checkGraphIncEdgeArcLists(G, n1, 1); - checkGraphIncEdgeArcLists(G, n2, 3); - checkGraphIncEdgeArcLists(G, n3, 1); - checkGraphIncEdgeArcLists(G, n4, 3); - - checkGraphConEdgeList(G, 4); - checkGraphConArcList(G, 8); -} - - -template -void checkBpGraphSnapshot() { - TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); - - BpGraph G; - RedNode - n1 = G.addRedNode(); - BlueNode - n2 = G.addBlueNode(), - n3 = G.addBlueNode(); - Edge - e1 = G.addEdge(n1, n2), - e2 = G.addEdge(n1, n3); - ::lemon::ignore_unused_variable_warning(e1,e2); - - checkGraphNodeList(G, 3); - checkGraphRedNodeList(G, 1); - checkGraphBlueNodeList(G, 2); - checkGraphEdgeList(G, 2); - checkGraphArcList(G, 4); - - typename BpGraph::Snapshot snapshot(G); - - RedNode n4 = G.addRedNode(); - G.addEdge(n4, n2); - G.addEdge(n4, n3); - - checkGraphNodeList(G, 4); - checkGraphRedNodeList(G, 2); - checkGraphBlueNodeList(G, 2); - checkGraphEdgeList(G, 4); - checkGraphArcList(G, 8); - - snapshot.restore(); - - checkGraphNodeList(G, 3); - checkGraphRedNodeList(G, 1); - checkGraphBlueNodeList(G, 2); - checkGraphEdgeList(G, 2); - checkGraphArcList(G, 4); - - checkGraphIncEdgeArcLists(G, n1, 2); - checkGraphIncEdgeArcLists(G, n2, 1); - checkGraphIncEdgeArcLists(G, n3, 1); - - checkGraphConEdgeList(G, 2); - checkGraphConArcList(G, 4); - - checkNodeIds(G); - checkRedNodeIds(G); - checkBlueNodeIds(G); - checkArcIds(G); - checkEdgeIds(G); - - checkGraphNodeMap(G); - checkGraphRedNodeMap(G); - checkGraphBlueNodeMap(G); - checkGraphArcMap(G); - checkGraphEdgeMap(G); - - G.addRedNode(); - snapshot.save(G); - - G.addEdge(G.addRedNode(), G.addBlueNode()); - - snapshot.restore(); - snapshot.save(G); - - checkGraphNodeList(G, 4); - checkGraphRedNodeList(G, 2); - checkGraphBlueNodeList(G, 2); - checkGraphEdgeList(G, 2); - checkGraphArcList(G, 4); - - G.addEdge(G.addRedNode(), G.addBlueNode()); - - snapshot.restore(); - - checkGraphNodeList(G, 4); - checkGraphRedNodeList(G, 2); - checkGraphBlueNodeList(G, 2); - checkGraphEdgeList(G, 2); - checkGraphArcList(G, 4); -} - -template -void checkBpGraphValidity() { - TEMPLATE_BPGRAPH_TYPEDEFS(BpGraph); - BpGraph g; - - RedNode - n1 = g.addRedNode(); - BlueNode - n2 = g.addBlueNode(), - n3 = g.addBlueNode(); - - Edge - e1 = g.addEdge(n1, n2), - e2 = g.addEdge(n1, n3); - ::lemon::ignore_unused_variable_warning(e2); - - check(g.valid(n1), "Wrong validity check"); - check(g.valid(e1), "Wrong validity check"); - check(g.valid(g.direct(e1, true)), "Wrong validity check"); - - check(!g.valid(g.nodeFromId(-1)), "Wrong validity check"); - check(!g.valid(g.edgeFromId(-1)), "Wrong validity check"); - check(!g.valid(g.arcFromId(-1)), "Wrong validity check"); -} - -void checkConcepts() { - { // Checking graph components - checkConcept(); - - checkConcept, - IDableBpGraphComponent<> >(); - - checkConcept, - IterableBpGraphComponent<> >(); - - checkConcept, - AlterableBpGraphComponent<> >(); - - checkConcept, - MappableBpGraphComponent<> >(); - - checkConcept, - ExtendableBpGraphComponent<> >(); - - checkConcept, - ErasableBpGraphComponent<> >(); - - checkConcept, - ClearableBpGraphComponent<> >(); - - } - { // Checking skeleton graph - checkConcept(); - } - { // Checking SmartBpGraph - checkConcept(); - checkConcept, SmartBpGraph>(); - checkConcept, SmartBpGraph>(); - checkConcept, SmartBpGraph>(); - } -} - -void checkFullBpGraph(int redNum, int blueNum) { - typedef FullBpGraph BpGraph; - BPGRAPH_TYPEDEFS(BpGraph); - - BpGraph G(redNum, blueNum); - checkGraphNodeList(G, redNum + blueNum); - checkGraphRedNodeList(G, redNum); - checkGraphBlueNodeList(G, blueNum); - checkGraphEdgeList(G, redNum * blueNum); - checkGraphArcList(G, 2 * redNum * blueNum); - - G.resize(redNum, blueNum); - checkGraphNodeList(G, redNum + blueNum); - checkGraphRedNodeList(G, redNum); - checkGraphBlueNodeList(G, blueNum); - checkGraphEdgeList(G, redNum * blueNum); - checkGraphArcList(G, 2 * redNum * blueNum); - - for (RedNodeIt n(G); n != INVALID; ++n) { - checkGraphOutArcList(G, n, blueNum); - checkGraphInArcList(G, n, blueNum); - checkGraphIncEdgeList(G, n, blueNum); - } - - for (BlueNodeIt n(G); n != INVALID; ++n) { - checkGraphOutArcList(G, n, redNum); - checkGraphInArcList(G, n, redNum); - checkGraphIncEdgeList(G, n, redNum); - } - - checkGraphConArcList(G, 2 * redNum * blueNum); - checkGraphConEdgeList(G, redNum * blueNum); - - checkArcDirections(G); - - checkNodeIds(G); - checkRedNodeIds(G); - checkBlueNodeIds(G); - checkArcIds(G); - checkEdgeIds(G); - - checkGraphNodeMap(G); - checkGraphRedNodeMap(G); - checkGraphBlueNodeMap(G); - checkGraphArcMap(G); - checkGraphEdgeMap(G); - - for (int i = 0; i < G.redNum(); ++i) { - check(G.red(G.redNode(i)), "Wrong node"); - check(G.index(G.redNode(i)) == i, "Wrong index"); - } - - for (int i = 0; i < G.blueNum(); ++i) { - check(G.blue(G.blueNode(i)), "Wrong node"); - check(G.index(G.blueNode(i)) == i, "Wrong index"); - } - - for (NodeIt u(G); u != INVALID; ++u) { - for (NodeIt v(G); v != INVALID; ++v) { - Edge e = G.edge(u, v); - Arc a = G.arc(u, v); - if (G.red(u) == G.red(v)) { - check(e == INVALID, "Wrong edge lookup"); - check(a == INVALID, "Wrong arc lookup"); - } else { - check((G.u(e) == u && G.v(e) == v) || - (G.u(e) == v && G.v(e) == u), "Wrong edge lookup"); - check(G.source(a) == u && G.target(a) == v, "Wrong arc lookup"); - } - } - } - -} - -void checkGraphs() { - { // Checking ListGraph - checkBpGraphBuild(); - checkBpGraphErase(); - checkBpGraphAlter(); - checkBpGraphSnapshot(); - checkBpGraphValidity(); - } - { // Checking SmartGraph - checkBpGraphBuild(); - checkBpGraphSnapshot(); - checkBpGraphValidity(); - } - { // Checking FullBpGraph - checkFullBpGraph(6, 8); - checkFullBpGraph(7, 4); - } -} - -int main() { - checkConcepts(); - checkGraphs(); - return 0; -} diff --git a/deps/lemon/test/circulation_test.cc b/deps/lemon/test/circulation_test.cc deleted file mode 100644 index 3b3a4a972..000000000 --- a/deps/lemon/test/circulation_test.cc +++ /dev/null @@ -1,169 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -#include "test_tools.h" -#include -#include -#include -#include -#include - -using namespace lemon; - -char test_lgf[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "@arcs\n" - " lcap ucap\n" - "0 1 2 10\n" - "0 2 2 6\n" - "1 3 4 7\n" - "1 4 0 5\n" - "2 4 1 3\n" - "3 5 3 8\n" - "4 5 3 7\n" - "@attributes\n" - "source 0\n" - "sink 5\n"; - -void checkCirculationCompile() -{ - typedef int VType; - typedef concepts::Digraph Digraph; - - typedef Digraph::Node Node; - typedef Digraph::Arc Arc; - typedef concepts::ReadMap CapMap; - typedef concepts::ReadMap SupplyMap; - typedef concepts::ReadWriteMap FlowMap; - typedef concepts::WriteMap BarrierMap; - - typedef Elevator Elev; - typedef LinkedElevator LinkedElev; - - Digraph g; - Node n; - Arc a; - CapMap lcap, ucap; - SupplyMap supply; - FlowMap flow; - BarrierMap bar; - VType v; - bool b; - ::lemon::ignore_unused_variable_warning(v,b); - - typedef Circulation - ::SetFlowMap - ::SetElevator - ::SetStandardElevator - ::Create CirculationType; - CirculationType circ_test(g, lcap, ucap, supply); - const CirculationType& const_circ_test = circ_test; - - circ_test - .lowerMap(lcap) - .upperMap(ucap) - .supplyMap(supply) - .flowMap(flow); - - const CirculationType::Elevator& elev = const_circ_test.elevator(); - circ_test.elevator(const_cast(elev)); - CirculationType::Tolerance tol = const_circ_test.tolerance(); - circ_test.tolerance(tol); - - circ_test.init(); - circ_test.greedyInit(); - circ_test.start(); - circ_test.run(); - - v = const_circ_test.flow(a); - const FlowMap& fm = const_circ_test.flowMap(); - b = const_circ_test.barrier(n); - const_circ_test.barrierMap(bar); - - ::lemon::ignore_unused_variable_warning(fm); -} - -template -void checkCirculation(const G& g, const LM& lm, const UM& um, - const DM& dm, bool find) -{ - Circulation circ(g, lm, um, dm); - bool ret = circ.run(); - if (find) { - check(ret, "A feasible solution should have been found."); - check(circ.checkFlow(), "The found flow is corrupt."); - check(!circ.checkBarrier(), "A barrier should not have been found."); - } else { - check(!ret, "A feasible solution should not have been found."); - check(circ.checkBarrier(), "The found barrier is corrupt."); - } -} - -int main (int, char*[]) -{ - typedef ListDigraph Digraph; - DIGRAPH_TYPEDEFS(Digraph); - - Digraph g; - IntArcMap lo(g), up(g); - IntNodeMap delta(g, 0); - Node s, t; - - std::istringstream input(test_lgf); - DigraphReader(g,input). - arcMap("lcap", lo). - arcMap("ucap", up). - node("source",s). - node("sink",t). - run(); - - delta[s] = 7; delta[t] = -7; - checkCirculation(g, lo, up, delta, true); - - delta[s] = 13; delta[t] = -13; - checkCirculation(g, lo, up, delta, true); - - delta[s] = 6; delta[t] = -6; - checkCirculation(g, lo, up, delta, false); - - delta[s] = 14; delta[t] = -14; - checkCirculation(g, lo, up, delta, false); - - delta[s] = 7; delta[t] = -13; - checkCirculation(g, lo, up, delta, true); - - delta[s] = 5; delta[t] = -15; - checkCirculation(g, lo, up, delta, true); - - delta[s] = 10; delta[t] = -11; - checkCirculation(g, lo, up, delta, true); - - delta[s] = 11; delta[t] = -10; - checkCirculation(g, lo, up, delta, false); - - return 0; -} diff --git a/deps/lemon/test/connectivity_test.cc b/deps/lemon/test/connectivity_test.cc deleted file mode 100644 index 4ab343ee0..000000000 --- a/deps/lemon/test/connectivity_test.cc +++ /dev/null @@ -1,316 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include - -#include "test_tools.h" - -using namespace lemon; - - -int main() -{ - typedef ListDigraph Digraph; - typedef Undirector Graph; - - { - Digraph d; - Digraph::NodeMap order(d); - Graph g(d); - - check(stronglyConnected(d), "The empty digraph is strongly connected"); - check(countStronglyConnectedComponents(d) == 0, - "The empty digraph has 0 strongly connected component"); - check(connected(g), "The empty graph is connected"); - check(countConnectedComponents(g) == 0, - "The empty graph has 0 connected component"); - - check(biNodeConnected(g), "The empty graph is bi-node-connected"); - check(countBiNodeConnectedComponents(g) == 0, - "The empty graph has 0 bi-node-connected component"); - check(biEdgeConnected(g), "The empty graph is bi-edge-connected"); - check(countBiEdgeConnectedComponents(g) == 0, - "The empty graph has 0 bi-edge-connected component"); - - check(dag(d), "The empty digraph is DAG."); - check(checkedTopologicalSort(d, order), "The empty digraph is DAG."); - check(loopFree(d), "The empty digraph is loop-free."); - check(parallelFree(d), "The empty digraph is parallel-free."); - check(simpleGraph(d), "The empty digraph is simple."); - - check(acyclic(g), "The empty graph is acyclic."); - check(tree(g), "The empty graph is tree."); - check(bipartite(g), "The empty graph is bipartite."); - check(loopFree(g), "The empty graph is loop-free."); - check(parallelFree(g), "The empty graph is parallel-free."); - check(simpleGraph(g), "The empty graph is simple."); - } - - { - Digraph d; - Digraph::NodeMap order(d); - Graph g(d); - Digraph::Node n = d.addNode(); - ::lemon::ignore_unused_variable_warning(n); - - check(stronglyConnected(d), "This digraph is strongly connected"); - check(countStronglyConnectedComponents(d) == 1, - "This digraph has 1 strongly connected component"); - check(connected(g), "This graph is connected"); - check(countConnectedComponents(g) == 1, - "This graph has 1 connected component"); - - check(biNodeConnected(g), "This graph is bi-node-connected"); - check(countBiNodeConnectedComponents(g) == 0, - "This graph has 0 bi-node-connected component"); - check(biEdgeConnected(g), "This graph is bi-edge-connected"); - check(countBiEdgeConnectedComponents(g) == 1, - "This graph has 1 bi-edge-connected component"); - - check(dag(d), "This digraph is DAG."); - check(checkedTopologicalSort(d, order), "This digraph is DAG."); - check(loopFree(d), "This digraph is loop-free."); - check(parallelFree(d), "This digraph is parallel-free."); - check(simpleGraph(d), "This digraph is simple."); - - check(acyclic(g), "This graph is acyclic."); - check(tree(g), "This graph is tree."); - check(bipartite(g), "This graph is bipartite."); - check(loopFree(g), "This graph is loop-free."); - check(parallelFree(g), "This graph is parallel-free."); - check(simpleGraph(g), "This graph is simple."); - } - - { - ListGraph g; - ListGraph::NodeMap map(g); - - ListGraph::Node n1 = g.addNode(); - ListGraph::Node n2 = g.addNode(); - - ListGraph::Edge e1 = g.addEdge(n1, n2); - ::lemon::ignore_unused_variable_warning(e1); - check(biNodeConnected(g), "Graph is bi-node-connected"); - - ListGraph::Node n3 = g.addNode(); - ::lemon::ignore_unused_variable_warning(n3); - check(!biNodeConnected(g), "Graph is not bi-node-connected"); - } - - - { - Digraph d; - Digraph::NodeMap order(d); - Graph g(d); - - Digraph::Node n1 = d.addNode(); - Digraph::Node n2 = d.addNode(); - Digraph::Node n3 = d.addNode(); - Digraph::Node n4 = d.addNode(); - Digraph::Node n5 = d.addNode(); - Digraph::Node n6 = d.addNode(); - - d.addArc(n1, n3); - d.addArc(n3, n2); - d.addArc(n2, n1); - d.addArc(n4, n2); - d.addArc(n4, n3); - d.addArc(n5, n6); - d.addArc(n6, n5); - - check(!stronglyConnected(d), "This digraph is not strongly connected"); - check(countStronglyConnectedComponents(d) == 3, - "This digraph has 3 strongly connected components"); - check(!connected(g), "This graph is not connected"); - check(countConnectedComponents(g) == 2, - "This graph has 2 connected components"); - - check(!dag(d), "This digraph is not DAG."); - check(!checkedTopologicalSort(d, order), "This digraph is not DAG."); - check(loopFree(d), "This digraph is loop-free."); - check(parallelFree(d), "This digraph is parallel-free."); - check(simpleGraph(d), "This digraph is simple."); - - check(!acyclic(g), "This graph is not acyclic."); - check(!tree(g), "This graph is not tree."); - check(!bipartite(g), "This graph is not bipartite."); - check(loopFree(g), "This graph is loop-free."); - check(!parallelFree(g), "This graph is not parallel-free."); - check(!simpleGraph(g), "This graph is not simple."); - - d.addArc(n3, n3); - - check(!loopFree(d), "This digraph is not loop-free."); - check(!loopFree(g), "This graph is not loop-free."); - check(!simpleGraph(d), "This digraph is not simple."); - - d.addArc(n3, n2); - - check(!parallelFree(d), "This digraph is not parallel-free."); - } - - { - Digraph d; - Digraph::ArcMap cutarcs(d, false); - Graph g(d); - - Digraph::Node n1 = d.addNode(); - Digraph::Node n2 = d.addNode(); - Digraph::Node n3 = d.addNode(); - Digraph::Node n4 = d.addNode(); - Digraph::Node n5 = d.addNode(); - Digraph::Node n6 = d.addNode(); - Digraph::Node n7 = d.addNode(); - Digraph::Node n8 = d.addNode(); - - d.addArc(n1, n2); - d.addArc(n5, n1); - d.addArc(n2, n8); - d.addArc(n8, n5); - d.addArc(n6, n4); - d.addArc(n4, n6); - d.addArc(n2, n5); - d.addArc(n1, n8); - d.addArc(n6, n7); - d.addArc(n7, n6); - - check(!stronglyConnected(d), "This digraph is not strongly connected"); - check(countStronglyConnectedComponents(d) == 3, - "This digraph has 3 strongly connected components"); - Digraph::NodeMap scomp1(d); - check(stronglyConnectedComponents(d, scomp1) == 3, - "This digraph has 3 strongly connected components"); - check(scomp1[n1] != scomp1[n3] && scomp1[n1] != scomp1[n4] && - scomp1[n3] != scomp1[n4], "Wrong stronglyConnectedComponents()"); - check(scomp1[n1] == scomp1[n2] && scomp1[n1] == scomp1[n5] && - scomp1[n1] == scomp1[n8], "Wrong stronglyConnectedComponents()"); - check(scomp1[n4] == scomp1[n6] && scomp1[n4] == scomp1[n7], - "Wrong stronglyConnectedComponents()"); - Digraph::ArcMap scut1(d, false); - check(stronglyConnectedCutArcs(d, scut1) == 0, - "This digraph has 0 strongly connected cut arc."); - for (Digraph::ArcIt a(d); a != INVALID; ++a) { - check(!scut1[a], "Wrong stronglyConnectedCutArcs()"); - } - - check(!connected(g), "This graph is not connected"); - check(countConnectedComponents(g) == 3, - "This graph has 3 connected components"); - Graph::NodeMap comp(g); - check(connectedComponents(g, comp) == 3, - "This graph has 3 connected components"); - check(comp[n1] != comp[n3] && comp[n1] != comp[n4] && - comp[n3] != comp[n4], "Wrong connectedComponents()"); - check(comp[n1] == comp[n2] && comp[n1] == comp[n5] && - comp[n1] == comp[n8], "Wrong connectedComponents()"); - check(comp[n4] == comp[n6] && comp[n4] == comp[n7], - "Wrong connectedComponents()"); - - cutarcs[d.addArc(n3, n1)] = true; - cutarcs[d.addArc(n3, n5)] = true; - cutarcs[d.addArc(n3, n8)] = true; - cutarcs[d.addArc(n8, n6)] = true; - cutarcs[d.addArc(n8, n7)] = true; - - check(!stronglyConnected(d), "This digraph is not strongly connected"); - check(countStronglyConnectedComponents(d) == 3, - "This digraph has 3 strongly connected components"); - Digraph::NodeMap scomp2(d); - check(stronglyConnectedComponents(d, scomp2) == 3, - "This digraph has 3 strongly connected components"); - check(scomp2[n3] == 0, "Wrong stronglyConnectedComponents()"); - check(scomp2[n1] == 1 && scomp2[n2] == 1 && scomp2[n5] == 1 && - scomp2[n8] == 1, "Wrong stronglyConnectedComponents()"); - check(scomp2[n4] == 2 && scomp2[n6] == 2 && scomp2[n7] == 2, - "Wrong stronglyConnectedComponents()"); - Digraph::ArcMap scut2(d, false); - check(stronglyConnectedCutArcs(d, scut2) == 5, - "This digraph has 5 strongly connected cut arcs."); - for (Digraph::ArcIt a(d); a != INVALID; ++a) { - check(scut2[a] == cutarcs[a], "Wrong stronglyConnectedCutArcs()"); - } - } - - { - // DAG example for topological sort from the book New Algorithms - // (T. H. Cormen, C. E. Leiserson, R. L. Rivest, C. Stein) - Digraph d; - Digraph::NodeMap order(d); - - Digraph::Node belt = d.addNode(); - Digraph::Node trousers = d.addNode(); - Digraph::Node necktie = d.addNode(); - Digraph::Node coat = d.addNode(); - Digraph::Node socks = d.addNode(); - Digraph::Node shirt = d.addNode(); - Digraph::Node shoe = d.addNode(); - Digraph::Node watch = d.addNode(); - Digraph::Node pants = d.addNode(); - ::lemon::ignore_unused_variable_warning(watch); - - d.addArc(socks, shoe); - d.addArc(pants, shoe); - d.addArc(pants, trousers); - d.addArc(trousers, shoe); - d.addArc(trousers, belt); - d.addArc(belt, coat); - d.addArc(shirt, belt); - d.addArc(shirt, necktie); - d.addArc(necktie, coat); - - check(dag(d), "This digraph is DAG."); - topologicalSort(d, order); - for (Digraph::ArcIt a(d); a != INVALID; ++a) { - check(order[d.source(a)] < order[d.target(a)], - "Wrong topologicalSort()"); - } - } - - { - ListGraph g; - ListGraph::NodeMap map(g); - - ListGraph::Node n1 = g.addNode(); - ListGraph::Node n2 = g.addNode(); - ListGraph::Node n3 = g.addNode(); - ListGraph::Node n4 = g.addNode(); - ListGraph::Node n5 = g.addNode(); - ListGraph::Node n6 = g.addNode(); - ListGraph::Node n7 = g.addNode(); - - g.addEdge(n1, n3); - g.addEdge(n1, n4); - g.addEdge(n2, n5); - g.addEdge(n3, n6); - g.addEdge(n4, n6); - g.addEdge(n4, n7); - g.addEdge(n5, n7); - - check(bipartite(g), "This graph is bipartite"); - check(bipartitePartitions(g, map), "This graph is bipartite"); - - check(map[n1] == map[n2] && map[n1] == map[n6] && map[n1] == map[n7], - "Wrong bipartitePartitions()"); - check(map[n3] == map[n4] && map[n3] == map[n5], - "Wrong bipartitePartitions()"); - } - - return 0; -} diff --git a/deps/lemon/test/counter_test.cc b/deps/lemon/test/counter_test.cc deleted file mode 100644 index df31dd4d3..000000000 --- a/deps/lemon/test/counter_test.cc +++ /dev/null @@ -1,118 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include - -#include "test/test_tools.h" - -using namespace lemon; - -template -void bubbleSort(std::vector& v) { - std::stringstream s1, s2, s3; - { - Counter op("Bubble Sort - Operations: ", s1); - Counter::SubCounter as(op, "Assignments: ", s2); - Counter::SubCounter co(op, "Comparisons: ", s3); - for (int i = v.size()-1; i > 0; --i) { - for (int j = 0; j < i; ++j) { - if (v[j] > v[j+1]) { - T tmp = v[j]; - v[j] = v[j+1]; - v[j+1] = tmp; - as += 3; - } - ++co; - } - } - } - check(s1.str() == "Bubble Sort - Operations: 102\n", "Wrong counter"); - check(s2.str() == "Assignments: 57\n", "Wrong subcounter"); - check(s3.str() == "Comparisons: 45\n", "Wrong subcounter"); -} - -template -void insertionSort(std::vector& v) { - std::stringstream s1, s2, s3; - { - Counter op("Insertion Sort - Operations: ", s1); - Counter::SubCounter as(op, "Assignments: ", s2); - Counter::SubCounter co(op, "Comparisons: ", s3); - for (int i = 1; i < int(v.size()); ++i) { - T value = v[i]; - ++as; - int j = i; - while (j > 0 && v[j-1] > value) { - v[j] = v[j-1]; - --j; - ++co; ++as; - } - v[j] = value; - ++as; - } - } - check(s1.str() == "Insertion Sort - Operations: 56\n", "Wrong counter"); - check(s2.str() == "Assignments: 37\n", "Wrong subcounter"); - check(s3.str() == "Comparisons: 19\n", "Wrong subcounter"); -} - -template -void counterTest(bool output) { - std::stringstream s1, s2, s3; - { - MyCounter c("Main Counter: ", s1); - c++; - typename MyCounter::SubCounter d(c, "SubCounter: ", s2); - d++; - typename MyCounter::SubCounter::NoSubCounter e(d, "SubSubCounter: ", s3); - e++; - d+=3; - c-=4; - e-=2; - c.reset(2); - c.reset(); - } - if (output) { - check(s1.str() == "Main Counter: 3\n", "Wrong Counter"); - check(s2.str() == "SubCounter: 3\n", "Wrong SubCounter"); - check(s3.str() == "", "Wrong NoSubCounter"); - } else { - check(s1.str() == "", "Wrong NoCounter"); - check(s2.str() == "", "Wrong SubCounter"); - check(s3.str() == "", "Wrong NoSubCounter"); - } -} - -void init(std::vector& v) { - v[0] = 10; v[1] = 60; v[2] = 20; v[3] = 90; v[4] = 100; - v[5] = 80; v[6] = 40; v[7] = 30; v[8] = 50; v[9] = 70; -} - -int main() -{ - counterTest(true); - counterTest(false); - - std::vector x(10); - init(x); bubbleSort(x); - init(x); insertionSort(x); - - return 0; -} diff --git a/deps/lemon/test/dfs_test.cc b/deps/lemon/test/dfs_test.cc deleted file mode 100644 index ef5049a00..000000000 --- a/deps/lemon/test/dfs_test.cc +++ /dev/null @@ -1,238 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "graph_test.h" -#include "test_tools.h" - -using namespace lemon; - -char test_lgf[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "@arcs\n" - " label\n" - "0 1 0\n" - "1 2 1\n" - "2 3 2\n" - "1 4 3\n" - "4 2 4\n" - "4 5 5\n" - "5 0 6\n" - "6 3 7\n" - "@attributes\n" - "source 0\n" - "target 5\n" - "source1 6\n" - "target1 3\n"; - - -void checkDfsCompile() -{ - typedef concepts::Digraph Digraph; - typedef Dfs DType; - typedef Digraph::Node Node; - typedef Digraph::Arc Arc; - - Digraph G; - Node s, t; - Arc e; - int l, i; - bool b; - ::lemon::ignore_unused_variable_warning(l,i,b); - - DType::DistMap d(G); - DType::PredMap p(G); - Path pp; - concepts::ReadMap am; - - { - DType dfs_test(G); - const DType& const_dfs_test = dfs_test; - - dfs_test.run(s); - dfs_test.run(s,t); - dfs_test.run(); - - dfs_test.init(); - dfs_test.addSource(s); - e = dfs_test.processNextArc(); - e = const_dfs_test.nextArc(); - b = const_dfs_test.emptyQueue(); - i = const_dfs_test.queueSize(); - - dfs_test.start(); - dfs_test.start(t); - dfs_test.start(am); - - l = const_dfs_test.dist(t); - e = const_dfs_test.predArc(t); - s = const_dfs_test.predNode(t); - b = const_dfs_test.reached(t); - d = const_dfs_test.distMap(); - p = const_dfs_test.predMap(); - pp = const_dfs_test.path(t); - } - { - DType - ::SetPredMap > - ::SetDistMap > - ::SetReachedMap > - ::SetStandardProcessedMap - ::SetProcessedMap > - ::Create dfs_test(G); - - concepts::ReadWriteMap pred_map; - concepts::ReadWriteMap dist_map; - concepts::ReadWriteMap reached_map; - concepts::WriteMap processed_map; - - dfs_test - .predMap(pred_map) - .distMap(dist_map) - .reachedMap(reached_map) - .processedMap(processed_map); - - dfs_test.run(s); - dfs_test.run(s,t); - dfs_test.run(); - dfs_test.init(); - - dfs_test.addSource(s); - e = dfs_test.processNextArc(); - e = dfs_test.nextArc(); - b = dfs_test.emptyQueue(); - i = dfs_test.queueSize(); - - dfs_test.start(); - dfs_test.start(t); - dfs_test.start(am); - - l = dfs_test.dist(t); - e = dfs_test.predArc(t); - s = dfs_test.predNode(t); - b = dfs_test.reached(t); - pp = dfs_test.path(t); - } -} - -void checkDfsFunctionCompile() -{ - typedef int VType; - typedef concepts::Digraph Digraph; - typedef Digraph::Arc Arc; - typedef Digraph::Node Node; - - Digraph g; - bool b; - ::lemon::ignore_unused_variable_warning(b); - - dfs(g).run(Node()); - b=dfs(g).run(Node(),Node()); - dfs(g).run(); - dfs(g) - .predMap(concepts::ReadWriteMap()) - .distMap(concepts::ReadWriteMap()) - .reachedMap(concepts::ReadWriteMap()) - .processedMap(concepts::WriteMap()) - .run(Node()); - b=dfs(g) - .predMap(concepts::ReadWriteMap()) - .distMap(concepts::ReadWriteMap()) - .reachedMap(concepts::ReadWriteMap()) - .processedMap(concepts::WriteMap()) - .path(concepts::Path()) - .dist(VType()) - .run(Node(),Node()); - dfs(g) - .predMap(concepts::ReadWriteMap()) - .distMap(concepts::ReadWriteMap()) - .reachedMap(concepts::ReadWriteMap()) - .processedMap(concepts::WriteMap()) - .run(); -} - -template -void checkDfs() { - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - Digraph G; - Node s, t; - Node s1, t1; - - std::istringstream input(test_lgf); - digraphReader(G, input). - node("source", s). - node("target", t). - node("source1", s1). - node("target1", t1). - run(); - - Dfs dfs_test(G); - dfs_test.run(s); - - Path p = dfs_test.path(t); - check(p.length() == dfs_test.dist(t),"path() found a wrong path."); - check(checkPath(G, p),"path() found a wrong path."); - check(pathSource(G, p) == s,"path() found a wrong path."); - check(pathTarget(G, p) == t,"path() found a wrong path."); - - for(NodeIt v(G); v!=INVALID; ++v) { - if (dfs_test.reached(v)) { - check(v==s || dfs_test.predArc(v)!=INVALID, "Wrong tree."); - if (dfs_test.predArc(v)!=INVALID ) { - Arc e=dfs_test.predArc(v); - Node u=G.source(e); - check(u==dfs_test.predNode(v),"Wrong tree."); - check(dfs_test.dist(v) - dfs_test.dist(u) == 1, - "Wrong distance. (" << dfs_test.dist(u) << "->" - << dfs_test.dist(v) << ")"); - } - } - } - - { - Dfs dfs(G); - check(dfs.run(s1,t1) && dfs.reached(t1),"Node 3 is reachable from Node 6."); - } - - { - NullMap myPredMap; - dfs(G).predMap(myPredMap).run(s); - } -} - -int main() -{ - checkDfs(); - checkDfs(); - return 0; -} diff --git a/deps/lemon/test/digraph_test.cc b/deps/lemon/test/digraph_test.cc deleted file mode 100644 index e3ff54577..000000000 --- a/deps/lemon/test/digraph_test.cc +++ /dev/null @@ -1,569 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include -#include - -#include "test_tools.h" -#include "graph_test.h" - -using namespace lemon; -using namespace lemon::concepts; - -template -void checkDigraphBuild() { - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - Digraph G; - - checkGraphNodeList(G, 0); - checkGraphArcList(G, 0); - - G.reserveNode(3); - G.reserveArc(4); - - Node - n1 = G.addNode(), - n2 = G.addNode(), - n3 = G.addNode(); - checkGraphNodeList(G, 3); - checkGraphArcList(G, 0); - - Arc a1 = G.addArc(n1, n2); - check(G.source(a1) == n1 && G.target(a1) == n2, "Wrong arc"); - checkGraphNodeList(G, 3); - checkGraphArcList(G, 1); - - checkGraphOutArcList(G, n1, 1); - checkGraphOutArcList(G, n2, 0); - checkGraphOutArcList(G, n3, 0); - - checkGraphInArcList(G, n1, 0); - checkGraphInArcList(G, n2, 1); - checkGraphInArcList(G, n3, 0); - - checkGraphConArcList(G, 1); - - Arc a2 = G.addArc(n2, n1), - a3 = G.addArc(n2, n3), - a4 = G.addArc(n2, n3); - ::lemon::ignore_unused_variable_warning(a2,a3,a4); - - checkGraphNodeList(G, 3); - checkGraphArcList(G, 4); - - checkGraphOutArcList(G, n1, 1); - checkGraphOutArcList(G, n2, 3); - checkGraphOutArcList(G, n3, 0); - - checkGraphInArcList(G, n1, 1); - checkGraphInArcList(G, n2, 1); - checkGraphInArcList(G, n3, 2); - - checkGraphConArcList(G, 4); - - checkNodeIds(G); - checkArcIds(G); - checkGraphNodeMap(G); - checkGraphArcMap(G); -} - -template -void checkDigraphSplit() { - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - Digraph G; - Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode(); - Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n2, n1), - a3 = G.addArc(n2, n3), a4 = G.addArc(n2, n3); - ::lemon::ignore_unused_variable_warning(a1,a2,a3,a4); - - Node n4 = G.split(n2); - - check(G.target(OutArcIt(G, n2)) == n4 && - G.source(InArcIt(G, n4)) == n2, - "Wrong split."); - - checkGraphNodeList(G, 4); - checkGraphArcList(G, 5); - - checkGraphOutArcList(G, n1, 1); - checkGraphOutArcList(G, n2, 1); - checkGraphOutArcList(G, n3, 0); - checkGraphOutArcList(G, n4, 3); - - checkGraphInArcList(G, n1, 1); - checkGraphInArcList(G, n2, 1); - checkGraphInArcList(G, n3, 2); - checkGraphInArcList(G, n4, 1); - - checkGraphConArcList(G, 5); -} - -template -void checkDigraphAlter() { - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - Digraph G; - Node n1 = G.addNode(), n2 = G.addNode(), - n3 = G.addNode(), n4 = G.addNode(); - Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n4, n1), - a3 = G.addArc(n4, n3), a4 = G.addArc(n4, n3), - a5 = G.addArc(n2, n4); - ::lemon::ignore_unused_variable_warning(a1,a2,a3,a5); - - checkGraphNodeList(G, 4); - checkGraphArcList(G, 5); - - // Check changeSource() and changeTarget() - G.changeTarget(a4, n1); - - checkGraphNodeList(G, 4); - checkGraphArcList(G, 5); - - checkGraphOutArcList(G, n1, 1); - checkGraphOutArcList(G, n2, 1); - checkGraphOutArcList(G, n3, 0); - checkGraphOutArcList(G, n4, 3); - - checkGraphInArcList(G, n1, 2); - checkGraphInArcList(G, n2, 1); - checkGraphInArcList(G, n3, 1); - checkGraphInArcList(G, n4, 1); - - checkGraphConArcList(G, 5); - - G.changeSource(a4, n3); - - checkGraphNodeList(G, 4); - checkGraphArcList(G, 5); - - checkGraphOutArcList(G, n1, 1); - checkGraphOutArcList(G, n2, 1); - checkGraphOutArcList(G, n3, 1); - checkGraphOutArcList(G, n4, 2); - - checkGraphInArcList(G, n1, 2); - checkGraphInArcList(G, n2, 1); - checkGraphInArcList(G, n3, 1); - checkGraphInArcList(G, n4, 1); - - checkGraphConArcList(G, 5); - - // Check contract() - G.contract(n2, n4, false); - - checkGraphNodeList(G, 3); - checkGraphArcList(G, 5); - - checkGraphOutArcList(G, n1, 1); - checkGraphOutArcList(G, n2, 3); - checkGraphOutArcList(G, n3, 1); - - checkGraphInArcList(G, n1, 2); - checkGraphInArcList(G, n2, 2); - checkGraphInArcList(G, n3, 1); - - checkGraphConArcList(G, 5); - - G.contract(n2, n1); - - checkGraphNodeList(G, 2); - checkGraphArcList(G, 3); - - checkGraphOutArcList(G, n2, 2); - checkGraphOutArcList(G, n3, 1); - - checkGraphInArcList(G, n2, 2); - checkGraphInArcList(G, n3, 1); - - checkGraphConArcList(G, 3); -} - -template -void checkDigraphErase() { - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - Digraph G; - Node n1 = G.addNode(), n2 = G.addNode(), - n3 = G.addNode(), n4 = G.addNode(); - Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n4, n1), - a3 = G.addArc(n4, n3), a4 = G.addArc(n3, n1), - a5 = G.addArc(n2, n4); - ::lemon::ignore_unused_variable_warning(a2,a3,a4,a5); - - // Check arc deletion - G.erase(a1); - - checkGraphNodeList(G, 4); - checkGraphArcList(G, 4); - - checkGraphOutArcList(G, n1, 0); - checkGraphOutArcList(G, n2, 1); - checkGraphOutArcList(G, n3, 1); - checkGraphOutArcList(G, n4, 2); - - checkGraphInArcList(G, n1, 2); - checkGraphInArcList(G, n2, 0); - checkGraphInArcList(G, n3, 1); - checkGraphInArcList(G, n4, 1); - - checkGraphConArcList(G, 4); - - // Check node deletion - G.erase(n4); - - checkGraphNodeList(G, 3); - checkGraphArcList(G, 1); - - checkGraphOutArcList(G, n1, 0); - checkGraphOutArcList(G, n2, 0); - checkGraphOutArcList(G, n3, 1); - checkGraphOutArcList(G, n4, 0); - - checkGraphInArcList(G, n1, 1); - checkGraphInArcList(G, n2, 0); - checkGraphInArcList(G, n3, 0); - checkGraphInArcList(G, n4, 0); - - checkGraphConArcList(G, 1); -} - - -template -void checkDigraphSnapshot() { - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - Digraph G; - Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode(); - Arc a1 = G.addArc(n1, n2), a2 = G.addArc(n2, n1), - a3 = G.addArc(n2, n3), a4 = G.addArc(n2, n3); - ::lemon::ignore_unused_variable_warning(a1,a2,a3,a4); - - typename Digraph::Snapshot snapshot(G); - - Node n = G.addNode(); - G.addArc(n3, n); - G.addArc(n, n3); - - checkGraphNodeList(G, 4); - checkGraphArcList(G, 6); - - snapshot.restore(); - - checkGraphNodeList(G, 3); - checkGraphArcList(G, 4); - - checkGraphOutArcList(G, n1, 1); - checkGraphOutArcList(G, n2, 3); - checkGraphOutArcList(G, n3, 0); - - checkGraphInArcList(G, n1, 1); - checkGraphInArcList(G, n2, 1); - checkGraphInArcList(G, n3, 2); - - checkGraphConArcList(G, 4); - - checkNodeIds(G); - checkArcIds(G); - checkGraphNodeMap(G); - checkGraphArcMap(G); - - G.addNode(); - snapshot.save(G); - - G.addArc(G.addNode(), G.addNode()); - - snapshot.restore(); - snapshot.save(G); - - checkGraphNodeList(G, 4); - checkGraphArcList(G, 4); - - G.addArc(G.addNode(), G.addNode()); - - snapshot.restore(); - - checkGraphNodeList(G, 4); - checkGraphArcList(G, 4); -} - -void checkConcepts() { - { // Checking digraph components - checkConcept(); - - checkConcept, - IDableDigraphComponent<> >(); - - checkConcept, - IterableDigraphComponent<> >(); - - checkConcept, - MappableDigraphComponent<> >(); - } - { // Checking skeleton digraph - checkConcept(); - } - { // Checking ListDigraph - checkConcept(); - checkConcept, ListDigraph>(); - checkConcept, ListDigraph>(); - checkConcept, ListDigraph>(); - checkConcept, ListDigraph>(); - } - { // Checking SmartDigraph - checkConcept(); - checkConcept, SmartDigraph>(); - checkConcept, SmartDigraph>(); - checkConcept, SmartDigraph>(); - } - { // Checking StaticDigraph - checkConcept(); - checkConcept, StaticDigraph>(); - } - { // Checking FullDigraph - checkConcept(); - } -} - -template -void checkDigraphValidity() { - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - Digraph g; - - Node - n1 = g.addNode(), - n2 = g.addNode(), - n3 = g.addNode(); - - Arc - e1 = g.addArc(n1, n2), - e2 = g.addArc(n2, n3); - ::lemon::ignore_unused_variable_warning(e2); - - check(g.valid(n1), "Wrong validity check"); - check(g.valid(e1), "Wrong validity check"); - - check(!g.valid(g.nodeFromId(-1)), "Wrong validity check"); - check(!g.valid(g.arcFromId(-1)), "Wrong validity check"); -} - -template -void checkDigraphValidityErase() { - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - Digraph g; - - Node - n1 = g.addNode(), - n2 = g.addNode(), - n3 = g.addNode(); - - Arc - e1 = g.addArc(n1, n2), - e2 = g.addArc(n2, n3); - - check(g.valid(n1), "Wrong validity check"); - check(g.valid(e1), "Wrong validity check"); - - g.erase(n1); - - check(!g.valid(n1), "Wrong validity check"); - check(g.valid(n2), "Wrong validity check"); - check(g.valid(n3), "Wrong validity check"); - check(!g.valid(e1), "Wrong validity check"); - check(g.valid(e2), "Wrong validity check"); - - check(!g.valid(g.nodeFromId(-1)), "Wrong validity check"); - check(!g.valid(g.arcFromId(-1)), "Wrong validity check"); -} - -void checkStaticDigraph() { - SmartDigraph g; - SmartDigraph::NodeMap nref(g); - SmartDigraph::ArcMap aref(g); - - StaticDigraph G; - - checkGraphNodeList(G, 0); - checkGraphArcList(G, 0); - - G.build(g, nref, aref); - - checkGraphNodeList(G, 0); - checkGraphArcList(G, 0); - - SmartDigraph::Node - n1 = g.addNode(), - n2 = g.addNode(), - n3 = g.addNode(); - - G.build(g, nref, aref); - - checkGraphNodeList(G, 3); - checkGraphArcList(G, 0); - - SmartDigraph::Arc a1 = g.addArc(n1, n2); - - G.build(g, nref, aref); - - check(G.source(aref[a1]) == nref[n1] && G.target(aref[a1]) == nref[n2], - "Wrong arc or wrong references"); - checkGraphNodeList(G, 3); - checkGraphArcList(G, 1); - - checkGraphOutArcList(G, nref[n1], 1); - checkGraphOutArcList(G, nref[n2], 0); - checkGraphOutArcList(G, nref[n3], 0); - - checkGraphInArcList(G, nref[n1], 0); - checkGraphInArcList(G, nref[n2], 1); - checkGraphInArcList(G, nref[n3], 0); - - checkGraphConArcList(G, 1); - - SmartDigraph::Arc - a2 = g.addArc(n2, n1), - a3 = g.addArc(n2, n3), - a4 = g.addArc(n2, n3); - ::lemon::ignore_unused_variable_warning(a2,a3,a4); - - digraphCopy(g, G).nodeRef(nref).run(); - - checkGraphNodeList(G, 3); - checkGraphArcList(G, 4); - - checkGraphOutArcList(G, nref[n1], 1); - checkGraphOutArcList(G, nref[n2], 3); - checkGraphOutArcList(G, nref[n3], 0); - - checkGraphInArcList(G, nref[n1], 1); - checkGraphInArcList(G, nref[n2], 1); - checkGraphInArcList(G, nref[n3], 2); - - checkGraphConArcList(G, 4); - - std::vector > arcs; - arcs.push_back(std::make_pair(0,1)); - arcs.push_back(std::make_pair(0,2)); - arcs.push_back(std::make_pair(1,3)); - arcs.push_back(std::make_pair(1,2)); - arcs.push_back(std::make_pair(3,0)); - arcs.push_back(std::make_pair(3,3)); - arcs.push_back(std::make_pair(4,2)); - arcs.push_back(std::make_pair(4,3)); - arcs.push_back(std::make_pair(4,1)); - - G.build(6, arcs.begin(), arcs.end()); - - checkGraphNodeList(G, 6); - checkGraphArcList(G, 9); - - checkGraphOutArcList(G, G.node(0), 2); - checkGraphOutArcList(G, G.node(1), 2); - checkGraphOutArcList(G, G.node(2), 0); - checkGraphOutArcList(G, G.node(3), 2); - checkGraphOutArcList(G, G.node(4), 3); - checkGraphOutArcList(G, G.node(5), 0); - - checkGraphInArcList(G, G.node(0), 1); - checkGraphInArcList(G, G.node(1), 2); - checkGraphInArcList(G, G.node(2), 3); - checkGraphInArcList(G, G.node(3), 3); - checkGraphInArcList(G, G.node(4), 0); - checkGraphInArcList(G, G.node(5), 0); - - checkGraphConArcList(G, 9); - - checkNodeIds(G); - checkArcIds(G); - checkGraphNodeMap(G); - checkGraphArcMap(G); - - int n = G.nodeNum(); - int m = G.arcNum(); - check(G.index(G.node(n-1)) == n-1, "Wrong index."); - check(G.index(G.arc(m-1)) == m-1, "Wrong index."); -} - -void checkFullDigraph(int num) { - typedef FullDigraph Digraph; - DIGRAPH_TYPEDEFS(Digraph); - - Digraph G(num); - check(G.nodeNum() == num && G.arcNum() == num * num, "Wrong size"); - - G.resize(num); - check(G.nodeNum() == num && G.arcNum() == num * num, "Wrong size"); - - checkGraphNodeList(G, num); - checkGraphArcList(G, num * num); - - for (NodeIt n(G); n != INVALID; ++n) { - checkGraphOutArcList(G, n, num); - checkGraphInArcList(G, n, num); - } - - checkGraphConArcList(G, num * num); - - checkNodeIds(G); - checkArcIds(G); - checkGraphNodeMap(G); - checkGraphArcMap(G); - - for (int i = 0; i < G.nodeNum(); ++i) { - check(G.index(G(i)) == i, "Wrong index"); - } - - for (NodeIt s(G); s != INVALID; ++s) { - for (NodeIt t(G); t != INVALID; ++t) { - Arc a = G.arc(s, t); - check(G.source(a) == s && G.target(a) == t, "Wrong arc lookup"); - } - } -} - -void checkDigraphs() { - { // Checking ListDigraph - checkDigraphBuild(); - checkDigraphSplit(); - checkDigraphAlter(); - checkDigraphErase(); - checkDigraphSnapshot(); - checkDigraphValidityErase(); - } - { // Checking SmartDigraph - checkDigraphBuild(); - checkDigraphSplit(); - checkDigraphSnapshot(); - checkDigraphValidity(); - } - { // Checking StaticDigraph - checkStaticDigraph(); - } - { // Checking FullDigraph - checkFullDigraph(8); - } -} - -int main() { - checkDigraphs(); - checkConcepts(); - return 0; -} diff --git a/deps/lemon/test/dijkstra_test.cc b/deps/lemon/test/dijkstra_test.cc deleted file mode 100644 index 20cc76b36..000000000 --- a/deps/lemon/test/dijkstra_test.cc +++ /dev/null @@ -1,246 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "graph_test.h" -#include "test_tools.h" - -using namespace lemon; - -char test_lgf[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "@arcs\n" - " label length\n" - "0 1 0 1\n" - "1 2 1 1\n" - "2 3 2 1\n" - "0 3 4 5\n" - "0 3 5 10\n" - "0 3 6 7\n" - "4 2 7 1\n" - "@attributes\n" - "source 0\n" - "target 3\n"; - -void checkDijkstraCompile() -{ - typedef int VType; - typedef concepts::Digraph Digraph; - typedef concepts::ReadMap LengthMap; - typedef Dijkstra DType; - typedef Digraph::Node Node; - typedef Digraph::Arc Arc; - - Digraph G; - Node s, t, n; - Arc e; - VType l; - int i; - bool b; - ::lemon::ignore_unused_variable_warning(l,i,b); - - DType::DistMap d(G); - DType::PredMap p(G); - LengthMap length; - Path pp; - concepts::ReadMap nm; - - { - DType dijkstra_test(G,length); - const DType& const_dijkstra_test = dijkstra_test; - - dijkstra_test.run(s); - dijkstra_test.run(s,t); - - dijkstra_test.init(); - dijkstra_test.addSource(s); - dijkstra_test.addSource(s, 1); - n = dijkstra_test.processNextNode(); - n = const_dijkstra_test.nextNode(); - b = const_dijkstra_test.emptyQueue(); - i = const_dijkstra_test.queueSize(); - - dijkstra_test.start(); - dijkstra_test.start(t); - dijkstra_test.start(nm); - - l = const_dijkstra_test.dist(t); - e = const_dijkstra_test.predArc(t); - s = const_dijkstra_test.predNode(t); - b = const_dijkstra_test.reached(t); - b = const_dijkstra_test.processed(t); - d = const_dijkstra_test.distMap(); - p = const_dijkstra_test.predMap(); - pp = const_dijkstra_test.path(t); - l = const_dijkstra_test.currentDist(t); - } - { - DType - ::SetPredMap > - ::SetDistMap > - ::SetStandardProcessedMap - ::SetProcessedMap > - ::SetOperationTraits > - ::SetHeap > > - ::SetStandardHeap > > - ::SetHeap >, - concepts::ReadWriteMap > - ::Create dijkstra_test(G,length); - - LengthMap length_map; - concepts::ReadWriteMap pred_map; - concepts::ReadWriteMap dist_map; - concepts::WriteMap processed_map; - concepts::ReadWriteMap heap_cross_ref; - BinHeap > heap(heap_cross_ref); - - dijkstra_test - .lengthMap(length_map) - .predMap(pred_map) - .distMap(dist_map) - .processedMap(processed_map) - .heap(heap, heap_cross_ref); - - dijkstra_test.run(s); - dijkstra_test.run(s,t); - - dijkstra_test.addSource(s); - dijkstra_test.addSource(s, 1); - n = dijkstra_test.processNextNode(); - n = dijkstra_test.nextNode(); - b = dijkstra_test.emptyQueue(); - i = dijkstra_test.queueSize(); - - dijkstra_test.start(); - dijkstra_test.start(t); - dijkstra_test.start(nm); - - l = dijkstra_test.dist(t); - e = dijkstra_test.predArc(t); - s = dijkstra_test.predNode(t); - b = dijkstra_test.reached(t); - b = dijkstra_test.processed(t); - pp = dijkstra_test.path(t); - l = dijkstra_test.currentDist(t); - } - -} - -void checkDijkstraFunctionCompile() -{ - typedef int VType; - typedef concepts::Digraph Digraph; - typedef Digraph::Arc Arc; - typedef Digraph::Node Node; - typedef concepts::ReadMap LengthMap; - - Digraph g; - bool b; - ::lemon::ignore_unused_variable_warning(b); - - dijkstra(g,LengthMap()).run(Node()); - b=dijkstra(g,LengthMap()).run(Node(),Node()); - dijkstra(g,LengthMap()) - .predMap(concepts::ReadWriteMap()) - .distMap(concepts::ReadWriteMap()) - .processedMap(concepts::WriteMap()) - .run(Node()); - b=dijkstra(g,LengthMap()) - .predMap(concepts::ReadWriteMap()) - .distMap(concepts::ReadWriteMap()) - .processedMap(concepts::WriteMap()) - .path(concepts::Path()) - .dist(VType()) - .run(Node(),Node()); -} - -template -void checkDijkstra() { - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - typedef typename Digraph::template ArcMap LengthMap; - - Digraph G; - Node s, t; - LengthMap length(G); - - std::istringstream input(test_lgf); - digraphReader(G, input). - arcMap("length", length). - node("source", s). - node("target", t). - run(); - - Dijkstra - dijkstra_test(G, length); - dijkstra_test.run(s); - - check(dijkstra_test.dist(t)==3,"Dijkstra found a wrong path."); - - Path p = dijkstra_test.path(t); - check(p.length()==3,"path() found a wrong path."); - check(checkPath(G, p),"path() found a wrong path."); - check(pathSource(G, p) == s,"path() found a wrong path."); - check(pathTarget(G, p) == t,"path() found a wrong path."); - - for(ArcIt e(G); e!=INVALID; ++e) { - Node u=G.source(e); - Node v=G.target(e); - check( !dijkstra_test.reached(u) || - (dijkstra_test.dist(v) - dijkstra_test.dist(u) <= length[e]), - "Wrong output. dist(target)-dist(source)-arc_length=" << - dijkstra_test.dist(v) - dijkstra_test.dist(u) - length[e]); - } - - for(NodeIt v(G); v!=INVALID; ++v) { - if (dijkstra_test.reached(v)) { - check(v==s || dijkstra_test.predArc(v)!=INVALID, "Wrong tree."); - if (dijkstra_test.predArc(v)!=INVALID ) { - Arc e=dijkstra_test.predArc(v); - Node u=G.source(e); - check(u==dijkstra_test.predNode(v),"Wrong tree."); - check(dijkstra_test.dist(v) - dijkstra_test.dist(u) == length[e], - "Wrong distance! Difference: " << - std::abs(dijkstra_test.dist(v)-dijkstra_test.dist(u)-length[e])); - } - } - } - - { - NullMap myPredMap; - dijkstra(G,length).predMap(myPredMap).run(s); - } -} - -int main() { - checkDijkstra(); - checkDijkstra(); - return 0; -} diff --git a/deps/lemon/test/dim_test.cc b/deps/lemon/test/dim_test.cc deleted file mode 100644 index 0b2b9250f..000000000 --- a/deps/lemon/test/dim_test.cc +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include "test_tools.h" - -using namespace std; -using namespace lemon; - -int main() -{ - typedef dim2::Point Point; - - Point p; - check(p.size()==2, "Wrong dim2::Point initialization."); - - Point a(1,2); - Point b(3,4); - check(a[0]==1 && a[1]==2, "Wrong dim2::Point initialization."); - - p = a+b; - check(p.x==4 && p.y==6, "Wrong dim2::Point addition."); - - p = a-b; - check(p.x==-2 && p.y==-2, "Wrong dim2::Point subtraction."); - - check(a.normSquare()==5,"Wrong dim2::Point norm calculation."); - check(a*b==11, "Wrong dim2::Point scalar product."); - - int l=2; - p = a*l; - check(p.x==2 && p.y==4, "Wrong dim2::Point multiplication by a scalar."); - - p = b/l; - check(p.x==1 && p.y==2, "Wrong dim2::Point division by a scalar."); - - typedef dim2::Box Box; - Box box1; - check(box1.empty(), "Wrong empty() in dim2::Box."); - - box1.add(a); - check(!box1.empty(), "Wrong empty() in dim2::Box."); - box1.add(b); - - check(box1.left()==1 && box1.bottom()==2 && - box1.right()==3 && box1.top()==4, - "Wrong addition of points to dim2::Box."); - - check(box1.inside(Point(2,3)), "Wrong inside() in dim2::Box."); - check(box1.inside(Point(1,3)), "Wrong inside() in dim2::Box."); - check(!box1.inside(Point(0,3)), "Wrong inside() in dim2::Box."); - - Box box2(Point(2,2)); - check(!box2.empty(), "Wrong empty() in dim2::Box."); - - box2.bottomLeft(Point(2,0)); - box2.topRight(Point(5,3)); - Box box3 = box1 & box2; - check(!box3.empty() && - box3.left()==2 && box3.bottom()==2 && - box3.right()==3 && box3.top()==3, - "Wrong intersection of two dim2::Box objects."); - - box1.add(box2); - check(!box1.empty() && - box1.left()==1 && box1.bottom()==0 && - box1.right()==5 && box1.top()==4, - "Wrong addition of two dim2::Box objects."); - - return 0; -} diff --git a/deps/lemon/test/edge_set_test.cc b/deps/lemon/test/edge_set_test.cc deleted file mode 100644 index dbe74a9fc..000000000 --- a/deps/lemon/test/edge_set_test.cc +++ /dev/null @@ -1,396 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include - -#include -#include -#include - -#include - -#include - -#include "graph_test.h" -#include "test_tools.h" - -using namespace lemon; - -void checkSmartArcSet() { - checkConcept >(); - - typedef ListDigraph Digraph; - typedef SmartArcSet ArcSet; - - Digraph digraph; - Digraph::Node - n1 = digraph.addNode(), - n2 = digraph.addNode(); - - Digraph::Arc ga1 = digraph.addArc(n1, n2); - ::lemon::ignore_unused_variable_warning(ga1); - - ArcSet arc_set(digraph); - - Digraph::Arc ga2 = digraph.addArc(n2, n1); - ::lemon::ignore_unused_variable_warning(ga2); - - checkGraphNodeList(arc_set, 2); - checkGraphArcList(arc_set, 0); - - Digraph::Node - n3 = digraph.addNode(); - checkGraphNodeList(arc_set, 3); - checkGraphArcList(arc_set, 0); - - ArcSet::Arc a1 = arc_set.addArc(n1, n2); - check(arc_set.source(a1) == n1 && arc_set.target(a1) == n2, "Wrong arc"); - checkGraphNodeList(arc_set, 3); - checkGraphArcList(arc_set, 1); - - checkGraphOutArcList(arc_set, n1, 1); - checkGraphOutArcList(arc_set, n2, 0); - checkGraphOutArcList(arc_set, n3, 0); - - checkGraphInArcList(arc_set, n1, 0); - checkGraphInArcList(arc_set, n2, 1); - checkGraphInArcList(arc_set, n3, 0); - - checkGraphConArcList(arc_set, 1); - - ArcSet::Arc a2 = arc_set.addArc(n2, n1), - a3 = arc_set.addArc(n2, n3), - a4 = arc_set.addArc(n2, n3); - ::lemon::ignore_unused_variable_warning(a2,a3,a4); - - checkGraphNodeList(arc_set, 3); - checkGraphArcList(arc_set, 4); - - checkGraphOutArcList(arc_set, n1, 1); - checkGraphOutArcList(arc_set, n2, 3); - checkGraphOutArcList(arc_set, n3, 0); - - checkGraphInArcList(arc_set, n1, 1); - checkGraphInArcList(arc_set, n2, 1); - checkGraphInArcList(arc_set, n3, 2); - - checkGraphConArcList(arc_set, 4); - - checkNodeIds(arc_set); - checkArcIds(arc_set); - checkGraphNodeMap(arc_set); - checkGraphArcMap(arc_set); - - check(arc_set.valid(), "Wrong validity"); - digraph.erase(n1); - check(!arc_set.valid(), "Wrong validity"); -} - -void checkListArcSet() { - checkConcept >(); - - typedef ListDigraph Digraph; - typedef ListArcSet ArcSet; - - Digraph digraph; - Digraph::Node - n1 = digraph.addNode(), - n2 = digraph.addNode(); - - Digraph::Arc ga1 = digraph.addArc(n1, n2); - ::lemon::ignore_unused_variable_warning(ga1); - - ArcSet arc_set(digraph); - - Digraph::Arc ga2 = digraph.addArc(n2, n1); - ::lemon::ignore_unused_variable_warning(ga2); - - checkGraphNodeList(arc_set, 2); - checkGraphArcList(arc_set, 0); - - Digraph::Node - n3 = digraph.addNode(); - checkGraphNodeList(arc_set, 3); - checkGraphArcList(arc_set, 0); - - ArcSet::Arc a1 = arc_set.addArc(n1, n2); - check(arc_set.source(a1) == n1 && arc_set.target(a1) == n2, "Wrong arc"); - checkGraphNodeList(arc_set, 3); - checkGraphArcList(arc_set, 1); - - checkGraphOutArcList(arc_set, n1, 1); - checkGraphOutArcList(arc_set, n2, 0); - checkGraphOutArcList(arc_set, n3, 0); - - checkGraphInArcList(arc_set, n1, 0); - checkGraphInArcList(arc_set, n2, 1); - checkGraphInArcList(arc_set, n3, 0); - - checkGraphConArcList(arc_set, 1); - - ArcSet::Arc a2 = arc_set.addArc(n2, n1), - a3 = arc_set.addArc(n2, n3), - a4 = arc_set.addArc(n2, n3); - ::lemon::ignore_unused_variable_warning(a2,a3,a4); - - checkGraphNodeList(arc_set, 3); - checkGraphArcList(arc_set, 4); - - checkGraphOutArcList(arc_set, n1, 1); - checkGraphOutArcList(arc_set, n2, 3); - checkGraphOutArcList(arc_set, n3, 0); - - checkGraphInArcList(arc_set, n1, 1); - checkGraphInArcList(arc_set, n2, 1); - checkGraphInArcList(arc_set, n3, 2); - - checkGraphConArcList(arc_set, 4); - - checkNodeIds(arc_set); - checkArcIds(arc_set); - checkGraphNodeMap(arc_set); - checkGraphArcMap(arc_set); - - digraph.erase(n1); - - checkGraphNodeList(arc_set, 2); - checkGraphArcList(arc_set, 2); - - checkGraphOutArcList(arc_set, n2, 2); - checkGraphOutArcList(arc_set, n3, 0); - - checkGraphInArcList(arc_set, n2, 0); - checkGraphInArcList(arc_set, n3, 2); - - checkNodeIds(arc_set); - checkArcIds(arc_set); - checkGraphNodeMap(arc_set); - checkGraphArcMap(arc_set); - - checkGraphConArcList(arc_set, 2); -} - -void checkSmartEdgeSet() { - checkConcept >(); - - typedef ListDigraph Digraph; - typedef SmartEdgeSet EdgeSet; - - Digraph digraph; - Digraph::Node - n1 = digraph.addNode(), - n2 = digraph.addNode(); - - Digraph::Arc ga1 = digraph.addArc(n1, n2); - ::lemon::ignore_unused_variable_warning(ga1); - - EdgeSet edge_set(digraph); - - Digraph::Arc ga2 = digraph.addArc(n2, n1); - ::lemon::ignore_unused_variable_warning(ga2); - - checkGraphNodeList(edge_set, 2); - checkGraphArcList(edge_set, 0); - checkGraphEdgeList(edge_set, 0); - - Digraph::Node - n3 = digraph.addNode(); - checkGraphNodeList(edge_set, 3); - checkGraphArcList(edge_set, 0); - checkGraphEdgeList(edge_set, 0); - - EdgeSet::Edge e1 = edge_set.addEdge(n1, n2); - check((edge_set.u(e1) == n1 && edge_set.v(e1) == n2) || - (edge_set.v(e1) == n1 && edge_set.u(e1) == n2), "Wrong edge"); - checkGraphNodeList(edge_set, 3); - checkGraphArcList(edge_set, 2); - checkGraphEdgeList(edge_set, 1); - - checkGraphOutArcList(edge_set, n1, 1); - checkGraphOutArcList(edge_set, n2, 1); - checkGraphOutArcList(edge_set, n3, 0); - - checkGraphInArcList(edge_set, n1, 1); - checkGraphInArcList(edge_set, n2, 1); - checkGraphInArcList(edge_set, n3, 0); - - checkGraphIncEdgeList(edge_set, n1, 1); - checkGraphIncEdgeList(edge_set, n2, 1); - checkGraphIncEdgeList(edge_set, n3, 0); - - checkGraphConEdgeList(edge_set, 1); - checkGraphConArcList(edge_set, 2); - - EdgeSet::Edge e2 = edge_set.addEdge(n2, n1), - e3 = edge_set.addEdge(n2, n3), - e4 = edge_set.addEdge(n2, n3); - ::lemon::ignore_unused_variable_warning(e2,e3,e4); - - checkGraphNodeList(edge_set, 3); - checkGraphEdgeList(edge_set, 4); - - checkGraphOutArcList(edge_set, n1, 2); - checkGraphOutArcList(edge_set, n2, 4); - checkGraphOutArcList(edge_set, n3, 2); - - checkGraphInArcList(edge_set, n1, 2); - checkGraphInArcList(edge_set, n2, 4); - checkGraphInArcList(edge_set, n3, 2); - - checkGraphIncEdgeList(edge_set, n1, 2); - checkGraphIncEdgeList(edge_set, n2, 4); - checkGraphIncEdgeList(edge_set, n3, 2); - - checkGraphConEdgeList(edge_set, 4); - checkGraphConArcList(edge_set, 8); - - checkArcDirections(edge_set); - - checkNodeIds(edge_set); - checkArcIds(edge_set); - checkEdgeIds(edge_set); - checkGraphNodeMap(edge_set); - checkGraphArcMap(edge_set); - checkGraphEdgeMap(edge_set); - - check(edge_set.valid(), "Wrong validity"); - digraph.erase(n1); - check(!edge_set.valid(), "Wrong validity"); -} - -void checkListEdgeSet() { - checkConcept >(); - - typedef ListDigraph Digraph; - typedef ListEdgeSet EdgeSet; - - Digraph digraph; - Digraph::Node - n1 = digraph.addNode(), - n2 = digraph.addNode(); - - Digraph::Arc ga1 = digraph.addArc(n1, n2); - ::lemon::ignore_unused_variable_warning(ga1); - - EdgeSet edge_set(digraph); - - Digraph::Arc ga2 = digraph.addArc(n2, n1); - ::lemon::ignore_unused_variable_warning(ga2); - - checkGraphNodeList(edge_set, 2); - checkGraphArcList(edge_set, 0); - checkGraphEdgeList(edge_set, 0); - - Digraph::Node - n3 = digraph.addNode(); - checkGraphNodeList(edge_set, 3); - checkGraphArcList(edge_set, 0); - checkGraphEdgeList(edge_set, 0); - - EdgeSet::Edge e1 = edge_set.addEdge(n1, n2); - check((edge_set.u(e1) == n1 && edge_set.v(e1) == n2) || - (edge_set.v(e1) == n1 && edge_set.u(e1) == n2), "Wrong edge"); - checkGraphNodeList(edge_set, 3); - checkGraphArcList(edge_set, 2); - checkGraphEdgeList(edge_set, 1); - - checkGraphOutArcList(edge_set, n1, 1); - checkGraphOutArcList(edge_set, n2, 1); - checkGraphOutArcList(edge_set, n3, 0); - - checkGraphInArcList(edge_set, n1, 1); - checkGraphInArcList(edge_set, n2, 1); - checkGraphInArcList(edge_set, n3, 0); - - checkGraphIncEdgeList(edge_set, n1, 1); - checkGraphIncEdgeList(edge_set, n2, 1); - checkGraphIncEdgeList(edge_set, n3, 0); - - checkGraphConEdgeList(edge_set, 1); - checkGraphConArcList(edge_set, 2); - - EdgeSet::Edge e2 = edge_set.addEdge(n2, n1), - e3 = edge_set.addEdge(n2, n3), - e4 = edge_set.addEdge(n2, n3); - ::lemon::ignore_unused_variable_warning(e2,e3,e4); - - checkGraphNodeList(edge_set, 3); - checkGraphEdgeList(edge_set, 4); - - checkGraphOutArcList(edge_set, n1, 2); - checkGraphOutArcList(edge_set, n2, 4); - checkGraphOutArcList(edge_set, n3, 2); - - checkGraphInArcList(edge_set, n1, 2); - checkGraphInArcList(edge_set, n2, 4); - checkGraphInArcList(edge_set, n3, 2); - - checkGraphIncEdgeList(edge_set, n1, 2); - checkGraphIncEdgeList(edge_set, n2, 4); - checkGraphIncEdgeList(edge_set, n3, 2); - - checkGraphConEdgeList(edge_set, 4); - checkGraphConArcList(edge_set, 8); - - checkArcDirections(edge_set); - - checkNodeIds(edge_set); - checkArcIds(edge_set); - checkEdgeIds(edge_set); - checkGraphNodeMap(edge_set); - checkGraphArcMap(edge_set); - checkGraphEdgeMap(edge_set); - - digraph.erase(n1); - - checkGraphNodeList(edge_set, 2); - checkGraphArcList(edge_set, 4); - checkGraphEdgeList(edge_set, 2); - - checkGraphOutArcList(edge_set, n2, 2); - checkGraphOutArcList(edge_set, n3, 2); - - checkGraphInArcList(edge_set, n2, 2); - checkGraphInArcList(edge_set, n3, 2); - - checkGraphIncEdgeList(edge_set, n2, 2); - checkGraphIncEdgeList(edge_set, n3, 2); - - checkNodeIds(edge_set); - checkArcIds(edge_set); - checkEdgeIds(edge_set); - checkGraphNodeMap(edge_set); - checkGraphArcMap(edge_set); - checkGraphEdgeMap(edge_set); - - checkGraphConEdgeList(edge_set, 2); - checkGraphConArcList(edge_set, 4); - -} - - -int main() { - - checkSmartArcSet(); - checkListArcSet(); - checkSmartEdgeSet(); - checkListEdgeSet(); - - return 0; -} diff --git a/deps/lemon/test/error_test.cc b/deps/lemon/test/error_test.cc deleted file mode 100644 index 152751981..000000000 --- a/deps/lemon/test/error_test.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -#include -#include "test_tools.h" - -using namespace lemon; - -#ifdef LEMON_ENABLE_ASSERTS -#undef LEMON_ENABLE_ASSERTS -#endif - -#ifdef LEMON_DISABLE_ASSERTS -#undef LEMON_DISABLE_ASSERTS -#endif - -#ifdef NDEBUG -#undef NDEBUG -#endif - -//checking disabled asserts -#define LEMON_DISABLE_ASSERTS -#include - -void no_assertion_text_disable() { - LEMON_ASSERT(true, "This is a fault message"); -} - -void assertion_text_disable() { - LEMON_ASSERT(false, "This is a fault message"); -} - -void check_assertion_disable() { - no_assertion_text_disable(); - assertion_text_disable(); -} -#undef LEMON_DISABLE_ASSERTS - -//checking custom assert handler -#define LEMON_ASSERT_CUSTOM - -static int cnt = 0; -void my_assert_handler(const char*, int, const char*, - const char*, const char*) { - ++cnt; -} - -#define LEMON_CUSTOM_ASSERT_HANDLER my_assert_handler -#include - -void no_assertion_text_custom() { - LEMON_ASSERT(true, "This is a fault message"); -} - -void assertion_text_custom() { - LEMON_ASSERT(false, "This is a fault message"); -} - -void check_assertion_custom() { - no_assertion_text_custom(); - assertion_text_custom(); - check(cnt == 1, "The custom assert handler does not work"); -} - -#undef LEMON_ASSERT_CUSTOM - - -int main() { - check_assertion_disable(); - check_assertion_custom(); - - return 0; -} diff --git a/deps/lemon/test/euler_test.cc b/deps/lemon/test/euler_test.cc deleted file mode 100644 index 11a39e470..000000000 --- a/deps/lemon/test/euler_test.cc +++ /dev/null @@ -1,225 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include "test_tools.h" - -using namespace lemon; - -template -void checkDiEulerIt(const Digraph& g, - const typename Digraph::Node& start = INVALID) -{ - typename Digraph::template ArcMap visitationNumber(g, 0); - - DiEulerIt e(g, start); - if (e == INVALID) return; - typename Digraph::Node firstNode = g.source(e); - typename Digraph::Node lastNode = g.target(e); - if (start != INVALID) { - check(firstNode == start, "checkDiEulerIt: Wrong first node"); - } - - for (; e != INVALID; ++e) { - if (e != INVALID) lastNode = g.target(e); - ++visitationNumber[e]; - } - - check(firstNode == lastNode, - "checkDiEulerIt: First and last nodes are not the same"); - - for (typename Digraph::ArcIt a(g); a != INVALID; ++a) - { - check(visitationNumber[a] == 1, - "checkDiEulerIt: Not visited or multiple times visited arc found"); - } -} - -template -void checkEulerIt(const Graph& g, - const typename Graph::Node& start = INVALID) -{ - typename Graph::template EdgeMap visitationNumber(g, 0); - - EulerIt e(g, start); - if (e == INVALID) return; - typename Graph::Node firstNode = g.source(typename Graph::Arc(e)); - typename Graph::Node lastNode = g.target(typename Graph::Arc(e)); - if (start != INVALID) { - check(firstNode == start, "checkEulerIt: Wrong first node"); - } - - for (; e != INVALID; ++e) { - if (e != INVALID) lastNode = g.target(typename Graph::Arc(e)); - ++visitationNumber[e]; - } - - check(firstNode == lastNode, - "checkEulerIt: First and last nodes are not the same"); - - for (typename Graph::EdgeIt e(g); e != INVALID; ++e) - { - check(visitationNumber[e] == 1, - "checkEulerIt: Not visited or multiple times visited edge found"); - } -} - -int main() -{ - typedef ListDigraph Digraph; - typedef Undirector Graph; - - { - Digraph d; - Graph g(d); - - checkDiEulerIt(d); - checkDiEulerIt(g); - checkEulerIt(g); - - check(eulerian(d), "This graph is Eulerian"); - check(eulerian(g), "This graph is Eulerian"); - } - { - Digraph d; - Graph g(d); - Digraph::Node n = d.addNode(); - ::lemon::ignore_unused_variable_warning(n); - - checkDiEulerIt(d); - checkDiEulerIt(g); - checkEulerIt(g); - - check(eulerian(d), "This graph is Eulerian"); - check(eulerian(g), "This graph is Eulerian"); - } - { - Digraph d; - Graph g(d); - Digraph::Node n = d.addNode(); - d.addArc(n, n); - - checkDiEulerIt(d); - checkDiEulerIt(g); - checkEulerIt(g); - - check(eulerian(d), "This graph is Eulerian"); - check(eulerian(g), "This graph is Eulerian"); - } - { - Digraph d; - Graph g(d); - Digraph::Node n1 = d.addNode(); - Digraph::Node n2 = d.addNode(); - Digraph::Node n3 = d.addNode(); - - d.addArc(n1, n2); - d.addArc(n2, n1); - d.addArc(n2, n3); - d.addArc(n3, n2); - - checkDiEulerIt(d); - checkDiEulerIt(d, n2); - checkDiEulerIt(g); - checkDiEulerIt(g, n2); - checkEulerIt(g); - checkEulerIt(g, n2); - - check(eulerian(d), "This graph is Eulerian"); - check(eulerian(g), "This graph is Eulerian"); - } - { - Digraph d; - Graph g(d); - Digraph::Node n1 = d.addNode(); - Digraph::Node n2 = d.addNode(); - Digraph::Node n3 = d.addNode(); - Digraph::Node n4 = d.addNode(); - Digraph::Node n5 = d.addNode(); - Digraph::Node n6 = d.addNode(); - - d.addArc(n1, n2); - d.addArc(n2, n4); - d.addArc(n1, n3); - d.addArc(n3, n4); - d.addArc(n4, n1); - d.addArc(n3, n5); - d.addArc(n5, n2); - d.addArc(n4, n6); - d.addArc(n2, n6); - d.addArc(n6, n1); - d.addArc(n6, n3); - - checkDiEulerIt(d); - checkDiEulerIt(d, n1); - checkDiEulerIt(d, n5); - - checkDiEulerIt(g); - checkDiEulerIt(g, n1); - checkDiEulerIt(g, n5); - checkEulerIt(g); - checkEulerIt(g, n1); - checkEulerIt(g, n5); - - check(eulerian(d), "This graph is Eulerian"); - check(eulerian(g), "This graph is Eulerian"); - } - { - Digraph d; - Graph g(d); - Digraph::Node n0 = d.addNode(); - Digraph::Node n1 = d.addNode(); - Digraph::Node n2 = d.addNode(); - Digraph::Node n3 = d.addNode(); - Digraph::Node n4 = d.addNode(); - Digraph::Node n5 = d.addNode(); - ::lemon::ignore_unused_variable_warning(n0,n4,n5); - - d.addArc(n1, n2); - d.addArc(n2, n3); - d.addArc(n3, n1); - - checkDiEulerIt(d); - checkDiEulerIt(d, n2); - - checkDiEulerIt(g); - checkDiEulerIt(g, n2); - checkEulerIt(g); - checkEulerIt(g, n2); - - check(!eulerian(d), "This graph is not Eulerian"); - check(!eulerian(g), "This graph is not Eulerian"); - } - { - Digraph d; - Graph g(d); - Digraph::Node n1 = d.addNode(); - Digraph::Node n2 = d.addNode(); - Digraph::Node n3 = d.addNode(); - - d.addArc(n1, n2); - d.addArc(n2, n3); - - check(!eulerian(d), "This graph is not Eulerian"); - check(!eulerian(g), "This graph is not Eulerian"); - } - - return 0; -} diff --git a/deps/lemon/test/fractional_matching_test.cc b/deps/lemon/test/fractional_matching_test.cc deleted file mode 100644 index bee866c01..000000000 --- a/deps/lemon/test/fractional_matching_test.cc +++ /dev/null @@ -1,527 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "test_tools.h" - -using namespace std; -using namespace lemon; - -GRAPH_TYPEDEFS(SmartGraph); - - -const int lgfn = 4; -const std::string lgf[lgfn] = { - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "7\n" - "@edges\n" - " label weight\n" - "7 4 0 984\n" - "0 7 1 73\n" - "7 1 2 204\n" - "2 3 3 583\n" - "2 7 4 565\n" - "2 1 5 582\n" - "0 4 6 551\n" - "2 5 7 385\n" - "1 5 8 561\n" - "5 3 9 484\n" - "7 5 10 904\n" - "3 6 11 47\n" - "7 6 12 888\n" - "3 0 13 747\n" - "6 1 14 310\n", - - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "7\n" - "@edges\n" - " label weight\n" - "2 5 0 710\n" - "0 5 1 241\n" - "2 4 2 856\n" - "2 6 3 762\n" - "4 1 4 747\n" - "6 1 5 962\n" - "4 7 6 723\n" - "1 7 7 661\n" - "2 3 8 376\n" - "1 0 9 416\n" - "6 7 10 391\n", - - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "7\n" - "@edges\n" - " label weight\n" - "6 2 0 553\n" - "0 7 1 653\n" - "6 3 2 22\n" - "4 7 3 846\n" - "7 2 4 981\n" - "7 6 5 250\n" - "5 2 6 539\n", - - "@nodes\n" - "label\n" - "0\n" - "@edges\n" - " label weight\n" - "0 0 0 100\n" -}; - -void checkMaxFractionalMatchingCompile() -{ - typedef concepts::Graph Graph; - typedef Graph::Node Node; - typedef Graph::Edge Edge; - - Graph g; - Node n; - Edge e; - - MaxFractionalMatching mat_test(g); - const MaxFractionalMatching& - const_mat_test = mat_test; - - mat_test.init(); - mat_test.start(); - mat_test.start(true); - mat_test.startPerfect(); - mat_test.startPerfect(true); - mat_test.run(); - mat_test.run(true); - mat_test.runPerfect(); - mat_test.runPerfect(true); - - const_mat_test.matchingSize(); - const_mat_test.matching(e); - const_mat_test.matching(n); - const MaxFractionalMatching::MatchingMap& mmap = - const_mat_test.matchingMap(); - e = mmap[n]; - - const_mat_test.barrier(n); -} - -void checkMaxWeightedFractionalMatchingCompile() -{ - typedef concepts::Graph Graph; - typedef Graph::Node Node; - typedef Graph::Edge Edge; - typedef Graph::EdgeMap WeightMap; - - Graph g; - Node n; - Edge e; - WeightMap w(g); - - MaxWeightedFractionalMatching mat_test(g, w); - const MaxWeightedFractionalMatching& - const_mat_test = mat_test; - - mat_test.init(); - mat_test.start(); - mat_test.run(); - - const_mat_test.matchingWeight(); - const_mat_test.matchingSize(); - const_mat_test.matching(e); - const_mat_test.matching(n); - const MaxWeightedFractionalMatching::MatchingMap& mmap = - const_mat_test.matchingMap(); - e = mmap[n]; - - const_mat_test.dualValue(); - const_mat_test.nodeValue(n); -} - -void checkMaxWeightedPerfectFractionalMatchingCompile() -{ - typedef concepts::Graph Graph; - typedef Graph::Node Node; - typedef Graph::Edge Edge; - typedef Graph::EdgeMap WeightMap; - - Graph g; - Node n; - Edge e; - WeightMap w(g); - - MaxWeightedPerfectFractionalMatching mat_test(g, w); - const MaxWeightedPerfectFractionalMatching& - const_mat_test = mat_test; - - mat_test.init(); - mat_test.start(); - mat_test.run(); - - const_mat_test.matchingWeight(); - const_mat_test.matching(e); - const_mat_test.matching(n); - const MaxWeightedPerfectFractionalMatching::MatchingMap& mmap = - const_mat_test.matchingMap(); - e = mmap[n]; - - const_mat_test.dualValue(); - const_mat_test.nodeValue(n); -} - -void checkFractionalMatching(const SmartGraph& graph, - const MaxFractionalMatching& mfm, - bool allow_loops = true) { - int pv = 0; - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - int indeg = 0; - for (InArcIt a(graph, n); a != INVALID; ++a) { - if (mfm.matching(graph.source(a)) == a) { - ++indeg; - } - } - if (mfm.matching(n) != INVALID) { - check(indeg == 1, "Invalid matching"); - ++pv; - } else { - check(indeg == 0, "Invalid matching"); - } - } - check(pv == mfm.matchingSize(), "Wrong matching size"); - - for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { - check((e == mfm.matching(graph.u(e)) ? 1 : 0) + - (e == mfm.matching(graph.v(e)) ? 1 : 0) == - mfm.matching(e), "Invalid matching"); - } - - SmartGraph::NodeMap processed(graph, false); - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - if (processed[n]) continue; - processed[n] = true; - if (mfm.matching(n) == INVALID) continue; - int num = 1; - Node v = graph.target(mfm.matching(n)); - while (v != n) { - processed[v] = true; - ++num; - v = graph.target(mfm.matching(v)); - } - check(num == 2 || num % 2 == 1, "Wrong cycle size"); - check(allow_loops || num != 1, "Wrong cycle size"); - } - - int anum = 0, bnum = 0; - SmartGraph::NodeMap neighbours(graph, false); - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - if (!mfm.barrier(n)) continue; - ++anum; - for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) { - Node u = graph.source(a); - if (!allow_loops && u == n) continue; - if (!neighbours[u]) { - neighbours[u] = true; - ++bnum; - } - } - } - check(anum - bnum + mfm.matchingSize() == countNodes(graph), - "Wrong barrier"); -} - -void checkPerfectFractionalMatching(const SmartGraph& graph, - const MaxFractionalMatching& mfm, - bool perfect, bool allow_loops = true) { - if (perfect) { - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - int indeg = 0; - for (InArcIt a(graph, n); a != INVALID; ++a) { - if (mfm.matching(graph.source(a)) == a) { - ++indeg; - } - } - check(mfm.matching(n) != INVALID, "Invalid matching"); - check(indeg == 1, "Invalid matching"); - } - for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { - check((e == mfm.matching(graph.u(e)) ? 1 : 0) + - (e == mfm.matching(graph.v(e)) ? 1 : 0) == - mfm.matching(e), "Invalid matching"); - } - } else { - int anum = 0, bnum = 0; - SmartGraph::NodeMap neighbours(graph, false); - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - if (!mfm.barrier(n)) continue; - ++anum; - for (SmartGraph::InArcIt a(graph, n); a != INVALID; ++a) { - Node u = graph.source(a); - if (!allow_loops && u == n) continue; - if (!neighbours[u]) { - neighbours[u] = true; - ++bnum; - } - } - } - check(anum - bnum > 0, "Wrong barrier"); - } -} - -void checkWeightedFractionalMatching(const SmartGraph& graph, - const SmartGraph::EdgeMap& weight, - const MaxWeightedFractionalMatching& mwfm, - bool allow_loops = true) { - for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { - if (graph.u(e) == graph.v(e) && !allow_loops) continue; - int rw = mwfm.nodeValue(graph.u(e)) + mwfm.nodeValue(graph.v(e)) - - weight[e] * mwfm.dualScale; - - check(rw >= 0, "Negative reduced weight"); - check(rw == 0 || !mwfm.matching(e), - "Non-zero reduced weight on matching edge"); - } - - int pv = 0; - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - int indeg = 0; - for (InArcIt a(graph, n); a != INVALID; ++a) { - if (mwfm.matching(graph.source(a)) == a) { - ++indeg; - } - } - check(indeg <= 1, "Invalid matching"); - if (mwfm.matching(n) != INVALID) { - check(mwfm.nodeValue(n) >= 0, "Invalid node value"); - check(indeg == 1, "Invalid matching"); - pv += weight[mwfm.matching(n)]; - SmartGraph::Node o = graph.target(mwfm.matching(n)); - ::lemon::ignore_unused_variable_warning(o); - } else { - check(mwfm.nodeValue(n) == 0, "Invalid matching"); - check(indeg == 0, "Invalid matching"); - } - } - - for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { - check((e == mwfm.matching(graph.u(e)) ? 1 : 0) + - (e == mwfm.matching(graph.v(e)) ? 1 : 0) == - mwfm.matching(e), "Invalid matching"); - } - - int dv = 0; - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - dv += mwfm.nodeValue(n); - } - - check(pv * mwfm.dualScale == dv * 2, "Wrong duality"); - - SmartGraph::NodeMap processed(graph, false); - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - if (processed[n]) continue; - processed[n] = true; - if (mwfm.matching(n) == INVALID) continue; - int num = 1; - Node v = graph.target(mwfm.matching(n)); - while (v != n) { - processed[v] = true; - ++num; - v = graph.target(mwfm.matching(v)); - } - check(num == 2 || num % 2 == 1, "Wrong cycle size"); - check(allow_loops || num != 1, "Wrong cycle size"); - } - - return; -} - -void checkWeightedPerfectFractionalMatching(const SmartGraph& graph, - const SmartGraph::EdgeMap& weight, - const MaxWeightedPerfectFractionalMatching& mwpfm, - bool allow_loops = true) { - for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { - if (graph.u(e) == graph.v(e) && !allow_loops) continue; - int rw = mwpfm.nodeValue(graph.u(e)) + mwpfm.nodeValue(graph.v(e)) - - weight[e] * mwpfm.dualScale; - - check(rw >= 0, "Negative reduced weight"); - check(rw == 0 || !mwpfm.matching(e), - "Non-zero reduced weight on matching edge"); - } - - int pv = 0; - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - int indeg = 0; - for (InArcIt a(graph, n); a != INVALID; ++a) { - if (mwpfm.matching(graph.source(a)) == a) { - ++indeg; - } - } - check(mwpfm.matching(n) != INVALID, "Invalid perfect matching"); - check(indeg == 1, "Invalid perfect matching"); - pv += weight[mwpfm.matching(n)]; - SmartGraph::Node o = graph.target(mwpfm.matching(n)); - ::lemon::ignore_unused_variable_warning(o); - } - - for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { - check((e == mwpfm.matching(graph.u(e)) ? 1 : 0) + - (e == mwpfm.matching(graph.v(e)) ? 1 : 0) == - mwpfm.matching(e), "Invalid matching"); - } - - int dv = 0; - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - dv += mwpfm.nodeValue(n); - } - - check(pv * mwpfm.dualScale == dv * 2, "Wrong duality"); - - SmartGraph::NodeMap processed(graph, false); - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - if (processed[n]) continue; - processed[n] = true; - if (mwpfm.matching(n) == INVALID) continue; - int num = 1; - Node v = graph.target(mwpfm.matching(n)); - while (v != n) { - processed[v] = true; - ++num; - v = graph.target(mwpfm.matching(v)); - } - check(num == 2 || num % 2 == 1, "Wrong cycle size"); - check(allow_loops || num != 1, "Wrong cycle size"); - } - - return; -} - - -int main() { - - for (int i = 0; i < lgfn; ++i) { - SmartGraph graph; - SmartGraph::EdgeMap weight(graph); - - istringstream lgfs(lgf[i]); - graphReader(graph, lgfs). - edgeMap("weight", weight).run(); - - bool perfect_with_loops; - { - MaxFractionalMatching mfm(graph, true); - mfm.run(); - checkFractionalMatching(graph, mfm, true); - perfect_with_loops = mfm.matchingSize() == countNodes(graph); - } - - bool perfect_without_loops; - { - MaxFractionalMatching mfm(graph, false); - mfm.run(); - checkFractionalMatching(graph, mfm, false); - perfect_without_loops = mfm.matchingSize() == countNodes(graph); - } - - { - MaxFractionalMatching mfm(graph, true); - bool result = mfm.runPerfect(); - checkPerfectFractionalMatching(graph, mfm, result, true); - check(result == perfect_with_loops, "Wrong perfect matching"); - } - - { - MaxFractionalMatching mfm(graph, false); - bool result = mfm.runPerfect(); - checkPerfectFractionalMatching(graph, mfm, result, false); - check(result == perfect_without_loops, "Wrong perfect matching"); - } - - { - MaxWeightedFractionalMatching mwfm(graph, weight, true); - mwfm.run(); - checkWeightedFractionalMatching(graph, weight, mwfm, true); - } - - { - MaxWeightedFractionalMatching mwfm(graph, weight, false); - mwfm.run(); - checkWeightedFractionalMatching(graph, weight, mwfm, false); - } - - { - MaxWeightedPerfectFractionalMatching mwpfm(graph, weight, - true); - bool perfect = mwpfm.run(); - check(perfect == (mwpfm.matchingSize() == countNodes(graph)), - "Perfect matching found"); - check(perfect == perfect_with_loops, "Wrong perfect matching"); - - if (perfect) { - checkWeightedPerfectFractionalMatching(graph, weight, mwpfm, true); - } - } - - { - MaxWeightedPerfectFractionalMatching mwpfm(graph, weight, - false); - bool perfect = mwpfm.run(); - check(perfect == (mwpfm.matchingSize() == countNodes(graph)), - "Perfect matching found"); - check(perfect == perfect_without_loops, "Wrong perfect matching"); - - if (perfect) { - checkWeightedPerfectFractionalMatching(graph, weight, mwpfm, false); - } - } - - } - - return 0; -} diff --git a/deps/lemon/test/gomory_hu_test.cc b/deps/lemon/test/gomory_hu_test.cc deleted file mode 100644 index 178f21fec..000000000 --- a/deps/lemon/test/gomory_hu_test.cc +++ /dev/null @@ -1,142 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -#include "test_tools.h" -#include -#include -#include -#include -#include -#include - -using namespace std; -using namespace lemon; - -typedef SmartGraph Graph; - -char test_lgf[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "@arcs\n" - " label capacity\n" - "0 1 0 1\n" - "1 2 1 1\n" - "2 3 2 1\n" - "0 3 4 5\n" - "0 3 5 10\n" - "0 3 6 7\n" - "4 2 7 1\n" - "@attributes\n" - "source 0\n" - "target 3\n"; - -void checkGomoryHuCompile() -{ - typedef int Value; - typedef concepts::Graph Graph; - - typedef Graph::Node Node; - typedef Graph::Edge Edge; - typedef concepts::ReadMap CapMap; - typedef concepts::ReadWriteMap CutMap; - - Graph g; - Node n; - CapMap cap; - CutMap cut; - Value v; - int d; - ::lemon::ignore_unused_variable_warning(v,d); - - GomoryHu gh_test(g, cap); - const GomoryHu& - const_gh_test = gh_test; - - gh_test.run(); - - n = const_gh_test.predNode(n); - v = const_gh_test.predValue(n); - d = const_gh_test.rootDist(n); - v = const_gh_test.minCutValue(n, n); - v = const_gh_test.minCutMap(n, n, cut); -} - -GRAPH_TYPEDEFS(Graph); -typedef Graph::EdgeMap IntEdgeMap; -typedef Graph::NodeMap BoolNodeMap; - -int cutValue(const Graph& graph, const BoolNodeMap& cut, - const IntEdgeMap& capacity) { - - int sum = 0; - for (EdgeIt e(graph); e != INVALID; ++e) { - Node s = graph.u(e); - Node t = graph.v(e); - - if (cut[s] != cut[t]) { - sum += capacity[e]; - } - } - return sum; -} - - -int main() { - Graph graph; - IntEdgeMap capacity(graph); - - std::istringstream input(test_lgf); - GraphReader(graph, input). - edgeMap("capacity", capacity).run(); - - GomoryHu ght(graph, capacity); - ght.run(); - - for (NodeIt u(graph); u != INVALID; ++u) { - for (NodeIt v(graph); v != u; ++v) { - Preflow pf(graph, capacity, u, v); - pf.runMinCut(); - BoolNodeMap cm(graph); - ght.minCutMap(u, v, cm); - check(pf.flowValue() == ght.minCutValue(u, v), "Wrong cut 1"); - check(cm[u] != cm[v], "Wrong cut 2"); - check(pf.flowValue() == cutValue(graph, cm, capacity), "Wrong cut 3"); - - int sum=0; - for(GomoryHu::MinCutEdgeIt a(ght, u, v);a!=INVALID;++a) - sum+=capacity[a]; - check(sum == ght.minCutValue(u, v), "Problem with MinCutEdgeIt"); - - sum=0; - for(GomoryHu::MinCutNodeIt n(ght, u, v,true);n!=INVALID;++n) - sum++; - for(GomoryHu::MinCutNodeIt n(ght, u, v,false);n!=INVALID;++n) - sum++; - check(sum == countNodes(graph), "Problem with MinCutNodeIt"); - } - } - - return 0; -} diff --git a/deps/lemon/test/graph_copy_test.cc b/deps/lemon/test/graph_copy_test.cc deleted file mode 100644 index 9a7d8155e..000000000 --- a/deps/lemon/test/graph_copy_test.cc +++ /dev/null @@ -1,388 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include -#include - -#include "test_tools.h" - -using namespace std; -using namespace lemon; - -template -void digraph_copy_test() { - const int nn = 10; - - // Build a digraph - SmartDigraph from; - SmartDigraph::NodeMap fnm(from); - SmartDigraph::ArcMap fam(from); - SmartDigraph::Node fn = INVALID; - SmartDigraph::Arc fa = INVALID; - - std::vector fnv; - for (int i = 0; i < nn; ++i) { - SmartDigraph::Node node = from.addNode(); - fnv.push_back(node); - fnm[node] = i * i; - if (i == 0) fn = node; - } - - for (int i = 0; i < nn; ++i) { - for (int j = 0; j < nn; ++j) { - SmartDigraph::Arc arc = from.addArc(fnv[i], fnv[j]); - fam[arc] = i + j * j; - if (i == 0 && j == 0) fa = arc; - } - } - - // Test digraph copy - GR to; - typename GR::template NodeMap tnm(to); - typename GR::template ArcMap tam(to); - typename GR::Node tn; - typename GR::Arc ta; - - SmartDigraph::NodeMap nr(from); - SmartDigraph::ArcMap er(from); - - typename GR::template NodeMap ncr(to); - typename GR::template ArcMap ecr(to); - - digraphCopy(from, to). - nodeMap(fnm, tnm).arcMap(fam, tam). - nodeRef(nr).arcRef(er). - nodeCrossRef(ncr).arcCrossRef(ecr). - node(fn, tn).arc(fa, ta).run(); - - check(countNodes(from) == countNodes(to), "Wrong copy."); - check(countArcs(from) == countArcs(to), "Wrong copy."); - - for (SmartDigraph::NodeIt it(from); it != INVALID; ++it) { - check(ncr[nr[it]] == it, "Wrong copy."); - check(fnm[it] == tnm[nr[it]], "Wrong copy."); - } - - for (SmartDigraph::ArcIt it(from); it != INVALID; ++it) { - check(ecr[er[it]] == it, "Wrong copy."); - check(fam[it] == tam[er[it]], "Wrong copy."); - check(nr[from.source(it)] == to.source(er[it]), "Wrong copy."); - check(nr[from.target(it)] == to.target(er[it]), "Wrong copy."); - } - - for (typename GR::NodeIt it(to); it != INVALID; ++it) { - check(nr[ncr[it]] == it, "Wrong copy."); - } - - for (typename GR::ArcIt it(to); it != INVALID; ++it) { - check(er[ecr[it]] == it, "Wrong copy."); - } - check(tn == nr[fn], "Wrong copy."); - check(ta == er[fa], "Wrong copy."); - - // Test repeated copy - digraphCopy(from, to).run(); - - check(countNodes(from) == countNodes(to), "Wrong copy."); - check(countArcs(from) == countArcs(to), "Wrong copy."); -} - -template -void graph_copy_test() { - const int nn = 10; - - // Build a graph - SmartGraph from; - SmartGraph::NodeMap fnm(from); - SmartGraph::ArcMap fam(from); - SmartGraph::EdgeMap fem(from); - SmartGraph::Node fn = INVALID; - SmartGraph::Arc fa = INVALID; - SmartGraph::Edge fe = INVALID; - - std::vector fnv; - for (int i = 0; i < nn; ++i) { - SmartGraph::Node node = from.addNode(); - fnv.push_back(node); - fnm[node] = i * i; - if (i == 0) fn = node; - } - - for (int i = 0; i < nn; ++i) { - for (int j = 0; j < nn; ++j) { - SmartGraph::Edge edge = from.addEdge(fnv[i], fnv[j]); - fem[edge] = i * i + j * j; - fam[from.direct(edge, true)] = i + j * j; - fam[from.direct(edge, false)] = i * i + j; - if (i == 0 && j == 0) fa = from.direct(edge, true); - if (i == 0 && j == 0) fe = edge; - } - } - - // Test graph copy - GR to; - typename GR::template NodeMap tnm(to); - typename GR::template ArcMap tam(to); - typename GR::template EdgeMap tem(to); - typename GR::Node tn; - typename GR::Arc ta; - typename GR::Edge te; - - SmartGraph::NodeMap nr(from); - SmartGraph::ArcMap ar(from); - SmartGraph::EdgeMap er(from); - - typename GR::template NodeMap ncr(to); - typename GR::template ArcMap acr(to); - typename GR::template EdgeMap ecr(to); - - graphCopy(from, to). - nodeMap(fnm, tnm).arcMap(fam, tam).edgeMap(fem, tem). - nodeRef(nr).arcRef(ar).edgeRef(er). - nodeCrossRef(ncr).arcCrossRef(acr).edgeCrossRef(ecr). - node(fn, tn).arc(fa, ta).edge(fe, te).run(); - - check(countNodes(from) == countNodes(to), "Wrong copy."); - check(countEdges(from) == countEdges(to), "Wrong copy."); - check(countArcs(from) == countArcs(to), "Wrong copy."); - - for (SmartGraph::NodeIt it(from); it != INVALID; ++it) { - check(ncr[nr[it]] == it, "Wrong copy."); - check(fnm[it] == tnm[nr[it]], "Wrong copy."); - } - - for (SmartGraph::ArcIt it(from); it != INVALID; ++it) { - check(acr[ar[it]] == it, "Wrong copy."); - check(fam[it] == tam[ar[it]], "Wrong copy."); - check(nr[from.source(it)] == to.source(ar[it]), "Wrong copy."); - check(nr[from.target(it)] == to.target(ar[it]), "Wrong copy."); - } - - for (SmartGraph::EdgeIt it(from); it != INVALID; ++it) { - check(ecr[er[it]] == it, "Wrong copy."); - check(fem[it] == tem[er[it]], "Wrong copy."); - check(nr[from.u(it)] == to.u(er[it]) || nr[from.u(it)] == to.v(er[it]), - "Wrong copy."); - check(nr[from.v(it)] == to.u(er[it]) || nr[from.v(it)] == to.v(er[it]), - "Wrong copy."); - check((from.u(it) != from.v(it)) == (to.u(er[it]) != to.v(er[it])), - "Wrong copy."); - } - - for (typename GR::NodeIt it(to); it != INVALID; ++it) { - check(nr[ncr[it]] == it, "Wrong copy."); - } - - for (typename GR::ArcIt it(to); it != INVALID; ++it) { - check(ar[acr[it]] == it, "Wrong copy."); - } - for (typename GR::EdgeIt it(to); it != INVALID; ++it) { - check(er[ecr[it]] == it, "Wrong copy."); - } - check(tn == nr[fn], "Wrong copy."); - check(ta == ar[fa], "Wrong copy."); - check(te == er[fe], "Wrong copy."); - - // Test repeated copy - graphCopy(from, to).run(); - - check(countNodes(from) == countNodes(to), "Wrong copy."); - check(countEdges(from) == countEdges(to), "Wrong copy."); - check(countArcs(from) == countArcs(to), "Wrong copy."); -} - -template -void bpgraph_copy_test() { - const int nn = 10; - - // Build a graph - SmartBpGraph from; - SmartBpGraph::NodeMap fnm(from); - SmartBpGraph::RedNodeMap frnm(from); - SmartBpGraph::BlueNodeMap fbnm(from); - SmartBpGraph::ArcMap fam(from); - SmartBpGraph::EdgeMap fem(from); - SmartBpGraph::Node fn = INVALID; - SmartBpGraph::RedNode frn = INVALID; - SmartBpGraph::BlueNode fbn = INVALID; - SmartBpGraph::Arc fa = INVALID; - SmartBpGraph::Edge fe = INVALID; - - std::vector frnv; - for (int i = 0; i < nn; ++i) { - SmartBpGraph::RedNode node = from.addRedNode(); - frnv.push_back(node); - fnm[node] = i * i; - frnm[node] = i + i; - if (i == 0) { - fn = node; - frn = node; - } - } - - std::vector fbnv; - for (int i = 0; i < nn; ++i) { - SmartBpGraph::BlueNode node = from.addBlueNode(); - fbnv.push_back(node); - fnm[node] = i * i; - fbnm[node] = i + i; - if (i == 0) fbn = node; - } - - for (int i = 0; i < nn; ++i) { - for (int j = 0; j < nn; ++j) { - SmartBpGraph::Edge edge = from.addEdge(frnv[i], fbnv[j]); - fem[edge] = i * i + j * j; - fam[from.direct(edge, true)] = i + j * j; - fam[from.direct(edge, false)] = i * i + j; - if (i == 0 && j == 0) fa = from.direct(edge, true); - if (i == 0 && j == 0) fe = edge; - } - } - - // Test graph copy - GR to; - typename GR::template NodeMap tnm(to); - typename GR::template RedNodeMap trnm(to); - typename GR::template BlueNodeMap tbnm(to); - typename GR::template ArcMap tam(to); - typename GR::template EdgeMap tem(to); - typename GR::Node tn; - typename GR::RedNode trn; - typename GR::BlueNode tbn; - typename GR::Arc ta; - typename GR::Edge te; - - SmartBpGraph::NodeMap nr(from); - SmartBpGraph::RedNodeMap rnr(from); - SmartBpGraph::BlueNodeMap bnr(from); - SmartBpGraph::ArcMap ar(from); - SmartBpGraph::EdgeMap er(from); - - typename GR::template NodeMap ncr(to); - typename GR::template RedNodeMap rncr(to); - typename GR::template BlueNodeMap bncr(to); - typename GR::template ArcMap acr(to); - typename GR::template EdgeMap ecr(to); - - bpGraphCopy(from, to). - nodeMap(fnm, tnm). - redNodeMap(frnm, trnm).blueNodeMap(fbnm, tbnm). - arcMap(fam, tam).edgeMap(fem, tem). - nodeRef(nr).redRef(rnr).blueRef(bnr). - arcRef(ar).edgeRef(er). - nodeCrossRef(ncr).redCrossRef(rncr).blueCrossRef(bncr). - arcCrossRef(acr).edgeCrossRef(ecr). - node(fn, tn).redNode(frn, trn).blueNode(fbn, tbn). - arc(fa, ta).edge(fe, te).run(); - - check(countNodes(from) == countNodes(to), "Wrong copy."); - check(countRedNodes(from) == countRedNodes(to), "Wrong copy."); - check(countBlueNodes(from) == countBlueNodes(to), "Wrong copy."); - check(countEdges(from) == countEdges(to), "Wrong copy."); - check(countArcs(from) == countArcs(to), "Wrong copy."); - - for (SmartBpGraph::NodeIt it(from); it != INVALID; ++it) { - check(ncr[nr[it]] == it, "Wrong copy."); - check(fnm[it] == tnm[nr[it]], "Wrong copy."); - } - - for (SmartBpGraph::RedNodeIt it(from); it != INVALID; ++it) { - check(ncr[nr[it]] == it, "Wrong copy."); - check(fnm[it] == tnm[nr[it]], "Wrong copy."); - check(rnr[it] == nr[it], "Wrong copy."); - check(rncr[rnr[it]] == it, "Wrong copy."); - check(frnm[it] == trnm[rnr[it]], "Wrong copy."); - check(to.red(rnr[it]), "Wrong copy."); - } - - for (SmartBpGraph::BlueNodeIt it(from); it != INVALID; ++it) { - check(ncr[nr[it]] == it, "Wrong copy."); - check(fnm[it] == tnm[nr[it]], "Wrong copy."); - check(bnr[it] == nr[it], "Wrong copy."); - check(bncr[bnr[it]] == it, "Wrong copy."); - check(fbnm[it] == tbnm[bnr[it]], "Wrong copy."); - check(to.blue(bnr[it]), "Wrong copy."); - } - - for (SmartBpGraph::ArcIt it(from); it != INVALID; ++it) { - check(acr[ar[it]] == it, "Wrong copy."); - check(fam[it] == tam[ar[it]], "Wrong copy."); - check(nr[from.source(it)] == to.source(ar[it]), "Wrong copy."); - check(nr[from.target(it)] == to.target(ar[it]), "Wrong copy."); - } - - for (SmartBpGraph::EdgeIt it(from); it != INVALID; ++it) { - check(ecr[er[it]] == it, "Wrong copy."); - check(fem[it] == tem[er[it]], "Wrong copy."); - check(nr[from.u(it)] == to.u(er[it]) || nr[from.u(it)] == to.v(er[it]), - "Wrong copy."); - check(nr[from.v(it)] == to.u(er[it]) || nr[from.v(it)] == to.v(er[it]), - "Wrong copy."); - check((from.u(it) != from.v(it)) == (to.u(er[it]) != to.v(er[it])), - "Wrong copy."); - } - - for (typename GR::NodeIt it(to); it != INVALID; ++it) { - check(nr[ncr[it]] == it, "Wrong copy."); - } - for (typename GR::RedNodeIt it(to); it != INVALID; ++it) { - check(rncr[it] == ncr[it], "Wrong copy."); - check(rnr[rncr[it]] == it, "Wrong copy."); - } - for (typename GR::BlueNodeIt it(to); it != INVALID; ++it) { - check(bncr[it] == ncr[it], "Wrong copy."); - check(bnr[bncr[it]] == it, "Wrong copy."); - } - for (typename GR::ArcIt it(to); it != INVALID; ++it) { - check(ar[acr[it]] == it, "Wrong copy."); - } - for (typename GR::EdgeIt it(to); it != INVALID; ++it) { - check(er[ecr[it]] == it, "Wrong copy."); - } - check(tn == nr[fn], "Wrong copy."); - check(trn == rnr[frn], "Wrong copy."); - check(tbn == bnr[fbn], "Wrong copy."); - check(ta == ar[fa], "Wrong copy."); - check(te == er[fe], "Wrong copy."); - - // Test repeated copy - bpGraphCopy(from, to).run(); - - check(countNodes(from) == countNodes(to), "Wrong copy."); - check(countRedNodes(from) == countRedNodes(to), "Wrong copy."); - check(countBlueNodes(from) == countBlueNodes(to), "Wrong copy."); - check(countEdges(from) == countEdges(to), "Wrong copy."); - check(countArcs(from) == countArcs(to), "Wrong copy."); -} - - -int main() { - digraph_copy_test(); - digraph_copy_test(); - digraph_copy_test(); - graph_copy_test(); - graph_copy_test(); - bpgraph_copy_test(); - bpgraph_copy_test(); - - return 0; -} diff --git a/deps/lemon/test/graph_test.cc b/deps/lemon/test/graph_test.cc deleted file mode 100644 index 283b02ef5..000000000 --- a/deps/lemon/test/graph_test.cc +++ /dev/null @@ -1,603 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "test_tools.h" -#include "graph_test.h" - -using namespace lemon; -using namespace lemon::concepts; - -template -void checkGraphBuild() { - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - Graph G; - checkGraphNodeList(G, 0); - checkGraphEdgeList(G, 0); - checkGraphArcList(G, 0); - - G.reserveNode(3); - G.reserveEdge(3); - - Node - n1 = G.addNode(), - n2 = G.addNode(), - n3 = G.addNode(); - checkGraphNodeList(G, 3); - checkGraphEdgeList(G, 0); - checkGraphArcList(G, 0); - - Edge e1 = G.addEdge(n1, n2); - check((G.u(e1) == n1 && G.v(e1) == n2) || (G.u(e1) == n2 && G.v(e1) == n1), - "Wrong edge"); - - checkGraphNodeList(G, 3); - checkGraphEdgeList(G, 1); - checkGraphArcList(G, 2); - - checkGraphIncEdgeArcLists(G, n1, 1); - checkGraphIncEdgeArcLists(G, n2, 1); - checkGraphIncEdgeArcLists(G, n3, 0); - - checkGraphConEdgeList(G, 1); - checkGraphConArcList(G, 2); - - Edge e2 = G.addEdge(n2, n1), - e3 = G.addEdge(n2, n3); - ::lemon::ignore_unused_variable_warning(e2,e3); - - checkGraphNodeList(G, 3); - checkGraphEdgeList(G, 3); - checkGraphArcList(G, 6); - - checkGraphIncEdgeArcLists(G, n1, 2); - checkGraphIncEdgeArcLists(G, n2, 3); - checkGraphIncEdgeArcLists(G, n3, 1); - - checkGraphConEdgeList(G, 3); - checkGraphConArcList(G, 6); - - checkArcDirections(G); - - checkNodeIds(G); - checkArcIds(G); - checkEdgeIds(G); - checkGraphNodeMap(G); - checkGraphArcMap(G); - checkGraphEdgeMap(G); -} - -template -void checkGraphAlter() { - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - Graph G; - Node n1 = G.addNode(), n2 = G.addNode(), - n3 = G.addNode(), n4 = G.addNode(); - Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1), - e3 = G.addEdge(n2, n3), e4 = G.addEdge(n1, n4), - e5 = G.addEdge(n4, n3); - ::lemon::ignore_unused_variable_warning(e1,e3,e4,e5); - - checkGraphNodeList(G, 4); - checkGraphEdgeList(G, 5); - checkGraphArcList(G, 10); - - // Check changeU() and changeV() - if (G.u(e2) == n2) { - G.changeU(e2, n3); - } else { - G.changeV(e2, n3); - } - - checkGraphNodeList(G, 4); - checkGraphEdgeList(G, 5); - checkGraphArcList(G, 10); - - checkGraphIncEdgeArcLists(G, n1, 3); - checkGraphIncEdgeArcLists(G, n2, 2); - checkGraphIncEdgeArcLists(G, n3, 3); - checkGraphIncEdgeArcLists(G, n4, 2); - - checkGraphConEdgeList(G, 5); - checkGraphConArcList(G, 10); - - if (G.u(e2) == n1) { - G.changeU(e2, n2); - } else { - G.changeV(e2, n2); - } - - checkGraphNodeList(G, 4); - checkGraphEdgeList(G, 5); - checkGraphArcList(G, 10); - - checkGraphIncEdgeArcLists(G, n1, 2); - checkGraphIncEdgeArcLists(G, n2, 3); - checkGraphIncEdgeArcLists(G, n3, 3); - checkGraphIncEdgeArcLists(G, n4, 2); - - checkGraphConEdgeList(G, 5); - checkGraphConArcList(G, 10); - - // Check contract() - G.contract(n1, n4, false); - - checkGraphNodeList(G, 3); - checkGraphEdgeList(G, 5); - checkGraphArcList(G, 10); - - checkGraphIncEdgeArcLists(G, n1, 4); - checkGraphIncEdgeArcLists(G, n2, 3); - checkGraphIncEdgeArcLists(G, n3, 3); - - checkGraphConEdgeList(G, 5); - checkGraphConArcList(G, 10); - - G.contract(n2, n3); - - checkGraphNodeList(G, 2); - checkGraphEdgeList(G, 3); - checkGraphArcList(G, 6); - - checkGraphIncEdgeArcLists(G, n1, 4); - checkGraphIncEdgeArcLists(G, n2, 2); - - checkGraphConEdgeList(G, 3); - checkGraphConArcList(G, 6); -} - -template -void checkGraphErase() { - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - Graph G; - Node n1 = G.addNode(), n2 = G.addNode(), - n3 = G.addNode(), n4 = G.addNode(); - Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1), - e3 = G.addEdge(n2, n3), e4 = G.addEdge(n1, n4), - e5 = G.addEdge(n4, n3); - ::lemon::ignore_unused_variable_warning(e1,e3,e4,e5); - - // Check edge deletion - G.erase(e2); - - checkGraphNodeList(G, 4); - checkGraphEdgeList(G, 4); - checkGraphArcList(G, 8); - - checkGraphIncEdgeArcLists(G, n1, 2); - checkGraphIncEdgeArcLists(G, n2, 2); - checkGraphIncEdgeArcLists(G, n3, 2); - checkGraphIncEdgeArcLists(G, n4, 2); - - checkGraphConEdgeList(G, 4); - checkGraphConArcList(G, 8); - - // Check node deletion - G.erase(n3); - - checkGraphNodeList(G, 3); - checkGraphEdgeList(G, 2); - checkGraphArcList(G, 4); - - checkGraphIncEdgeArcLists(G, n1, 2); - checkGraphIncEdgeArcLists(G, n2, 1); - checkGraphIncEdgeArcLists(G, n4, 1); - - checkGraphConEdgeList(G, 2); - checkGraphConArcList(G, 4); -} - - -template -void checkGraphSnapshot() { - TEMPLATE_GRAPH_TYPEDEFS(Graph); - - Graph G; - Node n1 = G.addNode(), n2 = G.addNode(), n3 = G.addNode(); - Edge e1 = G.addEdge(n1, n2), e2 = G.addEdge(n2, n1), - e3 = G.addEdge(n2, n3); - ::lemon::ignore_unused_variable_warning(e1,e2,e3); - - checkGraphNodeList(G, 3); - checkGraphEdgeList(G, 3); - checkGraphArcList(G, 6); - - typename Graph::Snapshot snapshot(G); - - Node n = G.addNode(); - G.addEdge(n3, n); - G.addEdge(n, n3); - G.addEdge(n3, n2); - - checkGraphNodeList(G, 4); - checkGraphEdgeList(G, 6); - checkGraphArcList(G, 12); - - snapshot.restore(); - - checkGraphNodeList(G, 3); - checkGraphEdgeList(G, 3); - checkGraphArcList(G, 6); - - checkGraphIncEdgeArcLists(G, n1, 2); - checkGraphIncEdgeArcLists(G, n2, 3); - checkGraphIncEdgeArcLists(G, n3, 1); - - checkGraphConEdgeList(G, 3); - checkGraphConArcList(G, 6); - - checkNodeIds(G); - checkEdgeIds(G); - checkArcIds(G); - checkGraphNodeMap(G); - checkGraphEdgeMap(G); - checkGraphArcMap(G); - - G.addNode(); - snapshot.save(G); - - G.addEdge(G.addNode(), G.addNode()); - - snapshot.restore(); - snapshot.save(G); - - checkGraphNodeList(G, 4); - checkGraphEdgeList(G, 3); - checkGraphArcList(G, 6); - - G.addEdge(G.addNode(), G.addNode()); - - snapshot.restore(); - - checkGraphNodeList(G, 4); - checkGraphEdgeList(G, 3); - checkGraphArcList(G, 6); -} - -void checkFullGraph(int num) { - typedef FullGraph Graph; - GRAPH_TYPEDEFS(Graph); - - Graph G(num); - check(G.nodeNum() == num && G.edgeNum() == num * (num - 1) / 2, - "Wrong size"); - - G.resize(num); - check(G.nodeNum() == num && G.edgeNum() == num * (num - 1) / 2, - "Wrong size"); - - checkGraphNodeList(G, num); - checkGraphEdgeList(G, num * (num - 1) / 2); - - for (NodeIt n(G); n != INVALID; ++n) { - checkGraphOutArcList(G, n, num - 1); - checkGraphInArcList(G, n, num - 1); - checkGraphIncEdgeList(G, n, num - 1); - } - - checkGraphConArcList(G, num * (num - 1)); - checkGraphConEdgeList(G, num * (num - 1) / 2); - - checkArcDirections(G); - - checkNodeIds(G); - checkArcIds(G); - checkEdgeIds(G); - checkGraphNodeMap(G); - checkGraphArcMap(G); - checkGraphEdgeMap(G); - - - for (int i = 0; i < G.nodeNum(); ++i) { - check(G.index(G(i)) == i, "Wrong index"); - } - - for (NodeIt u(G); u != INVALID; ++u) { - for (NodeIt v(G); v != INVALID; ++v) { - Edge e = G.edge(u, v); - Arc a = G.arc(u, v); - if (u == v) { - check(e == INVALID, "Wrong edge lookup"); - check(a == INVALID, "Wrong arc lookup"); - } else { - check((G.u(e) == u && G.v(e) == v) || - (G.u(e) == v && G.v(e) == u), "Wrong edge lookup"); - check(G.source(a) == u && G.target(a) == v, "Wrong arc lookup"); - } - } - } -} - -void checkConcepts() { - { // Checking graph components - checkConcept(); - - checkConcept, - IDableGraphComponent<> >(); - - checkConcept, - IterableGraphComponent<> >(); - - checkConcept, - MappableGraphComponent<> >(); - } - { // Checking skeleton graph - checkConcept(); - } - { // Checking ListGraph - checkConcept(); - checkConcept, ListGraph>(); - checkConcept, ListGraph>(); - checkConcept, ListGraph>(); - checkConcept, ListGraph>(); - } - { // Checking SmartGraph - checkConcept(); - checkConcept, SmartGraph>(); - checkConcept, SmartGraph>(); - checkConcept, SmartGraph>(); - } - { // Checking FullGraph - checkConcept(); - } - { // Checking GridGraph - checkConcept(); - } - { // Checking HypercubeGraph - checkConcept(); - } -} - -template -void checkGraphValidity() { - TEMPLATE_GRAPH_TYPEDEFS(Graph); - Graph g; - - Node - n1 = g.addNode(), - n2 = g.addNode(), - n3 = g.addNode(); - - Edge - e1 = g.addEdge(n1, n2), - e2 = g.addEdge(n2, n3); - ::lemon::ignore_unused_variable_warning(e2); - - check(g.valid(n1), "Wrong validity check"); - check(g.valid(e1), "Wrong validity check"); - check(g.valid(g.direct(e1, true)), "Wrong validity check"); - - check(!g.valid(g.nodeFromId(-1)), "Wrong validity check"); - check(!g.valid(g.edgeFromId(-1)), "Wrong validity check"); - check(!g.valid(g.arcFromId(-1)), "Wrong validity check"); -} - -template -void checkGraphValidityErase() { - TEMPLATE_GRAPH_TYPEDEFS(Graph); - Graph g; - - Node - n1 = g.addNode(), - n2 = g.addNode(), - n3 = g.addNode(); - - Edge - e1 = g.addEdge(n1, n2), - e2 = g.addEdge(n2, n3); - - check(g.valid(n1), "Wrong validity check"); - check(g.valid(e1), "Wrong validity check"); - check(g.valid(g.direct(e1, true)), "Wrong validity check"); - - g.erase(n1); - - check(!g.valid(n1), "Wrong validity check"); - check(g.valid(n2), "Wrong validity check"); - check(g.valid(n3), "Wrong validity check"); - check(!g.valid(e1), "Wrong validity check"); - check(g.valid(e2), "Wrong validity check"); - - check(!g.valid(g.nodeFromId(-1)), "Wrong validity check"); - check(!g.valid(g.edgeFromId(-1)), "Wrong validity check"); - check(!g.valid(g.arcFromId(-1)), "Wrong validity check"); -} - -void checkGridGraph(int width, int height) { - typedef GridGraph Graph; - GRAPH_TYPEDEFS(Graph); - Graph G(width, height); - - check(G.width() == width, "Wrong column number"); - check(G.height() == height, "Wrong row number"); - - G.resize(width, height); - check(G.width() == width, "Wrong column number"); - check(G.height() == height, "Wrong row number"); - - for (int i = 0; i < width; ++i) { - for (int j = 0; j < height; ++j) { - check(G.col(G(i, j)) == i, "Wrong column"); - check(G.row(G(i, j)) == j, "Wrong row"); - check(G.pos(G(i, j)).x == i, "Wrong column"); - check(G.pos(G(i, j)).y == j, "Wrong row"); - } - } - - for (int j = 0; j < height; ++j) { - for (int i = 0; i < width - 1; ++i) { - check(G.source(G.right(G(i, j))) == G(i, j), "Wrong right"); - check(G.target(G.right(G(i, j))) == G(i + 1, j), "Wrong right"); - } - check(G.right(G(width - 1, j)) == INVALID, "Wrong right"); - } - - for (int j = 0; j < height; ++j) { - for (int i = 1; i < width; ++i) { - check(G.source(G.left(G(i, j))) == G(i, j), "Wrong left"); - check(G.target(G.left(G(i, j))) == G(i - 1, j), "Wrong left"); - } - check(G.left(G(0, j)) == INVALID, "Wrong left"); - } - - for (int i = 0; i < width; ++i) { - for (int j = 0; j < height - 1; ++j) { - check(G.source(G.up(G(i, j))) == G(i, j), "Wrong up"); - check(G.target(G.up(G(i, j))) == G(i, j + 1), "Wrong up"); - } - check(G.up(G(i, height - 1)) == INVALID, "Wrong up"); - } - - for (int i = 0; i < width; ++i) { - for (int j = 1; j < height; ++j) { - check(G.source(G.down(G(i, j))) == G(i, j), "Wrong down"); - check(G.target(G.down(G(i, j))) == G(i, j - 1), "Wrong down"); - } - check(G.down(G(i, 0)) == INVALID, "Wrong down"); - } - - checkGraphNodeList(G, width * height); - checkGraphEdgeList(G, width * (height - 1) + (width - 1) * height); - checkGraphArcList(G, 2 * (width * (height - 1) + (width - 1) * height)); - - for (NodeIt n(G); n != INVALID; ++n) { - int nb = 4; - if (G.col(n) == 0) --nb; - if (G.col(n) == width - 1) --nb; - if (G.row(n) == 0) --nb; - if (G.row(n) == height - 1) --nb; - - checkGraphOutArcList(G, n, nb); - checkGraphInArcList(G, n, nb); - checkGraphIncEdgeList(G, n, nb); - } - - checkArcDirections(G); - - checkGraphConArcList(G, 2 * (width * (height - 1) + (width - 1) * height)); - checkGraphConEdgeList(G, width * (height - 1) + (width - 1) * height); - - checkNodeIds(G); - checkArcIds(G); - checkEdgeIds(G); - checkGraphNodeMap(G); - checkGraphArcMap(G); - checkGraphEdgeMap(G); - -} - -void checkHypercubeGraph(int dim) { - GRAPH_TYPEDEFS(HypercubeGraph); - - HypercubeGraph G(dim); - check(G.dimension() == dim, "Wrong dimension"); - - G.resize(dim); - check(G.dimension() == dim, "Wrong dimension"); - - checkGraphNodeList(G, 1 << dim); - checkGraphEdgeList(G, dim * (1 << (dim-1))); - checkGraphArcList(G, dim * (1 << dim)); - - Node n = G.nodeFromId(dim); - ::lemon::ignore_unused_variable_warning(n); - - for (NodeIt n(G); n != INVALID; ++n) { - checkGraphIncEdgeList(G, n, dim); - for (IncEdgeIt e(G, n); e != INVALID; ++e) { - check( (G.u(e) == n && - G.id(G.v(e)) == (G.id(n) ^ (1 << G.dimension(e)))) || - (G.v(e) == n && - G.id(G.u(e)) == (G.id(n) ^ (1 << G.dimension(e)))), - "Wrong edge or wrong dimension"); - } - - checkGraphOutArcList(G, n, dim); - for (OutArcIt a(G, n); a != INVALID; ++a) { - check(G.source(a) == n && - G.id(G.target(a)) == (G.id(n) ^ (1 << G.dimension(a))), - "Wrong arc or wrong dimension"); - } - - checkGraphInArcList(G, n, dim); - for (InArcIt a(G, n); a != INVALID; ++a) { - check(G.target(a) == n && - G.id(G.source(a)) == (G.id(n) ^ (1 << G.dimension(a))), - "Wrong arc or wrong dimension"); - } - } - - checkGraphConArcList(G, (1 << dim) * dim); - checkGraphConEdgeList(G, dim * (1 << (dim-1))); - - checkArcDirections(G); - - checkNodeIds(G); - checkArcIds(G); - checkEdgeIds(G); - checkGraphNodeMap(G); - checkGraphArcMap(G); - checkGraphEdgeMap(G); -} - -void checkGraphs() { - { // Checking ListGraph - checkGraphBuild(); - checkGraphAlter(); - checkGraphErase(); - checkGraphSnapshot(); - checkGraphValidityErase(); - } - { // Checking SmartGraph - checkGraphBuild(); - checkGraphSnapshot(); - checkGraphValidity(); - } - { // Checking FullGraph - checkFullGraph(7); - checkFullGraph(8); - } - { // Checking GridGraph - checkGridGraph(5, 8); - checkGridGraph(8, 5); - checkGridGraph(5, 5); - checkGridGraph(0, 0); - checkGridGraph(1, 1); - } - { // Checking HypercubeGraph - checkHypercubeGraph(1); - checkHypercubeGraph(2); - checkHypercubeGraph(3); - checkHypercubeGraph(4); - } -} - -int main() { - checkConcepts(); - checkGraphs(); - return 0; -} diff --git a/deps/lemon/test/graph_test.h b/deps/lemon/test/graph_test.h deleted file mode 100644 index 70558b768..000000000 --- a/deps/lemon/test/graph_test.h +++ /dev/null @@ -1,421 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_TEST_GRAPH_TEST_H -#define LEMON_TEST_GRAPH_TEST_H - -#include - -#include -#include - -#include "test_tools.h" - -namespace lemon { - - template - void checkGraphNodeList(const Graph &G, int cnt) - { - typename Graph::NodeIt n(G); - for(int i=0;i - void checkGraphRedNodeList(const Graph &G, int cnt) - { - typename Graph::RedNodeIt n(G); - for(int i=0;i - void checkGraphBlueNodeList(const Graph &G, int cnt) - { - typename Graph::BlueNodeIt n(G); - for(int i=0;i - void checkGraphArcList(const Graph &G, int cnt) - { - typename Graph::ArcIt e(G); - for(int i=0;i - void checkGraphOutArcList(const Graph &G, typename Graph::Node n, int cnt) - { - typename Graph::OutArcIt e(G,n); - for(int i=0;i - void checkGraphInArcList(const Graph &G, typename Graph::Node n, int cnt) - { - typename Graph::InArcIt e(G,n); - for(int i=0;i - void checkGraphEdgeList(const Graph &G, int cnt) - { - typename Graph::EdgeIt e(G); - for(int i=0;i - void checkGraphIncEdgeList(const Graph &G, typename Graph::Node n, int cnt) - { - typename Graph::IncEdgeIt e(G,n); - for(int i=0;i - void checkGraphIncEdgeArcLists(const Graph &G, typename Graph::Node n, - int cnt) - { - checkGraphIncEdgeList(G, n, cnt); - checkGraphOutArcList(G, n, cnt); - checkGraphInArcList(G, n, cnt); - } - - template - void checkGraphConArcList(const Graph &G, int cnt) { - int i = 0; - for (typename Graph::NodeIt u(G); u != INVALID; ++u) { - for (typename Graph::NodeIt v(G); v != INVALID; ++v) { - for (ConArcIt a(G, u, v); a != INVALID; ++a) { - check(G.source(a) == u, "Wrong iterator."); - check(G.target(a) == v, "Wrong iterator."); - ++i; - } - } - } - check(cnt == i, "Wrong iterator."); - } - - template - void checkGraphConEdgeList(const Graph &G, int cnt) { - int i = 0; - for (typename Graph::NodeIt u(G); u != INVALID; ++u) { - for (typename Graph::NodeIt v(G); v != INVALID; ++v) { - for (ConEdgeIt e(G, u, v); e != INVALID; ++e) { - check((G.u(e) == u && G.v(e) == v) || - (G.u(e) == v && G.v(e) == u), "Wrong iterator."); - i += u == v ? 2 : 1; - } - } - } - check(2 * cnt == i, "Wrong iterator."); - } - - template - void checkArcDirections(const Graph& G) { - for (typename Graph::ArcIt a(G); a != INVALID; ++a) { - check(G.source(a) == G.target(G.oppositeArc(a)), "Wrong direction"); - check(G.target(a) == G.source(G.oppositeArc(a)), "Wrong direction"); - check(G.direct(a, G.direction(a)) == a, "Wrong direction"); - } - } - - template - void checkNodeIds(const Graph& G) { - typedef typename Graph::Node Node; - std::set values; - for (typename Graph::NodeIt n(G); n != INVALID; ++n) { - check(G.nodeFromId(G.id(n)) == n, "Wrong id"); - check(values.find(G.id(n)) == values.end(), "Wrong id"); - check(G.id(n) <= G.maxNodeId(), "Wrong maximum id"); - values.insert(G.id(n)); - } - check(G.maxId(Node()) <= G.maxNodeId(), "Wrong maximum id"); - } - - template - void checkRedNodeIds(const Graph& G) { - typedef typename Graph::RedNode RedNode; - std::set values; - for (typename Graph::RedNodeIt n(G); n != INVALID; ++n) { - check(G.red(n), "Wrong partition"); - check(values.find(G.id(n)) == values.end(), "Wrong id"); - check(G.id(n) <= G.maxRedId(), "Wrong maximum id"); - values.insert(G.id(n)); - } - check(G.maxId(RedNode()) == G.maxRedId(), "Wrong maximum id"); - } - - template - void checkBlueNodeIds(const Graph& G) { - typedef typename Graph::BlueNode BlueNode; - std::set values; - for (typename Graph::BlueNodeIt n(G); n != INVALID; ++n) { - check(G.blue(n), "Wrong partition"); - check(values.find(G.id(n)) == values.end(), "Wrong id"); - check(G.id(n) <= G.maxBlueId(), "Wrong maximum id"); - values.insert(G.id(n)); - } - check(G.maxId(BlueNode()) == G.maxBlueId(), "Wrong maximum id"); - } - - template - void checkArcIds(const Graph& G) { - typedef typename Graph::Arc Arc; - std::set values; - for (typename Graph::ArcIt a(G); a != INVALID; ++a) { - check(G.arcFromId(G.id(a)) == a, "Wrong id"); - check(values.find(G.id(a)) == values.end(), "Wrong id"); - check(G.id(a) <= G.maxArcId(), "Wrong maximum id"); - values.insert(G.id(a)); - } - check(G.maxId(Arc()) <= G.maxArcId(), "Wrong maximum id"); - } - - template - void checkEdgeIds(const Graph& G) { - typedef typename Graph::Edge Edge; - std::set values; - for (typename Graph::EdgeIt e(G); e != INVALID; ++e) { - check(G.edgeFromId(G.id(e)) == e, "Wrong id"); - check(values.find(G.id(e)) == values.end(), "Wrong id"); - check(G.id(e) <= G.maxEdgeId(), "Wrong maximum id"); - values.insert(G.id(e)); - } - check(G.maxId(Edge()) <= G.maxEdgeId(), "Wrong maximum id"); - } - - template - void checkGraphNodeMap(const Graph& G) { - typedef typename Graph::Node Node; - typedef typename Graph::NodeIt NodeIt; - - typedef typename Graph::template NodeMap IntNodeMap; - IntNodeMap map(G, 42); - for (NodeIt it(G); it != INVALID; ++it) { - check(map[it] == 42, "Wrong map constructor."); - } - int s = 0; - for (NodeIt it(G); it != INVALID; ++it) { - map[it] = 0; - check(map[it] == 0, "Wrong operator[]."); - map.set(it, s); - check(map[it] == s, "Wrong set."); - ++s; - } - s = s * (s - 1) / 2; - for (NodeIt it(G); it != INVALID; ++it) { - s -= map[it]; - } - check(s == 0, "Wrong sum."); - - // map = constMap(12); - // for (NodeIt it(G); it != INVALID; ++it) { - // check(map[it] == 12, "Wrong operator[]."); - // } - } - - template - void checkGraphRedNodeMap(const Graph& G) { - typedef typename Graph::Node Node; - typedef typename Graph::RedNodeIt RedNodeIt; - - typedef typename Graph::template RedNodeMap IntRedNodeMap; - IntRedNodeMap map(G, 42); - for (RedNodeIt it(G); it != INVALID; ++it) { - check(map[it] == 42, "Wrong map constructor."); - } - int s = 0; - for (RedNodeIt it(G); it != INVALID; ++it) { - map[it] = 0; - check(map[it] == 0, "Wrong operator[]."); - map.set(it, s); - check(map[it] == s, "Wrong set."); - ++s; - } - s = s * (s - 1) / 2; - for (RedNodeIt it(G); it != INVALID; ++it) { - s -= map[it]; - } - check(s == 0, "Wrong sum."); - - // map = constMap(12); - // for (NodeIt it(G); it != INVALID; ++it) { - // check(map[it] == 12, "Wrong operator[]."); - // } - } - - template - void checkGraphBlueNodeMap(const Graph& G) { - typedef typename Graph::Node Node; - typedef typename Graph::BlueNodeIt BlueNodeIt; - - typedef typename Graph::template BlueNodeMap IntBlueNodeMap; - IntBlueNodeMap map(G, 42); - for (BlueNodeIt it(G); it != INVALID; ++it) { - check(map[it] == 42, "Wrong map constructor."); - } - int s = 0; - for (BlueNodeIt it(G); it != INVALID; ++it) { - map[it] = 0; - check(map[it] == 0, "Wrong operator[]."); - map.set(it, s); - check(map[it] == s, "Wrong set."); - ++s; - } - s = s * (s - 1) / 2; - for (BlueNodeIt it(G); it != INVALID; ++it) { - s -= map[it]; - } - check(s == 0, "Wrong sum."); - - // map = constMap(12); - // for (NodeIt it(G); it != INVALID; ++it) { - // check(map[it] == 12, "Wrong operator[]."); - // } - } - - template - void checkGraphArcMap(const Graph& G) { - typedef typename Graph::Arc Arc; - typedef typename Graph::ArcIt ArcIt; - - typedef typename Graph::template ArcMap IntArcMap; - IntArcMap map(G, 42); - for (ArcIt it(G); it != INVALID; ++it) { - check(map[it] == 42, "Wrong map constructor."); - } - int s = 0; - for (ArcIt it(G); it != INVALID; ++it) { - map[it] = 0; - check(map[it] == 0, "Wrong operator[]."); - map.set(it, s); - check(map[it] == s, "Wrong set."); - ++s; - } - s = s * (s - 1) / 2; - for (ArcIt it(G); it != INVALID; ++it) { - s -= map[it]; - } - check(s == 0, "Wrong sum."); - - // map = constMap(12); - // for (ArcIt it(G); it != INVALID; ++it) { - // check(map[it] == 12, "Wrong operator[]."); - // } - } - - template - void checkGraphEdgeMap(const Graph& G) { - typedef typename Graph::Edge Edge; - typedef typename Graph::EdgeIt EdgeIt; - - typedef typename Graph::template EdgeMap IntEdgeMap; - IntEdgeMap map(G, 42); - for (EdgeIt it(G); it != INVALID; ++it) { - check(map[it] == 42, "Wrong map constructor."); - } - int s = 0; - for (EdgeIt it(G); it != INVALID; ++it) { - map[it] = 0; - check(map[it] == 0, "Wrong operator[]."); - map.set(it, s); - check(map[it] == s, "Wrong set."); - ++s; - } - s = s * (s - 1) / 2; - for (EdgeIt it(G); it != INVALID; ++it) { - s -= map[it]; - } - check(s == 0, "Wrong sum."); - - // map = constMap(12); - // for (EdgeIt it(G); it != INVALID; ++it) { - // check(map[it] == 12, "Wrong operator[]."); - // } - } - - -} //namespace lemon - -#endif diff --git a/deps/lemon/test/graph_utils_test.cc b/deps/lemon/test/graph_utils_test.cc deleted file mode 100644 index 19a934a23..000000000 --- a/deps/lemon/test/graph_utils_test.cc +++ /dev/null @@ -1,217 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include - -#include -#include -#include -#include - -#include "graph_test.h" -#include "test_tools.h" - -using namespace lemon; - -template -void checkFindArcs() { - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - { - Digraph digraph; - for (int i = 0; i < 10; ++i) { - digraph.addNode(); - } - RangeIdMap nodes(digraph); - typename RangeIdMap::InverseMap invNodes(nodes); - for (int i = 0; i < 100; ++i) { - int src = rnd[invNodes.size()]; - int trg = rnd[invNodes.size()]; - digraph.addArc(invNodes[src], invNodes[trg]); - } - typename Digraph::template ArcMap found(digraph, false); - RangeIdMap arcs(digraph); - for (NodeIt src(digraph); src != INVALID; ++src) { - for (NodeIt trg(digraph); trg != INVALID; ++trg) { - for (ConArcIt con(digraph, src, trg); con != INVALID; ++con) { - check(digraph.source(con) == src, "Wrong source."); - check(digraph.target(con) == trg, "Wrong target."); - check(found[con] == false, "The arc found already."); - found[con] = true; - } - } - } - for (ArcIt it(digraph); it != INVALID; ++it) { - check(found[it] == true, "The arc is not found."); - } - } - - { - int num = 5; - Digraph fg; - std::vector nodes; - for (int i = 0; i < num; ++i) { - nodes.push_back(fg.addNode()); - } - for (int i = 0; i < num * num; ++i) { - fg.addArc(nodes[i / num], nodes[i % num]); - } - check(countNodes(fg) == num, "Wrong node number."); - check(countArcs(fg) == num*num, "Wrong arc number."); - for (NodeIt src(fg); src != INVALID; ++src) { - for (NodeIt trg(fg); trg != INVALID; ++trg) { - ConArcIt con(fg, src, trg); - check(con != INVALID, "There is no connecting arc."); - check(fg.source(con) == src, "Wrong source."); - check(fg.target(con) == trg, "Wrong target."); - check(++con == INVALID, "There is more connecting arc."); - } - } - ArcLookUp al1(fg); - DynArcLookUp al2(fg); - AllArcLookUp al3(fg); - for (NodeIt src(fg); src != INVALID; ++src) { - for (NodeIt trg(fg); trg != INVALID; ++trg) { - Arc con1 = al1(src, trg); - Arc con2 = al2(src, trg); - Arc con3 = al3(src, trg); - Arc con4 = findArc(fg, src, trg); - check(con1 == con2 && con2 == con3 && con3 == con4, - "Different results.") - check(con1 != INVALID, "There is no connecting arc."); - check(fg.source(con1) == src, "Wrong source."); - check(fg.target(con1) == trg, "Wrong target."); - check(al3(src, trg, con3) == INVALID, - "There is more connecting arc."); - check(findArc(fg, src, trg, con4) == INVALID, - "There is more connecting arc."); - } - } - } -} - -template -void checkFindEdges() { - TEMPLATE_GRAPH_TYPEDEFS(Graph); - Graph graph; - for (int i = 0; i < 10; ++i) { - graph.addNode(); - } - RangeIdMap nodes(graph); - typename RangeIdMap::InverseMap invNodes(nodes); - for (int i = 0; i < 100; ++i) { - int src = rnd[invNodes.size()]; - int trg = rnd[invNodes.size()]; - graph.addEdge(invNodes[src], invNodes[trg]); - } - typename Graph::template EdgeMap found(graph, 0); - RangeIdMap edges(graph); - for (NodeIt src(graph); src != INVALID; ++src) { - for (NodeIt trg(graph); trg != INVALID; ++trg) { - for (ConEdgeIt con(graph, src, trg); con != INVALID; ++con) { - check( (graph.u(con) == src && graph.v(con) == trg) || - (graph.v(con) == src && graph.u(con) == trg), - "Wrong end nodes."); - ++found[con]; - check(found[con] <= 2, "The edge found more than twice."); - } - } - } - for (EdgeIt it(graph); it != INVALID; ++it) { - check( (graph.u(it) != graph.v(it) && found[it] == 2) || - (graph.u(it) == graph.v(it) && found[it] == 1), - "The edge is not found correctly."); - } -} - -template -void checkDeg() -{ - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - const int nodeNum = 10; - const int arcNum = 100; - Digraph digraph; - InDegMap inDeg(digraph); - OutDegMap outDeg(digraph); - std::vector nodes(nodeNum); - for (int i = 0; i < nodeNum; ++i) { - nodes[i] = digraph.addNode(); - } - std::vector arcs(arcNum); - for (int i = 0; i < arcNum; ++i) { - arcs[i] = digraph.addArc(nodes[rnd[nodeNum]], nodes[rnd[nodeNum]]); - } - for (int i = 0; i < nodeNum; ++i) { - check(inDeg[nodes[i]] == countInArcs(digraph, nodes[i]), - "Wrong in degree map"); - } - for (int i = 0; i < nodeNum; ++i) { - check(outDeg[nodes[i]] == countOutArcs(digraph, nodes[i]), - "Wrong out degree map"); - } -} - -template -void checkSnapDeg() -{ - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - - Digraph g; - Node n1=g.addNode(); - Node n2=g.addNode(); - - InDegMap ind(g); - - g.addArc(n1,n2); - - typename Digraph::Snapshot snap(g); - - OutDegMap outd(g); - - check(ind[n1]==0 && ind[n2]==1, "Wrong InDegMap value."); - check(outd[n1]==1 && outd[n2]==0, "Wrong OutDegMap value."); - - g.addArc(n1,n2); - g.addArc(n2,n1); - - check(ind[n1]==1 && ind[n2]==2, "Wrong InDegMap value."); - check(outd[n1]==2 && outd[n2]==1, "Wrong OutDegMap value."); - - snap.restore(); - - check(ind[n1]==0 && ind[n2]==1, "Wrong InDegMap value."); - check(outd[n1]==1 && outd[n2]==0, "Wrong OutDegMap value."); -} - -int main() { - // Checking ConArcIt, ConEdgeIt, ArcLookUp, AllArcLookUp, and DynArcLookUp - checkFindArcs(); - checkFindArcs(); - checkFindEdges(); - checkFindEdges(); - - // Checking In/OutDegMap (and Snapshot feature) - checkDeg(); - checkDeg(); - checkSnapDeg(); - checkSnapDeg(); - - return 0; -} diff --git a/deps/lemon/test/hao_orlin_test.cc b/deps/lemon/test/hao_orlin_test.cc deleted file mode 100644 index c245cb7a7..000000000 --- a/deps/lemon/test/hao_orlin_test.cc +++ /dev/null @@ -1,164 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "test_tools.h" - -using namespace lemon; -using namespace std; - -const std::string lgf = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "@edges\n" - " cap1 cap2 cap3\n" - "0 1 1 1 1 \n" - "0 2 2 2 4 \n" - "1 2 4 4 4 \n" - "3 4 1 1 1 \n" - "3 5 2 2 4 \n" - "4 5 4 4 4 \n" - "5 4 4 4 4 \n" - "2 3 1 6 6 \n" - "4 0 1 6 6 \n"; - -void checkHaoOrlinCompile() -{ - typedef int Value; - typedef concepts::Digraph Digraph; - - typedef Digraph::Node Node; - typedef Digraph::Arc Arc; - typedef concepts::ReadMap CapMap; - typedef concepts::WriteMap CutMap; - - Digraph g; - Node n; - CapMap cap; - CutMap cut; - Value v; - ::lemon::ignore_unused_variable_warning(v); - - HaoOrlin ho_test(g, cap); - const HaoOrlin& - const_ho_test = ho_test; - - ho_test.init(); - ho_test.init(n); - ho_test.calculateOut(); - ho_test.calculateIn(); - ho_test.run(); - ho_test.run(n); - - v = const_ho_test.minCutValue(); - v = const_ho_test.minCutMap(cut); -} - -template -typename CapMap::Value - cutValue(const Graph& graph, const CapMap& cap, const CutMap& cut) -{ - typename CapMap::Value sum = 0; - for (typename Graph::ArcIt a(graph); a != INVALID; ++a) { - if (cut[graph.source(a)] && !cut[graph.target(a)]) - sum += cap[a]; - } - return sum; -} - -int main() { - SmartDigraph graph; - SmartDigraph::ArcMap cap1(graph), cap2(graph), cap3(graph); - SmartDigraph::NodeMap cut(graph); - - istringstream input(lgf); - digraphReader(graph, input) - .arcMap("cap1", cap1) - .arcMap("cap2", cap2) - .arcMap("cap3", cap3) - .run(); - - { - HaoOrlin ho(graph, cap1); - ho.run(); - ho.minCutMap(cut); - - check(ho.minCutValue() == 1, "Wrong cut value"); - check(ho.minCutValue() == cutValue(graph, cap1, cut), "Wrong cut value"); - } - { - HaoOrlin ho(graph, cap2); - ho.run(); - ho.minCutMap(cut); - - check(ho.minCutValue() == 1, "Wrong cut value"); - check(ho.minCutValue() == cutValue(graph, cap2, cut), "Wrong cut value"); - } - { - HaoOrlin ho(graph, cap3); - ho.run(); - ho.minCutMap(cut); - - check(ho.minCutValue() == 1, "Wrong cut value"); - check(ho.minCutValue() == cutValue(graph, cap3, cut), "Wrong cut value"); - } - - typedef Undirector UGraph; - UGraph ugraph(graph); - - { - HaoOrlin > ho(ugraph, cap1); - ho.run(); - ho.minCutMap(cut); - - check(ho.minCutValue() == 2, "Wrong cut value"); - check(ho.minCutValue() == cutValue(ugraph, cap1, cut), "Wrong cut value"); - } - { - HaoOrlin > ho(ugraph, cap2); - ho.run(); - ho.minCutMap(cut); - - check(ho.minCutValue() == 5, "Wrong cut value"); - check(ho.minCutValue() == cutValue(ugraph, cap2, cut), "Wrong cut value"); - } - { - HaoOrlin > ho(ugraph, cap3); - ho.run(); - ho.minCutMap(cut); - - check(ho.minCutValue() == 5, "Wrong cut value"); - check(ho.minCutValue() == cutValue(ugraph, cap3, cut), "Wrong cut value"); - } - - return 0; -} diff --git a/deps/lemon/test/heap_test.cc b/deps/lemon/test/heap_test.cc deleted file mode 100644 index 38e15771a..000000000 --- a/deps/lemon/test/heap_test.cc +++ /dev/null @@ -1,310 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "test_tools.h" - -using namespace lemon; -using namespace lemon::concepts; - -typedef ListDigraph Digraph; -DIGRAPH_TYPEDEFS(Digraph); - -char test_lgf[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "7\n" - "8\n" - "9\n" - "@arcs\n" - " label capacity\n" - "0 5 0 94\n" - "3 9 1 11\n" - "8 7 2 83\n" - "1 2 3 94\n" - "5 7 4 35\n" - "7 4 5 84\n" - "9 5 6 38\n" - "0 4 7 96\n" - "6 7 8 6\n" - "3 1 9 27\n" - "5 2 10 77\n" - "5 6 11 69\n" - "6 5 12 41\n" - "4 6 13 70\n" - "3 2 14 45\n" - "7 9 15 93\n" - "5 9 16 50\n" - "9 0 17 94\n" - "9 6 18 67\n" - "0 9 19 86\n" - "@attributes\n" - "source 3\n"; - -int test_seq[] = { 2, 28, 19, 27, 33, 25, 13, 41, 10, 26, 1, 9, 4, 34}; -int test_inc[] = {20, 28, 34, 16, 0, 46, 44, 0, 42, 32, 14, 8, 6, 37}; - -int test_len = sizeof(test_seq) / sizeof(test_seq[0]); - -template -void heapSortTest() { - RangeMap map(test_len, -1); - Heap heap(map); - - std::vector v(test_len); - for (int i = 0; i < test_len; ++i) { - v[i] = test_seq[i]; - heap.push(i, v[i]); - } - std::sort(v.begin(), v.end()); - for (int i = 0; i < test_len; ++i) { - check(v[i] == heap.prio(), "Wrong order in heap sort."); - heap.pop(); - } -} - -template -void heapIncreaseTest() { - RangeMap map(test_len, -1); - - Heap heap(map); - - std::vector v(test_len); - for (int i = 0; i < test_len; ++i) { - v[i] = test_seq[i]; - heap.push(i, v[i]); - } - for (int i = 0; i < test_len; ++i) { - v[i] += test_inc[i]; - heap.increase(i, v[i]); - } - std::sort(v.begin(), v.end()); - for (int i = 0; i < test_len; ++i) { - check(v[i] == heap.prio(), "Wrong order in heap increase test."); - heap.pop(); - } -} - -template -void dijkstraHeapTest(const Digraph& digraph, const IntArcMap& length, - Node source) { - - typename Dijkstra::template SetStandardHeap:: - Create dijkstra(digraph, length); - - dijkstra.run(source); - - for(ArcIt a(digraph); a != INVALID; ++a) { - Node s = digraph.source(a); - Node t = digraph.target(a); - if (dijkstra.reached(s)) { - check( dijkstra.dist(t) - dijkstra.dist(s) <= length[a], - "Error in shortest path tree."); - } - } - - for(NodeIt n(digraph); n != INVALID; ++n) { - if ( dijkstra.reached(n) && dijkstra.predArc(n) != INVALID ) { - Arc a = dijkstra.predArc(n); - Node s = digraph.source(a); - check( dijkstra.dist(n) - dijkstra.dist(s) == length[a], - "Error in shortest path tree."); - } - } - -} - -int main() { - - typedef int Item; - typedef int Prio; - typedef RangeMap ItemIntMap; - - Digraph digraph; - IntArcMap length(digraph); - Node source; - - std::istringstream input(test_lgf); - digraphReader(digraph, input). - arcMap("capacity", length). - node("source", source). - run(); - - // BinHeap - { - typedef BinHeap IntHeap; - checkConcept, IntHeap>(); - heapSortTest(); - heapIncreaseTest(); - - typedef BinHeap NodeHeap; - checkConcept, NodeHeap>(); - dijkstraHeapTest(digraph, length, source); - } - - // QuadHeap - { - typedef QuadHeap IntHeap; - checkConcept, IntHeap>(); - heapSortTest(); - heapIncreaseTest(); - - typedef QuadHeap NodeHeap; - checkConcept, NodeHeap>(); - dijkstraHeapTest(digraph, length, source); - } - - // DHeap - { - typedef DHeap IntHeap; - checkConcept, IntHeap>(); - heapSortTest(); - heapIncreaseTest(); - - typedef DHeap NodeHeap; - checkConcept, NodeHeap>(); - dijkstraHeapTest(digraph, length, source); - } - - // FibHeap - { - typedef FibHeap IntHeap; - checkConcept, IntHeap>(); - heapSortTest(); - heapIncreaseTest(); - - typedef FibHeap NodeHeap; - checkConcept, NodeHeap>(); - dijkstraHeapTest(digraph, length, source); - } - - // PairingHeap - { - typedef PairingHeap IntHeap; - checkConcept, IntHeap>(); - heapSortTest(); - heapIncreaseTest(); - - typedef PairingHeap NodeHeap; - checkConcept, NodeHeap>(); - dijkstraHeapTest(digraph, length, source); - } - - // RadixHeap - { - typedef RadixHeap IntHeap; - checkConcept, IntHeap>(); - heapSortTest(); - heapIncreaseTest(); - - typedef RadixHeap NodeHeap; - checkConcept, NodeHeap>(); - dijkstraHeapTest(digraph, length, source); - } - - // BinomialHeap - { - typedef BinomialHeap IntHeap; - checkConcept, IntHeap>(); - heapSortTest(); - heapIncreaseTest(); - - typedef BinomialHeap NodeHeap; - checkConcept, NodeHeap>(); - dijkstraHeapTest(digraph, length, source); - } - - // BucketHeap, SimpleBucketHeap - { - typedef BucketHeap IntHeap; - checkConcept, IntHeap>(); - heapSortTest(); - heapIncreaseTest(); - - typedef BucketHeap NodeHeap; - checkConcept, NodeHeap>(); - dijkstraHeapTest(digraph, length, source); - - typedef SimpleBucketHeap SimpleIntHeap; - heapSortTest(); - } - - { - typedef FibHeap IntHeap; - checkConcept, IntHeap>(); - heapSortTest(); - heapIncreaseTest(); - - typedef FibHeap NodeHeap; - checkConcept, NodeHeap>(); - dijkstraHeapTest(digraph, length, source); - } - - { - typedef RadixHeap IntHeap; - checkConcept, IntHeap>(); - heapSortTest(); - heapIncreaseTest(); - - typedef RadixHeap NodeHeap; - checkConcept, NodeHeap>(); - dijkstraHeapTest(digraph, length, source); - } - - { - typedef BucketHeap IntHeap; - checkConcept, IntHeap>(); - heapSortTest(); - heapIncreaseTest(); - - typedef BucketHeap NodeHeap; - checkConcept, NodeHeap>(); - dijkstraHeapTest(digraph, length, source); - } - - - return 0; -} diff --git a/deps/lemon/test/kruskal_test.cc b/deps/lemon/test/kruskal_test.cc deleted file mode 100644 index af36c72fd..000000000 --- a/deps/lemon/test/kruskal_test.cc +++ /dev/null @@ -1,147 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include - -#include "test_tools.h" -#include -#include -#include - -#include -#include -#include - -using namespace std; -using namespace lemon; - -void checkCompileKruskal() -{ - concepts::WriteMap w; - concepts::WriteMap uw; - - concepts::ReadMap r; - concepts::ReadMap ur; - - concepts::Digraph g; - concepts::Graph ug; - - kruskal(g, r, w); - kruskal(ug, ur, uw); - - std::vector > rs; - std::vector > urs; - - kruskal(g, rs, w); - kruskal(ug, urs, uw); - - std::vector ws; - std::vector uws; - - kruskal(g, r, ws.begin()); - kruskal(ug, ur, uws.begin()); -} - -int main() { - - typedef ListGraph::Node Node; - typedef ListGraph::Edge Edge; - typedef ListGraph::NodeIt NodeIt; - typedef ListGraph::ArcIt ArcIt; - - ListGraph G; - - Node s=G.addNode(); - Node v1=G.addNode(); - Node v2=G.addNode(); - Node v3=G.addNode(); - Node v4=G.addNode(); - Node t=G.addNode(); - - Edge e1 = G.addEdge(s, v1); - Edge e2 = G.addEdge(s, v2); - Edge e3 = G.addEdge(v1, v2); - Edge e4 = G.addEdge(v2, v1); - Edge e5 = G.addEdge(v1, v3); - Edge e6 = G.addEdge(v3, v2); - Edge e7 = G.addEdge(v2, v4); - Edge e8 = G.addEdge(v4, v3); - Edge e9 = G.addEdge(v3, t); - Edge e10 = G.addEdge(v4, t); - - typedef ListGraph::EdgeMap ECostMap; - typedef ListGraph::EdgeMap EBoolMap; - - ECostMap edge_cost_map(G, 2); - EBoolMap tree_map(G); - - - //Test with const map. - check(kruskal(G, ConstMap(2), tree_map)==10, - "Total cost should be 10"); - //Test with an edge map (filled with uniform costs). - check(kruskal(G, edge_cost_map, tree_map)==10, - "Total cost should be 10"); - - edge_cost_map[e1] = -10; - edge_cost_map[e2] = -9; - edge_cost_map[e3] = -8; - edge_cost_map[e4] = -7; - edge_cost_map[e5] = -6; - edge_cost_map[e6] = -5; - edge_cost_map[e7] = -4; - edge_cost_map[e8] = -3; - edge_cost_map[e9] = -2; - edge_cost_map[e10] = -1; - - vector tree_edge_vec(5); - - //Test with a edge map and inserter. - check(kruskal(G, edge_cost_map, - tree_edge_vec.begin()) - ==-31, - "Total cost should be -31."); - - tree_edge_vec.clear(); - - check(kruskal(G, edge_cost_map, - back_inserter(tree_edge_vec)) - ==-31, - "Total cost should be -31."); - -// tree_edge_vec.clear(); - -// //The above test could also be coded like this: -// check(kruskal(G, -// makeKruskalMapInput(G, edge_cost_map), -// makeKruskalSequenceOutput(back_inserter(tree_edge_vec))) -// ==-31, -// "Total cost should be -31."); - - check(tree_edge_vec.size()==5,"The tree should have 5 edges."); - - check(tree_edge_vec[0]==e1 && - tree_edge_vec[1]==e2 && - tree_edge_vec[2]==e5 && - tree_edge_vec[3]==e7 && - tree_edge_vec[4]==e9, - "Wrong tree."); - - return 0; -} diff --git a/deps/lemon/test/lgf_reader_writer_test.cc b/deps/lemon/test/lgf_reader_writer_test.cc deleted file mode 100644 index 25d9423ac..000000000 --- a/deps/lemon/test/lgf_reader_writer_test.cc +++ /dev/null @@ -1,578 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -#include -#include -#include - -#include -#include -#include - -#include "test_tools.h" - -struct ReaderConverter { - int operator()(const std::string& str) const { - return str.length(); - } -}; - -struct WriterConverter { - std::string operator()(int value) const { - return std::string(value, '*'); - } -}; - -void checkDigraphReaderCompile() { - typedef lemon::concepts::ExtendableDigraphComponent< - lemon::concepts::Digraph> Digraph; - Digraph digraph; - Digraph::NodeMap node_map(digraph); - Digraph::ArcMap arc_map(digraph); - Digraph::Node node; - Digraph::Arc arc; - int attr; - - lemon::DigraphReader reader(digraph, "filename"); - reader.nodeMap("node_map", node_map); - reader.nodeMap("node_map", node_map, ReaderConverter()); - reader.arcMap("arc_map", arc_map); - reader.arcMap("arc_map", arc_map, ReaderConverter()); - reader.attribute("attr", attr); - reader.attribute("attr", attr, ReaderConverter()); - reader.node("node", node); - reader.arc("arc", arc); - - reader.nodes("alt_nodes_caption"); - reader.arcs("alt_arcs_caption"); - reader.attributes("alt_attrs_caption"); - - reader.useNodes(node_map); - reader.useNodes(node_map, WriterConverter()); - reader.useArcs(arc_map); - reader.useArcs(arc_map, WriterConverter()); - - reader.skipNodes(); - reader.skipArcs(); - - reader.run(); - - lemon::DigraphReader reader2(digraph, std::cin); -} - -void checkDigraphWriterCompile() { - typedef lemon::concepts::Digraph Digraph; - Digraph digraph; - Digraph::NodeMap node_map(digraph); - Digraph::ArcMap arc_map(digraph); - Digraph::Node node; - Digraph::Arc arc; - int attr; - - lemon::DigraphWriter writer(digraph, "filename"); - writer.nodeMap("node_map", node_map); - writer.nodeMap("node_map", node_map, WriterConverter()); - writer.arcMap("arc_map", arc_map); - writer.arcMap("arc_map", arc_map, WriterConverter()); - writer.attribute("attr", attr); - writer.attribute("attr", attr, WriterConverter()); - writer.node("node", node); - writer.arc("arc", arc); - - writer.nodes("alt_nodes_caption"); - writer.arcs("alt_arcs_caption"); - writer.attributes("alt_attrs_caption"); - - writer.skipNodes(); - writer.skipArcs(); - - writer.run(); -} - -void checkGraphReaderCompile() { - typedef lemon::concepts::ExtendableGraphComponent< - lemon::concepts::Graph> Graph; - Graph graph; - Graph::NodeMap node_map(graph); - Graph::ArcMap arc_map(graph); - Graph::EdgeMap edge_map(graph); - Graph::Node node; - Graph::Arc arc; - Graph::Edge edge; - int attr; - - lemon::GraphReader reader(graph, "filename"); - reader.nodeMap("node_map", node_map); - reader.nodeMap("node_map", node_map, ReaderConverter()); - reader.arcMap("arc_map", arc_map); - reader.arcMap("arc_map", arc_map, ReaderConverter()); - reader.edgeMap("edge_map", edge_map); - reader.edgeMap("edge_map", edge_map, ReaderConverter()); - reader.attribute("attr", attr); - reader.attribute("attr", attr, ReaderConverter()); - reader.node("node", node); - reader.arc("arc", arc); - - reader.nodes("alt_nodes_caption"); - reader.edges("alt_edges_caption"); - reader.attributes("alt_attrs_caption"); - - reader.useNodes(node_map); - reader.useNodes(node_map, WriterConverter()); - reader.useEdges(edge_map); - reader.useEdges(edge_map, WriterConverter()); - - reader.skipNodes(); - reader.skipEdges(); - - reader.run(); - - lemon::GraphReader reader2(graph, std::cin); -} - -void checkGraphWriterCompile() { - typedef lemon::concepts::Graph Graph; - Graph graph; - Graph::NodeMap node_map(graph); - Graph::ArcMap arc_map(graph); - Graph::EdgeMap edge_map(graph); - Graph::Node node; - Graph::Arc arc; - Graph::Edge edge; - int attr; - - lemon::GraphWriter writer(graph, "filename"); - writer.nodeMap("node_map", node_map); - writer.nodeMap("node_map", node_map, WriterConverter()); - writer.arcMap("arc_map", arc_map); - writer.arcMap("arc_map", arc_map, WriterConverter()); - writer.edgeMap("edge_map", edge_map); - writer.edgeMap("edge_map", edge_map, WriterConverter()); - writer.attribute("attr", attr); - writer.attribute("attr", attr, WriterConverter()); - writer.node("node", node); - writer.arc("arc", arc); - writer.edge("edge", edge); - - writer.nodes("alt_nodes_caption"); - writer.edges("alt_edges_caption"); - writer.attributes("alt_attrs_caption"); - - writer.skipNodes(); - writer.skipEdges(); - - writer.run(); - - lemon::GraphWriter writer2(graph, std::cout); -} - -void checkBpGraphReaderCompile() { - typedef lemon::concepts::ExtendableBpGraphComponent< - lemon::concepts::BpGraph> BpGraph; - BpGraph graph; - BpGraph::NodeMap node_map(graph); - BpGraph::RedNodeMap red_node_map(graph); - BpGraph::BlueNodeMap blue_node_map(graph); - BpGraph::ArcMap arc_map(graph); - BpGraph::EdgeMap edge_map(graph); - BpGraph::Node node; - BpGraph::RedNode red_node; - BpGraph::BlueNode blue_node; - BpGraph::Arc arc; - BpGraph::Edge edge; - int attr; - - lemon::BpGraphReader reader(graph, "filename"); - reader.nodeMap("node_map", node_map); - reader.nodeMap("node_map", node_map, ReaderConverter()); - reader.redNodeMap("red_node_map", red_node_map); - reader.redNodeMap("red_node_map", red_node_map, ReaderConverter()); - reader.blueNodeMap("blue_node_map", blue_node_map); - reader.blueNodeMap("blue_node_map", blue_node_map, ReaderConverter()); - reader.arcMap("arc_map", arc_map); - reader.arcMap("arc_map", arc_map, ReaderConverter()); - reader.edgeMap("edge_map", edge_map); - reader.edgeMap("edge_map", edge_map, ReaderConverter()); - reader.attribute("attr", attr); - reader.attribute("attr", attr, ReaderConverter()); - reader.node("node", node); - reader.redNode("red_node", red_node); - reader.blueNode("blue_node", blue_node); - reader.arc("arc", arc); - - reader.nodes("alt_nodes_caption"); - reader.edges("alt_edges_caption"); - reader.attributes("alt_attrs_caption"); - - reader.useNodes(node_map); - reader.useNodes(node_map, WriterConverter()); - reader.useEdges(edge_map); - reader.useEdges(edge_map, WriterConverter()); - - reader.skipNodes(); - reader.skipEdges(); - - reader.run(); - - lemon::BpGraphReader reader2(graph, std::cin); -} - -void checkBpGraphWriterCompile() { - typedef lemon::concepts::BpGraph BpGraph; - BpGraph graph; - BpGraph::NodeMap node_map(graph); - BpGraph::RedNodeMap red_node_map(graph); - BpGraph::BlueNodeMap blue_node_map(graph); - BpGraph::ArcMap arc_map(graph); - BpGraph::EdgeMap edge_map(graph); - BpGraph::Node node; - BpGraph::RedNode red_node; - BpGraph::BlueNode blue_node; - BpGraph::Arc arc; - BpGraph::Edge edge; - int attr; - - lemon::BpGraphWriter writer(graph, "filename"); - writer.nodeMap("node_map", node_map); - writer.nodeMap("node_map", node_map, WriterConverter()); - writer.redNodeMap("red_node_map", red_node_map); - writer.redNodeMap("red_node_map", red_node_map, WriterConverter()); - writer.blueNodeMap("blue_node_map", blue_node_map); - writer.blueNodeMap("blue_node_map", blue_node_map, WriterConverter()); - writer.arcMap("arc_map", arc_map); - writer.arcMap("arc_map", arc_map, WriterConverter()); - writer.edgeMap("edge_map", edge_map); - writer.edgeMap("edge_map", edge_map, WriterConverter()); - writer.attribute("attr", attr); - writer.attribute("attr", attr, WriterConverter()); - writer.node("node", node); - writer.redNode("red_node", red_node); - writer.blueNode("blue_node", blue_node); - writer.arc("arc", arc); - - writer.nodes("alt_nodes_caption"); - writer.edges("alt_edges_caption"); - writer.attributes("alt_attrs_caption"); - - writer.skipNodes(); - writer.skipEdges(); - - writer.run(); - - lemon::BpGraphWriter writer2(graph, std::cout); -} - -void checkDigraphReaderWriter() { - typedef lemon::SmartDigraph Digraph; - Digraph digraph; - Digraph::Node n1 = digraph.addNode(); - Digraph::Node n2 = digraph.addNode(); - Digraph::Node n3 = digraph.addNode(); - - Digraph::Arc a1 = digraph.addArc(n1, n2); - Digraph::Arc a2 = digraph.addArc(n2, n3); - - Digraph::NodeMap node_map(digraph); - node_map[n1] = 11; - node_map[n2] = 12; - node_map[n3] = 13; - - Digraph::ArcMap arc_map(digraph); - arc_map[a1] = 21; - arc_map[a2] = 22; - - int attr = 100; - - std::ostringstream os; - lemon::DigraphWriter writer(digraph, os); - - writer.nodeMap("node_map1", node_map); - writer.nodeMap("node_map2", node_map, WriterConverter()); - writer.arcMap("arc_map1", arc_map); - writer.arcMap("arc_map2", arc_map, WriterConverter()); - writer.node("node", n2); - writer.arc("arc", a1); - writer.attribute("attr1", attr); - writer.attribute("attr2", attr, WriterConverter()); - - writer.run(); - - typedef lemon::ListDigraph ExpDigraph; - ExpDigraph exp_digraph; - ExpDigraph::NodeMap exp_node_map1(exp_digraph); - ExpDigraph::NodeMap exp_node_map2(exp_digraph); - ExpDigraph::ArcMap exp_arc_map1(exp_digraph); - ExpDigraph::ArcMap exp_arc_map2(exp_digraph); - ExpDigraph::Node exp_n2; - ExpDigraph::Arc exp_a1; - int exp_attr1; - int exp_attr2; - - std::istringstream is(os.str()); - lemon::DigraphReader reader(exp_digraph, is); - - reader.nodeMap("node_map1", exp_node_map1); - reader.nodeMap("node_map2", exp_node_map2, ReaderConverter()); - reader.arcMap("arc_map1", exp_arc_map1); - reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter()); - reader.node("node", exp_n2); - reader.arc("arc", exp_a1); - reader.attribute("attr1", exp_attr1); - reader.attribute("attr2", exp_attr2, ReaderConverter()); - - reader.run(); - - check(lemon::countNodes(exp_digraph) == 3, "Wrong number of nodes"); - check(lemon::countArcs(exp_digraph) == 2, "Wrong number of arcs"); - check(exp_node_map1[exp_n2] == 12, "Wrong map value"); - check(exp_node_map2[exp_n2] == 12, "Wrong map value"); - check(exp_arc_map1[exp_a1] == 21, "Wrong map value"); - check(exp_arc_map2[exp_a1] == 21, "Wrong map value"); - check(exp_attr1 == 100, "Wrong attr value"); - check(exp_attr2 == 100, "Wrong attr value"); -} - -void checkGraphReaderWriter() { - typedef lemon::SmartGraph Graph; - Graph graph; - Graph::Node n1 = graph.addNode(); - Graph::Node n2 = graph.addNode(); - Graph::Node n3 = graph.addNode(); - - Graph::Edge e1 = graph.addEdge(n1, n2); - Graph::Edge e2 = graph.addEdge(n2, n3); - - Graph::NodeMap node_map(graph); - node_map[n1] = 11; - node_map[n2] = 12; - node_map[n3] = 13; - - Graph::EdgeMap edge_map(graph); - edge_map[e1] = 21; - edge_map[e2] = 22; - - Graph::ArcMap arc_map(graph); - arc_map[graph.direct(e1, true)] = 211; - arc_map[graph.direct(e1, false)] = 212; - arc_map[graph.direct(e2, true)] = 221; - arc_map[graph.direct(e2, false)] = 222; - - int attr = 100; - - std::ostringstream os; - lemon::GraphWriter writer(graph, os); - - writer.nodeMap("node_map1", node_map); - writer.nodeMap("node_map2", node_map, WriterConverter()); - writer.edgeMap("edge_map1", edge_map); - writer.edgeMap("edge_map2", edge_map, WriterConverter()); - writer.arcMap("arc_map1", arc_map); - writer.arcMap("arc_map2", arc_map, WriterConverter()); - writer.node("node", n2); - writer.edge("edge", e1); - writer.arc("arc", graph.direct(e1, false)); - writer.attribute("attr1", attr); - writer.attribute("attr2", attr, WriterConverter()); - - writer.run(); - - typedef lemon::ListGraph ExpGraph; - ExpGraph exp_graph; - ExpGraph::NodeMap exp_node_map1(exp_graph); - ExpGraph::NodeMap exp_node_map2(exp_graph); - ExpGraph::EdgeMap exp_edge_map1(exp_graph); - ExpGraph::EdgeMap exp_edge_map2(exp_graph); - ExpGraph::ArcMap exp_arc_map1(exp_graph); - ExpGraph::ArcMap exp_arc_map2(exp_graph); - ExpGraph::Node exp_n2; - ExpGraph::Edge exp_e1; - ExpGraph::Arc exp_a1; - int exp_attr1; - int exp_attr2; - - std::istringstream is(os.str()); - lemon::GraphReader reader(exp_graph, is); - - reader.nodeMap("node_map1", exp_node_map1); - reader.nodeMap("node_map2", exp_node_map2, ReaderConverter()); - reader.edgeMap("edge_map1", exp_edge_map1); - reader.edgeMap("edge_map2", exp_edge_map2, ReaderConverter()); - reader.arcMap("arc_map1", exp_arc_map1); - reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter()); - reader.node("node", exp_n2); - reader.edge("edge", exp_e1); - reader.arc("arc", exp_a1); - reader.attribute("attr1", exp_attr1); - reader.attribute("attr2", exp_attr2, ReaderConverter()); - - reader.run(); - - check(lemon::countNodes(exp_graph) == 3, "Wrong number of nodes"); - check(lemon::countEdges(exp_graph) == 2, "Wrong number of edges"); - check(lemon::countArcs(exp_graph) == 4, "Wrong number of arcs"); - check(exp_node_map1[exp_n2] == 12, "Wrong map value"); - check(exp_node_map2[exp_n2] == 12, "Wrong map value"); - check(exp_edge_map1[exp_e1] == 21, "Wrong map value"); - check(exp_edge_map2[exp_e1] == 21, "Wrong map value"); - check(exp_arc_map1[exp_a1] == 212, "Wrong map value"); - check(exp_arc_map2[exp_a1] == 212, "Wrong map value"); - check(exp_attr1 == 100, "Wrong attr value"); - check(exp_attr2 == 100, "Wrong attr value"); -} - -void checkBpGraphReaderWriter() { - typedef lemon::SmartBpGraph Graph; - Graph graph; - Graph::RedNode rn1 = graph.addRedNode(); - Graph::RedNode rn2 = graph.addRedNode(); - Graph::RedNode rn3 = graph.addRedNode(); - Graph::BlueNode bn1 = graph.addBlueNode(); - Graph::BlueNode bn2 = graph.addBlueNode(); - Graph::Node n = bn1; - - Graph::Edge e1 = graph.addEdge(rn1, bn1); - Graph::Edge e2 = graph.addEdge(rn2, bn1); - - Graph::NodeMap node_map(graph); - node_map[rn1] = 11; - node_map[rn2] = 12; - node_map[rn3] = 13; - node_map[bn1] = 14; - node_map[bn2] = 15; - - Graph::NodeMap red_node_map(graph); - red_node_map[rn1] = 411; - red_node_map[rn2] = 412; - red_node_map[rn3] = 413; - - Graph::NodeMap blue_node_map(graph); - blue_node_map[bn1] = 414; - blue_node_map[bn2] = 415; - - Graph::EdgeMap edge_map(graph); - edge_map[e1] = 21; - edge_map[e2] = 22; - - Graph::ArcMap arc_map(graph); - arc_map[graph.direct(e1, true)] = 211; - arc_map[graph.direct(e1, false)] = 212; - arc_map[graph.direct(e2, true)] = 221; - arc_map[graph.direct(e2, false)] = 222; - - int attr = 100; - - std::ostringstream os; - lemon::BpGraphWriter writer(graph, os); - - writer.nodeMap("node_map1", node_map); - writer.nodeMap("node_map2", node_map, WriterConverter()); - writer.nodeMap("red_node_map1", red_node_map); - writer.nodeMap("red_node_map2", red_node_map, WriterConverter()); - writer.nodeMap("blue_node_map1", blue_node_map); - writer.nodeMap("blue_node_map2", blue_node_map, WriterConverter()); - writer.edgeMap("edge_map1", edge_map); - writer.edgeMap("edge_map2", edge_map, WriterConverter()); - writer.arcMap("arc_map1", arc_map); - writer.arcMap("arc_map2", arc_map, WriterConverter()); - writer.node("node", n); - writer.redNode("red_node", rn1); - writer.blueNode("blue_node", bn2); - writer.edge("edge", e1); - writer.arc("arc", graph.direct(e1, false)); - writer.attribute("attr1", attr); - writer.attribute("attr2", attr, WriterConverter()); - - writer.run(); - - typedef lemon::ListBpGraph ExpGraph; - ExpGraph exp_graph; - ExpGraph::NodeMap exp_node_map1(exp_graph); - ExpGraph::NodeMap exp_node_map2(exp_graph); - ExpGraph::RedNodeMap exp_red_node_map1(exp_graph); - ExpGraph::RedNodeMap exp_red_node_map2(exp_graph); - ExpGraph::BlueNodeMap exp_blue_node_map1(exp_graph); - ExpGraph::BlueNodeMap exp_blue_node_map2(exp_graph); - ExpGraph::EdgeMap exp_edge_map1(exp_graph); - ExpGraph::EdgeMap exp_edge_map2(exp_graph); - ExpGraph::ArcMap exp_arc_map1(exp_graph); - ExpGraph::ArcMap exp_arc_map2(exp_graph); - ExpGraph::Node exp_n; - ExpGraph::RedNode exp_rn1; - ExpGraph::BlueNode exp_bn2; - ExpGraph::Edge exp_e1; - ExpGraph::Arc exp_a1; - int exp_attr1; - int exp_attr2; - - std::istringstream is(os.str()); - lemon::BpGraphReader reader(exp_graph, is); - - reader.nodeMap("node_map1", exp_node_map1); - reader.nodeMap("node_map2", exp_node_map2, ReaderConverter()); - reader.redNodeMap("red_node_map1", exp_red_node_map1); - reader.redNodeMap("red_node_map2", exp_red_node_map2, ReaderConverter()); - reader.blueNodeMap("blue_node_map1", exp_blue_node_map1); - reader.blueNodeMap("blue_node_map2", exp_blue_node_map2, ReaderConverter()); - reader.edgeMap("edge_map1", exp_edge_map1); - reader.edgeMap("edge_map2", exp_edge_map2, ReaderConverter()); - reader.arcMap("arc_map1", exp_arc_map1); - reader.arcMap("arc_map2", exp_arc_map2, ReaderConverter()); - reader.node("node", exp_n); - reader.redNode("red_node", exp_rn1); - reader.blueNode("blue_node", exp_bn2); - reader.edge("edge", exp_e1); - reader.arc("arc", exp_a1); - reader.attribute("attr1", exp_attr1); - reader.attribute("attr2", exp_attr2, ReaderConverter()); - - reader.run(); - - check(lemon::countNodes(exp_graph) == 5, "Wrong number of nodes"); - check(lemon::countRedNodes(exp_graph) == 3, "Wrong number of red nodes"); - check(lemon::countBlueNodes(exp_graph) == 2, "Wrong number of blue nodes"); - check(lemon::countEdges(exp_graph) == 2, "Wrong number of edges"); - check(lemon::countArcs(exp_graph) == 4, "Wrong number of arcs"); - check(exp_node_map1[exp_n] == 14, "Wrong map value"); - check(exp_node_map2[exp_n] == 14, "Wrong map value"); - check(exp_red_node_map1[exp_rn1] == 411, "Wrong map value"); - check(exp_red_node_map2[exp_rn1] == 411, "Wrong map value"); - check(exp_blue_node_map1[exp_bn2] == 415, "Wrong map value"); - check(exp_blue_node_map2[exp_bn2] == 415, "Wrong map value"); - check(exp_edge_map1[exp_e1] == 21, "Wrong map value"); - check(exp_edge_map2[exp_e1] == 21, "Wrong map value"); - check(exp_arc_map1[exp_a1] == 212, "Wrong map value"); - check(exp_arc_map2[exp_a1] == 212, "Wrong map value"); - check(exp_attr1 == 100, "Wrong attr value"); - check(exp_attr2 == 100, "Wrong attr value"); -} - - -int main() { - { // Check digrpah - checkDigraphReaderWriter(); - } - { // Check graph - checkGraphReaderWriter(); - } - { // Check bipartite graph - checkBpGraphReaderWriter(); - } - return 0; -} diff --git a/deps/lemon/test/lgf_test.cc b/deps/lemon/test/lgf_test.cc deleted file mode 100644 index 839afb152..000000000 --- a/deps/lemon/test/lgf_test.cc +++ /dev/null @@ -1,169 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include "test_tools.h" - -using namespace lemon; - -char test_lgf[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "@arcs\n" - " label\n" - "0 1 0\n" - "1 0 1\n" - "@attributes\n" - "source 0\n" - "target 1\n"; - -char test_lgf_nomap[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "@arcs\n" - " -\n" - "0 1\n"; - -char test_lgf_bad1[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "@arcs\n" - " - another\n" - "0 1\n"; - -char test_lgf_bad2[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "@arcs\n" - " label -\n" - "0 1\n"; - - -int main() -{ - { - ListDigraph d; - ListDigraph::Node s,t; - ListDigraph::ArcMap label(d); - std::istringstream input(test_lgf); - digraphReader(d, input). - node("source", s). - node("target", t). - arcMap("label", label). - run(); - check(countNodes(d) == 2,"There should be 2 nodes"); - check(countArcs(d) == 2,"There should be 2 arcs"); - } - { - ListGraph g; - ListGraph::Node s,t; - ListGraph::EdgeMap label(g); - std::istringstream input(test_lgf); - graphReader(g, input). - node("source", s). - node("target", t). - edgeMap("label", label). - run(); - check(countNodes(g) == 2,"There should be 2 nodes"); - check(countEdges(g) == 2,"There should be 2 arcs"); - } - - { - ListDigraph d; - std::istringstream input(test_lgf_nomap); - digraphReader(d, input). - run(); - check(countNodes(d) == 2,"There should be 2 nodes"); - check(countArcs(d) == 1,"There should be 1 arc"); - } - { - ListGraph g; - std::istringstream input(test_lgf_nomap); - graphReader(g, input). - run(); - check(countNodes(g) == 2,"There should be 2 nodes"); - check(countEdges(g) == 1,"There should be 1 edge"); - } - - { - ListDigraph d; - std::istringstream input(test_lgf_bad1); - bool ok=false; - try { - digraphReader(d, input). - run(); - } - catch (FormatError&) - { - ok = true; - } - check(ok,"FormatError exception should have occured"); - } - { - ListGraph g; - std::istringstream input(test_lgf_bad1); - bool ok=false; - try { - graphReader(g, input). - run(); - } - catch (FormatError&) - { - ok = true; - } - check(ok,"FormatError exception should have occured"); - } - - { - ListDigraph d; - std::istringstream input(test_lgf_bad2); - bool ok=false; - try { - digraphReader(d, input). - run(); - } - catch (FormatError&) - { - ok = true; - } - check(ok,"FormatError exception should have occured"); - } - { - ListGraph g; - std::istringstream input(test_lgf_bad2); - bool ok=false; - try { - graphReader(g, input). - run(); - } - catch (FormatError&) - { - ok = true; - } - check(ok,"FormatError exception should have occured"); - } -} diff --git a/deps/lemon/test/lp_test.cc b/deps/lemon/test/lp_test.cc deleted file mode 100644 index 914a37643..000000000 --- a/deps/lemon/test/lp_test.cc +++ /dev/null @@ -1,470 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include "test_tools.h" -#include - -#include - -#ifdef LEMON_HAVE_GLPK -#include -#endif - -#ifdef LEMON_HAVE_CPLEX -#include -#endif - -#ifdef LEMON_HAVE_SOPLEX -#include -#endif - -#ifdef LEMON_HAVE_CLP -#include -#endif - -#ifdef LEMON_HAVE_LP -#include -#endif -using namespace lemon; - -int countCols(LpBase & lp) { - int count=0; - for (LpBase::ColIt c(lp); c!=INVALID; ++c) ++count; - return count; -} - -int countRows(LpBase & lp) { - int count=0; - for (LpBase::RowIt r(lp); r!=INVALID; ++r) ++count; - return count; -} - - -void lpTest(LpSolver& lp) -{ - - typedef LpSolver LP; - - // Test LpBase::clear() - check(countRows(lp)==0, "Wrong number of rows"); - check(countCols(lp)==0, "Wrong number of cols"); - lp.addCol(); lp.addRow(); lp.addRow(); - check(countRows(lp)==2, "Wrong number of rows"); - check(countCols(lp)==1, "Wrong number of cols"); - lp.clear(); - check(countRows(lp)==0, "Wrong number of rows"); - check(countCols(lp)==0, "Wrong number of cols"); - lp.addCol(); lp.addCol(); lp.addCol(); lp.addRow(); - check(countRows(lp)==1, "Wrong number of rows"); - check(countCols(lp)==3, "Wrong number of cols"); - lp.clear(); - - std::vector x(10); - // for(int i=0;i<10;i++) x.push_back(lp.addCol()); - lp.addColSet(x); - lp.colLowerBound(x,1); - lp.colUpperBound(x,1); - lp.colBounds(x,1,2); - - std::vector y(10); - lp.addColSet(y); - - lp.colLowerBound(y,1); - lp.colUpperBound(y,1); - lp.colBounds(y,1,2); - - std::map z; - - z.insert(std::make_pair(12,INVALID)); - z.insert(std::make_pair(2,INVALID)); - z.insert(std::make_pair(7,INVALID)); - z.insert(std::make_pair(5,INVALID)); - - lp.addColSet(z); - - lp.colLowerBound(z,1); - lp.colUpperBound(z,1); - lp.colBounds(z,1,2); - - { - LP::Expr e,f,g; - LP::Col p1,p2,p3,p4,p5; - LP::Constr c; - - p1=lp.addCol(); - p2=lp.addCol(); - p3=lp.addCol(); - p4=lp.addCol(); - p5=lp.addCol(); - - e[p1]=2; - *e=12; - e[p1]+=2; - *e+=12; - e[p1]-=2; - *e-=12; - - e=2; - e=2.2; - e=p1; - e=f; - - e+=2; - e+=2.2; - e+=p1; - e+=f; - - e-=2; - e-=2.2; - e-=p1; - e-=f; - - e*=2; - e*=2.2; - e/=2; - e/=2.2; - - e=((p1+p2)+(p1-p2)+(p1+12)+(12+p1)+(p1-12)+(12-p1)+ - (f+12)+(12+f)+(p1+f)+(f+p1)+(f+g)+ - (f-12)+(12-f)+(p1-f)+(f-p1)+(f-g)+ - 2.2*f+f*2.2+f/2.2+ - 2*f+f*2+f/2+ - 2.2*p1+p1*2.2+p1/2.2+ - 2*p1+p1*2+p1/2 - ); - - - c = (e <= f ); - c = (e <= 2.2); - c = (e <= 2 ); - c = (e <= p1 ); - c = (2.2<= f ); - c = (2 <= f ); - c = (p1 <= f ); - c = (p1 <= p2 ); - c = (p1 <= 2.2); - c = (p1 <= 2 ); - c = (2.2<= p2 ); - c = (2 <= p2 ); - - c = (e >= f ); - c = (e >= 2.2); - c = (e >= 2 ); - c = (e >= p1 ); - c = (2.2>= f ); - c = (2 >= f ); - c = (p1 >= f ); - c = (p1 >= p2 ); - c = (p1 >= 2.2); - c = (p1 >= 2 ); - c = (2.2>= p2 ); - c = (2 >= p2 ); - - c = (e == f ); - c = (e == 2.2); - c = (e == 2 ); - c = (e == p1 ); - c = (2.2== f ); - c = (2 == f ); - c = (p1 == f ); - //c = (p1 == p2 ); - c = (p1 == 2.2); - c = (p1 == 2 ); - c = (2.2== p2 ); - c = (2 == p2 ); - - c = ((2 <= e) <= 3); - c = ((2 <= p1) <= 3); - - c = ((2 >= e) >= 3); - c = ((2 >= p1) >= 3); - - { //Tests for #430 - LP::Col v=lp.addCol(); - LP::Constr c = v >= -3; - c = c <= 4; - LP::Constr c2; -#if ( __GNUC__ == 4 ) && ( __GNUC_MINOR__ == 3 ) - c2 = ( -3 <= v ) <= 4; -#else - c2 = -3 <= v <= 4; -#endif - - } - - e[x[3]]=2; - e[x[3]]=4; - e[x[3]]=1; - *e=12; - - lp.addRow(-LP::INF,e,23); - lp.addRow(-LP::INF,3.0*(x[1]+x[2]/2)-x[3],23); - lp.addRow(-LP::INF,3.0*(x[1]+x[2]*2-5*x[3]+12-x[4]/3)+2*x[4]-4,23); - - lp.addRow(x[1]+x[3]<=x[5]-3); - lp.addRow((-7<=x[1]+x[3]-12)<=3); - lp.addRow(x[1]<=x[5]); - - std::ostringstream buf; - - - e=((p1+p2)+(p1-0.99*p2)); - //e.prettyPrint(std::cout); - //(e<=2).prettyPrint(std::cout); - double tolerance=0.001; - e.simplify(tolerance); - buf << "Coeff. of p2 should be 0.01"; - check(e[p2]>0, buf.str()); - - tolerance=0.02; - e.simplify(tolerance); - buf << "Coeff. of p2 should be 0"; - check(const_cast(e)[p2]==0, buf.str()); - - //Test for clone/new - LP* lpnew = lp.newSolver(); - LP* lpclone = lp.cloneSolver(); - delete lpnew; - delete lpclone; - - } - - { - LP::DualExpr e,f,g; - LP::Row p1 = INVALID, p2 = INVALID; - - e[p1]=2; - e[p1]+=2; - e[p1]-=2; - - e=p1; - e=f; - - e+=p1; - e+=f; - - e-=p1; - e-=f; - - e*=2; - e*=2.2; - e/=2; - e/=2.2; - - e=((p1+p2)+(p1-p2)+ - (p1+f)+(f+p1)+(f+g)+ - (p1-f)+(f-p1)+(f-g)+ - 2.2*f+f*2.2+f/2.2+ - 2*f+f*2+f/2+ - 2.2*p1+p1*2.2+p1/2.2+ - 2*p1+p1*2+p1/2 - ); - } - -} - -void solveAndCheck(LpSolver& lp, LpSolver::ProblemType stat, - double exp_opt) { - using std::string; - lp.solve(); - - std::ostringstream buf; - buf << "PrimalType should be: " << int(stat) << int(lp.primalType()); - - check(lp.primalType()==stat, buf.str()); - - if (stat == LpSolver::OPTIMAL) { - std::ostringstream sbuf; - sbuf << "Wrong optimal value (" << lp.primal() <<") with " - << lp.solverName() <<"\n the right optimum is " << exp_opt; - check(std::abs(lp.primal()-exp_opt) < 1e-3, sbuf.str()); - } -} - -void aTest(LpSolver & lp) -{ - typedef LpSolver LP; - - //The following example is very simple - - typedef LpSolver::Row Row; - typedef LpSolver::Col Col; - - - Col x1 = lp.addCol(); - Col x2 = lp.addCol(); - - - //Constraints - Row upright=lp.addRow(x1+2*x2 <=1); - lp.addRow(x1+x2 >=-1); - lp.addRow(x1-x2 <=1); - lp.addRow(x1-x2 >=-1); - //Nonnegativity of the variables - lp.colLowerBound(x1, 0); - lp.colLowerBound(x2, 0); - //Objective function - lp.obj(x1+x2); - - lp.sense(lp.MAX); - - //Testing the problem retrieving routines - check(lp.objCoeff(x1)==1,"First term should be 1 in the obj function!"); - check(lp.sense() == lp.MAX,"This is a maximization!"); - check(lp.coeff(upright,x1)==1,"The coefficient in question is 1!"); - check(lp.colLowerBound(x1)==0, - "The lower bound for variable x1 should be 0."); - check(lp.colUpperBound(x1)==LpSolver::INF, - "The upper bound for variable x1 should be infty."); - check(lp.rowLowerBound(upright) == -LpSolver::INF, - "The lower bound for the first row should be -infty."); - check(lp.rowUpperBound(upright)==1, - "The upper bound for the first row should be 1."); - LpSolver::Expr e = lp.row(upright); - check(e[x1] == 1, "The first coefficient should 1."); - check(e[x2] == 2, "The second coefficient should 1."); - - lp.row(upright, x1+x2 <=1); - e = lp.row(upright); - check(e[x1] == 1, "The first coefficient should 1."); - check(e[x2] == 1, "The second coefficient should 1."); - - LpSolver::DualExpr de = lp.col(x1); - check( de[upright] == 1, "The first coefficient should 1."); - - LpSolver* clp = lp.cloneSolver(); - - //Testing the problem retrieving routines - check(clp->objCoeff(x1)==1,"First term should be 1 in the obj function!"); - check(clp->sense() == clp->MAX,"This is a maximization!"); - check(clp->coeff(upright,x1)==1,"The coefficient in question is 1!"); - // std::cout<colLowerBound(x1)==0, - "The lower bound for variable x1 should be 0."); - check(clp->colUpperBound(x1)==LpSolver::INF, - "The upper bound for variable x1 should be infty."); - - check(lp.rowLowerBound(upright)==-LpSolver::INF, - "The lower bound for the first row should be -infty."); - check(lp.rowUpperBound(upright)==1, - "The upper bound for the first row should be 1."); - e = clp->row(upright); - check(e[x1] == 1, "The first coefficient should 1."); - check(e[x2] == 1, "The second coefficient should 1."); - - de = clp->col(x1); - check(de[upright] == 1, "The first coefficient should 1."); - - delete clp; - - //Maximization of x1+x2 - //over the triangle with vertices (0,0) (0,1) (1,0) - double expected_opt=1; - solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt); - - //Minimization - lp.sense(lp.MIN); - expected_opt=0; - solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt); - - //Vertex (-1,0) instead of (0,0) - lp.colLowerBound(x1, -LpSolver::INF); - expected_opt=-1; - solveAndCheck(lp, LpSolver::OPTIMAL, expected_opt); - - //Erase one constraint and return to maximization - lp.erase(upright); - lp.sense(lp.MAX); - expected_opt=LpSolver::INF; - solveAndCheck(lp, LpSolver::UNBOUNDED, expected_opt); - - //Infeasibilty - lp.addRow(x1+x2 <=-2); - solveAndCheck(lp, LpSolver::INFEASIBLE, expected_opt); - -} - -template -void cloneTest() -{ - //Test for clone/new - - LP* lp = new LP(); - LP* lpnew = lp->newSolver(); - LP* lpclone = lp->cloneSolver(); - delete lp; - delete lpnew; - delete lpclone; -} - -int main() -{ - LpSkeleton lp_skel; - lpTest(lp_skel); - -#ifdef LEMON_HAVE_LP - { - Lp lp,lp2; - lpTest(lp); - aTest(lp2); - cloneTest(); - } -#endif - -#ifdef LEMON_HAVE_GLPK - { - GlpkLp lp_glpk1,lp_glpk2; - lpTest(lp_glpk1); - aTest(lp_glpk2); - cloneTest(); - } -#endif - -#ifdef LEMON_HAVE_CPLEX - try { - CplexLp lp_cplex1,lp_cplex2; - lpTest(lp_cplex1); - aTest(lp_cplex2); - cloneTest(); - } catch (CplexEnv::LicenseError& error) { - check(false, error.what()); - } -#endif - -#ifdef LEMON_HAVE_SOPLEX - { - SoplexLp lp_soplex1,lp_soplex2; - lpTest(lp_soplex1); - aTest(lp_soplex2); - cloneTest(); - } -#endif - -#ifdef LEMON_HAVE_CLP - { - ClpLp lp_clp1,lp_clp2; - lpTest(lp_clp1); - aTest(lp_clp2); - cloneTest(); - } -#endif - - return 0; -} diff --git a/deps/lemon/test/maps_test.cc b/deps/lemon/test/maps_test.cc deleted file mode 100644 index 5502e046f..000000000 --- a/deps/lemon/test/maps_test.cc +++ /dev/null @@ -1,1022 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "test_tools.h" - -using namespace lemon; -using namespace lemon::concepts; - -struct A {}; -inline bool operator<(A, A) { return true; } -struct B {}; - -class C { - int _x; -public: - C(int x) : _x(x) {} - int get() const { return _x; } -}; -inline bool operator<(C c1, C c2) { return c1.get() < c2.get(); } -inline bool operator==(C c1, C c2) { return c1.get() == c2.get(); } - -C createC(int x) { return C(x); } - -template -class Less { - T _t; -public: - Less(T t): _t(t) {} - bool operator()(const T& t) const { return t < _t; } -}; - -class F { -public: - typedef A argument_type; - typedef B result_type; - - B operator()(const A&) const { return B(); } -private: - F& operator=(const F&); -}; - -int func(A) { return 3; } - -int binc(int a, B) { return a+1; } - -template -class Sum { - T& _sum; -public: - Sum(T& sum) : _sum(sum) {} - void operator()(const T& t) { _sum += t; } -}; - -typedef ReadMap DoubleMap; -typedef ReadWriteMap DoubleWriteMap; -typedef ReferenceMap DoubleRefMap; - -typedef ReadMap BoolMap; -typedef ReadWriteMap BoolWriteMap; -typedef ReferenceMap BoolRefMap; - -int main() -{ - // Map concepts - checkConcept, ReadMap >(); - checkConcept, ReadMap >(); - checkConcept, WriteMap >(); - checkConcept, WriteMap >(); - checkConcept, ReadWriteMap >(); - checkConcept, ReadWriteMap >(); - checkConcept, ReferenceMap >(); - checkConcept, ReferenceMap >(); - - // NullMap - { - checkConcept, NullMap >(); - NullMap map1; - NullMap map2 = map1; - ::lemon::ignore_unused_variable_warning(map2); - map1 = nullMap(); - } - - // ConstMap - { - checkConcept, ConstMap >(); - checkConcept, ConstMap >(); - ConstMap map1; - ConstMap map2 = B(); - ConstMap map3 = map1; - ::lemon::ignore_unused_variable_warning(map2,map3); - - map1 = constMap(B()); - map1 = constMap(); - map1.setAll(B()); - ConstMap map4(C(1)); - ConstMap map5 = map4; - ::lemon::ignore_unused_variable_warning(map5); - - map4 = constMap(C(2)); - map4.setAll(C(3)); - - checkConcept, ConstMap >(); - check(constMap(10)[A()] == 10, "Something is wrong with ConstMap"); - - checkConcept, ConstMap > >(); - ConstMap > map6; - ConstMap > map7 = map6; - map6 = constMap(); - map7 = constMap >(); - check(map6[A()] == 10 && map7[A()] == 10, - "Something is wrong with ConstMap"); - } - - // IdentityMap - { - checkConcept, IdentityMap >(); - IdentityMap map1; - IdentityMap map2 = map1; - ::lemon::ignore_unused_variable_warning(map2); - - map1 = identityMap(); - - checkConcept, IdentityMap >(); - check(identityMap()[1.0] == 1.0 && - identityMap()[3.14] == 3.14, - "Something is wrong with IdentityMap"); - } - - // RangeMap - { - checkConcept, RangeMap >(); - RangeMap map1; - RangeMap map2(10); - RangeMap map3(10,B()); - RangeMap map4 = map1; - RangeMap map5 = rangeMap(); - RangeMap map6 = rangeMap(10); - RangeMap map7 = rangeMap(10,B()); - - checkConcept< ReferenceMap, - RangeMap >(); - std::vector v(10, 0); - v[5] = 100; - RangeMap map8(v); - RangeMap map9 = rangeMap(v); - check(map9.size() == 10 && map9[2] == 0 && map9[5] == 100, - "Something is wrong with RangeMap"); - } - - // SparseMap - { - checkConcept, SparseMap >(); - SparseMap map1; - SparseMap map2 = B(); - SparseMap map3 = sparseMap(); - SparseMap map4 = sparseMap(B()); - - checkConcept< ReferenceMap, - SparseMap >(); - std::map m; - SparseMap map5(m); - SparseMap map6(m,10); - SparseMap map7 = sparseMap(m); - SparseMap map8 = sparseMap(m,10); - - check(map5[1.0] == 0 && map5[3.14] == 0 && - map6[1.0] == 10 && map6[3.14] == 10, - "Something is wrong with SparseMap"); - map5[1.0] = map6[3.14] = 100; - check(map5[1.0] == 100 && map5[3.14] == 0 && - map6[1.0] == 10 && map6[3.14] == 100, - "Something is wrong with SparseMap"); - } - - // ComposeMap - { - typedef ComposeMap > CompMap; - checkConcept, CompMap>(); - CompMap map1 = CompMap(DoubleMap(),ReadMap()); - ::lemon::ignore_unused_variable_warning(map1); - CompMap map2 = composeMap(DoubleMap(), ReadMap()); - ::lemon::ignore_unused_variable_warning(map2); - - SparseMap m1(false); m1[3.14] = true; - RangeMap m2(2); m2[0] = 3.0; m2[1] = 3.14; - check(!composeMap(m1,m2)[0] && composeMap(m1,m2)[1], - "Something is wrong with ComposeMap") - } - - // CombineMap - { - typedef CombineMap > CombMap; - checkConcept, CombMap>(); - CombMap map1 = CombMap(DoubleMap(), DoubleMap()); - ::lemon::ignore_unused_variable_warning(map1); - CombMap map2 = combineMap(DoubleMap(), DoubleMap(), std::plus()); - ::lemon::ignore_unused_variable_warning(map2); - - check(combineMap(constMap(), identityMap(), &binc)[B()] == 3, - "Something is wrong with CombineMap"); - } - - // FunctorToMap, MapToFunctor - { - checkConcept, FunctorToMap >(); - checkConcept, FunctorToMap >(); - FunctorToMap map1; - FunctorToMap map2 = FunctorToMap(F()); - ::lemon::ignore_unused_variable_warning(map2); - - B b = functorToMap(F())[A()]; - ::lemon::ignore_unused_variable_warning(b); - - checkConcept, MapToFunctor > >(); - MapToFunctor > map = - MapToFunctor >(ReadMap()); - ::lemon::ignore_unused_variable_warning(map); - - check(functorToMap(&func)[A()] == 3, - "Something is wrong with FunctorToMap"); - check(mapToFunctor(constMap(2))(A()) == 2, - "Something is wrong with MapToFunctor"); - check(mapToFunctor(functorToMap(&func))(A()) == 3 && - mapToFunctor(functorToMap(&func))[A()] == 3, - "Something is wrong with FunctorToMap or MapToFunctor"); - check(functorToMap(mapToFunctor(constMap(2)))[A()] == 2, - "Something is wrong with FunctorToMap or MapToFunctor"); - } - - // ConvertMap - { - checkConcept, - ConvertMap, double> >(); - ConvertMap, int> map1(rangeMap(1, true)); - ::lemon::ignore_unused_variable_warning(map1); - ConvertMap, int> map2 = convertMap(rangeMap(2, false)); - ::lemon::ignore_unused_variable_warning(map2); - - } - - // ForkMap - { - checkConcept >(); - - typedef RangeMap RM; - typedef SparseMap SM; - RM m1(10, -1); - SM m2(-1); - checkConcept, ForkMap >(); - checkConcept, ForkMap >(); - ForkMap map1(m1,m2); - ForkMap map2 = forkMap(m2,m1); - map2.set(5, 10); - check(m1[1] == -1 && m1[5] == 10 && m2[1] == -1 && - m2[5] == 10 && map2[1] == -1 && map2[5] == 10, - "Something is wrong with ForkMap"); - } - - // Arithmetic maps: - // - AddMap, SubMap, MulMap, DivMap - // - ShiftMap, ShiftWriteMap, ScaleMap, ScaleWriteMap - // - NegMap, NegWriteMap, AbsMap - { - checkConcept >(); - checkConcept >(); - checkConcept >(); - checkConcept >(); - - ConstMap c1(1.0), c2(3.14); - IdentityMap im; - ConvertMap, double> id(im); - check(addMap(c1,id)[0] == 1.0 && addMap(c1,id)[10] == 11.0, - "Something is wrong with AddMap"); - check(subMap(id,c1)[0] == -1.0 && subMap(id,c1)[10] == 9.0, - "Something is wrong with SubMap"); - check(mulMap(id,c2)[0] == 0 && mulMap(id,c2)[2] == 6.28, - "Something is wrong with MulMap"); - check(divMap(c2,id)[1] == 3.14 && divMap(c2,id)[2] == 1.57, - "Something is wrong with DivMap"); - - checkConcept >(); - checkConcept >(); - checkConcept >(); - checkConcept >(); - checkConcept >(); - checkConcept >(); - checkConcept >(); - - check(shiftMap(id, 2.0)[1] == 3.0 && shiftMap(id, 2.0)[10] == 12.0, - "Something is wrong with ShiftMap"); - check(shiftWriteMap(id, 2.0)[1] == 3.0 && - shiftWriteMap(id, 2.0)[10] == 12.0, - "Something is wrong with ShiftWriteMap"); - check(scaleMap(id, 2.0)[1] == 2.0 && scaleMap(id, 2.0)[10] == 20.0, - "Something is wrong with ScaleMap"); - check(scaleWriteMap(id, 2.0)[1] == 2.0 && - scaleWriteMap(id, 2.0)[10] == 20.0, - "Something is wrong with ScaleWriteMap"); - check(negMap(id)[1] == -1.0 && negMap(id)[-10] == 10.0, - "Something is wrong with NegMap"); - check(negWriteMap(id)[1] == -1.0 && negWriteMap(id)[-10] == 10.0, - "Something is wrong with NegWriteMap"); - check(absMap(id)[1] == 1.0 && absMap(id)[-10] == 10.0, - "Something is wrong with AbsMap"); - } - - // Logical maps: - // - TrueMap, FalseMap - // - AndMap, OrMap - // - NotMap, NotWriteMap - // - EqualMap, LessMap - { - checkConcept >(); - checkConcept >(); - checkConcept >(); - checkConcept >(); - checkConcept >(); - checkConcept >(); - checkConcept >(); - checkConcept >(); - - TrueMap tm; - FalseMap fm; - RangeMap rm(2); - rm[0] = true; rm[1] = false; - check(andMap(tm,rm)[0] && !andMap(tm,rm)[1] && - !andMap(fm,rm)[0] && !andMap(fm,rm)[1], - "Something is wrong with AndMap"); - check(orMap(tm,rm)[0] && orMap(tm,rm)[1] && - orMap(fm,rm)[0] && !orMap(fm,rm)[1], - "Something is wrong with OrMap"); - check(!notMap(rm)[0] && notMap(rm)[1], - "Something is wrong with NotMap"); - check(!notWriteMap(rm)[0] && notWriteMap(rm)[1], - "Something is wrong with NotWriteMap"); - - ConstMap cm(2.0); - IdentityMap im; - ConvertMap, double> id(im); - check(lessMap(id,cm)[1] && !lessMap(id,cm)[2] && !lessMap(id,cm)[3], - "Something is wrong with LessMap"); - check(!equalMap(id,cm)[1] && equalMap(id,cm)[2] && !equalMap(id,cm)[3], - "Something is wrong with EqualMap"); - } - - // LoggerBoolMap - { - typedef std::vector vec; - checkConcept, LoggerBoolMap >(); - checkConcept, - LoggerBoolMap > >(); - - vec v1; - vec v2(10); - LoggerBoolMap > - map1(std::back_inserter(v1)); - LoggerBoolMap map2(v2.begin()); - map1.set(10, false); - map1.set(20, true); map2.set(20, true); - map1.set(30, false); map2.set(40, false); - map1.set(50, true); map2.set(50, true); - map1.set(60, true); map2.set(60, true); - check(v1.size() == 3 && v2.size() == 10 && - v1[0]==20 && v1[1]==50 && v1[2]==60 && - v2[0]==20 && v2[1]==50 && v2[2]==60, - "Something is wrong with LoggerBoolMap"); - - int i = 0; - for ( LoggerBoolMap::Iterator it = map2.begin(); - it != map2.end(); ++it ) - check(v1[i++] == *it, "Something is wrong with LoggerBoolMap"); - - typedef ListDigraph Graph; - DIGRAPH_TYPEDEFS(Graph); - Graph gr; - - Node n0 = gr.addNode(); - Node n1 = gr.addNode(); - Node n2 = gr.addNode(); - Node n3 = gr.addNode(); - - gr.addArc(n3, n0); - gr.addArc(n3, n2); - gr.addArc(n0, n2); - gr.addArc(n2, n1); - gr.addArc(n0, n1); - - { - std::vector v; - dfs(gr).processedMap(loggerBoolMap(std::back_inserter(v))).run(); - - check(v.size()==4 && v[0]==n1 && v[1]==n2 && v[2]==n0 && v[3]==n3, - "Something is wrong with LoggerBoolMap"); - } - { - std::vector v(countNodes(gr)); - dfs(gr).processedMap(loggerBoolMap(v.begin())).run(); - - check(v.size()==4 && v[0]==n1 && v[1]==n2 && v[2]==n0 && v[3]==n3, - "Something is wrong with LoggerBoolMap"); - } - } - - // IdMap, RangeIdMap - { - typedef ListDigraph Graph; - DIGRAPH_TYPEDEFS(Graph); - - checkConcept, IdMap >(); - checkConcept, IdMap >(); - checkConcept, RangeIdMap >(); - checkConcept, RangeIdMap >(); - - Graph gr; - IdMap nmap(gr); - IdMap amap(gr); - RangeIdMap nrmap(gr); - RangeIdMap armap(gr); - - Node n0 = gr.addNode(); - Node n1 = gr.addNode(); - Node n2 = gr.addNode(); - - Arc a0 = gr.addArc(n0, n1); - Arc a1 = gr.addArc(n0, n2); - Arc a2 = gr.addArc(n2, n1); - Arc a3 = gr.addArc(n2, n0); - - check(nmap[n0] == gr.id(n0) && nmap(gr.id(n0)) == n0, "Wrong IdMap"); - check(nmap[n1] == gr.id(n1) && nmap(gr.id(n1)) == n1, "Wrong IdMap"); - check(nmap[n2] == gr.id(n2) && nmap(gr.id(n2)) == n2, "Wrong IdMap"); - - check(amap[a0] == gr.id(a0) && amap(gr.id(a0)) == a0, "Wrong IdMap"); - check(amap[a1] == gr.id(a1) && amap(gr.id(a1)) == a1, "Wrong IdMap"); - check(amap[a2] == gr.id(a2) && amap(gr.id(a2)) == a2, "Wrong IdMap"); - check(amap[a3] == gr.id(a3) && amap(gr.id(a3)) == a3, "Wrong IdMap"); - - check(nmap.inverse()[gr.id(n0)] == n0, "Wrong IdMap::InverseMap"); - check(amap.inverse()[gr.id(a0)] == a0, "Wrong IdMap::InverseMap"); - - check(nrmap.size() == 3 && armap.size() == 4, - "Wrong RangeIdMap::size()"); - - check(nrmap[n0] == 0 && nrmap(0) == n0, "Wrong RangeIdMap"); - check(nrmap[n1] == 1 && nrmap(1) == n1, "Wrong RangeIdMap"); - check(nrmap[n2] == 2 && nrmap(2) == n2, "Wrong RangeIdMap"); - - check(armap[a0] == 0 && armap(0) == a0, "Wrong RangeIdMap"); - check(armap[a1] == 1 && armap(1) == a1, "Wrong RangeIdMap"); - check(armap[a2] == 2 && armap(2) == a2, "Wrong RangeIdMap"); - check(armap[a3] == 3 && armap(3) == a3, "Wrong RangeIdMap"); - - check(nrmap.inverse()[0] == n0, "Wrong RangeIdMap::InverseMap"); - check(armap.inverse()[0] == a0, "Wrong RangeIdMap::InverseMap"); - - gr.erase(n1); - - if (nrmap[n0] == 1) nrmap.swap(n0, n2); - nrmap.swap(n2, n0); - if (armap[a1] == 1) armap.swap(a1, a3); - armap.swap(a3, a1); - - check(nrmap.size() == 2 && armap.size() == 2, - "Wrong RangeIdMap::size()"); - - check(nrmap[n0] == 1 && nrmap(1) == n0, "Wrong RangeIdMap"); - check(nrmap[n2] == 0 && nrmap(0) == n2, "Wrong RangeIdMap"); - - check(armap[a1] == 1 && armap(1) == a1, "Wrong RangeIdMap"); - check(armap[a3] == 0 && armap(0) == a3, "Wrong RangeIdMap"); - - check(nrmap.inverse()[0] == n2, "Wrong RangeIdMap::InverseMap"); - check(armap.inverse()[0] == a3, "Wrong RangeIdMap::InverseMap"); - } - - // SourceMap, TargetMap, ForwardMap, BackwardMap, InDegMap, OutDegMap - { - typedef ListGraph Graph; - GRAPH_TYPEDEFS(Graph); - - checkConcept, SourceMap >(); - checkConcept, TargetMap >(); - checkConcept, ForwardMap >(); - checkConcept, BackwardMap >(); - checkConcept, InDegMap >(); - checkConcept, OutDegMap >(); - - Graph gr; - Node n0 = gr.addNode(); - Node n1 = gr.addNode(); - Node n2 = gr.addNode(); - - gr.addEdge(n0,n1); - gr.addEdge(n1,n2); - gr.addEdge(n0,n2); - gr.addEdge(n2,n1); - gr.addEdge(n1,n2); - gr.addEdge(n0,n1); - - for (EdgeIt e(gr); e != INVALID; ++e) { - check(forwardMap(gr)[e] == gr.direct(e, true), "Wrong ForwardMap"); - check(backwardMap(gr)[e] == gr.direct(e, false), "Wrong BackwardMap"); - } - - check(mapCompare(gr, - sourceMap(orienter(gr, constMap(true))), - targetMap(orienter(gr, constMap(false)))), - "Wrong SourceMap or TargetMap"); - - typedef Orienter > Digraph; - ConstMap true_edge_map(true); - Digraph dgr(gr, true_edge_map); - OutDegMap odm(dgr); - InDegMap idm(dgr); - - check(odm[n0] == 3 && odm[n1] == 2 && odm[n2] == 1, "Wrong OutDegMap"); - check(idm[n0] == 0 && idm[n1] == 3 && idm[n2] == 3, "Wrong InDegMap"); - - gr.addEdge(n2, n0); - - check(odm[n0] == 3 && odm[n1] == 2 && odm[n2] == 2, "Wrong OutDegMap"); - check(idm[n0] == 1 && idm[n1] == 3 && idm[n2] == 3, "Wrong InDegMap"); - } - - // CrossRefMap - { - typedef ListDigraph Graph; - DIGRAPH_TYPEDEFS(Graph); - - checkConcept, - CrossRefMap >(); - checkConcept, - CrossRefMap >(); - checkConcept, - CrossRefMap >(); - - Graph gr; - typedef CrossRefMap CRMap; - CRMap map(gr); - - Node n0 = gr.addNode(); - Node n1 = gr.addNode(); - Node n2 = gr.addNode(); - - map.set(n0, 'A'); - map.set(n1, 'B'); - map.set(n2, 'C'); - - check(map[n0] == 'A' && map('A') == n0 && map.inverse()['A'] == n0, - "Wrong CrossRefMap"); - check(map[n1] == 'B' && map('B') == n1 && map.inverse()['B'] == n1, - "Wrong CrossRefMap"); - check(map[n2] == 'C' && map('C') == n2 && map.inverse()['C'] == n2, - "Wrong CrossRefMap"); - check(map.count('A') == 1 && map.count('B') == 1 && map.count('C') == 1, - "Wrong CrossRefMap::count()"); - - CRMap::ValueIt it = map.beginValue(); - check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' && - it == map.endValue(), "Wrong value iterator"); - - map.set(n2, 'A'); - - check(map[n0] == 'A' && map[n1] == 'B' && map[n2] == 'A', - "Wrong CrossRefMap"); - check(map('A') == n0 && map.inverse()['A'] == n0, "Wrong CrossRefMap"); - check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap"); - check(map('C') == INVALID && map.inverse()['C'] == INVALID, - "Wrong CrossRefMap"); - check(map.count('A') == 2 && map.count('B') == 1 && map.count('C') == 0, - "Wrong CrossRefMap::count()"); - - it = map.beginValue(); - check(*it++ == 'A' && *it++ == 'A' && *it++ == 'B' && - it == map.endValue(), "Wrong value iterator"); - - map.set(n0, 'C'); - - check(map[n0] == 'C' && map[n1] == 'B' && map[n2] == 'A', - "Wrong CrossRefMap"); - check(map('A') == n2 && map.inverse()['A'] == n2, "Wrong CrossRefMap"); - check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap"); - check(map('C') == n0 && map.inverse()['C'] == n0, "Wrong CrossRefMap"); - check(map.count('A') == 1 && map.count('B') == 1 && map.count('C') == 1, - "Wrong CrossRefMap::count()"); - - it = map.beginValue(); - check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' && - it == map.endValue(), "Wrong value iterator"); - } - - // CrossRefMap - { - typedef SmartDigraph Graph; - DIGRAPH_TYPEDEFS(Graph); - - checkConcept, - CrossRefMap >(); - - Graph gr; - typedef CrossRefMap CRMap; - typedef CRMap::ValueIterator ValueIt; - CRMap map(gr); - - Node n0 = gr.addNode(); - Node n1 = gr.addNode(); - Node n2 = gr.addNode(); - - map.set(n0, 'A'); - map.set(n1, 'B'); - map.set(n2, 'C'); - map.set(n2, 'A'); - map.set(n0, 'C'); - - check(map[n0] == 'C' && map[n1] == 'B' && map[n2] == 'A', - "Wrong CrossRefMap"); - check(map('A') == n2 && map.inverse()['A'] == n2, "Wrong CrossRefMap"); - check(map('B') == n1 && map.inverse()['B'] == n1, "Wrong CrossRefMap"); - check(map('C') == n0 && map.inverse()['C'] == n0, "Wrong CrossRefMap"); - - ValueIt it = map.beginValue(); - check(*it++ == 'A' && *it++ == 'B' && *it++ == 'C' && - it == map.endValue(), "Wrong value iterator"); - } - - // Iterable bool map - { - typedef SmartGraph Graph; - typedef SmartGraph::Node Item; - - typedef IterableBoolMap Ibm; - checkConcept, Ibm>(); - - const int num = 10; - Graph g; - Ibm map0(g, true); - std::vector items; - for (int i = 0; i < num; ++i) { - items.push_back(g.addNode()); - } - - Ibm map1(g, true); - int n = 0; - for (Ibm::TrueIt it(map1); it != INVALID; ++it) { - check(map1[static_cast(it)], "Wrong TrueIt"); - ++n; - } - check(n == num, "Wrong number"); - - n = 0; - for (Ibm::ItemIt it(map1, true); it != INVALID; ++it) { - check(map1[static_cast(it)], "Wrong ItemIt for true"); - ++n; - } - check(n == num, "Wrong number"); - check(Ibm::FalseIt(map1) == INVALID, "Wrong FalseIt"); - check(Ibm::ItemIt(map1, false) == INVALID, "Wrong ItemIt for false"); - - map1[items[5]] = true; - - n = 0; - for (Ibm::ItemIt it(map1, true); it != INVALID; ++it) { - check(map1[static_cast(it)], "Wrong ItemIt for true"); - ++n; - } - check(n == num, "Wrong number"); - - map1[items[num / 2]] = false; - check(map1[items[num / 2]] == false, "Wrong map value"); - - n = 0; - for (Ibm::TrueIt it(map1); it != INVALID; ++it) { - check(map1[static_cast(it)], "Wrong TrueIt for true"); - ++n; - } - check(n == num - 1, "Wrong number"); - - n = 0; - for (Ibm::FalseIt it(map1); it != INVALID; ++it) { - check(!map1[static_cast(it)], "Wrong FalseIt for true"); - ++n; - } - check(n == 1, "Wrong number"); - - map1[items[0]] = false; - check(map1[items[0]] == false, "Wrong map value"); - - map1[items[num - 1]] = false; - check(map1[items[num - 1]] == false, "Wrong map value"); - - n = 0; - for (Ibm::TrueIt it(map1); it != INVALID; ++it) { - check(map1[static_cast(it)], "Wrong TrueIt for true"); - ++n; - } - check(n == num - 3, "Wrong number"); - check(map1.trueNum() == num - 3, "Wrong number"); - - n = 0; - for (Ibm::FalseIt it(map1); it != INVALID; ++it) { - check(!map1[static_cast(it)], "Wrong FalseIt for true"); - ++n; - } - check(n == 3, "Wrong number"); - check(map1.falseNum() == 3, "Wrong number"); - } - - // Iterable int map - { - typedef SmartGraph Graph; - typedef SmartGraph::Node Item; - typedef IterableIntMap Iim; - - checkConcept, Iim>(); - - const int num = 10; - Graph g; - Iim map0(g, 0); - std::vector items; - for (int i = 0; i < num; ++i) { - items.push_back(g.addNode()); - } - - Iim map1(g); - check(map1.size() == 0, "Wrong size"); - - for (int i = 0; i < num; ++i) { - map1[items[i]] = i; - } - check(map1.size() == num, "Wrong size"); - - for (int i = 0; i < num; ++i) { - Iim::ItemIt it(map1, i); - check(static_cast(it) == items[i], "Wrong value"); - ++it; - check(static_cast(it) == INVALID, "Wrong value"); - } - - for (int i = 0; i < num; ++i) { - map1[items[i]] = i % 2; - } - check(map1.size() == 2, "Wrong size"); - - int n = 0; - for (Iim::ItemIt it(map1, 0); it != INVALID; ++it) { - check(map1[static_cast(it)] == 0, "Wrong value"); - ++n; - } - check(n == (num + 1) / 2, "Wrong number"); - - for (Iim::ItemIt it(map1, 1); it != INVALID; ++it) { - check(map1[static_cast(it)] == 1, "Wrong value"); - ++n; - } - check(n == num, "Wrong number"); - - } - - // Iterable value map - { - typedef SmartGraph Graph; - typedef SmartGraph::Node Item; - typedef IterableValueMap Ivm; - - checkConcept, Ivm>(); - - const int num = 10; - Graph g; - Ivm map0(g, 0.0); - std::vector items; - for (int i = 0; i < num; ++i) { - items.push_back(g.addNode()); - } - - Ivm map1(g, 0.0); - check(distance(map1.beginValue(), map1.endValue()) == 1, "Wrong size"); - check(*map1.beginValue() == 0.0, "Wrong value"); - - for (int i = 0; i < num; ++i) { - map1.set(items[i], static_cast(i)); - } - check(distance(map1.beginValue(), map1.endValue()) == num, "Wrong size"); - - for (int i = 0; i < num; ++i) { - Ivm::ItemIt it(map1, static_cast(i)); - check(static_cast(it) == items[i], "Wrong value"); - ++it; - check(static_cast(it) == INVALID, "Wrong value"); - } - - for (Ivm::ValueIt vit = map1.beginValue(); - vit != map1.endValue(); ++vit) { - check(map1[static_cast(Ivm::ItemIt(map1, *vit))] == *vit, - "Wrong ValueIt"); - } - - for (int i = 0; i < num; ++i) { - map1.set(items[i], static_cast(i % 2)); - } - check(distance(map1.beginValue(), map1.endValue()) == 2, "Wrong size"); - - int n = 0; - for (Ivm::ItemIt it(map1, 0.0); it != INVALID; ++it) { - check(map1[static_cast(it)] == 0.0, "Wrong value"); - ++n; - } - check(n == (num + 1) / 2, "Wrong number"); - - for (Ivm::ItemIt it(map1, 1.0); it != INVALID; ++it) { - check(map1[static_cast(it)] == 1.0, "Wrong value"); - ++n; - } - check(n == num, "Wrong number"); - - } - - // Graph map utilities: - // mapMin(), mapMax(), mapMinValue(), mapMaxValue() - // mapFind(), mapFindIf(), mapCount(), mapCountIf() - // mapCopy(), mapCompare(), mapFill() - { - DIGRAPH_TYPEDEFS(SmartDigraph); - - SmartDigraph g; - Node n1 = g.addNode(); - Node n2 = g.addNode(); - Node n3 = g.addNode(); - - SmartDigraph::NodeMap map1(g); - SmartDigraph::ArcMap map2(g); - ConstMap cmap1 = A(); - ConstMap cmap2 = C(0); - - map1[n1] = 10; - map1[n2] = 5; - map1[n3] = 12; - - // mapMin(), mapMax(), mapMinValue(), mapMaxValue() - check(mapMin(g, map1) == n2, "Wrong mapMin()"); - check(mapMax(g, map1) == n3, "Wrong mapMax()"); - check(mapMin(g, map1, std::greater()) == n3, "Wrong mapMin()"); - check(mapMax(g, map1, std::greater()) == n2, "Wrong mapMax()"); - check(mapMinValue(g, map1) == 5, "Wrong mapMinValue()"); - check(mapMaxValue(g, map1) == 12, "Wrong mapMaxValue()"); - - check(mapMin(g, map2) == INVALID, "Wrong mapMin()"); - check(mapMax(g, map2) == INVALID, "Wrong mapMax()"); - - check(mapMin(g, cmap1) != INVALID, "Wrong mapMin()"); - check(mapMax(g, cmap2) == INVALID, "Wrong mapMax()"); - - Arc a1 = g.addArc(n1, n2); - Arc a2 = g.addArc(n1, n3); - Arc a3 = g.addArc(n2, n3); - Arc a4 = g.addArc(n3, n1); - - map2[a1] = 'b'; - map2[a2] = 'a'; - map2[a3] = 'b'; - map2[a4] = 'c'; - - // mapMin(), mapMax(), mapMinValue(), mapMaxValue() - check(mapMin(g, map2) == a2, "Wrong mapMin()"); - check(mapMax(g, map2) == a4, "Wrong mapMax()"); - check(mapMin(g, map2, std::greater()) == a4, "Wrong mapMin()"); - check(mapMax(g, map2, std::greater()) == a2, "Wrong mapMax()"); - check(mapMinValue(g, map2, std::greater()) == 'c', - "Wrong mapMinValue()"); - check(mapMaxValue(g, map2, std::greater()) == 'a', - "Wrong mapMaxValue()"); - - check(mapMin(g, cmap1) != INVALID, "Wrong mapMin()"); - check(mapMax(g, cmap2) != INVALID, "Wrong mapMax()"); - check(mapMaxValue(g, cmap2) == C(0), "Wrong mapMaxValue()"); - - check(mapMin(g, composeMap(functorToMap(&createC), map2)) == a2, - "Wrong mapMin()"); - check(mapMax(g, composeMap(functorToMap(&createC), map2)) == a4, - "Wrong mapMax()"); - check(mapMinValue(g, composeMap(functorToMap(&createC), map2)) == C('a'), - "Wrong mapMinValue()"); - check(mapMaxValue(g, composeMap(functorToMap(&createC), map2)) == C('c'), - "Wrong mapMaxValue()"); - - // mapFind(), mapFindIf() - check(mapFind(g, map1, 5) == n2, "Wrong mapFind()"); - check(mapFind(g, map1, 6) == INVALID, "Wrong mapFind()"); - check(mapFind(g, map2, 'a') == a2, "Wrong mapFind()"); - check(mapFind(g, map2, 'e') == INVALID, "Wrong mapFind()"); - check(mapFind(g, cmap2, C(0)) == ArcIt(g), "Wrong mapFind()"); - check(mapFind(g, cmap2, C(1)) == INVALID, "Wrong mapFind()"); - - check(mapFindIf(g, map1, Less(7)) == n2, - "Wrong mapFindIf()"); - check(mapFindIf(g, map1, Less(5)) == INVALID, - "Wrong mapFindIf()"); - check(mapFindIf(g, map2, Less('d')) == ArcIt(g), - "Wrong mapFindIf()"); - check(mapFindIf(g, map2, Less('a')) == INVALID, - "Wrong mapFindIf()"); - - // mapCount(), mapCountIf() - check(mapCount(g, map1, 5) == 1, "Wrong mapCount()"); - check(mapCount(g, map1, 6) == 0, "Wrong mapCount()"); - check(mapCount(g, map2, 'a') == 1, "Wrong mapCount()"); - check(mapCount(g, map2, 'b') == 2, "Wrong mapCount()"); - check(mapCount(g, map2, 'e') == 0, "Wrong mapCount()"); - check(mapCount(g, cmap2, C(0)) == 4, "Wrong mapCount()"); - check(mapCount(g, cmap2, C(1)) == 0, "Wrong mapCount()"); - - check(mapCountIf(g, map1, Less(11)) == 2, - "Wrong mapCountIf()"); - check(mapCountIf(g, map1, Less(13)) == 3, - "Wrong mapCountIf()"); - check(mapCountIf(g, map1, Less(5)) == 0, - "Wrong mapCountIf()"); - check(mapCountIf(g, map2, Less('d')) == 4, - "Wrong mapCountIf()"); - check(mapCountIf(g, map2, Less('c')) == 3, - "Wrong mapCountIf()"); - check(mapCountIf(g, map2, Less('a')) == 0, - "Wrong mapCountIf()"); - - // MapIt, ConstMapIt -/* -These tests can be used after applying bugfix #330 - typedef SmartDigraph::NodeMap::MapIt MapIt; - typedef SmartDigraph::NodeMap::ConstMapIt ConstMapIt; - check(*std::min_element(MapIt(map1), MapIt(INVALID)) == 5, - "Wrong NodeMap<>::MapIt"); - check(*std::max_element(ConstMapIt(map1), ConstMapIt(INVALID)) == 12, - "Wrong NodeMap<>::MapIt"); - - int sum = 0; - std::for_each(MapIt(map1), MapIt(INVALID), Sum(sum)); - check(sum == 27, "Wrong NodeMap<>::MapIt"); - std::for_each(ConstMapIt(map1), ConstMapIt(INVALID), Sum(sum)); - check(sum == 54, "Wrong NodeMap<>::ConstMapIt"); -*/ - - // mapCopy(), mapCompare(), mapFill() - check(mapCompare(g, map1, map1), "Wrong mapCompare()"); - check(mapCompare(g, cmap2, cmap2), "Wrong mapCompare()"); - check(mapCompare(g, map1, shiftMap(map1, 0)), "Wrong mapCompare()"); - check(mapCompare(g, map2, scaleMap(map2, 1)), "Wrong mapCompare()"); - check(!mapCompare(g, map1, shiftMap(map1, 1)), "Wrong mapCompare()"); - - SmartDigraph::NodeMap map3(g, 0); - SmartDigraph::ArcMap map4(g, 'a'); - - check(!mapCompare(g, map1, map3), "Wrong mapCompare()"); - check(!mapCompare(g, map2, map4), "Wrong mapCompare()"); - - mapCopy(g, map1, map3); - mapCopy(g, map2, map4); - - check(mapCompare(g, map1, map3), "Wrong mapCompare() or mapCopy()"); - check(mapCompare(g, map2, map4), "Wrong mapCompare() or mapCopy()"); - - Undirector ug(g); - Undirector::EdgeMap umap1(ug, 'x'); - Undirector::ArcMap umap2(ug, 3.14); - - check(!mapCompare(g, map2, umap1), "Wrong mapCompare() or mapCopy()"); - check(!mapCompare(g, umap1, map2), "Wrong mapCompare() or mapCopy()"); - check(!mapCompare(ug, map2, umap1), "Wrong mapCompare() or mapCopy()"); - check(!mapCompare(ug, umap1, map2), "Wrong mapCompare() or mapCopy()"); - - mapCopy(g, map2, umap1); - - check(mapCompare(g, map2, umap1), "Wrong mapCompare() or mapCopy()"); - check(mapCompare(g, umap1, map2), "Wrong mapCompare() or mapCopy()"); - check(mapCompare(ug, map2, umap1), "Wrong mapCompare() or mapCopy()"); - check(mapCompare(ug, umap1, map2), "Wrong mapCompare() or mapCopy()"); - - mapCopy(g, map2, umap1); - mapCopy(g, umap1, map2); - mapCopy(ug, map2, umap1); - mapCopy(ug, umap1, map2); - - check(!mapCompare(ug, umap1, umap2), "Wrong mapCompare() or mapCopy()"); - mapCopy(ug, umap1, umap2); - check(mapCompare(ug, umap1, umap2), "Wrong mapCompare() or mapCopy()"); - - check(!mapCompare(g, map1, constMap(2)), "Wrong mapCompare()"); - mapFill(g, map1, 2); - check(mapCompare(g, constMap(2), map1), "Wrong mapFill()"); - - check(!mapCompare(g, map2, constMap('z')), "Wrong mapCompare()"); - mapCopy(g, constMap('z'), map2); - check(mapCompare(g, constMap('z'), map2), "Wrong mapCopy()"); - } - - return 0; -} diff --git a/deps/lemon/test/matching_test.cc b/deps/lemon/test/matching_test.cc deleted file mode 100644 index dcb1d3b57..000000000 --- a/deps/lemon/test/matching_test.cc +++ /dev/null @@ -1,449 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "test_tools.h" - -using namespace std; -using namespace lemon; - -GRAPH_TYPEDEFS(SmartGraph); - - -const int lgfn = 3; -const std::string lgf[lgfn] = { - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "7\n" - "@edges\n" - " label weight\n" - "7 4 0 984\n" - "0 7 1 73\n" - "7 1 2 204\n" - "2 3 3 583\n" - "2 7 4 565\n" - "2 1 5 582\n" - "0 4 6 551\n" - "2 5 7 385\n" - "1 5 8 561\n" - "5 3 9 484\n" - "7 5 10 904\n" - "3 6 11 47\n" - "7 6 12 888\n" - "3 0 13 747\n" - "6 1 14 310\n", - - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "7\n" - "@edges\n" - " label weight\n" - "2 5 0 710\n" - "0 5 1 241\n" - "2 4 2 856\n" - "2 6 3 762\n" - "4 1 4 747\n" - "6 1 5 962\n" - "4 7 6 723\n" - "1 7 7 661\n" - "2 3 8 376\n" - "1 0 9 416\n" - "6 7 10 391\n", - - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "7\n" - "@edges\n" - " label weight\n" - "6 2 0 553\n" - "0 7 1 653\n" - "6 3 2 22\n" - "4 7 3 846\n" - "7 2 4 981\n" - "7 6 5 250\n" - "5 2 6 539\n", -}; - -void checkMaxMatchingCompile() -{ - typedef concepts::Graph Graph; - typedef Graph::Node Node; - typedef Graph::Edge Edge; - typedef Graph::EdgeMap MatMap; - - Graph g; - Node n; - Edge e; - MatMap mat(g); - - MaxMatching mat_test(g); - const MaxMatching& - const_mat_test = mat_test; - - mat_test.init(); - mat_test.greedyInit(); - mat_test.matchingInit(mat); - mat_test.startSparse(); - mat_test.startDense(); - mat_test.run(); - - const_mat_test.matchingSize(); - const_mat_test.matching(e); - const_mat_test.matching(n); - const MaxMatching::MatchingMap& mmap = - const_mat_test.matchingMap(); - e = mmap[n]; - const_mat_test.mate(n); - - MaxMatching::Status stat = - const_mat_test.status(n); - ::lemon::ignore_unused_variable_warning(stat); - const MaxMatching::StatusMap& smap = - const_mat_test.statusMap(); - stat = smap[n]; - const_mat_test.barrier(n); -} - -void checkMaxWeightedMatchingCompile() -{ - typedef concepts::Graph Graph; - typedef Graph::Node Node; - typedef Graph::Edge Edge; - typedef Graph::EdgeMap WeightMap; - - Graph g; - Node n; - Edge e; - WeightMap w(g); - - MaxWeightedMatching mat_test(g, w); - const MaxWeightedMatching& - const_mat_test = mat_test; - - mat_test.init(); - mat_test.start(); - mat_test.run(); - - const_mat_test.matchingWeight(); - const_mat_test.matchingSize(); - const_mat_test.matching(e); - const_mat_test.matching(n); - const MaxWeightedMatching::MatchingMap& mmap = - const_mat_test.matchingMap(); - e = mmap[n]; - const_mat_test.mate(n); - - int k = 0; - const_mat_test.dualValue(); - const_mat_test.nodeValue(n); - const_mat_test.blossomNum(); - const_mat_test.blossomSize(k); - const_mat_test.blossomValue(k); -} - -void checkMaxWeightedPerfectMatchingCompile() -{ - typedef concepts::Graph Graph; - typedef Graph::Node Node; - typedef Graph::Edge Edge; - typedef Graph::EdgeMap WeightMap; - - Graph g; - Node n; - Edge e; - WeightMap w(g); - - MaxWeightedPerfectMatching mat_test(g, w); - const MaxWeightedPerfectMatching& - const_mat_test = mat_test; - - mat_test.init(); - mat_test.start(); - mat_test.run(); - - const_mat_test.matchingWeight(); - const_mat_test.matching(e); - const_mat_test.matching(n); - const MaxWeightedPerfectMatching::MatchingMap& mmap = - const_mat_test.matchingMap(); - e = mmap[n]; - const_mat_test.mate(n); - - int k = 0; - const_mat_test.dualValue(); - const_mat_test.nodeValue(n); - const_mat_test.blossomNum(); - const_mat_test.blossomSize(k); - const_mat_test.blossomValue(k); -} - -void checkMatching(const SmartGraph& graph, - const MaxMatching& mm) { - int num = 0; - - IntNodeMap comp_index(graph); - UnionFind comp(comp_index); - - int barrier_num = 0; - - for (NodeIt n(graph); n != INVALID; ++n) { - check(mm.status(n) == MaxMatching::EVEN || - mm.matching(n) != INVALID, "Wrong Gallai-Edmonds decomposition"); - if (mm.status(n) == MaxMatching::ODD) { - ++barrier_num; - } else { - comp.insert(n); - } - } - - for (EdgeIt e(graph); e != INVALID; ++e) { - if (mm.matching(e)) { - check(e == mm.matching(graph.u(e)), "Wrong matching"); - check(e == mm.matching(graph.v(e)), "Wrong matching"); - ++num; - } - check(mm.status(graph.u(e)) != MaxMatching::EVEN || - mm.status(graph.v(e)) != MaxMatching::MATCHED, - "Wrong Gallai-Edmonds decomposition"); - - check(mm.status(graph.v(e)) != MaxMatching::EVEN || - mm.status(graph.u(e)) != MaxMatching::MATCHED, - "Wrong Gallai-Edmonds decomposition"); - - if (mm.status(graph.u(e)) != MaxMatching::ODD && - mm.status(graph.v(e)) != MaxMatching::ODD) { - comp.join(graph.u(e), graph.v(e)); - } - } - - std::set comp_root; - int odd_comp_num = 0; - for (NodeIt n(graph); n != INVALID; ++n) { - if (mm.status(n) != MaxMatching::ODD) { - int root = comp.find(n); - if (comp_root.find(root) == comp_root.end()) { - comp_root.insert(root); - if (comp.size(n) % 2 == 1) { - ++odd_comp_num; - } - } - } - } - - check(mm.matchingSize() == num, "Wrong matching"); - check(2 * num == countNodes(graph) - (odd_comp_num - barrier_num), - "Wrong matching"); - return; -} - -void checkWeightedMatching(const SmartGraph& graph, - const SmartGraph::EdgeMap& weight, - const MaxWeightedMatching& mwm) { - for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { - if (graph.u(e) == graph.v(e)) continue; - int rw = mwm.nodeValue(graph.u(e)) + mwm.nodeValue(graph.v(e)); - - for (int i = 0; i < mwm.blossomNum(); ++i) { - bool s = false, t = false; - for (MaxWeightedMatching::BlossomIt n(mwm, i); - n != INVALID; ++n) { - if (graph.u(e) == n) s = true; - if (graph.v(e) == n) t = true; - } - if (s == true && t == true) { - rw += mwm.blossomValue(i); - } - } - rw -= weight[e] * mwm.dualScale; - - check(rw >= 0, "Negative reduced weight"); - check(rw == 0 || !mwm.matching(e), - "Non-zero reduced weight on matching edge"); - } - - int pv = 0; - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - if (mwm.matching(n) != INVALID) { - check(mwm.nodeValue(n) >= 0, "Invalid node value"); - pv += weight[mwm.matching(n)]; - SmartGraph::Node o = graph.target(mwm.matching(n)); - check(mwm.mate(n) == o, "Invalid matching"); - check(mwm.matching(n) == graph.oppositeArc(mwm.matching(o)), - "Invalid matching"); - } else { - check(mwm.mate(n) == INVALID, "Invalid matching"); - check(mwm.nodeValue(n) == 0, "Invalid matching"); - } - } - - int dv = 0; - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - dv += mwm.nodeValue(n); - } - - for (int i = 0; i < mwm.blossomNum(); ++i) { - check(mwm.blossomValue(i) >= 0, "Invalid blossom value"); - check(mwm.blossomSize(i) % 2 == 1, "Even blossom size"); - dv += mwm.blossomValue(i) * ((mwm.blossomSize(i) - 1) / 2); - } - - check(pv * mwm.dualScale == dv * 2, "Wrong duality"); - - return; -} - -void checkWeightedPerfectMatching(const SmartGraph& graph, - const SmartGraph::EdgeMap& weight, - const MaxWeightedPerfectMatching& mwpm) { - for (SmartGraph::EdgeIt e(graph); e != INVALID; ++e) { - if (graph.u(e) == graph.v(e)) continue; - int rw = mwpm.nodeValue(graph.u(e)) + mwpm.nodeValue(graph.v(e)); - - for (int i = 0; i < mwpm.blossomNum(); ++i) { - bool s = false, t = false; - for (MaxWeightedPerfectMatching::BlossomIt n(mwpm, i); - n != INVALID; ++n) { - if (graph.u(e) == n) s = true; - if (graph.v(e) == n) t = true; - } - if (s == true && t == true) { - rw += mwpm.blossomValue(i); - } - } - rw -= weight[e] * mwpm.dualScale; - - check(rw >= 0, "Negative reduced weight"); - check(rw == 0 || !mwpm.matching(e), - "Non-zero reduced weight on matching edge"); - } - - int pv = 0; - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - check(mwpm.matching(n) != INVALID, "Non perfect"); - pv += weight[mwpm.matching(n)]; - SmartGraph::Node o = graph.target(mwpm.matching(n)); - check(mwpm.mate(n) == o, "Invalid matching"); - check(mwpm.matching(n) == graph.oppositeArc(mwpm.matching(o)), - "Invalid matching"); - } - - int dv = 0; - for (SmartGraph::NodeIt n(graph); n != INVALID; ++n) { - dv += mwpm.nodeValue(n); - } - - for (int i = 0; i < mwpm.blossomNum(); ++i) { - check(mwpm.blossomValue(i) >= 0, "Invalid blossom value"); - check(mwpm.blossomSize(i) % 2 == 1, "Even blossom size"); - dv += mwpm.blossomValue(i) * ((mwpm.blossomSize(i) - 1) / 2); - } - - check(pv * mwpm.dualScale == dv * 2, "Wrong duality"); - - return; -} - - -int main() { - - for (int i = 0; i < lgfn; ++i) { - SmartGraph graph; - SmartGraph::EdgeMap weight(graph); - - istringstream lgfs(lgf[i]); - graphReader(graph, lgfs). - edgeMap("weight", weight).run(); - - bool perfect; - { - MaxMatching mm(graph); - mm.run(); - checkMatching(graph, mm); - perfect = 2 * mm.matchingSize() == countNodes(graph); - } - - { - MaxWeightedMatching mwm(graph, weight); - mwm.run(); - checkWeightedMatching(graph, weight, mwm); - } - - { - MaxWeightedMatching mwm(graph, weight); - mwm.init(); - mwm.start(); - checkWeightedMatching(graph, weight, mwm); - } - - { - MaxWeightedPerfectMatching mwpm(graph, weight); - bool result = mwpm.run(); - - check(result == perfect, "Perfect matching found"); - if (perfect) { - checkWeightedPerfectMatching(graph, weight, mwpm); - } - } - - { - MaxWeightedPerfectMatching mwpm(graph, weight); - mwpm.init(); - bool result = mwpm.start(); - - check(result == perfect, "Perfect matching found"); - if (perfect) { - checkWeightedPerfectMatching(graph, weight, mwpm); - } - } - } - - return 0; -} diff --git a/deps/lemon/test/max_cardinality_search_test.cc b/deps/lemon/test/max_cardinality_search_test.cc deleted file mode 100644 index c01066f36..000000000 --- a/deps/lemon/test/max_cardinality_search_test.cc +++ /dev/null @@ -1,162 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -#include "test_tools.h" -#include -#include -#include -#include -#include -#include - -using namespace lemon; -using namespace std; - -char test_lgf[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "@arcs\n" - " label capacity\n" - "0 1 0 2\n" - "1 0 1 2\n" - "2 1 2 1\n" - "2 3 3 3\n" - "3 2 4 3\n" - "3 1 5 5\n" - "@attributes\n" - "s 0\n" - "x 1\n" - "y 2\n" - "z 3\n"; - -void checkMaxCardSearchCompile() { - - typedef concepts::Digraph Digraph; - typedef int Value; - typedef Digraph::Node Node; - typedef Digraph::Arc Arc; - typedef concepts::ReadMap CapMap; - typedef concepts::ReadWriteMap CardMap; - typedef concepts::ReadWriteMap ProcMap; - typedef Digraph::NodeMap HeapCrossRef; - - Digraph g; - Node n,s; - CapMap cap; - CardMap card; - ProcMap proc; - HeapCrossRef crossref(g); - - typedef MaxCardinalitySearch - ::SetCapacityMap - ::SetCardinalityMap - ::SetProcessedMap - ::SetStandardHeap > - ::Create MaxCardType; - - MaxCardType maxcard(g,cap); - const MaxCardType& const_maxcard = maxcard; - - const MaxCardType::Heap& heap_const = const_maxcard.heap(); - MaxCardType::Heap& heap = const_cast(heap_const); - maxcard.heap(heap,crossref); - - maxcard.capacityMap(cap).cardinalityMap(card).processedMap(proc); - - maxcard.init(); - maxcard.addSource(s); - n = maxcard.nextNode(); - maxcard.processNextNode(); - maxcard.start(); - maxcard.run(s); - maxcard.run(); - } - - void checkWithIntMap( std::istringstream& input) - { - typedef SmartDigraph Digraph; - typedef Digraph::Node Node; - typedef Digraph::ArcMap CapMap; - - Digraph g; - Node s,x,y,z,a; - CapMap cap(g); - - DigraphReader(g,input). - arcMap("capacity", cap). - node("s",s). - node("x",x). - node("y",y). - node("z",z). - run(); - - MaxCardinalitySearch maxcard(g,cap); - - maxcard.init(); - maxcard.addSource(s); - maxcard.start(x); - - check(maxcard.processed(s) && !maxcard.processed(x) && - !maxcard.processed(y), "Wrong processed()!"); - - a=maxcard.nextNode(); - check(maxcard.processNextNode()==a, - "Wrong nextNode() or processNextNode() return value!"); - - check(maxcard.processed(a), "Wrong processNextNode()!"); - - maxcard.start(); - check(maxcard.cardinality(x)==2 && maxcard.cardinality(y)>=4, - "Wrong cardinalities!"); - } - - void checkWithConst1Map(std::istringstream &input) { - typedef SmartDigraph Digraph; - typedef Digraph::Node Node; - - Digraph g; - Node s,x,y,z; - - DigraphReader(g,input). - node("s",s). - node("x",x). - node("y",y). - node("z",z). - run(); - - MaxCardinalitySearch maxcard(g); - maxcard.run(s); - check(maxcard.cardinality(x)==1 && - maxcard.cardinality(y)+maxcard.cardinality(z)==3, - "Wrong cardinalities!"); -} - -int main() { - - std::istringstream input1(test_lgf); - checkWithIntMap(input1); - - std::istringstream input2(test_lgf); - checkWithConst1Map(input2); -} diff --git a/deps/lemon/test/max_clique_test.cc b/deps/lemon/test/max_clique_test.cc deleted file mode 100644 index d16f0f990..000000000 --- a/deps/lemon/test/max_clique_test.cc +++ /dev/null @@ -1,188 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "test_tools.h" - -using namespace lemon; - -char test_lgf[] = - "@nodes\n" - "label max_clique\n" - "1 0\n" - "2 0\n" - "3 0\n" - "4 1\n" - "5 1\n" - "6 1\n" - "7 1\n" - "@edges\n" - " label\n" - "1 2 1\n" - "1 3 2\n" - "1 4 3\n" - "1 6 4\n" - "2 3 5\n" - "2 5 6\n" - "2 7 7\n" - "3 4 8\n" - "3 5 9\n" - "4 5 10\n" - "4 6 11\n" - "4 7 12\n" - "5 6 13\n" - "5 7 14\n" - "6 7 15\n"; - - -// Check with general graphs -template -void checkMaxCliqueGeneral(Param rule) { - typedef ListGraph GR; - typedef GrossoLocatelliPullanMc McAlg; - typedef McAlg::CliqueNodeIt CliqueIt; - - // Basic tests - { - GR g; - GR::NodeMap map(g); - McAlg mc(g); - mc.iterationLimit(50); - check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause"); - check(mc.cliqueSize() == 0, "Wrong clique size"); - check(CliqueIt(mc) == INVALID, "Wrong CliqueNodeIt"); - - GR::Node u = g.addNode(); - check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause"); - check(mc.cliqueSize() == 1, "Wrong clique size"); - mc.cliqueMap(map); - check(map[u], "Wrong clique map"); - CliqueIt it1(mc); - check(static_cast(it1) == u && ++it1 == INVALID, - "Wrong CliqueNodeIt"); - - GR::Node v = g.addNode(); - check(mc.run(rule) == McAlg::ITERATION_LIMIT, "Wrong termination cause"); - check(mc.cliqueSize() == 1, "Wrong clique size"); - mc.cliqueMap(map); - check((map[u] && !map[v]) || (map[v] && !map[u]), "Wrong clique map"); - CliqueIt it2(mc); - check(it2 != INVALID && ++it2 == INVALID, "Wrong CliqueNodeIt"); - - g.addEdge(u, v); - check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause"); - check(mc.cliqueSize() == 2, "Wrong clique size"); - mc.cliqueMap(map); - check(map[u] && map[v], "Wrong clique map"); - CliqueIt it3(mc); - check(it3 != INVALID && ++it3 != INVALID && ++it3 == INVALID, - "Wrong CliqueNodeIt"); - } - - // Test graph - { - GR g; - GR::NodeMap max_clique(g); - GR::NodeMap map(g); - std::istringstream input(test_lgf); - graphReader(g, input) - .nodeMap("max_clique", max_clique) - .run(); - - McAlg mc(g); - mc.iterationLimit(50); - check(mc.run(rule) == McAlg::ITERATION_LIMIT, "Wrong termination cause"); - check(mc.cliqueSize() == 4, "Wrong clique size"); - mc.cliqueMap(map); - for (GR::NodeIt n(g); n != INVALID; ++n) { - check(map[n] == max_clique[n], "Wrong clique map"); - } - int cnt = 0; - for (CliqueIt n(mc); n != INVALID; ++n) { - cnt++; - check(map[n] && max_clique[n], "Wrong CliqueNodeIt"); - } - check(cnt == 4, "Wrong CliqueNodeIt"); - } -} - -// Check with full graphs -template -void checkMaxCliqueFullGraph(Param rule) { - typedef FullGraph GR; - typedef GrossoLocatelliPullanMc McAlg; - typedef McAlg::CliqueNodeIt CliqueIt; - - for (int size = 0; size <= 40; size = size * 3 + 1) { - GR g(size); - GR::NodeMap map(g); - McAlg mc(g); - check(mc.run(rule) == McAlg::SIZE_LIMIT, "Wrong termination cause"); - check(mc.cliqueSize() == size, "Wrong clique size"); - mc.cliqueMap(map); - for (GR::NodeIt n(g); n != INVALID; ++n) { - check(map[n], "Wrong clique map"); - } - int cnt = 0; - for (CliqueIt n(mc); n != INVALID; ++n) cnt++; - check(cnt == size, "Wrong CliqueNodeIt"); - } -} - -// Check with grid graphs -template -void checkMaxCliqueGridGraph(Param rule) { - GridGraph g(5, 7); - GridGraph::NodeMap map(g); - GrossoLocatelliPullanMc mc(g); - - mc.iterationLimit(100); - check(mc.run(rule) == mc.ITERATION_LIMIT, "Wrong termination cause"); - check(mc.cliqueSize() == 2, "Wrong clique size"); - - mc.stepLimit(100); - check(mc.run(rule) == mc.STEP_LIMIT, "Wrong termination cause"); - check(mc.cliqueSize() == 2, "Wrong clique size"); - - mc.sizeLimit(2); - check(mc.run(rule) == mc.SIZE_LIMIT, "Wrong termination cause"); - check(mc.cliqueSize() == 2, "Wrong clique size"); -} - - -int main() { - checkMaxCliqueGeneral(GrossoLocatelliPullanMc::RANDOM); - checkMaxCliqueGeneral(GrossoLocatelliPullanMc::DEGREE_BASED); - checkMaxCliqueGeneral(GrossoLocatelliPullanMc::PENALTY_BASED); - - checkMaxCliqueFullGraph(GrossoLocatelliPullanMc::RANDOM); - checkMaxCliqueFullGraph(GrossoLocatelliPullanMc::DEGREE_BASED); - checkMaxCliqueFullGraph(GrossoLocatelliPullanMc::PENALTY_BASED); - - checkMaxCliqueGridGraph(GrossoLocatelliPullanMc::RANDOM); - checkMaxCliqueGridGraph(GrossoLocatelliPullanMc::DEGREE_BASED); - checkMaxCliqueGridGraph(GrossoLocatelliPullanMc::PENALTY_BASED); - - return 0; -} diff --git a/deps/lemon/test/max_flow_test.cc b/deps/lemon/test/max_flow_test.cc deleted file mode 100644 index f63874a61..000000000 --- a/deps/lemon/test/max_flow_test.cc +++ /dev/null @@ -1,395 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -#include "test_tools.h" -#include -#include -#include -#include -#include -#include -#include - -using namespace lemon; - -char test_lgf[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "7\n" - "8\n" - "9\n" - "@arcs\n" - " label capacity\n" - "0 1 0 20\n" - "0 2 1 0\n" - "1 1 2 3\n" - "1 2 3 8\n" - "1 3 4 8\n" - "2 5 5 5\n" - "3 2 6 5\n" - "3 5 7 5\n" - "3 6 8 5\n" - "4 3 9 3\n" - "5 7 10 3\n" - "5 6 11 10\n" - "5 8 12 10\n" - "6 8 13 8\n" - "8 9 14 20\n" - "8 1 15 5\n" - "9 5 16 5\n" - "@attributes\n" - "source 1\n" - "target 8\n"; - - -// Checks the general interface of a max flow algorithm -template -struct MaxFlowClassConcept -{ - - template - struct Constraints { - - typedef typename GR::Node Node; - typedef typename GR::Arc Arc; - typedef typename CAP::Value Value; - typedef concepts::ReadWriteMap FlowMap; - typedef concepts::WriteMap CutMap; - - GR g; - Node n; - Arc e; - CAP cap; - FlowMap flow; - CutMap cut; - Value v; - bool b; - - void constraints() { - checkConcept(); - - const Constraints& me = *this; - - typedef typename MF - ::template SetFlowMap - ::Create MaxFlowType; - typedef typename MF::Create MaxFlowType2; - MaxFlowType max_flow(me.g, me.cap, me.n, me.n); - const MaxFlowType& const_max_flow = max_flow; - - max_flow - .capacityMap(cap) - .flowMap(flow) - .source(n) - .target(n); - - typename MaxFlowType::Tolerance tol = const_max_flow.tolerance(); - max_flow.tolerance(tol); - - max_flow.init(); - max_flow.init(cap); - max_flow.run(); - - v = const_max_flow.flowValue(); - v = const_max_flow.flow(e); - const FlowMap& fm = const_max_flow.flowMap(); - - b = const_max_flow.minCut(n); - const_max_flow.minCutMap(cut); - - ::lemon::ignore_unused_variable_warning(fm); - } - - }; - -}; - -// Checks the specific parts of Preflow's interface -void checkPreflowCompile() -{ - typedef int Value; - typedef concepts::Digraph Digraph; - typedef concepts::ReadMap CapMap; - typedef Elevator Elev; - typedef LinkedElevator LinkedElev; - - Digraph g; - Digraph::Node n; - CapMap cap; - - typedef Preflow - ::SetElevator - ::SetStandardElevator - ::Create PreflowType; - PreflowType preflow_test(g, cap, n, n); - const PreflowType& const_preflow_test = preflow_test; - - const PreflowType::Elevator& elev = const_preflow_test.elevator(); - preflow_test.elevator(const_cast(elev)); - - bool b = preflow_test.init(cap); - preflow_test.startFirstPhase(); - preflow_test.startSecondPhase(); - preflow_test.runMinCut(); - - ::lemon::ignore_unused_variable_warning(b); -} - -// Checks the specific parts of EdmondsKarp's interface -void checkEdmondsKarpCompile() -{ - typedef int Value; - typedef concepts::Digraph Digraph; - typedef concepts::ReadMap CapMap; - typedef Elevator Elev; - typedef LinkedElevator LinkedElev; - - Digraph g; - Digraph::Node n; - CapMap cap; - - EdmondsKarp ek_test(g, cap, n, n); - - ek_test.init(cap); - bool b = ek_test.checkedInit(cap); - b = ek_test.augment(); - ek_test.start(); - - ::lemon::ignore_unused_variable_warning(b); -} - - -template -T cutValue (const SmartDigraph& g, - const SmartDigraph::NodeMap& cut, - const SmartDigraph::ArcMap& cap) { - - T c=0; - for(SmartDigraph::ArcIt e(g); e!=INVALID; ++e) { - if (cut[g.source(e)] && !cut[g.target(e)]) c+=cap[e]; - } - return c; -} - -template -bool checkFlow(const SmartDigraph& g, - const SmartDigraph::ArcMap& flow, - const SmartDigraph::ArcMap& cap, - SmartDigraph::Node s, SmartDigraph::Node t) { - - for (SmartDigraph::ArcIt e(g); e != INVALID; ++e) { - if (flow[e] < 0 || flow[e] > cap[e]) return false; - } - - for (SmartDigraph::NodeIt n(g); n != INVALID; ++n) { - if (n == s || n == t) continue; - T sum = 0; - for (SmartDigraph::OutArcIt e(g, n); e != INVALID; ++e) { - sum += flow[e]; - } - for (SmartDigraph::InArcIt e(g, n); e != INVALID; ++e) { - sum -= flow[e]; - } - if (sum != 0) return false; - } - return true; -} - -void initFlowTest() -{ - DIGRAPH_TYPEDEFS(SmartDigraph); - - SmartDigraph g; - SmartDigraph::ArcMap cap(g),iflow(g); - Node s=g.addNode(); Node t=g.addNode(); - Node n1=g.addNode(); Node n2=g.addNode(); - Arc a; - a=g.addArc(s,n1); cap[a]=20; iflow[a]=20; - a=g.addArc(n1,n2); cap[a]=10; iflow[a]=0; - a=g.addArc(n2,t); cap[a]=20; iflow[a]=0; - - Preflow pre(g,cap,s,t); - pre.init(iflow); - pre.startFirstPhase(); - check(pre.flowValue() == 10, "The incorrect max flow value."); - check(pre.minCut(s), "Wrong min cut (Node s)."); - check(pre.minCut(n1), "Wrong min cut (Node n1)."); - check(!pre.minCut(n2), "Wrong min cut (Node n2)."); - check(!pre.minCut(t), "Wrong min cut (Node t)."); -} - -template -void checkMaxFlowAlg() { - typedef SmartDigraph Digraph; - DIGRAPH_TYPEDEFS(Digraph); - - typedef typename MF::Value Value; - typedef Digraph::ArcMap CapMap; - typedef CapMap FlowMap; - typedef BoolNodeMap CutMap; - - Digraph g; - Node s, t; - CapMap cap(g); - std::istringstream input(test_lgf); - DigraphReader(g,input) - .arcMap("capacity", cap) - .node("source",s) - .node("target",t) - .run(); - - MF max_flow(g, cap, s, t); - max_flow.run(); - - check(checkFlow(g, max_flow.flowMap(), cap, s, t), - "The flow is not feasible."); - - CutMap min_cut(g); - max_flow.minCutMap(min_cut); - Value min_cut_value = cutValue(g, min_cut, cap); - - check(max_flow.flowValue() == min_cut_value, - "The max flow value is not equal to the min cut value."); - - FlowMap flow(g); - for (ArcIt e(g); e != INVALID; ++e) flow[e] = max_flow.flowMap()[e]; - - Value flow_value = max_flow.flowValue(); - - for (ArcIt e(g); e != INVALID; ++e) cap[e] = 2 * cap[e]; - max_flow.init(flow); - - SF::startFirstPhase(max_flow); // start first phase of the algorithm - - CutMap min_cut1(g); - max_flow.minCutMap(min_cut1); - min_cut_value = cutValue(g, min_cut1, cap); - - check(max_flow.flowValue() == min_cut_value && - min_cut_value == 2 * flow_value, - "The max flow value or the min cut value is wrong."); - - SF::startSecondPhase(max_flow); // start second phase of the algorithm - - check(checkFlow(g, max_flow.flowMap(), cap, s, t), - "The flow is not feasible."); - - CutMap min_cut2(g); - max_flow.minCutMap(min_cut2); - min_cut_value = cutValue(g, min_cut2, cap); - - check(max_flow.flowValue() == min_cut_value && - min_cut_value == 2 * flow_value, - "The max flow value or the min cut value was not doubled"); - - - max_flow.flowMap(flow); - - NodeIt tmp1(g, s); - ++tmp1; - if (tmp1 != INVALID) s = tmp1; - - NodeIt tmp2(g, t); - ++tmp2; - if (tmp2 != INVALID) t = tmp2; - - max_flow.source(s); - max_flow.target(t); - - max_flow.run(); - - CutMap min_cut3(g); - max_flow.minCutMap(min_cut3); - min_cut_value=cutValue(g, min_cut3, cap); - - check(max_flow.flowValue() == min_cut_value, - "The max flow value or the min cut value is wrong."); -} - -// Struct for calling start functions of a general max flow algorithm -template -struct GeneralStartFunctions { - - static void startFirstPhase(MF& mf) { - mf.start(); - } - - static void startSecondPhase(MF& mf) { - ::lemon::ignore_unused_variable_warning(mf); - } - -}; - -// Struct for calling start functions of Preflow -template -struct PreflowStartFunctions { - - static void startFirstPhase(MF& mf) { - mf.startFirstPhase(); - } - - static void startSecondPhase(MF& mf) { - mf.startSecondPhase(); - } - -}; - -int main() { - - typedef concepts::Digraph GR; - typedef concepts::ReadMap CM1; - typedef concepts::ReadMap CM2; - - // Check the interface of Preflow - checkConcept< MaxFlowClassConcept, - Preflow >(); - checkConcept< MaxFlowClassConcept, - Preflow >(); - - // Check the interface of EdmondsKarp - checkConcept< MaxFlowClassConcept, - EdmondsKarp >(); - checkConcept< MaxFlowClassConcept, - EdmondsKarp >(); - - // Check Preflow - typedef Preflow > PType1; - typedef Preflow > PType2; - checkMaxFlowAlg >(); - checkMaxFlowAlg >(); - initFlowTest(); - - // Check EdmondsKarp - typedef EdmondsKarp > EKType1; - typedef EdmondsKarp > EKType2; - checkMaxFlowAlg >(); - checkMaxFlowAlg >(); - - initFlowTest(); - - return 0; -} diff --git a/deps/lemon/test/min_cost_arborescence_test.cc b/deps/lemon/test/min_cost_arborescence_test.cc deleted file mode 100644 index 3a5ea36f1..000000000 --- a/deps/lemon/test/min_cost_arborescence_test.cc +++ /dev/null @@ -1,207 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "test_tools.h" - -using namespace lemon; -using namespace std; - -const char test_lgf[] = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "7\n" - "8\n" - "9\n" - "@arcs\n" - " label cost\n" - "1 8 0 107\n" - "0 3 1 70\n" - "2 1 2 46\n" - "4 1 3 28\n" - "4 4 4 91\n" - "3 9 5 76\n" - "9 8 6 61\n" - "8 1 7 39\n" - "9 8 8 74\n" - "8 0 9 39\n" - "4 3 10 45\n" - "2 2 11 34\n" - "0 1 12 100\n" - "6 3 13 95\n" - "4 1 14 22\n" - "1 1 15 31\n" - "7 2 16 51\n" - "2 6 17 29\n" - "8 3 18 115\n" - "6 9 19 32\n" - "1 1 20 60\n" - "0 3 21 40\n" - "@attributes\n" - "source 0\n"; - - -void checkMinCostArborescenceCompile() -{ - typedef double VType; - typedef concepts::Digraph Digraph; - typedef concepts::ReadMap CostMap; - typedef Digraph::Node Node; - typedef Digraph::Arc Arc; - typedef concepts::WriteMap ArbMap; - typedef concepts::ReadWriteMap PredMap; - - typedef MinCostArborescence:: - SetArborescenceMap:: - SetPredMap::Create MinCostArbType; - - Digraph g; - Node s, n; - Arc e; - VType c; - bool b; - ::lemon::ignore_unused_variable_warning(c,b); - int i; - CostMap cost; - ArbMap arb; - PredMap pred; - - MinCostArbType mcarb_test(g, cost); - const MinCostArbType& const_mcarb_test = mcarb_test; - - mcarb_test - .arborescenceMap(arb) - .predMap(pred) - .run(s); - - mcarb_test.init(); - mcarb_test.addSource(s); - mcarb_test.start(); - n = mcarb_test.processNextNode(); - b = const_mcarb_test.emptyQueue(); - i = const_mcarb_test.queueSize(); - - c = const_mcarb_test.arborescenceCost(); - b = const_mcarb_test.arborescence(e); - e = const_mcarb_test.pred(n); - const MinCostArbType::ArborescenceMap &am = - const_mcarb_test.arborescenceMap(); - const MinCostArbType::PredMap &pm = - const_mcarb_test.predMap(); - b = const_mcarb_test.reached(n); - b = const_mcarb_test.processed(n); - - i = const_mcarb_test.dualNum(); - c = const_mcarb_test.dualValue(); - i = const_mcarb_test.dualSize(i); - c = const_mcarb_test.dualValue(i); - - ::lemon::ignore_unused_variable_warning(am); - ::lemon::ignore_unused_variable_warning(pm); -} - -int main() { - typedef SmartDigraph Digraph; - DIGRAPH_TYPEDEFS(Digraph); - - typedef Digraph::ArcMap CostMap; - - Digraph digraph; - CostMap cost(digraph); - Node source; - - std::istringstream is(test_lgf); - digraphReader(digraph, is). - arcMap("cost", cost). - node("source", source).run(); - - MinCostArborescence mca(digraph, cost); - mca.run(source); - - vector > > dualSolution(mca.dualNum()); - - for (int i = 0; i < mca.dualNum(); ++i) { - dualSolution[i].first = mca.dualValue(i); - for (MinCostArborescence::DualIt it(mca, i); - it != INVALID; ++it) { - dualSolution[i].second.insert(it); - } - } - - for (ArcIt it(digraph); it != INVALID; ++it) { - if (mca.reached(digraph.source(it))) { - double sum = 0.0; - for (int i = 0; i < int(dualSolution.size()); ++i) { - if (dualSolution[i].second.find(digraph.target(it)) - != dualSolution[i].second.end() && - dualSolution[i].second.find(digraph.source(it)) - == dualSolution[i].second.end()) { - sum += dualSolution[i].first; - } - } - if (mca.arborescence(it)) { - check(sum == cost[it], "Invalid dual solution"); - } - check(sum <= cost[it], "Invalid dual solution"); - } - } - - - check(mca.dualValue() == mca.arborescenceCost(), "Invalid dual solution"); - - check(mca.reached(source), "Invalid arborescence"); - for (ArcIt a(digraph); a != INVALID; ++a) { - check(!mca.reached(digraph.source(a)) || - mca.reached(digraph.target(a)), "Invalid arborescence"); - } - - for (NodeIt n(digraph); n != INVALID; ++n) { - if (!mca.reached(n)) continue; - int cnt = 0; - for (InArcIt a(digraph, n); a != INVALID; ++a) { - if (mca.arborescence(a)) { - check(mca.pred(n) == a, "Invalid arborescence"); - ++cnt; - } - } - check((n == source ? cnt == 0 : cnt == 1), "Invalid arborescence"); - } - - Digraph::ArcMap arborescence(digraph); - check(mca.arborescenceCost() == - minCostArborescence(digraph, cost, source, arborescence), - "Wrong result of the function interface"); - - return 0; -} diff --git a/deps/lemon/test/min_cost_flow_test.cc b/deps/lemon/test/min_cost_flow_test.cc deleted file mode 100644 index 15dcf542d..000000000 --- a/deps/lemon/test/min_cost_flow_test.cc +++ /dev/null @@ -1,548 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "test_tools.h" - -using namespace lemon; - -// Test networks -char test_lgf[] = - "@nodes\n" - "label sup1 sup2 sup3 sup4 sup5 sup6\n" - " 1 20 27 0 30 20 30\n" - " 2 -4 0 0 0 -8 -3\n" - " 3 0 0 0 0 0 0\n" - " 4 0 0 0 0 0 0\n" - " 5 9 0 0 0 6 11\n" - " 6 -6 0 0 0 -5 -6\n" - " 7 0 0 0 0 0 0\n" - " 8 0 0 0 0 0 3\n" - " 9 3 0 0 0 0 0\n" - " 10 -2 0 0 0 -7 -2\n" - " 11 0 0 0 0 -10 0\n" - " 12 -20 -27 0 -30 -30 -20\n" - "\n" - "@arcs\n" - " cost cap low1 low2 low3\n" - " 1 2 70 11 0 8 8\n" - " 1 3 150 3 0 1 0\n" - " 1 4 80 15 0 2 2\n" - " 2 8 80 12 0 0 0\n" - " 3 5 140 5 0 3 1\n" - " 4 6 60 10 0 1 0\n" - " 4 7 80 2 0 0 0\n" - " 4 8 110 3 0 0 0\n" - " 5 7 60 14 0 0 0\n" - " 5 11 120 12 0 0 0\n" - " 6 3 0 3 0 0 0\n" - " 6 9 140 4 0 0 0\n" - " 6 10 90 8 0 0 0\n" - " 7 1 30 5 0 0 -5\n" - " 8 12 60 16 0 4 3\n" - " 9 12 50 6 0 0 0\n" - "10 12 70 13 0 5 2\n" - "10 2 100 7 0 0 0\n" - "10 7 60 10 0 0 -3\n" - "11 10 20 14 0 6 -20\n" - "12 11 30 10 0 0 -10\n" - "\n" - "@attributes\n" - "source 1\n" - "target 12\n"; - -char test_neg1_lgf[] = - "@nodes\n" - "label sup\n" - " 1 100\n" - " 2 0\n" - " 3 0\n" - " 4 -100\n" - " 5 0\n" - " 6 0\n" - " 7 0\n" - "@arcs\n" - " cost low1 low2\n" - "1 2 100 0 0\n" - "1 3 30 0 0\n" - "2 4 20 0 0\n" - "3 4 80 0 0\n" - "3 2 50 0 0\n" - "5 3 10 0 0\n" - "5 6 80 0 1000\n" - "6 7 30 0 -1000\n" - "7 5 -120 0 0\n"; - -char test_neg2_lgf[] = - "@nodes\n" - "label sup\n" - " 1 100\n" - " 2 -300\n" - "@arcs\n" - " cost\n" - "1 2 -1\n"; - - -// Test data -typedef ListDigraph Digraph; -DIGRAPH_TYPEDEFS(ListDigraph); - -Digraph gr; -Digraph::ArcMap c(gr), l1(gr), l2(gr), l3(gr), u(gr); -Digraph::NodeMap s1(gr), s2(gr), s3(gr), s4(gr), s5(gr), s6(gr); -ConstMap cc(1), cu(std::numeric_limits::max()); -Node v, w; - -Digraph neg1_gr; -Digraph::ArcMap neg1_c(neg1_gr), neg1_l1(neg1_gr), neg1_l2(neg1_gr); -ConstMap neg1_u1(std::numeric_limits::max()), neg1_u2(5000); -Digraph::NodeMap neg1_s(neg1_gr); - -Digraph neg2_gr; -Digraph::ArcMap neg2_c(neg2_gr); -ConstMap neg2_l(0), neg2_u(1000); -Digraph::NodeMap neg2_s(neg2_gr); - - -enum SupplyType { - EQ, - GEQ, - LEQ -}; - - -// Check the interface of an MCF algorithm -template -class McfClassConcept -{ -public: - - template - struct Constraints { - void constraints() { - checkConcept(); - - const Constraints& me = *this; - - MCF mcf(me.g); - const MCF& const_mcf = mcf; - - b = mcf.reset().resetParams() - .lowerMap(me.lower) - .upperMap(me.upper) - .costMap(me.cost) - .supplyMap(me.sup) - .stSupply(me.n, me.n, me.k) - .run(); - - c = const_mcf.totalCost(); - x = const_mcf.template totalCost(); - v = const_mcf.flow(me.a); - c = const_mcf.potential(me.n); - const_mcf.flowMap(fm); - const_mcf.potentialMap(pm); - } - - typedef typename GR::Node Node; - typedef typename GR::Arc Arc; - typedef concepts::ReadMap NM; - typedef concepts::ReadMap VAM; - typedef concepts::ReadMap CAM; - typedef concepts::WriteMap FlowMap; - typedef concepts::WriteMap PotMap; - - GR g; - VAM lower; - VAM upper; - CAM cost; - NM sup; - Node n; - Arc a; - Value k; - - FlowMap fm; - PotMap pm; - bool b; - double x; - typename MCF::Value v; - typename MCF::Cost c; - }; - -}; - - -// Check the feasibility of the given flow (primal soluiton) -template < typename GR, typename LM, typename UM, - typename SM, typename FM > -bool checkFlow( const GR& gr, const LM& lower, const UM& upper, - const SM& supply, const FM& flow, - SupplyType type = EQ ) -{ - TEMPLATE_DIGRAPH_TYPEDEFS(GR); - - for (ArcIt e(gr); e != INVALID; ++e) { - if (flow[e] < lower[e] || flow[e] > upper[e]) return false; - } - - for (NodeIt n(gr); n != INVALID; ++n) { - typename SM::Value sum = 0; - for (OutArcIt e(gr, n); e != INVALID; ++e) - sum += flow[e]; - for (InArcIt e(gr, n); e != INVALID; ++e) - sum -= flow[e]; - bool b = (type == EQ && sum == supply[n]) || - (type == GEQ && sum >= supply[n]) || - (type == LEQ && sum <= supply[n]); - if (!b) return false; - } - - return true; -} - -// Check the feasibility of the given potentials (dual soluiton) -// using the "Complementary Slackness" optimality condition -template < typename GR, typename LM, typename UM, - typename CM, typename SM, typename FM, typename PM > -bool checkPotential( const GR& gr, const LM& lower, const UM& upper, - const CM& cost, const SM& supply, const FM& flow, - const PM& pi, SupplyType type ) -{ - TEMPLATE_DIGRAPH_TYPEDEFS(GR); - - bool opt = true; - for (ArcIt e(gr); opt && e != INVALID; ++e) { - typename CM::Value red_cost = - cost[e] + pi[gr.source(e)] - pi[gr.target(e)]; - opt = red_cost == 0 || - (red_cost > 0 && flow[e] == lower[e]) || - (red_cost < 0 && flow[e] == upper[e]); - } - - for (NodeIt n(gr); opt && n != INVALID; ++n) { - typename SM::Value sum = 0; - for (OutArcIt e(gr, n); e != INVALID; ++e) - sum += flow[e]; - for (InArcIt e(gr, n); e != INVALID; ++e) - sum -= flow[e]; - if (type != LEQ) { - opt = (pi[n] <= 0) && (sum == supply[n] || pi[n] == 0); - } else { - opt = (pi[n] >= 0) && (sum == supply[n] || pi[n] == 0); - } - } - - return opt; -} - -// Check whether the dual cost is equal to the primal cost -template < typename GR, typename LM, typename UM, - typename CM, typename SM, typename PM > -bool checkDualCost( const GR& gr, const LM& lower, const UM& upper, - const CM& cost, const SM& supply, const PM& pi, - typename CM::Value total ) -{ - TEMPLATE_DIGRAPH_TYPEDEFS(GR); - - typename CM::Value dual_cost = 0; - SM red_supply(gr); - for (NodeIt n(gr); n != INVALID; ++n) { - red_supply[n] = supply[n]; - } - for (ArcIt a(gr); a != INVALID; ++a) { - if (lower[a] != 0) { - dual_cost += lower[a] * cost[a]; - red_supply[gr.source(a)] -= lower[a]; - red_supply[gr.target(a)] += lower[a]; - } - } - - for (NodeIt n(gr); n != INVALID; ++n) { - dual_cost -= red_supply[n] * pi[n]; - } - for (ArcIt a(gr); a != INVALID; ++a) { - typename CM::Value red_cost = - cost[a] + pi[gr.source(a)] - pi[gr.target(a)]; - dual_cost -= (upper[a] - lower[a]) * std::max(-red_cost, 0); - } - - return dual_cost == total; -} - -// Run a minimum cost flow algorithm and check the results -template < typename MCF, typename GR, - typename LM, typename UM, - typename CM, typename SM, - typename PT > -void checkMcf( const MCF& mcf, PT mcf_result, - const GR& gr, const LM& lower, const UM& upper, - const CM& cost, const SM& supply, - PT result, bool optimal, typename CM::Value total, - const std::string &test_id = "", - SupplyType type = EQ ) -{ - check(mcf_result == result, "Wrong result " + test_id); - if (optimal) { - typename GR::template ArcMap flow(gr); - typename GR::template NodeMap pi(gr); - mcf.flowMap(flow); - mcf.potentialMap(pi); - check(checkFlow(gr, lower, upper, supply, flow, type), - "The flow is not feasible " + test_id); - check(mcf.totalCost() == total, "The flow is not optimal " + test_id); - check(checkPotential(gr, lower, upper, cost, supply, flow, pi, type), - "Wrong potentials " + test_id); - check(checkDualCost(gr, lower, upper, cost, supply, pi, total), - "Wrong dual cost " + test_id); - } -} - -template < typename MCF, typename Param > -void runMcfGeqTests( Param param, - const std::string &test_str = "", - bool full_neg_cost_support = false ) -{ - MCF mcf1(gr), mcf2(neg1_gr), mcf3(neg2_gr); - - // Basic tests - mcf1.upperMap(u).costMap(c).supplyMap(s1); - checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s1, - mcf1.OPTIMAL, true, 5240, test_str + "-1"); - mcf1.stSupply(v, w, 27); - checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s2, - mcf1.OPTIMAL, true, 7620, test_str + "-2"); - mcf1.lowerMap(l2).supplyMap(s1); - checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s1, - mcf1.OPTIMAL, true, 5970, test_str + "-3"); - mcf1.stSupply(v, w, 27); - checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s2, - mcf1.OPTIMAL, true, 8010, test_str + "-4"); - mcf1.resetParams().supplyMap(s1); - checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s1, - mcf1.OPTIMAL, true, 74, test_str + "-5"); - mcf1.lowerMap(l2).stSupply(v, w, 27); - checkMcf(mcf1, mcf1.run(param), gr, l2, cu, cc, s2, - mcf1.OPTIMAL, true, 94, test_str + "-6"); - mcf1.reset(); - checkMcf(mcf1, mcf1.run(param), gr, l1, cu, cc, s3, - mcf1.OPTIMAL, true, 0, test_str + "-7"); - mcf1.lowerMap(l2).upperMap(u); - checkMcf(mcf1, mcf1.run(param), gr, l2, u, cc, s3, - mcf1.INFEASIBLE, false, 0, test_str + "-8"); - mcf1.lowerMap(l3).upperMap(u).costMap(c).supplyMap(s4); - checkMcf(mcf1, mcf1.run(param), gr, l3, u, c, s4, - mcf1.OPTIMAL, true, 6360, test_str + "-9"); - - // Tests for the GEQ form - mcf1.resetParams().upperMap(u).costMap(c).supplyMap(s5); - checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s5, - mcf1.OPTIMAL, true, 3530, test_str + "-10", GEQ); - mcf1.lowerMap(l2); - checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5, - mcf1.OPTIMAL, true, 4540, test_str + "-11", GEQ); - mcf1.supplyMap(s6); - checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6, - mcf1.INFEASIBLE, false, 0, test_str + "-12", GEQ); - - // Tests with negative costs - mcf2.lowerMap(neg1_l1).costMap(neg1_c).supplyMap(neg1_s); - checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u1, neg1_c, neg1_s, - mcf2.UNBOUNDED, false, 0, test_str + "-13"); - mcf2.upperMap(neg1_u2); - checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l1, neg1_u2, neg1_c, neg1_s, - mcf2.OPTIMAL, true, -40000, test_str + "-14"); - mcf2.resetParams().lowerMap(neg1_l2).costMap(neg1_c).supplyMap(neg1_s); - checkMcf(mcf2, mcf2.run(param), neg1_gr, neg1_l2, neg1_u1, neg1_c, neg1_s, - mcf2.UNBOUNDED, false, 0, test_str + "-15"); - - mcf3.costMap(neg2_c).supplyMap(neg2_s); - if (full_neg_cost_support) { - checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s, - mcf3.OPTIMAL, true, -300, test_str + "-16", GEQ); - } else { - checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s, - mcf3.UNBOUNDED, false, 0, test_str + "-17", GEQ); - } - mcf3.upperMap(neg2_u); - checkMcf(mcf3, mcf3.run(param), neg2_gr, neg2_l, neg2_u, neg2_c, neg2_s, - mcf3.OPTIMAL, true, -300, test_str + "-18", GEQ); - - // Tests for empty graph - Digraph gr0; - MCF mcf0(gr0); - mcf0.run(param); - check(mcf0.totalCost() == 0, "Wrong total cost"); -} - -template < typename MCF, typename Param > -void runMcfLeqTests( Param param, - const std::string &test_str = "" ) -{ - // Tests for the LEQ form - MCF mcf1(gr); - mcf1.supplyType(mcf1.LEQ); - mcf1.upperMap(u).costMap(c).supplyMap(s6); - checkMcf(mcf1, mcf1.run(param), gr, l1, u, c, s6, - mcf1.OPTIMAL, true, 5080, test_str + "-19", LEQ); - mcf1.lowerMap(l2); - checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s6, - mcf1.OPTIMAL, true, 5930, test_str + "-20", LEQ); - mcf1.supplyMap(s5); - checkMcf(mcf1, mcf1.run(param), gr, l2, u, c, s5, - mcf1.INFEASIBLE, false, 0, test_str + "-21", LEQ); -} - - -int main() -{ - // Read the test networks - std::istringstream input(test_lgf); - DigraphReader(gr, input) - .arcMap("cost", c) - .arcMap("cap", u) - .arcMap("low1", l1) - .arcMap("low2", l2) - .arcMap("low3", l3) - .nodeMap("sup1", s1) - .nodeMap("sup2", s2) - .nodeMap("sup3", s3) - .nodeMap("sup4", s4) - .nodeMap("sup5", s5) - .nodeMap("sup6", s6) - .node("source", v) - .node("target", w) - .run(); - - std::istringstream neg_inp1(test_neg1_lgf); - DigraphReader(neg1_gr, neg_inp1) - .arcMap("cost", neg1_c) - .arcMap("low1", neg1_l1) - .arcMap("low2", neg1_l2) - .nodeMap("sup", neg1_s) - .run(); - - std::istringstream neg_inp2(test_neg2_lgf); - DigraphReader(neg2_gr, neg_inp2) - .arcMap("cost", neg2_c) - .nodeMap("sup", neg2_s) - .run(); - - // Check the interface of NetworkSimplex - { - typedef concepts::Digraph GR; - checkConcept< McfClassConcept, - NetworkSimplex >(); - checkConcept< McfClassConcept, - NetworkSimplex >(); - checkConcept< McfClassConcept, - NetworkSimplex >(); - } - - // Check the interface of CapacityScaling - { - typedef concepts::Digraph GR; - checkConcept< McfClassConcept, - CapacityScaling >(); - checkConcept< McfClassConcept, - CapacityScaling >(); - checkConcept< McfClassConcept, - CapacityScaling >(); - typedef CapacityScaling:: - SetHeap > >::Create CAS; - checkConcept< McfClassConcept, CAS >(); - } - - // Check the interface of CostScaling - { - typedef concepts::Digraph GR; - checkConcept< McfClassConcept, - CostScaling >(); - checkConcept< McfClassConcept, - CostScaling >(); - checkConcept< McfClassConcept, - CostScaling >(); - typedef CostScaling:: - SetLargeCost::Create COS; - checkConcept< McfClassConcept, COS >(); - } - - // Check the interface of CycleCanceling - { - typedef concepts::Digraph GR; - checkConcept< McfClassConcept, - CycleCanceling >(); - checkConcept< McfClassConcept, - CycleCanceling >(); - checkConcept< McfClassConcept, - CycleCanceling >(); - } - - // Test NetworkSimplex - { - typedef NetworkSimplex MCF; - runMcfGeqTests(MCF::FIRST_ELIGIBLE, "NS-FE", true); - runMcfLeqTests(MCF::FIRST_ELIGIBLE, "NS-FE"); - runMcfGeqTests(MCF::BEST_ELIGIBLE, "NS-BE", true); - runMcfLeqTests(MCF::BEST_ELIGIBLE, "NS-BE"); - runMcfGeqTests(MCF::BLOCK_SEARCH, "NS-BS", true); - runMcfLeqTests(MCF::BLOCK_SEARCH, "NS-BS"); - runMcfGeqTests(MCF::CANDIDATE_LIST, "NS-CL", true); - runMcfLeqTests(MCF::CANDIDATE_LIST, "NS-CL"); - runMcfGeqTests(MCF::ALTERING_LIST, "NS-AL", true); - runMcfLeqTests(MCF::ALTERING_LIST, "NS-AL"); - } - - // Test CapacityScaling - { - typedef CapacityScaling MCF; - runMcfGeqTests(0, "SSP"); - runMcfGeqTests(2, "CAS"); - } - - // Test CostScaling - { - typedef CostScaling MCF; - runMcfGeqTests(MCF::PUSH, "COS-PR"); - runMcfGeqTests(MCF::AUGMENT, "COS-AR"); - runMcfGeqTests(MCF::PARTIAL_AUGMENT, "COS-PAR"); - } - - // Test CycleCanceling - { - typedef CycleCanceling MCF; - runMcfGeqTests(MCF::SIMPLE_CYCLE_CANCELING, "SCC"); - runMcfGeqTests(MCF::MINIMUM_MEAN_CYCLE_CANCELING, "MMCC"); - runMcfGeqTests(MCF::CANCEL_AND_TIGHTEN, "CAT"); - } - - return 0; -} diff --git a/deps/lemon/test/min_mean_cycle_test.cc b/deps/lemon/test/min_mean_cycle_test.cc deleted file mode 100644 index e7524546e..000000000 --- a/deps/lemon/test/min_mean_cycle_test.cc +++ /dev/null @@ -1,223 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "test_tools.h" - -using namespace lemon; - -char test_lgf[] = - "@nodes\n" - "label\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "7\n" - "@arcs\n" - " len1 len2 len3 len4 c1 c2 c3 c4\n" - "1 2 1 1 1 1 0 0 0 0\n" - "2 4 5 5 5 5 1 0 0 0\n" - "2 3 8 8 8 8 0 0 0 0\n" - "3 2 -2 0 0 0 1 0 0 0\n" - "3 4 4 4 4 4 0 0 0 0\n" - "3 7 -4 -4 -4 -4 0 0 0 0\n" - "4 1 2 2 2 2 0 0 0 0\n" - "4 3 3 3 3 3 1 0 0 0\n" - "4 4 3 3 0 0 0 0 1 0\n" - "5 2 4 4 4 4 0 0 0 0\n" - "5 6 3 3 3 3 0 1 0 0\n" - "6 5 2 2 2 2 0 1 0 0\n" - "6 4 -1 -1 -1 -1 0 0 0 0\n" - "6 7 1 1 1 1 0 0 0 0\n" - "7 7 4 4 4 -1 0 0 0 1\n"; - - -// Check the interface of an MMC algorithm -template -struct MmcClassConcept -{ - template - struct Constraints { - void constraints() { - const Constraints& me = *this; - - typedef typename MMC - ::template SetPath > - ::template SetLargeCost - ::Create MmcAlg; - MmcAlg mmc(me.g, me.cost); - const MmcAlg& const_mmc = mmc; - - typename MmcAlg::Tolerance tol = const_mmc.tolerance(); - mmc.tolerance(tol); - - b = mmc.cycle(p).run(); - b = mmc.findCycleMean(); - b = mmc.findCycle(); - - v = const_mmc.cycleCost(); - i = const_mmc.cycleSize(); - d = const_mmc.cycleMean(); - p = const_mmc.cycle(); - } - - typedef concepts::ReadMap CM; - - GR g; - CM cost; - ListPath p; - Cost v; - int i; - double d; - bool b; - }; -}; - -// Perform a test with the given parameters -template -void checkMmcAlg(const SmartDigraph& gr, - const SmartDigraph::ArcMap& lm, - const SmartDigraph::ArcMap& cm, - int cost, int size) { - MMC alg(gr, lm); - check(alg.findCycleMean(), "Wrong result"); - check(alg.cycleMean() == static_cast(cost) / size, - "Wrong cycle mean"); - alg.findCycle(); - check(alg.cycleCost() == cost && alg.cycleSize() == size, - "Wrong path"); - SmartDigraph::ArcMap cycle(gr, 0); - for (typename MMC::Path::ArcIt a(alg.cycle()); a != INVALID; ++a) { - ++cycle[a]; - } - for (SmartDigraph::ArcIt a(gr); a != INVALID; ++a) { - check(cm[a] == cycle[a], "Wrong path"); - } -} - -// Class for comparing types -template -struct IsSameType { - static const int result = 0; -}; - -template -struct IsSameType { - static const int result = 1; -}; - - -int main() { - #ifdef LEMON_HAVE_LONG_LONG - typedef long long long_int; - #else - typedef long long_int; - #endif - - // Check the interface - { - typedef concepts::Digraph GR; - - // KarpMmc - checkConcept< MmcClassConcept, - KarpMmc > >(); - checkConcept< MmcClassConcept, - KarpMmc > >(); - - // HartmannOrlinMmc - checkConcept< MmcClassConcept, - HartmannOrlinMmc > >(); - checkConcept< MmcClassConcept, - HartmannOrlinMmc > >(); - - // HowardMmc - checkConcept< MmcClassConcept, - HowardMmc > >(); - checkConcept< MmcClassConcept, - HowardMmc > >(); - - check((IsSameType > - ::LargeCost, long_int>::result == 1), "Wrong LargeCost type"); - check((IsSameType > - ::LargeCost, double>::result == 1), "Wrong LargeCost type"); - } - - // Run various tests - { - typedef SmartDigraph GR; - DIGRAPH_TYPEDEFS(GR); - - GR gr; - IntArcMap l1(gr), l2(gr), l3(gr), l4(gr); - IntArcMap c1(gr), c2(gr), c3(gr), c4(gr); - - std::istringstream input(test_lgf); - digraphReader(gr, input). - arcMap("len1", l1). - arcMap("len2", l2). - arcMap("len3", l3). - arcMap("len4", l4). - arcMap("c1", c1). - arcMap("c2", c2). - arcMap("c3", c3). - arcMap("c4", c4). - run(); - - // Karp - checkMmcAlg >(gr, l1, c1, 6, 3); - checkMmcAlg >(gr, l2, c2, 5, 2); - checkMmcAlg >(gr, l3, c3, 0, 1); - checkMmcAlg >(gr, l4, c4, -1, 1); - - // HartmannOrlin - checkMmcAlg >(gr, l1, c1, 6, 3); - checkMmcAlg >(gr, l2, c2, 5, 2); - checkMmcAlg >(gr, l3, c3, 0, 1); - checkMmcAlg >(gr, l4, c4, -1, 1); - - // Howard - checkMmcAlg >(gr, l1, c1, 6, 3); - checkMmcAlg >(gr, l2, c2, 5, 2); - checkMmcAlg >(gr, l3, c3, 0, 1); - checkMmcAlg >(gr, l4, c4, -1, 1); - - // Howard with iteration limit - HowardMmc mmc(gr, l1); - check((mmc.findCycleMean(2) == HowardMmc::ITERATION_LIMIT), - "Wrong termination cause"); - check((mmc.findCycleMean(4) == HowardMmc::OPTIMAL), - "Wrong termination cause"); - } - - return 0; -} diff --git a/deps/lemon/test/mip_test.cc b/deps/lemon/test/mip_test.cc deleted file mode 100644 index 641ceb5fe..000000000 --- a/deps/lemon/test/mip_test.cc +++ /dev/null @@ -1,171 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include "test_tools.h" - -#include - -#ifdef LEMON_HAVE_CPLEX -#include -#endif - -#ifdef LEMON_HAVE_GLPK -#include -#endif - -#ifdef LEMON_HAVE_CBC -#include -#endif - -#ifdef LEMON_HAVE_MIP -#include -#endif - - -using namespace lemon; - -void solveAndCheck(MipSolver& mip, MipSolver::ProblemType stat, - double exp_opt) { - using std::string; - - mip.solve(); - //int decimal,sign; - std::ostringstream buf; - buf << "Type should be: " << int(stat)<<" and it is "< -void cloneTest() -{ - - MIP* mip = new MIP(); - MIP* mipnew = mip->newSolver(); - MIP* mipclone = mip->cloneSolver(); - delete mip; - delete mipnew; - delete mipclone; -} - -int main() -{ - -#ifdef LEMON_HAVE_MIP - { - Mip mip1; - aTest(mip1); - cloneTest(); - } -#endif - -#ifdef LEMON_HAVE_GLPK - { - GlpkMip mip1; - aTest(mip1); - cloneTest(); - } -#endif - -#ifdef LEMON_HAVE_CPLEX - try { - CplexMip mip2; - aTest(mip2); - cloneTest(); - } catch (CplexEnv::LicenseError& error) { - check(false, error.what()); - } -#endif - -#ifdef LEMON_HAVE_CBC - { - CbcMip mip1; - aTest(mip1); - cloneTest(); - } -#endif - - return 0; - -} diff --git a/deps/lemon/test/nagamochi_ibaraki_test.cc b/deps/lemon/test/nagamochi_ibaraki_test.cc deleted file mode 100644 index 94ec29d93..000000000 --- a/deps/lemon/test/nagamochi_ibaraki_test.cc +++ /dev/null @@ -1,142 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "test_tools.h" - -using namespace lemon; -using namespace std; - -const std::string lgf = - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "@edges\n" - " cap1 cap2 cap3\n" - "0 1 1 1 1 \n" - "0 2 2 2 4 \n" - "1 2 4 4 4 \n" - "3 4 1 1 1 \n" - "3 5 2 2 4 \n" - "4 5 4 4 4 \n" - "2 3 1 6 6 \n"; - -void checkNagamochiIbarakiCompile() -{ - typedef int Value; - typedef concepts::Graph Graph; - - typedef Graph::Node Node; - typedef Graph::Edge Edge; - typedef concepts::ReadMap CapMap; - typedef concepts::WriteMap CutMap; - - Graph g; - Node n; - CapMap cap; - CutMap cut; - Value v; - bool b; - ::lemon::ignore_unused_variable_warning(v,b); - - NagamochiIbaraki ni_test(g, cap); - const NagamochiIbaraki& const_ni_test = ni_test; - - ni_test.init(); - ni_test.start(); - b = ni_test.processNextPhase(); - ni_test.run(); - - v = const_ni_test.minCutValue(); - v = const_ni_test.minCutMap(cut); -} - -template -typename CapMap::Value - cutValue(const Graph& graph, const CapMap& cap, const CutMap& cut) -{ - typename CapMap::Value sum = 0; - for (typename Graph::EdgeIt e(graph); e != INVALID; ++e) { - if (cut[graph.u(e)] != cut[graph.v(e)]) { - sum += cap[e]; - } - } - return sum; -} - -int main() { - SmartGraph graph; - SmartGraph::EdgeMap cap1(graph), cap2(graph), cap3(graph); - SmartGraph::NodeMap cut(graph); - - istringstream input(lgf); - graphReader(graph, input) - .edgeMap("cap1", cap1) - .edgeMap("cap2", cap2) - .edgeMap("cap3", cap3) - .run(); - - { - NagamochiIbaraki ni(graph, cap1); - ni.run(); - ni.minCutMap(cut); - - check(ni.minCutValue() == 1, "Wrong cut value"); - check(ni.minCutValue() == cutValue(graph, cap1, cut), "Wrong cut value"); - } - { - NagamochiIbaraki ni(graph, cap2); - ni.run(); - ni.minCutMap(cut); - - check(ni.minCutValue() == 3, "Wrong cut value"); - check(ni.minCutValue() == cutValue(graph, cap2, cut), "Wrong cut value"); - } - { - NagamochiIbaraki ni(graph, cap3); - ni.run(); - ni.minCutMap(cut); - - check(ni.minCutValue() == 5, "Wrong cut value"); - check(ni.minCutValue() == cutValue(graph, cap3, cut), "Wrong cut value"); - } - { - NagamochiIbaraki::SetUnitCapacity::Create ni(graph); - ni.run(); - ni.minCutMap(cut); - - ConstMap cap4(1); - check(ni.minCutValue() == 1, "Wrong cut value"); - check(ni.minCutValue() == cutValue(graph, cap4, cut), "Wrong cut value"); - } - - return 0; -} diff --git a/deps/lemon/test/path_test.cc b/deps/lemon/test/path_test.cc deleted file mode 100644 index f2d960381..000000000 --- a/deps/lemon/test/path_test.cc +++ /dev/null @@ -1,339 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include - -#include -#include -#include - -#include -#include - -#include "test_tools.h" - -using namespace std; -using namespace lemon; - -template -void checkConcepts() { - checkConcept, concepts::Path >(); - checkConcept, Path >(); - checkConcept, SimplePath >(); - checkConcept, StaticPath >(); - checkConcept, ListPath >(); -} - -// Conecpt checking for path structures -void checkPathConcepts() { - checkConcepts(); - checkConcepts(); -} - -// Check if proper copy consructor is called (use valgrind for testing) -template -void checkCopy(typename GR::Arc a) { - P1 p; - p.addBack(a); - P1 q; - q = p; - P1 r(p); - P2 q2; - q2 = p; - P2 r2(p); -} - -// Tests for copy constructors and assignment operators of paths -void checkPathCopy() { - ListDigraph g; - ListDigraph::Arc a = g.addArc(g.addNode(), g.addNode()); - - typedef Path Path1; - typedef SimplePath Path2; - typedef ListPath Path3; - typedef StaticPath Path4; - checkCopy(a); - checkCopy(a); - checkCopy(a); - checkCopy(a); - checkCopy(a); - checkCopy(a); - checkCopy(a); - checkCopy(a); - checkCopy(a); -} - -// Class for testing path functions -class CheckPathFunctions { - typedef ListDigraph GR; - DIGRAPH_TYPEDEFS(GR); - GR gr; - const GR& cgr; - Node n1, n2, n3, n4; - Node tmp_n; - Arc a1, a2, a3, a4; - Arc tmp_a; - -public: - - CheckPathFunctions() : cgr(gr) { - n1 = gr.addNode(); - n2 = gr.addNode(); - n3 = gr.addNode(); - n4 = gr.addNode(); - a1 = gr.addArc(n1, n2); - a2 = gr.addArc(n2, n3); - a3 = gr.addArc(n3, n4); - a4 = gr.addArc(n4, n1); - } - - void run() { - checkBackAndFrontInsertablePath >(); - checkBackAndFrontInsertablePath >(); - checkBackInsertablePath >(); - - checkListPathSplitAndSplice(); - } - -private: - - template - void checkBackInsertablePath() { - - // Create and check empty path - P p; - const P& cp = p; - check(cp.empty(), "The path is not empty"); - check(cp.length() == 0, "The path is not empty"); -// check(cp.front() == INVALID, "Wrong front()"); -// check(cp.back() == INVALID, "Wrong back()"); - typename P::ArcIt ai(cp); - check(ai == INVALID, "Wrong ArcIt"); - check(pathSource(cgr, cp) == INVALID, "Wrong pathSource()"); - check(pathTarget(cgr, cp) == INVALID, "Wrong pathTarget()"); - check(checkPath(cgr, cp), "Wrong checkPath()"); - PathNodeIt

ni(cgr, cp); - check(ni == INVALID, "Wrong PathNodeIt"); - - // Check single-arc path - p.addBack(a1); - check(!cp.empty(), "Wrong empty()"); - check(cp.length() == 1, "Wrong length"); - check(cp.front() == a1, "Wrong front()"); - check(cp.back() == a1, "Wrong back()"); - check(cp.nth(0) == a1, "Wrong nth()"); - ai = cp.nthIt(0); - check((tmp_a = ai) == a1, "Wrong nthIt()"); - check(++ai == INVALID, "Wrong nthIt()"); - typename P::ArcIt ai2(cp); - check((tmp_a = ai2) == a1, "Wrong ArcIt"); - check(++ai2 == INVALID, "Wrong ArcIt"); - check(pathSource(cgr, cp) == n1, "Wrong pathSource()"); - check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()"); - check(checkPath(cgr, cp), "Wrong checkPath()"); - PathNodeIt

ni2(cgr, cp); - check((tmp_n = ni2) == n1, "Wrong PathNodeIt"); - check((tmp_n = ++ni2) == n2, "Wrong PathNodeIt"); - check(++ni2 == INVALID, "Wrong PathNodeIt"); - - // Check adding more arcs - p.addBack(a2); - p.addBack(a3); - check(!cp.empty(), "Wrong empty()"); - check(cp.length() == 3, "Wrong length"); - check(cp.front() == a1, "Wrong front()"); - check(cp.back() == a3, "Wrong back()"); - check(cp.nth(0) == a1, "Wrong nth()"); - check(cp.nth(1) == a2, "Wrong nth()"); - check(cp.nth(2) == a3, "Wrong nth()"); - typename P::ArcIt ai3(cp); - check((tmp_a = ai3) == a1, "Wrong ArcIt"); - check((tmp_a = ++ai3) == a2, "Wrong nthIt()"); - check((tmp_a = ++ai3) == a3, "Wrong nthIt()"); - check(++ai3 == INVALID, "Wrong nthIt()"); - ai = cp.nthIt(0); - check((tmp_a = ai) == a1, "Wrong nthIt()"); - check((tmp_a = ++ai) == a2, "Wrong nthIt()"); - ai = cp.nthIt(2); - check((tmp_a = ai) == a3, "Wrong nthIt()"); - check(++ai == INVALID, "Wrong nthIt()"); - check(pathSource(cgr, cp) == n1, "Wrong pathSource()"); - check(pathTarget(cgr, cp) == n4, "Wrong pathTarget()"); - check(checkPath(cgr, cp), "Wrong checkPath()"); - PathNodeIt

ni3(cgr, cp); - check((tmp_n = ni3) == n1, "Wrong PathNodeIt"); - check((tmp_n = ++ni3) == n2, "Wrong PathNodeIt"); - check((tmp_n = ++ni3) == n3, "Wrong PathNodeIt"); - check((tmp_n = ++ni3) == n4, "Wrong PathNodeIt"); - check(++ni3 == INVALID, "Wrong PathNodeIt"); - - // Check arc removal and addition - p.eraseBack(); - p.eraseBack(); - p.addBack(a2); - check(!cp.empty(), "Wrong empty()"); - check(cp.length() == 2, "Wrong length"); - check(cp.front() == a1, "Wrong front()"); - check(cp.back() == a2, "Wrong back()"); - check(pathSource(cgr, cp) == n1, "Wrong pathSource()"); - check(pathTarget(cgr, cp) == n3, "Wrong pathTarget()"); - check(checkPath(cgr, cp), "Wrong checkPath()"); - - // Check clear() - p.clear(); - check(cp.empty(), "The path is not empty"); - check(cp.length() == 0, "The path is not empty"); - - // Check inconsistent path - p.addBack(a4); - p.addBack(a2); - p.addBack(a1); - check(!cp.empty(), "Wrong empty()"); - check(cp.length() == 3, "Wrong length"); - check(cp.front() == a4, "Wrong front()"); - check(cp.back() == a1, "Wrong back()"); - check(pathSource(cgr, cp) == n4, "Wrong pathSource()"); - check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()"); - check(!checkPath(cgr, cp), "Wrong checkPath()"); - } - - template - void checkBackAndFrontInsertablePath() { - - // Include back insertable test cases - checkBackInsertablePath

(); - - // Check front and back insertion - P p; - const P& cp = p; - p.addFront(a4); - p.addBack(a1); - p.addFront(a3); - check(!cp.empty(), "Wrong empty()"); - check(cp.length() == 3, "Wrong length"); - check(cp.front() == a3, "Wrong front()"); - check(cp.back() == a1, "Wrong back()"); - check(cp.nth(0) == a3, "Wrong nth()"); - check(cp.nth(1) == a4, "Wrong nth()"); - check(cp.nth(2) == a1, "Wrong nth()"); - typename P::ArcIt ai(cp); - check((tmp_a = ai) == a3, "Wrong ArcIt"); - check((tmp_a = ++ai) == a4, "Wrong nthIt()"); - check((tmp_a = ++ai) == a1, "Wrong nthIt()"); - check(++ai == INVALID, "Wrong nthIt()"); - ai = cp.nthIt(0); - check((tmp_a = ai) == a3, "Wrong nthIt()"); - check((tmp_a = ++ai) == a4, "Wrong nthIt()"); - ai = cp.nthIt(2); - check((tmp_a = ai) == a1, "Wrong nthIt()"); - check(++ai == INVALID, "Wrong nthIt()"); - check(pathSource(cgr, cp) == n3, "Wrong pathSource()"); - check(pathTarget(cgr, cp) == n2, "Wrong pathTarget()"); - check(checkPath(cgr, cp), "Wrong checkPath()"); - - // Check eraseFront() - p.eraseFront(); - p.addBack(a2); - check(!cp.empty(), "Wrong empty()"); - check(cp.length() == 3, "Wrong length"); - check(cp.front() == a4, "Wrong front()"); - check(cp.back() == a2, "Wrong back()"); - check(cp.nth(0) == a4, "Wrong nth()"); - check(cp.nth(1) == a1, "Wrong nth()"); - check(cp.nth(2) == a2, "Wrong nth()"); - typename P::ArcIt ai2(cp); - check((tmp_a = ai2) == a4, "Wrong ArcIt"); - check((tmp_a = ++ai2) == a1, "Wrong nthIt()"); - check((tmp_a = ++ai2) == a2, "Wrong nthIt()"); - check(++ai2 == INVALID, "Wrong nthIt()"); - ai = cp.nthIt(0); - check((tmp_a = ai) == a4, "Wrong nthIt()"); - check((tmp_a = ++ai) == a1, "Wrong nthIt()"); - ai = cp.nthIt(2); - check((tmp_a = ai) == a2, "Wrong nthIt()"); - check(++ai == INVALID, "Wrong nthIt()"); - check(pathSource(cgr, cp) == n4, "Wrong pathSource()"); - check(pathTarget(cgr, cp) == n3, "Wrong pathTarget()"); - check(checkPath(cgr, cp), "Wrong checkPath()"); - } - - void checkListPathSplitAndSplice() { - - // Build a path with spliceFront() and spliceBack() - ListPath p1, p2, p3, p4; - p1.addBack(a3); - p1.addFront(a2); - p2.addBack(a1); - p1.spliceFront(p2); - p3.addFront(a4); - p1.spliceBack(p3); - check(p1.length() == 4, "Wrong length"); - check(p1.front() == a1, "Wrong front()"); - check(p1.back() == a4, "Wrong back()"); - ListPath::ArcIt ai(p1); - check((tmp_a = ai) == a1, "Wrong ArcIt"); - check((tmp_a = ++ai) == a2, "Wrong nthIt()"); - check((tmp_a = ++ai) == a3, "Wrong nthIt()"); - check((tmp_a = ++ai) == a4, "Wrong nthIt()"); - check(++ai == INVALID, "Wrong nthIt()"); - check(checkPath(cgr, p1), "Wrong checkPath()"); - - // Check split() - p1.split(p1.nthIt(2), p2); - check(p1.length() == 2, "Wrong length"); - ai = p1.nthIt(0); - check((tmp_a = ai) == a1, "Wrong ArcIt"); - check((tmp_a = ++ai) == a2, "Wrong nthIt()"); - check(++ai == INVALID, "Wrong nthIt()"); - check(checkPath(cgr, p1), "Wrong checkPath()"); - check(p2.length() == 2, "Wrong length"); - ai = p2.nthIt(0); - check((tmp_a = ai) == a3, "Wrong ArcIt"); - check((tmp_a = ++ai) == a4, "Wrong nthIt()"); - check(++ai == INVALID, "Wrong nthIt()"); - check(checkPath(cgr, p2), "Wrong checkPath()"); - - // Check split() and splice() - p1.spliceFront(p2); - p1.split(p1.nthIt(2), p2); - p2.split(p2.nthIt(1), p3); - p2.spliceBack(p1); - p2.splice(p2.nthIt(1), p3); - check(p2.length() == 4, "Wrong length"); - check(p2.front() == a1, "Wrong front()"); - check(p2.back() == a4, "Wrong back()"); - ai = p2.nthIt(0); - check((tmp_a = ai) == a1, "Wrong ArcIt"); - check((tmp_a = ++ai) == a2, "Wrong nthIt()"); - check((tmp_a = ++ai) == a3, "Wrong nthIt()"); - check((tmp_a = ++ai) == a4, "Wrong nthIt()"); - check(++ai == INVALID, "Wrong nthIt()"); - check(checkPath(cgr, p2), "Wrong checkPath()"); - } - -}; - -int main() { - checkPathConcepts(); - checkPathCopy(); - CheckPathFunctions cpf; - cpf.run(); - - return 0; -} diff --git a/deps/lemon/test/planarity_test.cc b/deps/lemon/test/planarity_test.cc deleted file mode 100644 index 0ac11eebb..000000000 --- a/deps/lemon/test/planarity_test.cc +++ /dev/null @@ -1,262 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -#include - -#include -#include -#include -#include - -#include "test_tools.h" - -using namespace lemon; -using namespace lemon::dim2; - -const int lgfn = 4; -const std::string lgf[lgfn] = { - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "@edges\n" - " label\n" - "0 1 0\n" - "0 2 0\n" - "0 3 0\n" - "0 4 0\n" - "1 2 0\n" - "1 3 0\n" - "1 4 0\n" - "2 3 0\n" - "2 4 0\n" - "3 4 0\n", - - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "@edges\n" - " label\n" - "0 1 0\n" - "0 2 0\n" - "0 3 0\n" - "0 4 0\n" - "1 2 0\n" - "1 3 0\n" - "2 3 0\n" - "2 4 0\n" - "3 4 0\n", - - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "@edges\n" - " label\n" - "0 3 0\n" - "0 4 0\n" - "0 5 0\n" - "1 3 0\n" - "1 4 0\n" - "1 5 0\n" - "2 3 0\n" - "2 4 0\n" - "2 5 0\n", - - "@nodes\n" - "label\n" - "0\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "@edges\n" - " label\n" - "0 3 0\n" - "0 4 0\n" - "0 5 0\n" - "1 3 0\n" - "1 4 0\n" - "1 5 0\n" - "2 3 0\n" - "2 5 0\n" -}; - - - -typedef SmartGraph Graph; -GRAPH_TYPEDEFS(Graph); - -typedef PlanarEmbedding PE; -typedef PlanarDrawing PD; -typedef PlanarColoring PC; - -void checkEmbedding(const Graph& graph, PE& pe) { - int face_num = 0; - - Graph::ArcMap face(graph, -1); - - for (ArcIt a(graph); a != INVALID; ++a) { - if (face[a] == -1) { - Arc b = a; - while (face[b] == -1) { - face[b] = face_num; - b = pe.next(graph.oppositeArc(b)); - } - check(face[b] == face_num, "Wrong face"); - ++face_num; - } - } - check(face_num + countNodes(graph) - countConnectedComponents(graph) == - countEdges(graph) + 1, "Euler test does not passed"); -} - -void checkKuratowski(const Graph& graph, PE& pe) { - std::map degs; - for (NodeIt n(graph); n != INVALID; ++n) { - int deg = 0; - for (IncEdgeIt e(graph, n); e != INVALID; ++e) { - if (pe.kuratowski(e)) { - ++deg; - } - } - ++degs[deg]; - } - for (std::map::iterator it = degs.begin(); it != degs.end(); ++it) { - check(it->first == 0 || it->first == 2 || - (it->first == 3 && it->second == 6) || - (it->first == 4 && it->second == 5), - "Wrong degree in Kuratowski graph"); - } - - // Not full test - check((degs[3] == 0) != (degs[4] == 0), "Wrong Kuratowski graph"); -} - -bool intersect(Point e1, Point e2, Point f1, Point f2) { - int l, r; - if (std::min(e1.x, e2.x) > std::max(f1.x, f2.x)) return false; - if (std::max(e1.x, e2.x) < std::min(f1.x, f2.x)) return false; - if (std::min(e1.y, e2.y) > std::max(f1.y, f2.y)) return false; - if (std::max(e1.y, e2.y) < std::min(f1.y, f2.y)) return false; - - l = (e2.x - e1.x) * (f1.y - e1.y) - (e2.y - e1.y) * (f1.x - e1.x); - r = (e2.x - e1.x) * (f2.y - e1.y) - (e2.y - e1.y) * (f2.x - e1.x); - if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false; - l = (f2.x - f1.x) * (e1.y - f1.y) - (f2.y - f1.y) * (e1.x - f1.x); - r = (f2.x - f1.x) * (e2.y - f1.y) - (f2.y - f1.y) * (e2.x - f1.x); - if (!((l >= 0 && r <= 0) || (l <= 0 && r >= 0))) return false; - return true; -} - -bool collinear(Point p, Point q, Point r) { - int v; - v = (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x); - if (v != 0) return false; - v = (q.x - p.x) * (r.x - p.x) + (q.y - p.y) * (r.y - p.y); - if (v < 0) return false; - return true; -} - -void checkDrawing(const Graph& graph, PD& pd) { - for (Graph::NodeIt n(graph); n != INVALID; ++n) { - Graph::NodeIt m(n); - for (++m; m != INVALID; ++m) { - check(pd[m] != pd[n], "Two nodes with identical coordinates"); - } - } - - for (Graph::EdgeIt e(graph); e != INVALID; ++e) { - for (Graph::EdgeIt f(e); f != e; ++f) { - Point e1 = pd[graph.u(e)]; - Point e2 = pd[graph.v(e)]; - Point f1 = pd[graph.u(f)]; - Point f2 = pd[graph.v(f)]; - - if (graph.u(e) == graph.u(f)) { - check(!collinear(e1, e2, f2), "Wrong drawing"); - } else if (graph.u(e) == graph.v(f)) { - check(!collinear(e1, e2, f1), "Wrong drawing"); - } else if (graph.v(e) == graph.u(f)) { - check(!collinear(e2, e1, f2), "Wrong drawing"); - } else if (graph.v(e) == graph.v(f)) { - check(!collinear(e2, e1, f1), "Wrong drawing"); - } else { - check(!intersect(e1, e2, f1, f2), "Wrong drawing"); - } - } - } -} - -void checkColoring(const Graph& graph, PC& pc, int num) { - for (NodeIt n(graph); n != INVALID; ++n) { - check(pc.colorIndex(n) >= 0 && pc.colorIndex(n) < num, - "Wrong coloring"); - } - for (EdgeIt e(graph); e != INVALID; ++e) { - check(pc.colorIndex(graph.u(e)) != pc.colorIndex(graph.v(e)), - "Wrong coloring"); - } -} - -int main() { - - for (int i = 0; i < lgfn; ++i) { - std::istringstream lgfs(lgf[i]); - - SmartGraph graph; - graphReader(graph, lgfs).run(); - - check(simpleGraph(graph), "Test graphs must be simple"); - - PE pe(graph); - bool planar = pe.run(); - check(checkPlanarity(graph) == planar, "Planarity checking failed"); - - if (planar) { - checkEmbedding(graph, pe); - - PlanarDrawing pd(graph); - pd.run(pe.embeddingMap()); - checkDrawing(graph, pd); - - PlanarColoring pc(graph); - pc.runFiveColoring(pe.embeddingMap()); - checkColoring(graph, pc, 5); - - } else { - checkKuratowski(graph, pe); - } - } - - return 0; -} diff --git a/deps/lemon/test/radix_sort_test.cc b/deps/lemon/test/radix_sort_test.cc deleted file mode 100644 index 6ae2debfa..000000000 --- a/deps/lemon/test/radix_sort_test.cc +++ /dev/null @@ -1,266 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include -#include - -#include "test_tools.h" - -#include -#include -#include - -using namespace lemon; - -static const int n = 10000; - -struct Negate { - typedef int argument_type; - typedef int result_type; - int operator()(int a) { return - a; } -}; - -int negate(int a) { return - a; } - -template -bool isTheSame(T &a, T&b) -{ - typename T::iterator ai=a.begin(); - typename T::iterator bi=b.begin(); - for(;ai!=a.end()||bi!=b.end();++ai,++bi) - if(*ai!=*bi) return false; - return ai==a.end()&&bi==b.end(); -} - -template -T listsort(typename T::iterator b, typename T::iterator e) -{ - if(b==e) return T(); - typename T::iterator bn=b; - if(++bn==e) { - T l; - l.push_back(*b); - return l; - } - typename T::iterator m=b; - bool x=false; - for(typename T::iterator i=b;i!=e;++i,x=!x) - if(x) ++m; - T l1(listsort(b,m)); - T l2(listsort(m,e)); - T l; - while((!l1.empty())&&(!l2.empty())) - if(l1.front()<=l2.front()) - { - l.push_back(l1.front()); - l1.pop_front(); - } - else { - l.push_back(l2.front()); - l2.pop_front(); - } - while(!l1.empty()) - { - l.push_back(l1.front()); - l1.pop_front(); - } - while(!l2.empty()) - { - l.push_back(l2.front()); - l2.pop_front(); - } - return l; -} - -template -void generateIntSequence(int n, T & data) { - int prime = 9973; - int root = 136, value = 1; - for (int i = 0; i < n; ++i) { - data.push_back(value - prime / 2); - value = (value * root) % prime; - } -} - -template -void generateCharSequence(int n, T & data) { - int prime = 251; - int root = 3, value = root; - for (int i = 0; i < n; ++i) { - data.push_back(static_cast(value)); - value = (value * root) % prime; - } -} - -void checkRadixSort() { - { - std::vector data1; - generateIntSequence(n, data1); - - std::vector data2(data1); - std::sort(data1.begin(), data1.end()); - - radixSort(data2.begin(), data2.end()); - for (int i = 0; i < n; ++i) { - check(data1[i] == data2[i], "Test failed"); - } - - // radixSort(data2.begin(), data2.end(), Negate()); - // for (int i = 0; i < n; ++i) { - // check(data1[i] == data2[n - 1 - i], "Test failed"); - // } - - // radixSort(data2.begin(), data2.end(), negate); - // for (int i = 0; i < n; ++i) { - // check(data1[i] == data2[n - 1 - i], "Test failed"); - // } - - } - - { - std::vector data1(n); - generateCharSequence(n, data1); - - std::vector data2(data1); - std::sort(data1.begin(), data1.end()); - - radixSort(data2.begin(), data2.end()); - for (int i = 0; i < n; ++i) { - check(data1[i] == data2[i], "Test failed"); - } - - } - { - std::list data1; - generateIntSequence(n, data1); - - std::list data2(listsort >(data1.begin(), data1.end())); - - radixSort(data1.begin(), data1.end()); - - check(isTheSame(data1,data2), "Test failed"); - - - // radixSort(data2.begin(), data2.end(), Negate()); - // check(isTheSame(data1,data2), "Test failed"); - // for (int i = 0; i < n; ++i) { - // check(data1[i] == data2[n - 1 - i], "Test failed"); - // } - - // radixSort(data2.begin(), data2.end(), negate); - // for (int i = 0; i < n; ++i) { - // check(data1[i] == data2[n - 1 - i], "Test failed"); - // } - - } - - { - std::list data1(n); - generateCharSequence(n, data1); - - std::list data2(listsort > - (data1.begin(), - data1.end())); - - radixSort(data1.begin(), data1.end()); - check(isTheSame(data1,data2), "Test failed"); - - } -} - - -void checkStableRadixSort() { - { - std::vector data1; - generateIntSequence(n, data1); - - std::vector data2(data1); - std::sort(data1.begin(), data1.end()); - - stableRadixSort(data2.begin(), data2.end()); - for (int i = 0; i < n; ++i) { - check(data1[i] == data2[i], "Test failed"); - } - - stableRadixSort(data2.begin(), data2.end(), Negate()); - for (int i = 0; i < n; ++i) { - check(data1[i] == data2[n - 1 - i], "Test failed"); - } - - stableRadixSort(data2.begin(), data2.end(), negate); - for (int i = 0; i < n; ++i) { - check(data1[i] == data2[n - 1 - i], "Test failed"); - } - } - - { - std::vector data1(n); - generateCharSequence(n, data1); - - std::vector data2(data1); - std::sort(data1.begin(), data1.end()); - - radixSort(data2.begin(), data2.end()); - for (int i = 0; i < n; ++i) { - check(data1[i] == data2[i], "Test failed"); - } - - } - { - std::list data1; - generateIntSequence(n, data1); - - std::list data2(listsort >(data1.begin(), - data1.end())); - stableRadixSort(data1.begin(), data1.end()); - check(isTheSame(data1,data2), "Test failed"); - - // stableRadixSort(data2.begin(), data2.end(), Negate()); - // for (int i = 0; i < n; ++i) { - // check(data1[i] == data2[n - 1 - i], "Test failed"); - // } - - // stableRadixSort(data2.begin(), data2.end(), negate); - // for (int i = 0; i < n; ++i) { - // check(data1[i] == data2[n - 1 - i], "Test failed"); - // } - } - - { - std::list data1(n); - generateCharSequence(n, data1); - - std::list data2(listsort > - (data1.begin(), - data1.end())); - radixSort(data1.begin(), data1.end()); - check(isTheSame(data1,data2), "Test failed"); - - } -} - -int main() { - - checkRadixSort(); - checkStableRadixSort(); - - return 0; -} diff --git a/deps/lemon/test/random_test.cc b/deps/lemon/test/random_test.cc deleted file mode 100644 index 49dd8b603..000000000 --- a/deps/lemon/test/random_test.cc +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include "test_tools.h" - -int seed_array[] = {1, 2}; - -int main() -{ - double a=lemon::rnd(); - check(a<1.0&&a>0.0,"This should be in [0,1)"); - a=lemon::rnd.gauss(); - a=lemon::rnd.gamma(3.45,0); - a=lemon::rnd.gamma(4); - //Does gamma work with integer k? - a=lemon::rnd.gamma(4.0,0); - a=lemon::rnd.poisson(.5); - - lemon::rnd.seed(100); - lemon::rnd.seed(seed_array, seed_array + - (sizeof(seed_array) / sizeof(seed_array[0]))); - - return 0; -} diff --git a/deps/lemon/test/suurballe_test.cc b/deps/lemon/test/suurballe_test.cc deleted file mode 100644 index 7c00f212a..000000000 --- a/deps/lemon/test/suurballe_test.cc +++ /dev/null @@ -1,267 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "test_tools.h" - -using namespace lemon; - -char test_lgf[] = - "@nodes\n" - "label\n" - "1\n" - "2\n" - "3\n" - "4\n" - "5\n" - "6\n" - "7\n" - "8\n" - "9\n" - "10\n" - "11\n" - "12\n" - "@arcs\n" - " length\n" - " 1 2 70\n" - " 1 3 150\n" - " 1 4 80\n" - " 2 8 80\n" - " 3 5 140\n" - " 4 6 60\n" - " 4 7 80\n" - " 4 8 110\n" - " 5 7 60\n" - " 5 11 120\n" - " 6 3 0\n" - " 6 9 140\n" - " 6 10 90\n" - " 7 1 30\n" - " 8 12 60\n" - " 9 12 50\n" - "10 12 70\n" - "10 2 100\n" - "10 7 60\n" - "11 10 20\n" - "12 11 30\n" - "@attributes\n" - "source 1\n" - "target 12\n" - "@end\n"; - -// Check the interface of Suurballe -void checkSuurballeCompile() -{ - typedef int VType; - typedef concepts::Digraph Digraph; - - typedef Digraph::Node Node; - typedef Digraph::Arc Arc; - typedef concepts::ReadMap LengthMap; - - typedef Suurballe ST; - typedef Suurballe - ::SetFlowMap - ::SetPotentialMap - ::SetPath > - ::SetHeap > > - ::Create SuurballeType; - - Digraph g; - Node n; - Arc e; - LengthMap len; - SuurballeType::FlowMap flow(g); - SuurballeType::PotentialMap pi(g); - - SuurballeType suurb_test(g, len); - const SuurballeType& const_suurb_test = suurb_test; - - suurb_test - .flowMap(flow) - .potentialMap(pi); - - int k; - k = suurb_test.run(n, n); - k = suurb_test.run(n, n, k); - suurb_test.init(n); - suurb_test.fullInit(n); - suurb_test.start(n); - suurb_test.start(n, k); - k = suurb_test.findFlow(n); - k = suurb_test.findFlow(n, k); - suurb_test.findPaths(); - - int f; - VType c; - ::lemon::ignore_unused_variable_warning(f,c); - - c = const_suurb_test.totalLength(); - f = const_suurb_test.flow(e); - const SuurballeType::FlowMap& fm = - const_suurb_test.flowMap(); - c = const_suurb_test.potential(n); - const SuurballeType::PotentialMap& pm = - const_suurb_test.potentialMap(); - k = const_suurb_test.pathNum(); - Path p = const_suurb_test.path(k); - - ::lemon::ignore_unused_variable_warning(fm); - ::lemon::ignore_unused_variable_warning(pm); -} - -// Check the feasibility of the flow -template -bool checkFlow( const Digraph& gr, const FlowMap& flow, - typename Digraph::Node s, typename Digraph::Node t, - int value ) -{ - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - for (ArcIt e(gr); e != INVALID; ++e) - if (!(flow[e] == 0 || flow[e] == 1)) return false; - - for (NodeIt n(gr); n != INVALID; ++n) { - int sum = 0; - for (OutArcIt e(gr, n); e != INVALID; ++e) - sum += flow[e]; - for (InArcIt e(gr, n); e != INVALID; ++e) - sum -= flow[e]; - if (n == s && sum != value) return false; - if (n == t && sum != -value) return false; - if (n != s && n != t && sum != 0) return false; - } - - return true; -} - -// Check the optimalitiy of the flow -template < typename Digraph, typename CostMap, - typename FlowMap, typename PotentialMap > -bool checkOptimality( const Digraph& gr, const CostMap& cost, - const FlowMap& flow, const PotentialMap& pi ) -{ - // Check the "Complementary Slackness" optimality condition - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - bool opt = true; - for (ArcIt e(gr); e != INVALID; ++e) { - typename CostMap::Value red_cost = - cost[e] + pi[gr.source(e)] - pi[gr.target(e)]; - opt = (flow[e] == 0 && red_cost >= 0) || - (flow[e] == 1 && red_cost <= 0); - if (!opt) break; - } - return opt; -} - -// Check a path -template -bool checkPath( const Digraph& gr, const Path& path, - typename Digraph::Node s, typename Digraph::Node t) -{ - TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); - Node n = s; - for (int i = 0; i < path.length(); ++i) { - if (gr.source(path.nth(i)) != n) return false; - n = gr.target(path.nth(i)); - } - return n == t; -} - - -int main() -{ - DIGRAPH_TYPEDEFS(ListDigraph); - - // Read the test digraph - ListDigraph digraph; - ListDigraph::ArcMap length(digraph); - Node s, t; - - std::istringstream input(test_lgf); - DigraphReader(digraph, input). - arcMap("length", length). - node("source", s). - node("target", t). - run(); - - // Check run() - { - Suurballe suurballe(digraph, length); - - // Find 2 paths - check(suurballe.run(s, t) == 2, "Wrong number of paths"); - check(checkFlow(digraph, suurballe.flowMap(), s, t, 2), - "The flow is not feasible"); - check(suurballe.totalLength() == 510, "The flow is not optimal"); - check(checkOptimality(digraph, length, suurballe.flowMap(), - suurballe.potentialMap()), - "Wrong potentials"); - for (int i = 0; i < suurballe.pathNum(); ++i) - check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path"); - - // Find 3 paths - check(suurballe.run(s, t, 3) == 3, "Wrong number of paths"); - check(checkFlow(digraph, suurballe.flowMap(), s, t, 3), - "The flow is not feasible"); - check(suurballe.totalLength() == 1040, "The flow is not optimal"); - check(checkOptimality(digraph, length, suurballe.flowMap(), - suurballe.potentialMap()), - "Wrong potentials"); - for (int i = 0; i < suurballe.pathNum(); ++i) - check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path"); - - // Find 5 paths (only 3 can be found) - check(suurballe.run(s, t, 5) == 3, "Wrong number of paths"); - check(checkFlow(digraph, suurballe.flowMap(), s, t, 3), - "The flow is not feasible"); - check(suurballe.totalLength() == 1040, "The flow is not optimal"); - check(checkOptimality(digraph, length, suurballe.flowMap(), - suurballe.potentialMap()), - "Wrong potentials"); - for (int i = 0; i < suurballe.pathNum(); ++i) - check(checkPath(digraph, suurballe.path(i), s, t), "Wrong path"); - } - - // Check fullInit() + start() - { - Suurballe suurballe(digraph, length); - suurballe.fullInit(s); - - // Find 2 paths - check(suurballe.start(t) == 2, "Wrong number of paths"); - check(suurballe.totalLength() == 510, "The flow is not optimal"); - - // Find 3 paths - check(suurballe.start(t, 3) == 3, "Wrong number of paths"); - check(suurballe.totalLength() == 1040, "The flow is not optimal"); - - // Find 5 paths (only 3 can be found) - check(suurballe.start(t, 5) == 3, "Wrong number of paths"); - check(suurballe.totalLength() == 1040, "The flow is not optimal"); - } - - return 0; -} diff --git a/deps/lemon/test/test_tools.h b/deps/lemon/test/test_tools.h deleted file mode 100644 index 330035667..000000000 --- a/deps/lemon/test/test_tools.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2010 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#ifndef LEMON_TEST_TEST_TOOLS_H -#define LEMON_TEST_TEST_TOOLS_H - -///\ingroup misc -///\file -///\brief Some utilities to write test programs. - -#include -#include - -///If \c rc is fail, writes an error message and exits. - -///If \c rc is fail, writes an error message and exits. -///The error message contains the file name and the line number of the -///source code in a standard from, which makes it possible to go there -///using good source browsers like e.g. \c emacs. -/// -///For example -///\code check(0==1,"This is obviously false.");\endcode will -///print something like this (and then exits). -///\verbatim file_name.cc:123: error: This is obviously false. \endverbatim -#define check(rc, msg) \ - { \ - if(!(rc)) { \ - std::cerr << __FILE__ ":" << __LINE__ << ": error: " \ - << msg << std::endl; \ - abort(); \ - } else { } \ - } \ - - -#endif diff --git a/deps/lemon/test/test_tools_fail.cc b/deps/lemon/test/test_tools_fail.cc deleted file mode 100644 index 6407cd15b..000000000 --- a/deps/lemon/test/test_tools_fail.cc +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include "test_tools.h" - -int main() -{ - check(false, "Don't panic. Failing is the right behaviour here."); - return 0; -} diff --git a/deps/lemon/test/test_tools_pass.cc b/deps/lemon/test/test_tools_pass.cc deleted file mode 100644 index b590c15a6..000000000 --- a/deps/lemon/test/test_tools_pass.cc +++ /dev/null @@ -1,25 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include "test_tools.h" - -int main() -{ - check(true, "It should pass."); - return 0; -} diff --git a/deps/lemon/test/time_measure_test.cc b/deps/lemon/test/time_measure_test.cc deleted file mode 100644 index 4e7155a91..000000000 --- a/deps/lemon/test/time_measure_test.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include - -using namespace lemon; - -void f() -{ - double d=0; - for(int i=0;i<1000;i++) - d+=0.1; -} - -void g() -{ - static Timer T; - - for(int i=0;i<1000;i++) - { - TimeStamp x(T); - ::lemon::ignore_unused_variable_warning(x); - } -} - -int main() -{ - Timer T; - unsigned int n; - for(n=0;T.realTime()<0.1;n++) ; - std::cout << T << " (" << n << " time queries)\n"; - - TimeStamp full; - TimeStamp t; - t=runningTimeTest(f,0.1,&n,&full); - std::cout << t << " (" << n << " tests)\n"; - std::cout << "Total: " << full << "\n"; - - t=runningTimeTest(g,0.1,&n,&full); - std::cout << t << " (" << n << " tests)\n"; - std::cout << "Total: " << full << "\n"; - - return 0; -} diff --git a/deps/lemon/test/tsp_test.cc b/deps/lemon/test/tsp_test.cc deleted file mode 100644 index 398a812e0..000000000 --- a/deps/lemon/test/tsp_test.cc +++ /dev/null @@ -1,287 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "test_tools.h" - -using namespace lemon; - -// // Tests checkMetricCost() function -// void metricCostTest() { -// GRAPH_TYPEDEFS(FullGraph); -// FullGraph g(10); -// check(checkMetricCost(g, constMap(0)), "Wrong checkMetricCost()"); -// check(checkMetricCost(g, constMap(1)), "Wrong checkMetricCost()"); -// check(!checkMetricCost(g, constMap(-1)), "Wrong checkMetricCost()"); -// -// FullGraph::EdgeMap cost(g); -// for (NodeIt u(g); u != INVALID; ++u) { -// for (NodeIt v(g); v != INVALID; ++v) { -// if (u == v) continue; -// float x1 = g.id(u), x2 = g.id(v); -// float y1 = x1 * x1, y2 = x2 * x2; -// cost[g.edge(u, v)] = std::sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); -// } -// } -// check(checkMetricCost(g, cost), "Wrong checkMetricCost()"); -// float eps = Tolerance::defaultEpsilon(); -// cost[g.edge(g(0), g(9))] = -// cost[g.edge(g(0), g(8))] + cost[g.edge(g(8), g(9))] + eps * 2; -// check(!checkMetricCost(g, cost), "Wrong checkMetricCost()"); -// check(checkMetricCost(g, cost, Tolerance(eps * 4)), -// "Wrong checkMetricCost()"); -// } - -// Checks tour validity -template -bool checkTour(const FullGraph &gr, const Container &p) { - FullGraph::NodeMap used(gr, false); - - int node_cnt = 0; - for (typename Container::const_iterator it = p.begin(); it != p.end(); ++it) - { - FullGraph::Node node = *it; - if (used[node]) return false; - used[node] = true; - ++node_cnt; - } - - return (node_cnt == gr.nodeNum()); -} - -// Checks tour validity -bool checkTourPath(const FullGraph &gr, const Path &p) { - FullGraph::NodeMap used(gr, false); - - if (!checkPath(gr, p)) return false; - if (gr.nodeNum() <= 1 && p.length() != 0) return false; - if (gr.nodeNum() > 1 && p.length() != gr.nodeNum()) return false; - - for (int i = 0; i < p.length(); ++i) { - if (used[gr.target(p.nth(i))]) return false; - used[gr.target(p.nth(i))] = true; - } - return true; -} - -// Checks tour cost -template -bool checkCost(const FullGraph &gr, const std::vector &p, - const CostMap &cost, typename CostMap::Value total) -{ - typedef typename CostMap::Value Cost; - - Cost s = 0; - for (int i = 0; i < int(p.size()) - 1; ++i) - s += cost[gr.edge(p[i], p[i+1])]; - if (int(p.size()) >= 2) - s += cost[gr.edge(p.back(), p.front())]; - - return !Tolerance().different(s, total); -} - -// Checks tour cost -template -bool checkCost(const FullGraph &, const Path &p, - const CostMap &cost, typename CostMap::Value total) -{ - typedef typename CostMap::Value Cost; - - Cost s = 0; - for (int i = 0; i < p.length(); ++i) - s += cost[p.nth(i)]; - - return !Tolerance().different(s, total); -} - -// Tests a TSP algorithm on small graphs -template -void tspTestSmall(const std::string &alg_name) { - GRAPH_TYPEDEFS(FullGraph); - - for (int n = 0; n <= 5; ++n) { - FullGraph g(n); - unsigned nsize = n; - int esize = n <= 1 ? 0 : n; - - ConstMap cost_map(1); - TSP alg(g, cost_map); - - check(alg.run() == esize, alg_name + ": Wrong total cost"); - check(alg.tourCost() == esize, alg_name + ": Wrong total cost"); - - std::list list1(nsize), list2; - std::vector vec1(nsize), vec2; - alg.tourNodes(list1.begin()); - alg.tourNodes(vec1.begin()); - alg.tourNodes(std::front_inserter(list2)); - alg.tourNodes(std::back_inserter(vec2)); - check(checkTour(g, alg.tourNodes()), alg_name + ": Wrong node sequence"); - check(checkTour(g, list1), alg_name + ": Wrong node sequence"); - check(checkTour(g, vec1), alg_name + ": Wrong node sequence"); - check(checkTour(g, list2), alg_name + ": Wrong node sequence"); - check(checkTour(g, vec2), alg_name + ": Wrong node sequence"); - check(checkCost(g, vec1, constMap(1), esize), - alg_name + ": Wrong tour cost"); - - SimplePath path; - alg.tour(path); - check(path.length() == esize, alg_name + ": Wrong tour"); - check(checkTourPath(g, path), alg_name + ": Wrong tour"); - check(checkCost(g, path, constMap(1), esize), - alg_name + ": Wrong tour cost"); - } -} - -// Tests a TSP algorithm on random graphs -template -void tspTestRandom(const std::string &alg_name) { - GRAPH_TYPEDEFS(FullGraph); - - FullGraph g(20); - FullGraph::NodeMap > pos(g); - DoubleEdgeMap cost(g); - - TSP alg(g, cost); - Opt2Tsp opt2(g, cost); - - for (int i = 1; i <= 3; i++) { - for (NodeIt u(g); u != INVALID; ++u) { - pos[u] = dim2::Point(rnd(), rnd()); - } - for (NodeIt u(g); u != INVALID; ++u) { - for (NodeIt v(g); v != INVALID; ++v) { - if (u == v) continue; - cost[g.edge(u, v)] = (pos[u] - pos[v]).normSquare(); - } - } - - check(alg.run() > 0, alg_name + ": Wrong total cost"); - - std::vector vec; - alg.tourNodes(std::back_inserter(vec)); - check(checkTour(g, vec), alg_name + ": Wrong node sequence"); - check(checkCost(g, vec, cost, alg.tourCost()), - alg_name + ": Wrong tour cost"); - - SimplePath path; - alg.tour(path); - check(checkTourPath(g, path), alg_name + ": Wrong tour"); - check(checkCost(g, path, cost, alg.tourCost()), - alg_name + ": Wrong tour cost"); - - check(!Tolerance().less(alg.tourCost(), opt2.run(alg.tourNodes())), - "2-opt improvement: Wrong total cost"); - check(checkTour(g, opt2.tourNodes()), - "2-opt improvement: Wrong node sequence"); - check(checkCost(g, opt2.tourNodes(), cost, opt2.tourCost()), - "2-opt improvement: Wrong tour cost"); - - check(!Tolerance().less(alg.tourCost(), opt2.run(path)), - "2-opt improvement: Wrong total cost"); - check(checkTour(g, opt2.tourNodes()), - "2-opt improvement: Wrong node sequence"); - check(checkCost(g, opt2.tourNodes(), cost, opt2.tourCost()), - "2-opt improvement: Wrong tour cost"); - } -} - -// Algorithm class for Nearest Insertion -template -class NearestInsertionTsp : public InsertionTsp { -public: - NearestInsertionTsp(const FullGraph &gr, const CM &cost) - : InsertionTsp(gr, cost) {} - typename CM::Value run() { - return InsertionTsp::run(InsertionTsp::NEAREST); - } -}; - -// Algorithm class for Farthest Insertion -template -class FarthestInsertionTsp : public InsertionTsp { -public: - FarthestInsertionTsp(const FullGraph &gr, const CM &cost) - : InsertionTsp(gr, cost) {} - typename CM::Value run() { - return InsertionTsp::run(InsertionTsp::FARTHEST); - } -}; - -// Algorithm class for Cheapest Insertion -template -class CheapestInsertionTsp : public InsertionTsp { -public: - CheapestInsertionTsp(const FullGraph &gr, const CM &cost) - : InsertionTsp(gr, cost) {} - typename CM::Value run() { - return InsertionTsp::run(InsertionTsp::CHEAPEST); - } -}; - -// Algorithm class for Random Insertion -template -class RandomInsertionTsp : public InsertionTsp { -public: - RandomInsertionTsp(const FullGraph &gr, const CM &cost) - : InsertionTsp(gr, cost) {} - typename CM::Value run() { - return InsertionTsp::run(InsertionTsp::RANDOM); - } -}; - -int main() { - GRAPH_TYPEDEFS(FullGraph); - - // metricCostTest(); - - tspTestSmall > >("Nearest Neighbor"); - tspTestSmall > >("Greedy"); - tspTestSmall > >("Nearest Insertion"); - tspTestSmall > > - ("Farthest Insertion"); - tspTestSmall > > - ("Cheapest Insertion"); - tspTestSmall > >("Random Insertion"); - tspTestSmall > >("Christofides"); - tspTestSmall > >("2-opt"); - - tspTestRandom >("Nearest Neighbor"); - tspTestRandom >("Greedy"); - tspTestRandom >("Nearest Insertion"); - tspTestRandom >("Farthest Insertion"); - tspTestRandom >("Cheapest Insertion"); - tspTestRandom >("Random Insertion"); - tspTestRandom >("Christofides"); - tspTestRandom >("2-opt"); - - return 0; -} diff --git a/deps/lemon/test/unionfind_test.cc b/deps/lemon/test/unionfind_test.cc deleted file mode 100644 index e82d8e64a..000000000 --- a/deps/lemon/test/unionfind_test.cc +++ /dev/null @@ -1,102 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -#include -#include -#include -#include "test_tools.h" - -using namespace lemon; -using namespace std; - -typedef UnionFindEnum > UFE; - -int main() { - ListGraph g; - ListGraph::NodeMap base(g); - UFE U(base); - vector n; - - for(int i=0;i<20;i++) n.push_back(g.addNode()); - - U.insert(n[1]); - U.insert(n[2]); - - check(U.join(n[1],n[2]) != -1, "Something is wrong with UnionFindEnum"); - - U.insert(n[3]); - U.insert(n[4]); - U.insert(n[5]); - U.insert(n[6]); - U.insert(n[7]); - - - check(U.join(n[1],n[4]) != -1, "Something is wrong with UnionFindEnum"); - check(U.join(n[2],n[4]) == -1, "Something is wrong with UnionFindEnum"); - check(U.join(n[3],n[5]) != -1, "Something is wrong with UnionFindEnum"); - - - U.insert(n[8],U.find(n[5])); - - - check(U.size(U.find(n[4])) == 3, "Something is wrong with UnionFindEnum"); - check(U.size(U.find(n[5])) == 3, "Something is wrong with UnionFindEnum"); - check(U.size(U.find(n[6])) == 1, "Something is wrong with UnionFindEnum"); - check(U.size(U.find(n[2])) == 3, "Something is wrong with UnionFindEnum"); - - - U.insert(n[9]); - U.insert(n[10],U.find(n[9])); - - - check(U.join(n[8],n[10]) != -1, "Something is wrong with UnionFindEnum"); - - - check(U.size(U.find(n[4])) == 3, "Something is wrong with UnionFindEnum"); - check(U.size(U.find(n[9])) == 5, "Something is wrong with UnionFindEnum"); - - check(U.size(U.find(n[8])) == 5, "Something is wrong with UnionFindEnum"); - - U.erase(n[9]); - U.erase(n[1]); - - check(U.size(U.find(n[10])) == 4, "Something is wrong with UnionFindEnum"); - check(U.size(U.find(n[2])) == 2, "Something is wrong with UnionFindEnum"); - - U.erase(n[6]); - U.split(U.find(n[8])); - - - check(U.size(U.find(n[4])) == 2, "Something is wrong with UnionFindEnum"); - check(U.size(U.find(n[3])) == 1, "Something is wrong with UnionFindEnum"); - check(U.size(U.find(n[2])) == 2, "Something is wrong with UnionFindEnum"); - - - check(U.join(n[3],n[4]) != -1, "Something is wrong with UnionFindEnum"); - check(U.join(n[2],n[4]) == -1, "Something is wrong with UnionFindEnum"); - - - check(U.size(U.find(n[4])) == 3, "Something is wrong with UnionFindEnum"); - check(U.size(U.find(n[3])) == 3, "Something is wrong with UnionFindEnum"); - check(U.size(U.find(n[2])) == 3, "Something is wrong with UnionFindEnum"); - - U.eraseClass(U.find(n[4])); - U.eraseClass(U.find(n[7])); - - return 0; -} diff --git a/deps/lemon/tools/CMakeLists.txt b/deps/lemon/tools/CMakeLists.txt deleted file mode 100644 index fe06efdca..000000000 --- a/deps/lemon/tools/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -INCLUDE_DIRECTORIES( - ${PROJECT_SOURCE_DIR} - ${PROJECT_BINARY_DIR} -) - -LINK_DIRECTORIES( - ${PROJECT_BINARY_DIR}/lemon -) - -ADD_EXECUTABLE(lgf-gen lgf-gen.cc) -TARGET_LINK_LIBRARIES(lgf-gen lemon) - -ADD_EXECUTABLE(dimacs-to-lgf dimacs-to-lgf.cc) -TARGET_LINK_LIBRARIES(dimacs-to-lgf lemon) - -ADD_EXECUTABLE(dimacs-solver dimacs-solver.cc) -TARGET_LINK_LIBRARIES(dimacs-solver lemon) - -INCLUDE(GNUInstallDirs) - -INSTALL( - TARGETS lgf-gen dimacs-to-lgf dimacs-solver - RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" - COMPONENT bin -) - -IF(NOT WIN32) - INSTALL( - PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/lemon-0.x-to-1.x.sh - DESTINATION "${CMAKE_INSTALL_BINDIR}" - COMPONENT bin - ) -ENDIF() diff --git a/deps/lemon/tools/dimacs-solver.cc b/deps/lemon/tools/dimacs-solver.cc deleted file mode 100644 index 60da2330e..000000000 --- a/deps/lemon/tools/dimacs-solver.cc +++ /dev/null @@ -1,279 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2013 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\ingroup tools -///\file -///\brief DIMACS problem solver. -/// -/// This program solves various problems given in DIMACS format. -/// -/// See -/// \code -/// dimacs-solver --help -/// \endcode -/// for more info on usage. - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -using namespace lemon; -typedef SmartDigraph Digraph; -DIGRAPH_TYPEDEFS(Digraph); -typedef SmartGraph Graph; - -template -void solve_sp(ArgParser &ap, std::istream &is, std::ostream &, - DimacsDescriptor &desc) -{ - bool report = !ap.given("q"); - Digraph g; - Node s; - Digraph::ArcMap len(g); - Timer t; - t.restart(); - readDimacsSp(is, g, len, s, desc); - if(report) std::cerr << "Read the file: " << t << '\n'; - t.restart(); - Dijkstra > dij(g,len); - if(report) std::cerr << "Setup Dijkstra class: " << t << '\n'; - t.restart(); - dij.run(s); - if(report) std::cerr << "Run Dijkstra: " << t << '\n'; -} - -template -void solve_max(ArgParser &ap, std::istream &is, std::ostream &, - Value infty, DimacsDescriptor &desc) -{ - bool report = !ap.given("q"); - Digraph g; - Node s,t; - Digraph::ArcMap cap(g); - Timer ti; - ti.restart(); - readDimacsMax(is, g, cap, s, t, infty, desc); - if(report) std::cerr << "Read the file: " << ti << '\n'; - ti.restart(); - Preflow > pre(g,cap,s,t); - if(report) std::cerr << "Setup Preflow class: " << ti << '\n'; - ti.restart(); - pre.run(); - if(report) std::cerr << "Run Preflow: " << ti << '\n'; - if(report) std::cerr << "\nMax flow value: " << pre.flowValue() << '\n'; -} - -template -void solve_min(ArgParser &ap, std::istream &is, std::ostream &, - Value infty, DimacsDescriptor &desc) -{ - bool report = !ap.given("q"); - Digraph g; - Digraph::ArcMap lower(g), cap(g), cost(g); - Digraph::NodeMap sup(g); - Timer ti; - - ti.restart(); - readDimacsMin(is, g, lower, cap, cost, sup, infty, desc); - ti.stop(); - Value sum_sup = 0; - for (Digraph::NodeIt n(g); n != INVALID; ++n) { - sum_sup += sup[n]; - } - if (report) { - std::cerr << "Sum of supply values: " << sum_sup << "\n"; - if (sum_sup <= 0) - std::cerr << "GEQ supply contraints are used for NetworkSimplex\n\n"; - else - std::cerr << "LEQ supply contraints are used for NetworkSimplex\n\n"; - } - if (report) std::cerr << "Read the file: " << ti << '\n'; - - typedef NetworkSimplex MCF; - ti.restart(); - MCF ns(g); - ns.lowerMap(lower).upperMap(cap).costMap(cost).supplyMap(sup); - if (sum_sup > 0) ns.supplyType(ns.LEQ); - if (report) std::cerr << "Setup NetworkSimplex class: " << ti << '\n'; - ti.restart(); - typename MCF::ProblemType res = ns.run(); - if (report) { - std::cerr << "Run NetworkSimplex: " << ti << "\n\n"; - std::cerr << "Feasible flow: " << (res == MCF::OPTIMAL ? "found" : - "not found") << '\n'; - if (res) std::cerr << "Min flow cost: " - << ns.template totalCost() << '\n'; - } -} - -void solve_mat(ArgParser &ap, std::istream &is, std::ostream &, - DimacsDescriptor &desc) -{ - bool report = !ap.given("q"); - Graph g; - Timer ti; - ti.restart(); - readDimacsMat(is, g, desc); - if(report) std::cerr << "Read the file: " << ti << '\n'; - ti.restart(); - MaxMatching mat(g); - if(report) std::cerr << "Setup MaxMatching class: " << ti << '\n'; - ti.restart(); - mat.run(); - if(report) std::cerr << "Run MaxMatching: " << ti << '\n'; - if(report) std::cerr << "\nCardinality of max matching: " - << mat.matchingSize() << '\n'; -} - - -template -void solve(ArgParser &ap, std::istream &is, std::ostream &os, - DimacsDescriptor &desc) -{ - std::stringstream iss(static_cast(ap["infcap"])); - Value infty; - iss >> infty; - if(iss.fail()) - { - std::cerr << "Cannot interpret '" - << static_cast(ap["infcap"]) << "' as infinite" - << std::endl; - exit(1); - } - - switch(desc.type) - { - case DimacsDescriptor::MIN: - solve_min(ap,is,os,infty,desc); - break; - case DimacsDescriptor::MAX: - solve_max(ap,is,os,infty,desc); - break; - case DimacsDescriptor::SP: - solve_sp(ap,is,os,desc); - break; - case DimacsDescriptor::MAT: - solve_mat(ap,is,os,desc); - break; - default: - break; - } -} - -int main(int argc, const char *argv[]) { - - std::string inputName; - std::string outputName; - - ArgParser ap(argc, argv); - ap.other("[INFILE [OUTFILE]]", - "If either the INFILE or OUTFILE file is missing the standard\n" - " input/output will be used instead.") - .boolOption("q", "Do not print any report") - .boolOption("int","Use 'int' for capacities, costs etc. (default)") - .optionGroup("datatype","int") -#ifdef LEMON_HAVE_LONG_LONG - .boolOption("long","Use 'long long' for capacities, costs etc.") - .optionGroup("datatype","long") -#endif - .boolOption("double","Use 'double' for capacities, costs etc.") - .optionGroup("datatype","double") - .boolOption("ldouble","Use 'long double' for capacities, costs etc.") - .optionGroup("datatype","ldouble") - .onlyOneGroup("datatype") - .stringOption("infcap","Value used for 'very high' capacities","0") - .run(); - - std::ifstream input; - std::ofstream output; - - switch(ap.files().size()) - { - case 2: - output.open(ap.files()[1].c_str()); - if (!output) { - throw IoError("Cannot open the file for writing", ap.files()[1]); - } - case 1: - input.open(ap.files()[0].c_str()); - if (!input) { - throw IoError("File cannot be found", ap.files()[0]); - } - case 0: - break; - default: - std::cerr << ap.commandName() << ": too many arguments\n"; - return 1; - } - std::istream& is = (ap.files().size()<1 ? std::cin : input); - std::ostream& os = (ap.files().size()<2 ? std::cout : output); - - DimacsDescriptor desc = dimacsType(is); - - if(!ap.given("q")) - { - std::cout << "Problem type: "; - switch(desc.type) - { - case DimacsDescriptor::MIN: - std::cout << "min"; - break; - case DimacsDescriptor::MAX: - std::cout << "max"; - break; - case DimacsDescriptor::SP: - std::cout << "sp"; - case DimacsDescriptor::MAT: - std::cout << "mat"; - break; - default: - exit(1); - break; - } - std::cout << "\nNum of nodes: " << desc.nodeNum; - std::cout << "\nNum of arcs: " << desc.edgeNum; - std::cout << "\n\n"; - } - - if(ap.given("double")) - solve(ap,is,os,desc); - else if(ap.given("ldouble")) - solve(ap,is,os,desc); -#ifdef LEMON_HAVE_LONG_LONG - else if(ap.given("long")) - solve(ap,is,os,desc); - else solve(ap,is,os,desc); -#else - else solve(ap,is,os,desc); -#endif - - return 0; -} diff --git a/deps/lemon/tools/dimacs-to-lgf.cc b/deps/lemon/tools/dimacs-to-lgf.cc deleted file mode 100644 index 3968645dd..000000000 --- a/deps/lemon/tools/dimacs-to-lgf.cc +++ /dev/null @@ -1,148 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -///\ingroup tools -///\file -///\brief DIMACS to LGF converter. -/// -/// This program converts various DIMACS formats to the LEMON Digraph Format -/// (LGF). -/// -/// See -/// \code -/// dimacs-to-lgf --help -/// \endcode -/// for more info on the usage. - -#include -#include -#include - -#include -#include -#include - -#include -#include - -using namespace std; -using namespace lemon; - - -int main(int argc, const char *argv[]) { - typedef SmartDigraph Digraph; - - typedef Digraph::Arc Arc; - typedef Digraph::Node Node; - typedef Digraph::ArcIt ArcIt; - typedef Digraph::NodeIt NodeIt; - typedef Digraph::ArcMap DoubleArcMap; - typedef Digraph::NodeMap DoubleNodeMap; - - std::string inputName; - std::string outputName; - - ArgParser ap(argc, argv); - ap.other("[INFILE [OUTFILE]]", - "If either the INFILE or OUTFILE file is missing the standard\n" - " input/output will be used instead.") - .run(); - - ifstream input; - ofstream output; - - switch(ap.files().size()) - { - case 2: - output.open(ap.files()[1].c_str()); - if (!output) { - throw IoError("Cannot open the file for writing", ap.files()[1]); - } - case 1: - input.open(ap.files()[0].c_str()); - if (!input) { - throw IoError("File cannot be found", ap.files()[0]); - } - case 0: - break; - default: - cerr << ap.commandName() << ": too many arguments\n"; - return 1; - } - istream& is = (ap.files().size()<1 ? cin : input); - ostream& os = (ap.files().size()<2 ? cout : output); - - DimacsDescriptor desc = dimacsType(is); - switch(desc.type) - { - case DimacsDescriptor::MIN: - { - Digraph digraph; - DoubleArcMap lower(digraph), capacity(digraph), cost(digraph); - DoubleNodeMap supply(digraph); - readDimacsMin(is, digraph, lower, capacity, cost, supply, 0, desc); - DigraphWriter(digraph, os). - nodeMap("supply", supply). - arcMap("lower", lower). - arcMap("capacity", capacity). - arcMap("cost", cost). - attribute("problem","min"). - run(); - } - break; - case DimacsDescriptor::MAX: - { - Digraph digraph; - Node s, t; - DoubleArcMap capacity(digraph); - readDimacsMax(is, digraph, capacity, s, t, 0, desc); - DigraphWriter(digraph, os). - arcMap("capacity", capacity). - node("source", s). - node("target", t). - attribute("problem","max"). - run(); - } - break; - case DimacsDescriptor::SP: - { - Digraph digraph; - Node s; - DoubleArcMap capacity(digraph); - readDimacsSp(is, digraph, capacity, s, desc); - DigraphWriter(digraph, os). - arcMap("capacity", capacity). - node("source", s). - attribute("problem","sp"). - run(); - } - break; - case DimacsDescriptor::MAT: - { - Digraph digraph; - readDimacsMat(is, digraph,desc); - DigraphWriter(digraph, os). - attribute("problem","mat"). - run(); - } - break; - default: - break; - } - return 0; -} diff --git a/deps/lemon/tools/lemon-0.x-to-1.x.sh b/deps/lemon/tools/lemon-0.x-to-1.x.sh deleted file mode 100755 index 1dac1be65..000000000 --- a/deps/lemon/tools/lemon-0.x-to-1.x.sh +++ /dev/null @@ -1,134 +0,0 @@ -#!/bin/bash - -set -e - -if [ $# -eq 0 -o x$1 = "x-h" -o x$1 = "x-help" -o x$1 = "x--help" ]; then - echo "Usage:" - echo " $0 source-file(s)" - exit -fi - -for i in $@ -do - echo Update $i... - TMP=`mktemp` - sed -e "s/\/_gr_aph_label_/g"\ - -e "s/\/_gr_aph_label_s/g"\ - -e "s/\/_ed_ge_label_/g"\ - -e "s/\/_ed_ge_label_s/g"\ - -e "s/\/_digr_aph_label_/g"\ - -e "s/\/_digr_aph_label_s/g"\ - -e "s/\/_ar_c_label_/g"\ - -e "s/\/_ar_c_label_s/g"\ - -e "s/UGraph/_Gr_aph_label_/g"\ - -e "s/u[Gg]raph/_gr_aph_label_/g"\ - -e "s/Graph\>/_Digr_aph_label_/g"\ - -e "s/\/_digr_aph_label_/g"\ - -e "s/Graphs\>/_Digr_aph_label_s/g"\ - -e "s/\/_digr_aph_label_s/g"\ - -e "s/\([Gg]\)raph\([a-z]\)/_\1r_aph_label_\2/g"\ - -e "s/\([a-z_]\)graph/\1_gr_aph_label_/g"\ - -e "s/Graph/_Digr_aph_label_/g"\ - -e "s/graph/_digr_aph_label_/g"\ - -e "s/UEdge/_Ed_ge_label_/g"\ - -e "s/u[Ee]dge/_ed_ge_label_/g"\ - -e "s/IncEdgeIt/_In_cEd_geIt_label_/g"\ - -e "s/Edge\>/_Ar_c_label_/g"\ - -e "s/\/_ar_c_label_/g"\ - -e "s/_edge\>/__ar_c_label_/g"\ - -e "s/Edges\>/_Ar_c_label_s/g"\ - -e "s/\/_ar_c_label_s/g"\ - -e "s/_edges\>/__ar_c_label_s/g"\ - -e "s/\([Ee]\)dge\([a-z]\)/_\1d_ge_label_\2/g"\ - -e "s/\([a-z]\)edge/\1_ed_ge_label_/g"\ - -e "s/Edge/_Ar_c_label_/g"\ - -e "s/edge/_ar_c_label_/g"\ - -e "s/A[Nn]ode/_Re_d_label_/g"\ - -e "s/B[Nn]ode/_Blu_e_label_/g"\ - -e "s/A-[Nn]ode/_Re_d_label_/g"\ - -e "s/B-[Nn]ode/_Blu_e_label_/g"\ - -e "s/a[Nn]ode/_re_d_label_/g"\ - -e "s/b[Nn]ode/_blu_e_label_/g"\ - -e "s/\/_GR_APH_TY_PEDE_FS_label_/g"\ - -e "s/\/_DIGR_APH_TY_PEDE_FS_label_/g"\ - -e "s/_Digr_aph_label_/Digraph/g"\ - -e "s/_digr_aph_label_/digraph/g"\ - -e "s/_Gr_aph_label_/Graph/g"\ - -e "s/_gr_aph_label_/graph/g"\ - -e "s/_Ar_c_label_/Arc/g"\ - -e "s/_ar_c_label_/arc/g"\ - -e "s/_Ed_ge_label_/Edge/g"\ - -e "s/_ed_ge_label_/edge/g"\ - -e "s/_In_cEd_geIt_label_/IncEdgeIt/g"\ - -e "s/_Re_d_label_/Red/g"\ - -e "s/_Blu_e_label_/Blue/g"\ - -e "s/_re_d_label_/red/g"\ - -e "s/_blu_e_label_/blue/g"\ - -e "s/_GR_APH_TY_PEDE_FS_label_/GRAPH_TYPEDEFS/g"\ - -e "s/_DIGR_APH_TY_PEDE_FS_label_/DIGRAPH_TYPEDEFS/g"\ - -e "s/\/adaptors.h/g"\ - -e "s/\/core.h/g"\ - -e "s/\/lgf_reader.h/g"\ - -e "s/\/lgf_writer.h/g"\ - -e "s/\/connectivity.h/g"\ - -e "s/DigraphToEps/GraphToEps/g"\ - -e "s/digraphToEps/graphToEps/g"\ - -e "s/\/SetPredMap/g"\ - -e "s/\/SetDistMap/g"\ - -e "s/\/SetReachedMap/g"\ - -e "s/\/SetProcessedMap/g"\ - -e "s/\/SetHeap/g"\ - -e "s/\/SetStandradHeap/g"\ - -e "s/\/SetOperationTraits/g"\ - -e "s/\/SetStandardProcessedMap/g"\ - -e "s/\/graphCopy/g"\ - -e "s/\/digraphCopy/g"\ - -e "s/\/HypercubeGraph/g"\ - -e "s/\/RangeMap/g"\ - -e "s/\/rangeMap/g"\ - -e "s/\<\([sS]\)tdMap\>/\1parseMap/g"\ - -e "s/\<\([Ff]\)unctorMap\>/\1unctorToMap/g"\ - -e "s/\<\([Mm]\)apFunctor\>/\1apToFunctor/g"\ - -e "s/\<\([Ff]\)orkWriteMap\>/\1orkMap/g"\ - -e "s/\/LoggerBoolMap/g"\ - -e "s/\/loggerBoolMap/g"\ - -e "s/\/CrossRefMap/g"\ - -e "s/\/crossRefMap/g"\ - -e "s/\/RangeIdMap/g"\ - -e "s/\/rangeIdMap/g"\ - -e "s/\/Box/g"\ - -e "s/\/readNautyGraph/g"\ - -e "s/\/ReverseDigraph/g"\ - -e "s/\/reverseDigraph/g"\ - -e "s/\/SubDigraph/g"\ - -e "s/\/subDigraph/g"\ - -e "s/\/SubGraph/g"\ - -e "s/\/subGraph/g"\ - -e "s/\/FilterNodes/g"\ - -e "s/\/filterNodes/g"\ - -e "s/\/FilterArcs/g"\ - -e "s/\/filterArcs/g"\ - -e "s/\/Undirector/g"\ - -e "s/\/undirector/g"\ - -e "s/\/ResidualDigraph/g"\ - -e "s/\/residualDigraph/g"\ - -e "s/\/SplitNodes/g"\ - -e "s/\/splitNodes/g"\ - -e "s/\/SubGraph/g"\ - -e "s/\/subGraph/g"\ - -e "s/\/FilterNodes/g"\ - -e "s/\/filterNodes/g"\ - -e "s/\/FilterEdges/g"\ - -e "s/\/filterEdges/g"\ - -e "s/\/Orienter/g"\ - -e "s/\/orienter/g"\ - -e "s/\/CplexLp/g"\ - -e "s/\/CplexMip/g"\ - -e "s/\/GlpkLp/g"\ - -e "s/\/GlpkMip/g"\ - -e "s/\/SoplexLp/g"\ - <$i > $TMP - mv $TMP $i -done diff --git a/deps/lemon/tools/lgf-gen.cc b/deps/lemon/tools/lgf-gen.cc deleted file mode 100644 index 390c8ae59..000000000 --- a/deps/lemon/tools/lgf-gen.cc +++ /dev/null @@ -1,847 +0,0 @@ -/* -*- mode: C++; indent-tabs-mode: nil; -*- - * - * This file is a part of LEMON, a generic C++ optimization library. - * - * Copyright (C) 2003-2009 - * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport - * (Egervary Research Group on Combinatorial Optimization, EGRES). - * - * Permission to use, modify and distribute this software is granted - * provided that this copyright notice appears in all copies. For - * precise terms see the accompanying LICENSE file. - * - * This software is provided "AS IS" with no warranty of any kind, - * express or implied, and with no claim as to its suitability for any - * purpose. - * - */ - -/// \ingroup tools -/// \file -/// \brief Special plane graph generator. -/// -/// Graph generator application for various types of plane graphs. -/// -/// See -/// \code -/// lgf-gen --help -/// \endcode -/// for more information on the usage. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace lemon; - -typedef dim2::Point Point; - -GRAPH_TYPEDEFS(ListGraph); - -bool progress=true; - -int N; -// int girth; - -ListGraph g; - -std::vector nodes; -ListGraph::NodeMap coords(g); - - -double totalLen(){ - double tlen=0; - for(EdgeIt e(g);e!=INVALID;++e) - tlen+=std::sqrt((coords[g.v(e)]-coords[g.u(e)]).normSquare()); - return tlen; -} - -int tsp_impr_num=0; - -const double EPSILON=1e-8; -bool tsp_improve(Node u, Node v) -{ - double luv=std::sqrt((coords[v]-coords[u]).normSquare()); - Node u2=u; - Node v2=v; - do { - Node n; - for(IncEdgeIt e(g,v2);(n=g.runningNode(e))==u2;++e) { } - u2=v2; - v2=n; - if(luv+std::sqrt((coords[v2]-coords[u2]).normSquare())-EPSILON> - std::sqrt((coords[u]-coords[u2]).normSquare())+ - std::sqrt((coords[v]-coords[v2]).normSquare())) - { - g.erase(findEdge(g,u,v)); - g.erase(findEdge(g,u2,v2)); - g.addEdge(u2,u); - g.addEdge(v,v2); - tsp_impr_num++; - return true; - } - } while(v2!=u); - return false; -} - -bool tsp_improve(Node u) -{ - for(IncEdgeIt e(g,u);e!=INVALID;++e) - if(tsp_improve(u,g.runningNode(e))) return true; - return false; -} - -void tsp_improve() -{ - bool b; - do { - b=false; - for(NodeIt n(g);n!=INVALID;++n) - if(tsp_improve(n)) b=true; - } while(b); -} - -void tsp() -{ - for(int i=0;i" << l.b; - return os; -} - -bool cross(Line a, Line b) -{ - Point ao=rot90(a.b-a.a); - Point bo=rot90(b.b-b.a); - return (ao*(b.a-a.a))*(ao*(b.b-a.a))<0 && - (bo*(a.a-b.a))*(bo*(a.b-b.a))<0; -} - -struct Parc -{ - Node a; - Node b; - double len; -}; - -bool pedgeLess(Parc a,Parc b) -{ - return a.len arcs; - -namespace _delaunay_bits { - - struct Part { - int prev, curr, next; - - Part(int p, int c, int n) : prev(p), curr(c), next(n) {} - }; - - inline std::ostream& operator<<(std::ostream& os, const Part& part) { - os << '(' << part.prev << ',' << part.curr << ',' << part.next << ')'; - return os; - } - - inline double circle_point(const Point& p, const Point& q, const Point& r) { - double a = p.x * (q.y - r.y) + q.x * (r.y - p.y) + r.x * (p.y - q.y); - if (a == 0) return std::numeric_limits::quiet_NaN(); - - double d = (p.x * p.x + p.y * p.y) * (q.y - r.y) + - (q.x * q.x + q.y * q.y) * (r.y - p.y) + - (r.x * r.x + r.y * r.y) * (p.y - q.y); - - double e = (p.x * p.x + p.y * p.y) * (q.x - r.x) + - (q.x * q.x + q.y * q.y) * (r.x - p.x) + - (r.x * r.x + r.y * r.y) * (p.x - q.x); - - double f = (p.x * p.x + p.y * p.y) * (q.x * r.y - r.x * q.y) + - (q.x * q.x + q.y * q.y) * (r.x * p.y - p.x * r.y) + - (r.x * r.x + r.y * r.y) * (p.x * q.y - q.x * p.y); - - return d / (2 * a) + std::sqrt((d * d + e * e) / (4 * a * a) + f / a); - } - - inline bool circle_form(const Point& p, const Point& q, const Point& r) { - return rot90(q - p) * (r - q) < 0.0; - } - - inline double intersection(const Point& p, const Point& q, double sx) { - const double epsilon = 1e-8; - - if (p.x == q.x) return (p.y + q.y) / 2.0; - - if (sx < p.x + epsilon) return p.y; - if (sx < q.x + epsilon) return q.y; - - double a = q.x - p.x; - double b = (q.x - sx) * p.y - (p.x - sx) * q.y; - double d = (q.x - sx) * (p.x - sx) * (p - q).normSquare(); - return (b - std::sqrt(d)) / a; - } - - struct YLess { - - - YLess(const std::vector& points, double& sweep) - : _points(points), _sweep(sweep) {} - - bool operator()(const Part& l, const Part& r) const { - const double epsilon = 1e-8; - - // std::cerr << l << " vs " << r << std::endl; - double lbx = l.prev != -1 ? - intersection(_points[l.prev], _points[l.curr], _sweep) : - - std::numeric_limits::infinity(); - double rbx = r.prev != -1 ? - intersection(_points[r.prev], _points[r.curr], _sweep) : - - std::numeric_limits::infinity(); - double lex = l.next != -1 ? - intersection(_points[l.curr], _points[l.next], _sweep) : - std::numeric_limits::infinity(); - double rex = r.next != -1 ? - intersection(_points[r.curr], _points[r.next], _sweep) : - std::numeric_limits::infinity(); - - if (lbx > lex) std::swap(lbx, lex); - if (rbx > rex) std::swap(rbx, rex); - - if (lex < epsilon + rex && lbx + epsilon < rex) return true; - if (rex < epsilon + lex && rbx + epsilon < lex) return false; - return lex < rex; - } - - const std::vector& _points; - double& _sweep; - }; - - struct BeachIt; - - typedef std::multimap SpikeHeap; - - typedef std::multimap Beach; - - struct BeachIt { - Beach::iterator it; - - BeachIt(Beach::iterator iter) : it(iter) {} - }; - -} - -inline void delaunay() { - Counter cnt("Number of arcs added: "); - - using namespace _delaunay_bits; - - typedef _delaunay_bits::Part Part; - typedef std::vector > SiteHeap; - - - std::vector points; - std::vector nodes; - - for (NodeIt it(g); it != INVALID; ++it) { - nodes.push_back(it); - points.push_back(coords[it]); - } - - SiteHeap siteheap(points.size()); - - double sweep; - - - for (int i = 0; i < int(siteheap.size()); ++i) { - siteheap[i] = std::make_pair(points[i].x, i); - } - - std::sort(siteheap.begin(), siteheap.end()); - sweep = siteheap.front().first; - - YLess yless(points, sweep); - Beach beach(yless); - - SpikeHeap spikeheap; - - std::set > arcs; - - int siteindex = 0; - { - SiteHeap front; - - while (siteindex < int(siteheap.size()) && - siteheap[0].first == siteheap[siteindex].first) { - front.push_back(std::make_pair(points[siteheap[siteindex].second].y, - siteheap[siteindex].second)); - ++siteindex; - } - - std::sort(front.begin(), front.end()); - - for (int i = 0; i < int(front.size()); ++i) { - int prev = (i == 0 ? -1 : front[i - 1].second); - int curr = front[i].second; - int next = (i + 1 == int(front.size()) ? -1 : front[i + 1].second); - - beach.insert(std::make_pair(Part(prev, curr, next), - spikeheap.end())); - } - } - - while (siteindex < int(points.size()) || !spikeheap.empty()) { - - SpikeHeap::iterator spit = spikeheap.begin(); - - if (siteindex < int(points.size()) && - (spit == spikeheap.end() || siteheap[siteindex].first < spit->first)) { - int site = siteheap[siteindex].second; - sweep = siteheap[siteindex].first; - - Beach::iterator bit = beach.upper_bound(Part(site, site, site)); - - if (bit->second != spikeheap.end()) { - delete bit->second->second; - spikeheap.erase(bit->second); - } - - int prev = bit->first.prev; - int curr = bit->first.curr; - int next = bit->first.next; - - beach.erase(bit); - - SpikeHeap::iterator pit = spikeheap.end(); - if (prev != -1 && - circle_form(points[prev], points[curr], points[site])) { - double x = circle_point(points[prev], points[curr], points[site]); - pit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end()))); - pit->second->it = - beach.insert(std::make_pair(Part(prev, curr, site), pit)); - } else { - beach.insert(std::make_pair(Part(prev, curr, site), pit)); - } - - beach.insert(std::make_pair(Part(curr, site, curr), spikeheap.end())); - - SpikeHeap::iterator nit = spikeheap.end(); - if (next != -1 && - circle_form(points[site], points[curr],points[next])) { - double x = circle_point(points[site], points[curr], points[next]); - nit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end()))); - nit->second->it = - beach.insert(std::make_pair(Part(site, curr, next), nit)); - } else { - beach.insert(std::make_pair(Part(site, curr, next), nit)); - } - - ++siteindex; - } else { - sweep = spit->first; - - Beach::iterator bit = spit->second->it; - - int prev = bit->first.prev; - int curr = bit->first.curr; - int next = bit->first.next; - - { - std::pair arc; - - arc = prev < curr ? - std::make_pair(prev, curr) : std::make_pair(curr, prev); - - if (arcs.find(arc) == arcs.end()) { - arcs.insert(arc); - g.addEdge(nodes[prev], nodes[curr]); - ++cnt; - } - - arc = curr < next ? - std::make_pair(curr, next) : std::make_pair(next, curr); - - if (arcs.find(arc) == arcs.end()) { - arcs.insert(arc); - g.addEdge(nodes[curr], nodes[next]); - ++cnt; - } - } - - Beach::iterator pbit = bit; --pbit; - int ppv = pbit->first.prev; - Beach::iterator nbit = bit; ++nbit; - int nnt = nbit->first.next; - - if (bit->second != spikeheap.end()) - { - delete bit->second->second; - spikeheap.erase(bit->second); - } - if (pbit->second != spikeheap.end()) - { - delete pbit->second->second; - spikeheap.erase(pbit->second); - } - if (nbit->second != spikeheap.end()) - { - delete nbit->second->second; - spikeheap.erase(nbit->second); - } - - beach.erase(nbit); - beach.erase(bit); - beach.erase(pbit); - - SpikeHeap::iterator pit = spikeheap.end(); - if (ppv != -1 && ppv != next && - circle_form(points[ppv], points[prev], points[next])) { - double x = circle_point(points[ppv], points[prev], points[next]); - if (x < sweep) x = sweep; - pit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end()))); - pit->second->it = - beach.insert(std::make_pair(Part(ppv, prev, next), pit)); - } else { - beach.insert(std::make_pair(Part(ppv, prev, next), pit)); - } - - SpikeHeap::iterator nit = spikeheap.end(); - if (nnt != -1 && prev != nnt && - circle_form(points[prev], points[next], points[nnt])) { - double x = circle_point(points[prev], points[next], points[nnt]); - if (x < sweep) x = sweep; - nit = spikeheap.insert(std::make_pair(x, new BeachIt(beach.end()))); - nit->second->it = - beach.insert(std::make_pair(Part(prev, next, nnt), nit)); - } else { - beach.insert(std::make_pair(Part(prev, next, nnt), nit)); - } - - } - } - - for (Beach::iterator it = beach.begin(); it != beach.end(); ++it) { - int curr = it->first.curr; - int next = it->first.next; - - if (next == -1) continue; - - std::pair arc; - - arc = curr < next ? - std::make_pair(curr, next) : std::make_pair(next, curr); - - if (arcs.find(arc) == arcs.end()) { - arcs.insert(arc); - g.addEdge(nodes[curr], nodes[next]); - ++cnt; - } - } -} - -void sparse(int d) -{ - Counter cnt("Number of arcs removed: "); - Bfs bfs(g); - for(std::vector::reverse_iterator ei=arcs.rbegin(); - ei!=arcs.rend();++ei) - { - Node a=g.u(*ei); - Node b=g.v(*ei); - g.erase(*ei); - bfs.run(a,b); - if(bfs.predArc(b)==INVALID || bfs.dist(b)>d) - g.addEdge(a,b); - else cnt++; - } -} - -void sparse2(int d) -{ - Counter cnt("Number of arcs removed: "); - for(std::vector::reverse_iterator ei=arcs.rbegin(); - ei!=arcs.rend();++ei) - { - Node a=g.u(*ei); - Node b=g.v(*ei); - g.erase(*ei); - ConstMap cegy(1); - Suurballe > sur(g,cegy); - int k=sur.run(a,b,2); - if(k<2 || sur.totalLength()>d) - g.addEdge(a,b); - else cnt++; -// else std::cout << "Remove arc " << g.id(a) << "-" << g.id(b) << '\n'; - } -} - -void sparseTriangle(int d) -{ - Counter cnt("Number of arcs added: "); - std::vector pedges; - for(NodeIt n(g);n!=INVALID;++n) - for(NodeIt m=++(NodeIt(n));m!=INVALID;++m) - { - Parc p; - p.a=n; - p.b=m; - p.len=(coords[m]-coords[n]).normSquare(); - pedges.push_back(p); - } - std::sort(pedges.begin(),pedges.end(),pedgeLess); - for(std::vector::iterator pi=pedges.begin();pi!=pedges.end();++pi) - { - Line li(pi->a,pi->b); - EdgeIt e(g); - for(;e!=INVALID && !cross(e,li);++e) ; - Edge ne; - if(e==INVALID) { - ConstMap cegy(1); - Suurballe > sur(g,cegy); - int k=sur.run(pi->a,pi->b,2); - if(k<2 || sur.totalLength()>d) - { - ne=g.addEdge(pi->a,pi->b); - arcs.push_back(ne); - cnt++; - } - } - } -} - -template -class LengthSquareMap { -public: - typedef typename Graph::Edge Key; - typedef typename CoordMap::Value::Value Value; - - LengthSquareMap(const Graph& graph, const CoordMap& coords) - : _graph(graph), _coords(coords) {} - - Value operator[](const Key& key) const { - return (_coords[_graph.v(key)] - - _coords[_graph.u(key)]).normSquare(); - } - -private: - - const Graph& _graph; - const CoordMap& _coords; -}; - -void minTree() { - std::vector pedges; - Timer T; - std::cout << T.realTime() << "s: Creating delaunay triangulation...\n"; - delaunay(); - std::cout << T.realTime() << "s: Calculating spanning tree...\n"; - LengthSquareMap > ls(g, coords); - ListGraph::EdgeMap tree(g); - kruskal(g, ls, tree); - std::cout << T.realTime() << "s: Removing non tree arcs...\n"; - std::vector remove; - for (EdgeIt e(g); e != INVALID; ++e) { - if (!tree[e]) remove.push_back(e); - } - for(int i = 0; i < int(remove.size()); ++i) { - g.erase(remove[i]); - } - std::cout << T.realTime() << "s: Done\n"; -} - -void tsp2() -{ - std::cout << "Find a tree..." << std::endl; - - minTree(); - - std::cout << "Total arc length (tree) : " << totalLen() << std::endl; - - std::cout << "Make it Euler..." << std::endl; - - { - std::vector leafs; - for(NodeIt n(g);n!=INVALID;++n) - if(countIncEdges(g,n)%2==1) leafs.push_back(n); - -// for(unsigned int i=0;i pedges; - for(unsigned int i=0;i enext(g); - { - EulerIt e(g); - Arc eo=e; - Arc ef=e; -// std::cout << "Tour arc: " << g.id(Edge(e)) << std::endl; - for(++e;e!=INVALID;++e) - { -// std::cout << "Tour arc: " << g.id(Edge(e)) << std::endl; - enext[eo]=e; - eo=e; - } - enext[eo]=ef; - } - - std::cout << "Creating a tour from that..." << std::endl; - - int nnum = countNodes(g); - int ednum = countEdges(g); - - for(Arc p=enext[EdgeIt(g)];ednum>nnum;p=enext[p]) - { -// std::cout << "Checking arc " << g.id(p) << std::endl; - Arc e=enext[p]; - Arc f=enext[e]; - Node n2=g.source(f); - Node n1=g.oppositeNode(n2,e); - Node n3=g.oppositeNode(n2,f); - if(countIncEdges(g,n2)>2) - { -// std::cout << "Remove an Arc" << std::endl; - Arc ff=enext[f]; - g.erase(e); - g.erase(f); - if(n1!=n3) - { - Arc ne=g.direct(g.addEdge(n1,n3),n1); - enext[p]=ne; - enext[ne]=ff; - ednum--; - } - else { - enext[p]=ff; - ednum-=2; - } - } - } - - std::cout << "Total arc length (tour) : " << totalLen() << std::endl; - - std::cout << "2-opt the tour..." << std::endl; - - tsp_improve(); - - std::cout << "Total arc length (2-opt tour) : " << totalLen() << std::endl; -} - - -int main(int argc,const char **argv) -{ - ArgParser ap(argc,argv); - -// bool eps; - bool disc_d, square_d, gauss_d; -// bool tsp_a,two_a,tree_a; - int num_of_cities=1; - double area=1; - N=100; -// girth=10; - std::string ndist("disc"); - ap.refOption("n", "Number of nodes (default is 100)", N) - .intOption("g", "Girth parameter (default is 10)", 10) - .refOption("cities", "Number of cities (default is 1)", num_of_cities) - .refOption("area", "Full relative area of the cities (default is 1)", area) - .refOption("disc", "Nodes are evenly distributed on a unit disc (default)", - disc_d) - .optionGroup("dist", "disc") - .refOption("square", "Nodes are evenly distributed on a unit square", - square_d) - .optionGroup("dist", "square") - .refOption("gauss", "Nodes are located according to a two-dim Gauss " - "distribution", gauss_d) - .optionGroup("dist", "gauss") - .onlyOneGroup("dist") - .boolOption("eps", "Also generate .eps output (.eps)") - .boolOption("nonodes", "Draw only the edges in the generated .eps output") - .boolOption("dir", "Directed graph is generated (each edge is replaced by " - "two directed arcs)") - .boolOption("2con", "Create a two connected planar graph") - .optionGroup("alg","2con") - .boolOption("tree", "Create a min. cost spanning tree") - .optionGroup("alg","tree") - .boolOption("tsp", "Create a TSP tour") - .optionGroup("alg","tsp") - .boolOption("tsp2", "Create a TSP tour (tree based)") - .optionGroup("alg","tsp2") - .boolOption("dela", "Delaunay triangulation graph") - .optionGroup("alg","dela") - .onlyOneGroup("alg") - .boolOption("rand", "Use time seed for random number generator") - .optionGroup("rand", "rand") - .intOption("seed", "Random seed", -1) - .optionGroup("rand", "seed") - .onlyOneGroup("rand") - .other("[prefix]","Prefix of the output files. Default is 'lgf-gen-out'") - .run(); - - if (ap["rand"]) { - int seed = int(time(0)); - std::cout << "Random number seed: " << seed << std::endl; - rnd = Random(seed); - } - if (ap.given("seed")) { - int seed = ap["seed"]; - std::cout << "Random number seed: " << seed << std::endl; - rnd = Random(seed); - } - - std::string prefix; - switch(ap.files().size()) - { - case 0: - prefix="lgf-gen-out"; - break; - case 1: - prefix=ap.files()[0]; - break; - default: - std::cerr << "\nAt most one prefix can be given\n\n"; - exit(1); - } - - double sum_sizes=0; - std::vector sizes; - std::vector cum_sizes; - for(int s=0;s(g,prefix+".lgf"). - nodeMap("coordinates_x",scaleMap(xMap(coords),600)). - nodeMap("coordinates_y",scaleMap(yMap(coords),600)). - run(); - else GraphWriter(g,prefix+".lgf"). - nodeMap("coordinates_x",scaleMap(xMap(coords),600)). - nodeMap("coordinates_y",scaleMap(yMap(coords),600)). - run(); -} - diff --git a/deps/libqasm b/deps/libqasm deleted file mode 160000 index 1f317077e..000000000 --- a/deps/libqasm +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1f317077e2f2462cafec8385666d6e996340d2e8 diff --git a/docs/developer/build.rst b/docs/developer/build.rst index 0548170e3..545be6c2c 100644 --- a/docs/developer/build.rst +++ b/docs/developer/build.rst @@ -17,11 +17,9 @@ Dependencies The following packages are required to compile OpenQL from sources: -- a C++ compiler with C++11 support (Linux: gcc, MacOS: LLVM/clang, Windows: MSVC 2015 with update 3 or above) +- a C++ compiler with C++23 support (Linux: gcc, MacOS: LLVM/clang, Windows: Visual Studio 17 2022, MSVC 19.35.32217.1) - git -- flex > 2.6 -- bison > 3.0 -- cmake >= 3.0 +- cmake >= 3.25 - swig (Linux: >= 3.0.12, Windows: >= 4.0.0) - Python 3.x + pip, with the following packages: - ``plumbum`` @@ -54,19 +52,17 @@ Windows-specific instructions Dependencies can be installed with: -- `win_flex_bison 2.5.20 `_ -- `cmake 3.15.3 `_ +- `cmake 3.25.0 `_ - `swigwin 4.0.0 `_ Make sure the above mentioned binaries are added to the system path. -Alternatively, you can use Chocolatey to install packages. This is how CI currently does it. They just chain to -sourceforge downloads, though. +Alternatively, you can use Chocolatey to install packages. The actual build and install should be done with PowerShell, for which some modifications (may?) need to be made first. -- Use Power Shell for installation +- Use Power Shell for installation. - Set execution policy by: :: @@ -79,21 +75,23 @@ first. Install-Module -AllowClobber -Name Pscx -RequiredVersion 3.2.2 -- MSVC 2015 should be added to the path by using the following command: +- Visual Studio 17 2022 should be added to the path by using the following command: :: - Invoke-BatchFile "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 + Invoke-BatchFile "C:\Program Files\Microsoft Visual Studio 17.0\VC\vcvarsall.bat" amd64 - but when you installed Microsoft Visual Studio Community Edition do: :: - Invoke-BatchFile "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 + Invoke-BatchFile "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 -- To make your life easier, you can add this command to the profile you are using for power shell, avoiding the need to manually run this command every time you open a power shell. You can see the path of this profile by `echo $PROFILE`. Create/Edit this file to add the above command. +- To make your life easier, you can add this command to the profile you are using for power shell, +avoiding the need to manually run this command every time you open a power shell. +You can see the path of this profile by `echo $PROFILE`. Create/Edit this file to add the above command. -- Python.exe, win_flex.exe, win_bison.exe and swig.exe should be in the path of power shell. To test if swig.exe is the path, run: +- Python.exe and swig.exe should be in the path of power shell. To test if swig.exe is the path, run: :: @@ -127,10 +125,11 @@ All dependencies can be installed using `Homebrew `_ and pip: :: brew update - brew install llvm flex bison cmake swig python3 doxygen graphviz xquartz + brew install llvm cmake swig python3 doxygen graphviz xquartz pip3 install wheel plumbum pytest numpy sphinx==3.5.4 sphinx-rtd-theme m2r2 -Make sure the above mentioned binaries are added to the system path in front of ``/usr/bin``, otherwise CMake finds the default versions. +Make sure the above mentioned binaries are added to the system path in front of ``/usr/bin``, +otherwise CMake finds the default versions. Linux-specific instructions ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -143,9 +142,9 @@ If you're for some reason using CentOS, you'll need to use a ``devtoolset`` comp shipped with it is too old. Likewise, CentOS ships with cmake 2.9 installed in ``/usr/bin`` and depends on this; while ``cmake3`` is in the package manager, you actually need to call ``cmake3`` instead of ``cmake``, which ``setup.py`` is not smart enough for. On CentOS or other batteries-not-included systems -you might also have to compile some dependencies manually (``swig``, ``flex``, ``bison``, and their -dependencies ``m4`` and possibly ``gettext``), but they shouldn't give you too much drama. ``cmake`` has -distro-agnostic binary distributions on github that are a only ``wget`` and ``tar xzv`` away. +you might also have to compile some dependencies manually (``swig`` and possibly ``gettext``), +but they shouldn't give you too much drama. ``cmake`` has distro-agnostic binary distributions on github that are +only a ``wget`` and ``tar xzv`` away. Obtaining OpenQL @@ -157,10 +156,7 @@ cloned by: :: - git clone https://github.com/QuTech-Delft/OpenQL.git --recursive - -Note the ``--recursive``: the repository depends on various submodules. If you forgot the ``--recursive``, -you can get/synchronize them later with ``git submodule update --init --recursive``. + git clone https://github.com/QuTech-Delft/OpenQL.git Building the ``qutechopenql`` Python package @@ -216,6 +212,7 @@ Once installed, and assuming you have the requisite optional dependencies instal from the root of the OpenQL repository) using :: + pytest -v .. note:: diff --git a/docs/developer/resources.rst b/docs/developer/resources.rst index fa12ef87f..5adbda214 100644 --- a/docs/developer/resources.rst +++ b/docs/developer/resources.rst @@ -5,7 +5,7 @@ Resources In OpenQL, the term "resources" is reserved for *scheduling* resources. Conceptually, a resource models a physical thing that prevents two instructions -from executing simulaneously due to resource contention, but ultimately it can +from executing simultaneously due to resource contention, but ultimately it can be anything that prevents an instruction from starting in a particular cycle. Implementation diff --git a/docs/manual/dqcsim.rst b/docs/manual/dqcsim.rst index 0f92113d1..5ee1215c0 100644 --- a/docs/manual/dqcsim.rst +++ b/docs/manual/dqcsim.rst @@ -54,12 +54,12 @@ The results we got when using QX directly are pretty easy to replicate. Here's h shutil.copyfile('output/dice.qasm', 'output/dice.cq') # open the simulation context and run the simulation. the cQASM frontend - # returns the results as a JSON object for us to parse througn run() + # returns the results as a JSON object for us to parse through run() with Simulator('output/dice.cq', 'qx') as sim: results = sim.run() # parse the measurement results - res = [results['qubits'][q]['value'] for q in range(nqubits)] + res = [results['qubits'][q]['value'] for q in range(num_qubits)] # convert the measurement results from 3 qubits to dice face value dice_face = reduce(lambda x, y: 2*x+y, res, 0) +1 diff --git a/docs/manual/first_program.rst b/docs/manual/first_program.rst index d642634f9..b279f35e8 100644 --- a/docs/manual/first_program.rst +++ b/docs/manual/first_program.rst @@ -103,9 +103,9 @@ number of qubits used in it as parameters. We'll use 3 in this example: .. code-block:: python - nqubits = 3 - program = ql.Program('my_program', platform, nqubits) - kernel = ql.Kernel('my_kernel', platform, nqubits) + num_qubits = 3 + program = ql.Program('my_program', platform, num_qubits) + kernel = ql.Kernel('my_kernel', platform, num_qubits) When needed, the number of used CRegs (classical integer registers) and BRegs (bit registers) used by the program/kernel must also be specified, but we don't @@ -120,7 +120,7 @@ Once you have a kernel, you can add gates to it: .. code:: python - for i in range(nqubits): + for i in range(num_qubits): kernel.prepz(i) kernel.x(0) diff --git a/docs/manual/qx.rst b/docs/manual/qx.rst index 8e38ac96c..048fb48e9 100644 --- a/docs/manual/qx.rst +++ b/docs/manual/qx.rst @@ -19,16 +19,16 @@ is done by the following code snippet: .. code:: python - from openql import openql as ql + import openql as ql import qxelarator - from functools import reduce - import os import matplotlib.pyplot as plt + import os + from functools import reduce ql.set_option('output_dir', 'output') ql.set_option('log_level', 'LOG_INFO') - nqubits = 3 + num_qubits = 3 Next, we create a platform, a program and a kernel. We populate the kernel with 3 hadamard gates being applied on each qubits. This will put each qubit in @@ -39,13 +39,13 @@ getting either 0 or 1. This is done by dice_compile() as shown below: def dice_compile(): platform = ql.Platform('myPlatform', 'none') - p = ql.Program('dice', platform, nqubits) - k = ql.Kernel('aKernel', platform, nqubits) + p = ql.Program('dice', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) - for q in range(nqubits): + for q in range(num_qubits): k.gate('h', [q]) - for q in range(nqubits): + for q in range(num_qubits): k.gate('measure', [q]) p.add_kernel(k) @@ -92,7 +92,7 @@ This is done by the following code snippet: qx.execute() # get the measurement results - res = [int(qx.get_measurement_outcome(q)) for q in range(nqubits)] + res = [int(qx.get_measurement_outcome(q)) for q in range(num_qubits)] # convert the measurement results from 3 qubits to dice face value dice_face = reduce(lambda x, y: 2*x+y, res, 0) + 1 @@ -132,7 +132,7 @@ of each face by the following code snippet: ntests = 100 for i in range(ntests): qx.execute() - res = [int(qx.get_measurement_outcome(q)) for q in range(nqubits)] + res = [int(qx.get_measurement_outcome(q)) for q in range(num_qubits)] dice_face = reduce(lambda x, y: 2*x+y, res, 0) +1 dice_faces.append(dice_face) diff --git a/docs/old/compiler.rst b/docs/old/compiler.rst index f6cf9f772..4f16b6aa2 100644 --- a/docs/old/compiler.rst +++ b/docs/old/compiler.rst @@ -49,7 +49,7 @@ Furthermore, an additional option to configure a compiler is to use the ``compil .. code:: python - from openql import openql as ql + import openql as ql c = ql.Compiler("testCompiler") diff --git a/docs/old/program.rst b/docs/old/program.rst index 2f8b990dd..eb18fb7f2 100644 --- a/docs/old/program.rst +++ b/docs/old/program.rst @@ -17,17 +17,17 @@ Here it is again but then with everything glued together: .. code:: python - from openql import openql as ql + import openql as ql - platform = ql.Platform("myPlatform", "hardware_config_cc_light.json") + platform = ql.Platform("myPlatform", "config_cc_light.json") - nqubits = 3 + num_qubits = 3 - p = ql.Program("aProgram", platform, nqubits) + p = ql.Program("aProgram", platform, num_qubits) - k = ql.Kernel("aKernel", platform, nqubits) + k = ql.Kernel("aKernel", platform, num_qubits) - for i in range(nqubits): + for i in range(num_qubits): k.gate('prepz', [i]) k.gate('x', [0]) diff --git a/examples/.gitignore b/examples/.gitignore deleted file mode 100644 index 9af26c1e9..000000000 --- a/examples/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/output/ -/hist.png diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt deleted file mode 100644 index d91eb6efd..000000000 --- a/examples/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -cmake_minimum_required(VERSION 3.1 FATAL_ERROR) - -add_openql_test(multi_qubits_randomized_benchmarking multi_qubits_randomized_benchmarking.cc ../tests) -add_openql_test(randomized_benchmarking randomized_benchmarking.cc ../tests) -add_openql_test(rb_single rb_single.cc ../tests) -add_openql_test(simple simple.cc ../tests) diff --git a/examples/cpp-standalone-example/CMakeLists.txt b/examples/cpp-standalone-example/CMakeLists.txt deleted file mode 100644 index 8cedad9ee..000000000 --- a/examples/cpp-standalone-example/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -cmake_minimum_required(VERSION 3.1 FATAL_ERROR) - -# This would be just add_subdirectory(OpenQL) for your program, or perhaps -# add_subdirectory(deps/OpenQL) if you prefer; wherever your OpenQL git -# submodule is. -add_subdirectory(../.. OpenQL) - -# Use whatever CMake magic you need to build your program, but linking -# something against OpenQL should be as easy as the second line. This should -# take care of both the libraries and header file include directories. -add_executable(example example.cc) -target_link_libraries(example ql) diff --git a/examples/cpp-standalone-example/example.cc b/examples/cpp-standalone-example/example.cc deleted file mode 100644 index b8113e195..000000000 --- a/examples/cpp-standalone-example/example.cc +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include - -int main(int argc, char **argv) { - // create platform - auto platf = ql::Platform("seven_qubits_chip", "cc_light"); - - // create program - auto prog = ql::Program("aProgram", platf, 2); - - // create kernel - auto k = ql::Kernel("aKernel", platf, 2); - - k.gate("prepz", 0); - k.gate("prepz", 1); - k.gate("x", 0); - k.gate("y", 1); - k.measure(0); - k.measure(1); - - // add kernel to program - prog.add_kernel(k); - - // compile the program - prog.compile(); - - std::cout << "Seems good to me!" << std::endl; - return 0; -} diff --git a/examples/diamond/test.py b/examples/diamond/test.py deleted file mode 100644 index 6b581baca..000000000 --- a/examples/diamond/test.py +++ /dev/null @@ -1,83 +0,0 @@ -import openql as ql - -# turn off automatic scheduling by OpenQL to preserve instruction order -ql.set_option('prescheduler', 'no') - -# Specify the platform -platform = ql.Platform("diamond_test", "diamond") - -# Put a cQASM reader before the diamond pass, so a cQASM file is read instead of the python code -#platform.get_compiler().prefix_pass('io.cqasm.Read', '', {'cqasm_file': 'cqasm_test.cq', 'measure_all_target': 'measure_z'}) - -nqubits = 3 -p = ql.Program("testProgram", platform, nqubits) -k = ql.Kernel("testKernel", platform, nqubits) - - -# Below follow examples for all gates that are supported, arranged by category: - -# Initialization -#k.gate('prep_z', [0]) -#k.gate('prep_x', [0]) -#k.gate('prep_y', [0]) -#k.gate('initialize', [0]) - -# Measurement -#k.gate('measure', [0]) -#k.gate('measure_z', [0]) -#k.gate('measure_x', [0]) -#k.gate('measure_y', [0]) - -# single qubit gates -#k.x(0) -#k.y(0) -#k.z(0) -#k.s(0) -#k.t(0) - -# two qubit gates -#k.gate('cnot', [0, 1]) # only between color center - nuclear spin qubit -#k.gate('cz', [0, 1]) - -# three qubit gate -#k.gate('toffoli', [0, 1, 2]) - -# calibration -#k.gate('cal_measure', [0]) -#k.gate('cal_pi', [0]) -#k.gate('cal_halfpi', [0]) -#k.gate('decouple', [0]) - -# custom rotations -#k.gate('rx', [0], 0, 1.57) -#k.gate('ry', [0], 0, 1.57) -#k.gate('crk', [0, 1], 0, 1) -#k.gate('cr', [0, 1], 0, 3.14) - -# diamond protocols/sequences -#k.diamond_crc(0,30,5) -#k.diamond_rabi_check(0, 100, 2, 3) # qubit, duration, measurement, t_max -#k.diamond_excite_mw(1, 100, 200, 0, 60, 0) # envelope, duration, frequency, phase, amplitude, qubit -#k.diamond_qentangle(0,15) # qubit, nuclear qubit -#k.gate('nventangle', [0, 1]) -#k.diamond_memswap(0,1) # qubit, nuclear qubit -#k.diamond_sweep_bias(0, 10, 0, 0, 10, 100, 0) #qubit, value, dacreg, start, step, max, memaddress - -# timing -#k.gate('wait', [], 200) -#k.gate('qnop', [0]) # qubit, mandatory from openQL - -# calculate bias -#k.gate('calculate_current', [0]) - -# calculate voltage -#k.gate('calculate_voltage', [0]) - -# magnetic bias check -#k.diamond_sweep_bias(0, 10, 0, 0, 10, 100, 0) -#k.gate('calculate_voltage', [0]) - -p.add_kernel(k) -p.compile() - - diff --git a/examples/grover.py b/examples/grover.py deleted file mode 100644 index 64ba27630..000000000 --- a/examples/grover.py +++ /dev/null @@ -1,130 +0,0 @@ -import os -import unittest -from openql import openql as ql -import numpy as np - -rootDir = os.path.dirname(os.path.realpath(__file__)) -curdir = os.path.dirname(__file__) -output_dir = os.path.join(curdir, 'test_output') -num_qubits = 9 - - -''' - grover algorithm implementation -''' - -def init(platform): - init_k = ql.Kernel('init', platform, num_qubits) - - # oracle qubit - oracle = 4 - - # init - init_k.x(oracle) - init_k.hadamard(oracle) - - # Hn search space - for i in range(4): - init_k.hadamard(i) - - return init_k - - -def grover(platform): - grover_k = ql.Kernel('grover', platform, num_qubits) - # oracle qubit - oracle = 4 - # name search space - s0 = 0 - s1 = 1 - s2 = 2 - s3 = 3 - - # oracle - grover_k.x(s0) - grover_k.x(s1) - grover_k.toffoli(s0,s1, 5) - grover_k.toffoli(s1, 5, 6) - grover_k.toffoli(s2, 6, 7) - grover_k.toffoli(s3, 7, 8) - grover_k.cnot(8, oracle) - grover_k.toffoli(s3,7,8) - grover_k.toffoli(s2,6,7) - grover_k.toffoli(s1,5,6) - grover_k.toffoli(s0,1,5) - - # restore ss - grover_k.x(s0) - grover_k.x(s1) - - # diffusion - for i in range(4): - grover_k.hadamard(i) - - for i in range(4): - grover_k.x(i) - - # controlled-phase shift - grover_k.hadamard(s3) - grover_k.toffoli(s0,s1,5) - grover_k.toffoli(s1,5,6) - grover_k.toffoli(s2,6,7) - grover_k.cnot(7,s3) - grover_k.toffoli(s2,6,7) - grover_k.toffoli(s1,5,6) - grover_k.toffoli(s0,s1,5) - grover_k.hadamard(s3) - - # restore search space - for i in range(4): - grover_k.x(i) - for i in range(4): - grover_k.hadamard(i) - - grover_k.gate('display',[]) - - return grover_k - - - -def grover_algorithm(): - ql.set_option('output_dir', output_dir) - ql.set_option('optimize', 'no') - ql.set_option('scheduler', 'ASAP') - ql.set_option('log_level', 'LOG_CRITICAL') - ql.set_option('write_qasm_files', 'yes') - - config_fn = os.path.join(curdir, '../tests/hardware_config_qx.json') - platform = ql.Platform('platform_none', config_fn) - # num_qubits = 9 - # oracle qubit - oracle = 4 - - # create a grover program - p = ql.Program('test_grover', platform, num_qubits, 0) - - # kernels - init_k = init(platform) - grover_k = grover(platform) - result_k = ql.Kernel('result', platform, num_qubits) - - # result - result_k.hadamard(oracle) - result_k.measure(oracle) - result_k.gate("display",[]) - - result_k.measure(0) - result_k.measure(1) - result_k.measure(2) - result_k.measure(3) - result_k.gate("display_binary",[]) - - # build the program - p.add_kernel(init_k) - p.add_kernel(grover_k) - p.add_kernel(result_k) - ql.set_option('decompose_toffoli', 'NC') - p.compile() - -if __name__ == '__main__': - grover_algorithm() diff --git a/examples/simple.cc b/examples/simple.cc deleted file mode 100644 index acb23ae58..000000000 --- a/examples/simple.cc +++ /dev/null @@ -1,28 +0,0 @@ -#include -#include - -int main(int argc, char **argv) { - // create platform - auto platf = ql::Platform("seven_qubits_chip", "cc_light"); - - // create program - auto prog = ql::Program("aProgram", platf, 2); - - // create kernel - auto k = ql::Kernel("aKernel", platf, 2); - - k.gate("prepz", 0); - k.gate("prepz", 1); - k.gate("x", 0); - k.gate("y", 1); - k.measure(0); - k.measure(1); - - // add kernel to program - prog.add_kernel(k); - - // compile the program - prog.compile(); - - return 0; -} diff --git a/include/ql/ir/cqasm/read.h b/include/ql/ir/cqasm/read.h index cdd09c1dd..3260fa11e 100644 --- a/include/ql/ir/cqasm/read.h +++ b/include/ql/ir/cqasm/read.h @@ -83,6 +83,13 @@ struct ReadOptions { * the filename if one exists for the purpose of generating better error * messages. */ +void read_v1( + const Ref &ir, + const utils::Str &data, + const utils::Str &fname = "", + const ReadOptions &options = {} +); + void read( const Ref &ir, const utils::Str &data, diff --git a/include/ql/ir/ir_gen_ex.h b/include/ql/ir/ir_gen_ex.h new file mode 100644 index 000000000..d23ab0e7b --- /dev/null +++ b/include/ql/ir/ir_gen_ex.h @@ -0,0 +1,13 @@ +#include "ql/ir/ir.gen.h" // Object, PhysicalObject +#include "ql/utils/tree.h" // Link + +namespace ql { +namespace ir { + +bool operator==(const utils::Link &lhs, const utils::Link &rhs); +bool operator==(const utils::Link &lhs, const utils::Link &rhs); +bool operator==(const utils::tree::base::One &lhs, const utils::tree::base::One &rhs); +bool operator==(const utils::tree::base::One &lhs, const utils::tree::base::One &rhs); + +} // namespace ir +} // namespace ql diff --git a/include/ql/ir/ops.h b/include/ql/ir/ops.h index cff17e268..1080e11dd 100644 --- a/include/ql/ir/ops.h +++ b/include/ql/ir/ops.h @@ -6,6 +6,7 @@ #include "ql/utils/map.h" #include "ql/ir/ir.h" +#include "ql/ir/ir_gen_ex.h" namespace ql { namespace ir { diff --git a/include/ql/ir/prim.h b/include/ql/ir/prim.h index 10b32fedc..e4b179baf 100644 --- a/include/ql/ir/prim.h +++ b/include/ql/ir/prim.h @@ -26,7 +26,7 @@ namespace prim { * generated tree nodes to ensure that there's no garbage in the nodes. */ template -T initialize() { return T(); }; +T initialize() { return T(); } /** * Serializes the given primitive object to CBOR. @@ -201,22 +201,22 @@ class Matrix { /** * Creates a vector. */ - Matrix(utils::UInt ncols) - : data(ncols), nrows(1), ncols(ncols) + explicit Matrix(utils::UInt cols) + : data(cols), nrows(1), ncols(cols) {} /** * Creates a zero-initialized matrix of the given size. */ - Matrix(utils::UInt nrows, utils::UInt ncols) - : data(nrows*ncols), nrows(nrows), ncols(ncols) + Matrix(utils::UInt rows, utils::UInt cols) + : data(rows*cols), nrows(rows), ncols(cols) {} /** * Creates a column vector with the given data. */ - Matrix(const utils::Vec &data) - : data(data), nrows(data.size()), ncols(1) + explicit Matrix(const utils::Vec &vec) + : data(vec), nrows(vec.size()), ncols(1) {} /** @@ -224,12 +224,14 @@ class Matrix { * the number of data elements is not divisible by the number of columns, a * range error is thrown. */ - Matrix(const utils::Vec &data, utils::UInt ncols) - : data(data), nrows(data.size() / ncols), ncols(ncols) + Matrix(const utils::Vec &vec, utils::UInt cols) { - if (data.size() % ncols != 0) { + if (vec.size() % cols != 0) { throw utils::Exception("invalid matrix shape"); } + data = vec; + nrows = vec.size() / cols; + ncols = cols; } /** diff --git a/include/ql/utils/list.h b/include/ql/utils/list.h index 53dad9766..bb852e450 100644 --- a/include/ql/utils/list.h +++ b/include/ql/utils/list.h @@ -873,7 +873,7 @@ class CheckedList { */ template void emplace_back(Args&&... args) { - return get_data().get_mut_element_only().emplace_back(std::forward(args)...); + get_data().get_mut_element_only().emplace_back(std::forward(args)...); } /** @@ -888,7 +888,7 @@ class CheckedList { if (v.empty()) { QL_CONTAINER_ERROR("pop_back() called on empty list"); } - return v.pop_back(); + v.pop_back(); } /** @@ -898,7 +898,7 @@ class CheckedList { * Iterators and references remain valid. */ void push_front(const T &value) { - return get_data().get_mut_element_only().push_front(value); + get_data().get_mut_element_only().push_front(value); } /** @@ -908,7 +908,7 @@ class CheckedList { * Iterators and references remain valid. */ void push_front(T &&value) { - return get_data().get_mut_element_only().push_front(std::move(value)); + get_data().get_mut_element_only().push_front(std::move(value)); } /** @@ -922,7 +922,7 @@ class CheckedList { */ template void emplace_front(Args&&... args) { - return get_data().get_mut_element_only().emplace_front(std::forward(args)...); + get_data().get_mut_element_only().emplace_front(std::forward(args)...); } /** @@ -938,7 +938,7 @@ class CheckedList { if (v.empty()) { QL_CONTAINER_ERROR("pop_back() called on empty list"); } - return v.pop_front(); + v.pop_front(); } /** diff --git a/include/ql/utils/vec.h b/include/ql/utils/vec.h index 622cbc3fd..231f3e0c3 100644 --- a/include/ql/utils/vec.h +++ b/include/ql/utils/vec.h @@ -1091,7 +1091,7 @@ class CheckedVec { * All iterators and references are invalidated. */ void push_back(const T &value) { - return get_data().get_mut().push_back(value); + get_data().get_mut().push_back(value); } /** @@ -1101,7 +1101,7 @@ class CheckedVec { * All iterators and references are invalidated. */ void push_back(T &&value) { - return get_data().get_mut().push_back(std::move(value)); + get_data().get_mut().push_back(std::move(value)); } /** @@ -1115,7 +1115,7 @@ class CheckedVec { */ template void emplace_back(Args&&... args) { - return get_data().get_mut().emplace_back(std::forward(args)...); + get_data().get_mut().emplace_back(std::forward(args)...); } /** @@ -1130,7 +1130,7 @@ class CheckedVec { if (v.empty()) { QL_CONTAINER_ERROR("pop_back() called on empty vector"); } - return v.pop_back(); + v.pop_back(); } /** diff --git a/pytest.ini b/pytest.ini index 200db62f7..f5bf0bc13 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,4 +1,3 @@ [pytest] -testpaths = tests +testpaths = test/v1x/python python_files = test_*.py - diff --git a/python/openql.i b/python/openql.i index 455b5396a..05a64b256 100644 --- a/python/openql.i +++ b/python/openql.i @@ -4,7 +4,12 @@ * @brief swig interface file */ %define DOCSTRING -"`OpenQL` is a C++/Python framework for high-level quantum programming. The framework provides a compiler for compiling and optimizing quantum code. The compiler produces the intermediate quantum assembly language in cQASM (Common QASM) and the compiled eQASM (executable QASM) for various target platforms. While the eQASM is platform-specific, the quantum assembly code (QASM) is hardware-agnostic and can be simulated on the QX simulator." +"`OpenQL` is a C++/Python framework for high-level quantum programming. " +"The framework provides a compiler for compiling and optimizing quantum code. " +"The compiler produces the intermediate quantum assembly language in cQASM (Common QASM) " +"and the compiled eQASM (executable QASM) for various target platforms. " +"While the eQASM is platform-specific, the quantum assembly code (QASM) is hardware-agnostic " +"and can be simulated on the QX simulator." %enddef %module(docstring=DOCSTRING) openql diff --git a/examples/diamond/cqasm_test.cq b/res/v1x/cq/example/diamond.cq similarity index 100% rename from examples/diamond/cqasm_test.cq rename to res/v1x/cq/example/diamond.cq diff --git a/tests/golden/decompose_after_schedule_dec.cq b/res/v1x/cq/golden/decompose_after_schedule_dec.cq similarity index 100% rename from tests/golden/decompose_after_schedule_dec.cq rename to res/v1x/cq/golden/decompose_after_schedule_dec.cq diff --git a/tests/golden/decompose_after_schedule_in.cq b/res/v1x/cq/golden/decompose_after_schedule_in.cq similarity index 100% rename from tests/golden/decompose_after_schedule_in.cq rename to res/v1x/cq/golden/decompose_after_schedule_in.cq diff --git a/tests/golden/decompose_after_schedule_sch.cq b/res/v1x/cq/golden/decompose_after_schedule_sch.cq similarity index 100% rename from tests/golden/decompose_after_schedule_sch.cq rename to res/v1x/cq/golden/decompose_after_schedule_sch.cq diff --git a/tests/golden/decompose_before_schedule_dec.cq b/res/v1x/cq/golden/decompose_before_schedule_dec.cq similarity index 100% rename from tests/golden/decompose_before_schedule_dec.cq rename to res/v1x/cq/golden/decompose_before_schedule_dec.cq diff --git a/tests/golden/decompose_before_schedule_in.cq b/res/v1x/cq/golden/decompose_before_schedule_in.cq similarity index 100% rename from tests/golden/decompose_before_schedule_in.cq rename to res/v1x/cq/golden/decompose_before_schedule_in.cq diff --git a/tests/golden/decompose_before_schedule_sch.cq b/res/v1x/cq/golden/decompose_before_schedule_sch.cq similarity index 100% rename from tests/golden/decompose_before_schedule_sch.cq rename to res/v1x/cq/golden/decompose_before_schedule_sch.cq diff --git a/tests/golden/empty_infinite_loop_out.cq b/res/v1x/cq/golden/empty_infinite_loop_out.cq similarity index 100% rename from tests/golden/empty_infinite_loop_out.cq rename to res/v1x/cq/golden/empty_infinite_loop_out.cq diff --git a/tests/golden/structure_decomposition_for_out.cq b/res/v1x/cq/golden/structure_decomposition_for_out.cq similarity index 100% rename from tests/golden/structure_decomposition_for_out.cq rename to res/v1x/cq/golden/structure_decomposition_for_out.cq diff --git a/tests/golden/structure_decomposition_foreach_out.cq b/res/v1x/cq/golden/structure_decomposition_foreach_out.cq similarity index 100% rename from tests/golden/structure_decomposition_foreach_out.cq rename to res/v1x/cq/golden/structure_decomposition_foreach_out.cq diff --git a/tests/golden/structure_decomposition_goto_out.cq b/res/v1x/cq/golden/structure_decomposition_goto_out.cq similarity index 100% rename from tests/golden/structure_decomposition_goto_out.cq rename to res/v1x/cq/golden/structure_decomposition_goto_out.cq diff --git a/tests/golden/structure_decomposition_if_else_out.cq b/res/v1x/cq/golden/structure_decomposition_if_else_out.cq similarity index 100% rename from tests/golden/structure_decomposition_if_else_out.cq rename to res/v1x/cq/golden/structure_decomposition_if_else_out.cq diff --git a/tests/golden/structure_decomposition_repeat_until_out.cq b/res/v1x/cq/golden/structure_decomposition_repeat_until_out.cq similarity index 100% rename from tests/golden/structure_decomposition_repeat_until_out.cq rename to res/v1x/cq/golden/structure_decomposition_repeat_until_out.cq diff --git a/tests/golden/structure_decomposition_while_out.cq b/res/v1x/cq/golden/structure_decomposition_while_out.cq similarity index 100% rename from tests/golden/structure_decomposition_while_out.cq rename to res/v1x/cq/golden/structure_decomposition_while_out.cq diff --git a/tests/cc/test_cond_gate.cq b/res/v1x/cq/test_cond_gate.cq similarity index 100% rename from tests/cc/test_cond_gate.cq rename to res/v1x/cq/test_cond_gate.cq diff --git a/tests/cc/test_const_prop.cq b/res/v1x/cq/test_const_prop.cq similarity index 100% rename from tests/cc/test_const_prop.cq rename to res/v1x/cq/test_const_prop.cq diff --git a/tests/diamond_cqasm_test.cq b/res/v1x/cq/test_diamond.cq similarity index 100% rename from tests/diamond_cqasm_test.cq rename to res/v1x/cq/test_diamond.cq diff --git a/tests/test_empty_infinite_loop.cq b/res/v1x/cq/test_empty_infinite_loop.cq similarity index 100% rename from tests/test_empty_infinite_loop.cq rename to res/v1x/cq/test_empty_infinite_loop.cq diff --git a/tests/cc/test_looping.cq b/res/v1x/cq/test_looping.cq similarity index 100% rename from tests/cc/test_looping.cq rename to res/v1x/cq/test_looping.cq diff --git a/tests/cc/test_rus_elements.cq b/res/v1x/cq/test_rus_elements.cq similarity index 100% rename from tests/cc/test_rus_elements.cq rename to res/v1x/cq/test_rus_elements.cq diff --git a/tests/test_structure_decomposition_for.cq b/res/v1x/cq/test_structure_decomposition_for.cq similarity index 100% rename from tests/test_structure_decomposition_for.cq rename to res/v1x/cq/test_structure_decomposition_for.cq diff --git a/tests/test_structure_decomposition_foreach.cq b/res/v1x/cq/test_structure_decomposition_foreach.cq similarity index 100% rename from tests/test_structure_decomposition_foreach.cq rename to res/v1x/cq/test_structure_decomposition_foreach.cq diff --git a/tests/test_structure_decomposition_goto.cq b/res/v1x/cq/test_structure_decomposition_goto.cq similarity index 100% rename from tests/test_structure_decomposition_goto.cq rename to res/v1x/cq/test_structure_decomposition_goto.cq diff --git a/tests/test_structure_decomposition_if_else.cq b/res/v1x/cq/test_structure_decomposition_if_else.cq similarity index 100% rename from tests/test_structure_decomposition_if_else.cq rename to res/v1x/cq/test_structure_decomposition_if_else.cq diff --git a/tests/test_structure_decomposition_repeat_until.cq b/res/v1x/cq/test_structure_decomposition_repeat_until.cq similarity index 100% rename from tests/test_structure_decomposition_repeat_until.cq rename to res/v1x/cq/test_structure_decomposition_repeat_until.cq diff --git a/tests/test_structure_decomposition_while.cq b/res/v1x/cq/test_structure_decomposition_while.cq similarity index 100% rename from tests/test_structure_decomposition_while.cq rename to res/v1x/cq/test_structure_decomposition_while.cq diff --git a/tests/cc/cqasm_config_cc.json b/res/v1x/json/config_cc.json similarity index 100% rename from tests/cc/cqasm_config_cc.json rename to res/v1x/json/config_cc.json diff --git a/tests/cqasm_config_cc_light.json b/res/v1x/json/config_cc_light.json similarity index 100% rename from tests/cqasm_config_cc_light.json rename to res/v1x/json/config_cc_light.json diff --git a/tests/cc/config_cc_s17_direct_iq.json b/res/v1x/json/config_cc_s17_direct_iq.json similarity index 100% rename from tests/cc/config_cc_s17_direct_iq.json rename to res/v1x/json/config_cc_s17_direct_iq.json diff --git a/tests/cc/config_cc_s17_direct_iq_openql_0_10.json b/res/v1x/json/config_cc_s17_direct_iq_openql_0_10.json similarity index 100% rename from tests/cc/config_cc_s17_direct_iq_openql_0_10.json rename to res/v1x/json/config_cc_s17_direct_iq_openql_0_10.json diff --git a/tests/cc/cc_s5_direct_iq.json b/res/v1x/json/config_cc_s5_direct_iq.json similarity index 96% rename from tests/cc/cc_s5_direct_iq.json rename to res/v1x/json/config_cc_s5_direct_iq.json index 6b17c5fea..469be879e 100644 --- a/tests/cc/cc_s5_direct_iq.json +++ b/res/v1x/json/config_cc_s5_direct_iq.json @@ -1,970 +1,970 @@ -// do NOT EDIT, generated by generate_CC_cfg.py on 2020-03-25 09:59:18.525156. Parameters were: -// out_filename = d:\githubrepos\pycqed_py3\pycqed\measurement\openql_experiments\output_cc_s5_direct_iq\cc_s5_direct_iq.json -// mw_pulse_duration = 20 -// flux_pulse_duration = 80 -// ro_duration = 2000 -// init_duration = 200000 -// in_filename = d:\githubrepos\pycqed_py3\pycqed\measurement\openql_experiments\config_cc_s5_direct_iq.json.in -{ - // FIXME: proposed header, not used - //"file_type": "OpenQL-config", - //"file_version": "0.3", - //"min_version_openql": "0.7.1", - - "eqasm_compiler" : "cc", - - "hardware_settings": { - "qubit_number": 5, - "cycle_time" : 20, // in [ns] - - // FIXME: we put this key inside "hardware_settings" for now, but it should preferably be below "backend" or "eqasm_compiler" - "eqasm_backend_cc": { - // Immutable properties of instruments. - // Sub keys for "instrument_definitions": - // - a name which can be referred to from key 'instruments/[]/ref_instrument_definition' - // - /channels number of channels (either firmware (UHF-QC) or hardware) - // - /control_group_sizes possible arrangements of channels operating as a vector - // - /latency latency from trigger to output in [ns]. FIXME: where do we account for other latencies - // FIXME: introduce 'controller_definitions' for CC and friends? - "instrument_definitions": { - "qutech-qwg": { - "channels": 4, - "control_group_sizes": [1, 4], - "latency": 50 // FIXME: check - }, - "zi-hdawg": { - "channels": 8, - "control_group_sizes": [1, 2, 4, 8], // NB: size=1 needs special treatment of waveforms because one AWG unit drives 2 channels - "latency": 300 // FIXME: check. If latency depends on FW version, several definitions must be present - }, - "qutech-vsm": { - "channels": 32, - "control_group_sizes": [1], - "latency": 10 // FIXME: check - }, - "zi-uhfqa": { - "channels": 9, - "control_group_sizes": [1], - "latency": 150 // FIXME: check. FIXME: specify latency if trigger to output, also measurement latency - } - }, // instrument_definitions - - - - // Modes to control instruments. These define which bits are used to control groups of channels - // and/or get back measurement results. - // Sub keys for "control_modes": - // - a name which can be referred to from key 'instruments/[]/ref_control_mode' - // - /control_bits G groups of B bits: - // - G defines the 'instrument_definitions//control_group_sizes' used - // - B is an ordered list of bits (MSB to LSB) used for the code word - // - /trigger_bits vector of bits used to trigger the instrument. Must either be size 1 (common trigger) - // or size G (separate trigger per group) - // - /result_bits future - // - /data_valid_bits future - "control_modes": { - "awg8-mw-vsm-hack": { // ZI_HDAWG8.py::cfg_codeword_protocol() == 'microwave'. Old hack to skip DIO[8]. Doesn't support QWG - "control_bits": [ - [7,6,5,4,3,2,1,0], // group 0 - [16,15,14,13,12,11,10,9] // group 1 - ], - "trigger_bits": [31] - }, - "awg8-mw-vsm": { // the way the mode above should have been and support for QWG - "control_bits": [ - [7,6,5,4,3,2,1,0], // group 0 - [23,22,21,20,19,18,17,16] // group 1 - ], - "trigger_bits": [31] - }, - "awg8-mw-direct-iq": { // just I&Q to generate microwave without VSM. HDAWG8: "new_novsm_microwave" - "control_bits": [ - [6,5,4,3,2,1,0], // group 0 - [13,12,11,10,9,8,7], // group 1 - [22,21,20,19,18,17,16], // group 2. NB: starts at bit 16 so twin-QWG can also support it - [29,28,27,26,25,24,23] // group 4 - ], - "trigger_bits": [15,31] // FIXME: 15 is for dual QWG - }, - "awg8-flux": { // ZI_HDAWG8.py::cfg_codeword_protocol() == 'flux' - // NB: please note that internally one AWG unit handles 2 channels, which requires special handling of the waveforms - "control_bits": [ - [2,1,0], // group 0 - [5,4,3], - [8,7,6], - [11,10,9], - [18,17,16], // group 4. NB: starts at bit 16 so twin-QWG can also support it - [21,20,19], - [24,23,22], - [27,26,25] // group 7 - ], - "trigger_bits": [31] - }, - "awg8-flux-vector-8": { // single code word for 8 flux channels. FIXME: no official mode yet - "control_bits": [ - [7,6,5,4,3,2,1,0] // FIXME: how many bits are available - ], - "trigger_bits": [31] - }, - "dualqwg-mw-direct-iq": { // just I&Q to generate microwave without VSM - "control_bits": [ - [6,5,4,3,2,1,0], // group 0 - [13,12,11,10,9,8,7], // group 1 - [22,21,20,19,18,17,16], // group 2. NB: starts at bit 16 so twin-QWG can also support it - [29,28,27,26,25,24,23] // group 4 - ], - "trigger_bits": [15,31] - }, - "uhfqa-9ch": { - "control_bits": [[17],[18],[19],[20],[21],[22],[23],[24],[25]], // group[0:8] - "trigger_bits": [16], - "result_bits": [[1],[2],[3],[4],[5],[6],[7],[8],[9]], // group[0:8] - "data_valid_bits": [0] - }, - "vsm-32ch":{ - "control_bits": [ - [0],[1],[2],[3],[4],[5],[6],[7], // group[0:7] - [8],[9],[10],[11],[12],[13],[14],[15], // group[8:15] - [16],[17],[18],[19],[20],[21],[22],[23], // group[16:23] - [24],[25],[26],[27],[28],[28],[30],[31] // group[24:31] - ], - "trigger_bits": [] // no trigger - } - }, // control_modes - - - - // Signal library that gate definitions can refer to. - // Sub keys for "signals": - // - a name which can be referred to from key 'instructions/<>/cc/ref_signal' - // - /* see 'instructions/<>/cc/signal' - // NB: our JSON library does not yet support JSON pointers like: - // "signal": {"$ref": "#/hardware_settings/eqasm_backend_cc/signals/single-qubit-mw"} - "signals": { - "single-qubit-mw": [ - { "type": "mw", - "operand_idx": 0, - "value": [ - "{gateName}-{instrumentName}:{instrumentGroup}-i", - "{gateName}-{instrumentName}:{instrumentGroup}-q" - ] - } - ], - "two-qubit-flux": [ - { "type": "flux", - "operand_idx": 0, // control - "value": ["flux-0-{qubit}"] - }, - { "type": "flux", - "operand_idx": 1, // target - "value": ["flux-1-{qubit}"] - } - // FIXME: CZ(a,b) and CZ(a,c) requires different waveforms on a - ], - "single-qubit-flux": [ - { "type": "flux", - "operand_idx": 0, // control - "value": ["flux-0-{qubit}"] - } - ] - }, // signals - - - - // Instruments used in this setup, their configuration and connectivity. - "instruments": [ - // readout. - // FIXME: must match 'resources/meas_units' if resource constraint scheduler is used - { - "name": "ro_1", - "qubits": [[0], [2], [3], [4], [], [], [], [], []], - "signal_type": "measure", - "ref_instrument_definition": "zi-uhfqa", - "ref_control_mode": "uhfqa-9ch", - "controller": { - "name": "cc", // FIXME - "slot": 0, - "io_module": "CC-CONN-DIO" - } - }, - { - "name": "ro_2", - "qubits": [[1], [], [], [], [], [], [], [], []], - "signal_type": "measure", - "ref_instrument_definition": "zi-uhfqa", - "ref_control_mode": "uhfqa-9ch", - "controller": { - "name": "cc", // FIXME - "slot": 1, - "io_module": "CC-CONN-DIO" - } - }, - // microwave. - // FIXME: must match 'resources/qwgs' if resource constraint scheduler is used - { - "name": "mw_0", - "qubits": [ // data qubits: - [0], - [1], - [2], - [3] - ], - "signal_type": "mw", - "ref_instrument_definition": "zi-hdawg", - "ref_control_mode": "awg8-mw-direct-iq", - "controller": { - "name": "cc", // FIXME - "slot": 2, - "io_module": "CC-CONN-DIO-DIFF" - } - }, - { - "name": "mw_1", - "qubits": [ // data qubits: - [4], - [], - [], - [] - ], - "signal_type": "mw", - "ref_instrument_definition": "zi-hdawg", - "ref_control_mode": "awg8-mw-direct-iq", - "controller": { - "name": "cc", // FIXME - "slot": 3, - "io_module": "CC-CONN-DIO-DIFF" - } - }, - - // flux - { - "name": "flux_0", - "qubits": [[0], [1], [2], [3], [4], [], [], []], - "signal_type": "flux", - "ref_instrument_definition": "zi-hdawg", - "ref_control_mode": "awg8-flux", -// "ref_control_mode": "awg8-flux-vector-8", - "controller": { - "name": "cc", // FIXME - "slot": 4, - "io_module": "CC-CONN-DIO-DIFF" - } - } - ] // instruments - } - }, - - - - // extracted from PyqQED_py3 'generate_CCL_cfg.py' - "gate_decomposition": { - // necessary to support measz cQASM operation, using measure operation - "measz %0": ["measure %0"], - - // gate decompositions for quantum inspire starmon-5 - "x %0": ["rx180 %0"], - "y %0": ["ry180 %0"], - "h %0": ["ry90 %0", "ry180 %0"], - "z %0": ["rx180 %0","ry180 %0"], - - "t %0": ["ry90 %0","rx45 %0","rym90 %0"], - "tdag %0": ["ry90 %0","rxm45 %0","rym90 %0"], - - "s %0": ["ry90 %0","rx90 %0","rym90 %0"], - "sdag %0": ["ry90 %0","rxm90 %0","rym90 %0"], - - "cnot %0,%1": ["rym90 %1", "cz %0 %1", "ry90 %1"], - - "cz q0,q2": ["barrier q0,q2", "sf_cz_se q0", "sf_cz_nw q2", "barrier q0,q2"], - "cz q2,q0": ["barrier q0,q2", "sf_cz_se q0", "sf_cz_nw q2", "barrier q0,q2"], - - "cz q1,q2": ["barrier q1,q2", "sf_cz_sw q1", "sf_cz_ne q2", "barrier q1,q2"], - "cz q2,q1": ["barrier q1,q2", "sf_cz_sw q1", "sf_cz_ne q2", "barrier q1,q2"], - - "cz q3,q2": ["barrier q2,q3,q4", "sf_cz_sw q2", "sf_cz_ne q3", "sf_park q4", "barrier q2,q3,q4"], - "cz q2,q3": ["barrier q2,q3,q4", "sf_cz_sw q2", "sf_cz_ne q3", "sf_park q4", "barrier q2,q3,q4"], - - "cz q4,q2": ["barrier q2,q3,q4", "sf_cz_se q2", "sf_cz_nw q4", "sf_park q3", "barrier q2,q3,q4"], - "cz q2,q4": ["barrier q2,q3,q4", "sf_cz_se q2", "sf_cz_nw q4", "sf_park q3", "barrier q2,q3,q4"], - - // To support other forms of writing the same gates - "x180 %0": ["rx180 %0"], - "y180 %0": ["ry180 %0"], - "y90 %0": ["ry90 %0"], - "x90 %0": ["rx90 %0"], - "ym90 %0": ["rym90 %0"], - "xm90 %0": ["rxm90 %0"], - - // Clifford decomposition per Epstein et al. Phys. Rev. A 89, 062321 (2014) - "cl_0 %0": ["i %0"], - "cl_1 %0": ["ry90 %0", "rx90 %0"], - "cl_2 %0": ["rxm90 %0", "rym90 %0"], - "cl_3 %0": ["rx180 %0"], - "cl_4 %0": ["rym90 %0", "rxm90 %0"], - "cl_5 %0": ["rx90 %0", "rym90 %0"], - "cl_6 %0": ["ry180 %0"], - "cl_7 %0": ["rym90 %0", "rx90 %0"], - "cl_8 %0": ["rx90 %0", "ry90 %0"], - "cl_9 %0": ["rx180 %0", "ry180 %0"], - "cl_10 %0": ["ry90 %0", "rxm90 %0"], - "cl_11 %0": ["rxm90 %0", "ry90 %0"], - "cl_12 %0": ["ry90 %0", "rx180 %0"], - "cl_13 %0": ["rxm90 %0"], - "cl_14 %0": ["rx90 %0", "rym90 %0", "rxm90 %0"], - "cl_15 %0": ["rym90 %0"], - "cl_16 %0": ["rx90 %0"], - "cl_17 %0": ["rx90 %0", "ry90 %0", "rx90 %0"], - "cl_18 %0": ["rym90 %0", "rx180 %0"], - "cl_19 %0": ["rx90 %0", "ry180 %0"], - "cl_20 %0": ["rx90 %0", "rym90 %0", "rx90 %0"], - "cl_21 %0": ["ry90 %0"], - "cl_22 %0": ["rxm90 %0", "ry180 %0"], - "cl_23 %0": ["rx90 %0", "ry90 %0", "rxm90 %0"], - - // CC feedback - "measure_fb %0": ["measure %0", "_wait_uhfqa %0", "_dist_dsm %0", "_wait_dsm %0"] - }, - - - - // User defined instruction set. - // Sub keys for "instructions", standard OpenQL: - // - name for the instruction (NB: supports several naming schemes) - // - /duration duration in [ns] - // - /latency optional instruction latency (effect unclear) - // - /matrix required, but generally does not contain useful information - // - // The cc-light scheduler that we currently use requires the following sub keys: - // - /type - // Sub keys for "instructions", CC additions: - // - /cc/signal/type - // - /cc/signal/operand_idx - // - /cc/signal/value - // Supports the following macro expansions: - // * {gateName} - // * {instrumentName} - // * {instrumentGroup} - // * {qubit} - // - /cc/ref_signal reference to key 'signals/ instead of '/cc/signal' - // - // - // FIXME: allow AWG8 setPrecompClear with wave - - "instructions": { - // based on PyqQED_py3 'mw_lutman.py' and 'generate_CCL_cfg.py': - "i": { - "duration": 20, - "cc": { -// "ref_signal": "single-qubit-mw", - "signal": [], // no signal, to prevent conflicts with other gates (NB: will output nothing because VSM stays off) - "static_codeword_override": [0] - } - }, - "rx180": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", // NB: reference, instead of defining "signal" here - "static_codeword_override": [1] - } - }, - "ry180": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [2] - } - }, - "rx90": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [3] - } - }, - "ry90": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [4] - } - }, - "rxm90": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [5] - } - }, - "rym90": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [6] - } - }, - - ////////////////////////////////////////// - // Custom operations for Quantum Inspire - ////////////////////////////////////////// - "ry45": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [1] - } - }, - - "rym45": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [2] - } - }, - - "rx45": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [3] - } - }, - - "rxm45": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [4] - } - }, - ////////////////////////////////////////// - - "cz": { - "duration": 80, - "cc": { - "ref_signal": "two-qubit-flux", // NB: reference, instead of defining "signal" here - "static_codeword_override": [1,1] // FIXME - } - }, - "cz_park": { - "duration": 80, - "cc": { - "signal": [ - { "type": "flux", - "operand_idx": 0, // control - "value": ["flux-0-{qubit}"] - }, - { "type": "flux", - "operand_idx": 1, // target - "value": ["flux-1-{qubit}"] - }, - { "type": "flux", - "operand_idx": 2, // park - "value": ["park_cz-{qubit}"] - } - ], - "static_codeword_override": [0,0,0] // FIXME - } - }, - - // additions from 'CC-software-implementation.docx' - // flux pulses, see: - // - https://github.com/QuTech-Delft/OpenQL/issues/176 - // - https://github.com/QuTech-Delft/OpenQL/issues/224 - // - https://github.com/QuTech-Delft/OpenQL/pull/238 - - "park_cz" : { // park signal with same length as cz gate - "duration" : 80, - "cc": { - "signal": [ - { "type": "flux", - "operand_idx": 0, - "value": ["park_cz-{qubit}"] - } - ], - "static_codeword_override": [0] // FIXME - } - }, - - "park_measure" : { // park signal with same length as measurement - "duration" : 2000, - "cc": { - "signal": [ - { "type": "flux", - "operand_idx": 0, - "value": ["park_measure-{qubit}"] - } - ], - "static_codeword_override": [0] // FIXME - } - }, - - - // based on PyqQED_py3 'generate_CCL_cfg.py': - "prepz": { - "duration": 200000, - "cc": { -// "ref_signal": "single-qubit-mw" - "signal": [], // FIXME: no signal, pycQED::test_multi_qubit_oql_CC.py fails otherwise on scheduling issues - "static_codeword_override": [0] // FIXME - } - }, - - "measure": { - "duration": 2000, - "cc": { - "readout_mode": "", - "signal": [ - { "type": "measure", - "operand_idx": 0, - "value": ["dummy"], // Future extension: specify output, and generate code word. Use "" if no output is present - "weight": ["dummy"] // Future extension: specify weight (implies readout? How about INT_AVG) - } - ], - "static_codeword_override": [0] // FIXME - } - }, - - // additions for feedback - "_wait_uhfqa": { - "duration": 220, - "cc": { - "signal": [] - } - }, - "_dist_dsm": { - "duration": 20, - "cc": { - "readout_mode": "feedback", - "signal": [ - { "type": "measure", - "operand_idx": 0, - "value": [] - } - ] - } - }, - "_wait_dsm": { - "duration": 80, - "cc": { - "signal": [] - } - }, - - "if_0_break": { - "duration": 60, - "cc": { - "signal": [], - "pragma": { - "break": 0 - } - } - }, - - "if_1_break": { - "duration": 60, - "cc": { - "signal": [], - "pragma": { - "break": 1 - } - } - }, - - // additions for pycQED::test_single_qubit_oql_CC.py - // FIXME: contents untested - "square": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [0] - } - }, - "spec": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [0] - } - }, - "rx12": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [0] - } - }, - // ensure codewords to 32 for echo sequences generated - "cw_00": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [0] - } - }, - "cw_01": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [1] - } - }, - "cw_02": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [2] - } - }, - "cw_03": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [3] - } - }, - "cw_04": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [4] - } - }, - "cw_05": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [5] - } - }, - "cw_06": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [6] - } - }, - "cw_07": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [7] - } - }, - "cw_08": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [8] - } - }, - "cw_09": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [9] - } - }, - "cw_10": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [0] - } - }, - "cw_11": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [1] - } - }, - "cw_12": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [2] - } - }, - "cw_13": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [3] - } - }, - "cw_14": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [4] - } - }, - "cw_15": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [5] - } - }, - "cw_16": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [6] - } - }, - "cw_17": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [7] - } - }, - "cw_18": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [8] - } - }, - "cw_19": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [9] - } - }, - "cw_20": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [0] - } - }, - "cw_21": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [1] - } - }, - "cw_22": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [2] - } - }, - "cw_23": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [3] - } - }, - "cw_24": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [4] - } - }, - "cw_25": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [5] - } - }, - "cw_26": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [6] - } - }, - "cw_27": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [7] - } - }, - "cw_28": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [8] - } - }, - "cw_29": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [9] - } - }, - "cw_30": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [0] - } - }, - "cw_31": { - "duration": 20, - "cc": { - "ref_signal": "single-qubit-mw", - "static_codeword_override": [1] - } - }, - - - // fl_cw_00 .. fl_cw_07 - "fl_cw_00": { - "duration": 80, - "cc": { - "ref_signal": "two-qubit-flux", // FIXME - "static_codeword_override": [0] - } - }, - "fl_cw_01": { - "duration": 80, - "cc": { - "ref_signal": "two-qubit-flux", - "static_codeword_override": [1] - } - }, - "fl_cw_02": { - "duration": 80, - "cc": { - "ref_signal": "two-qubit-flux", - "static_codeword_override": [2] - } - }, - "fl_cw_03": { - "duration": 80, - "cc": { - "ref_signal": "two-qubit-flux", - "static_codeword_override": [3] - } - }, - "fl_cw_04": { - "duration": 80, - "cc": { - "ref_signal": "two-qubit-flux", - "static_codeword_override": [4] - } - }, - "fl_cw_05": { - "duration": 80, - "cc": { - "ref_signal": "two-qubit-flux", - "static_codeword_override": [5] - } - }, - "fl_cw_06": { - "duration": 80, - "cc": { - "ref_signal": "two-qubit-flux", - "static_codeword_override": [6] - } - }, - "fl_cw_07": { - "duration": 80, - "cc": { - "ref_signal": "two-qubit-flux", - "static_codeword_override": [7] - } - }, - - // single qubit flux hacks (compatible with QCC demo/flux lutman) - // (qubit numbers defined to allow cz decomposition to ne,nw,se,sw based - // on topology through gate decompositions defined above) - "sf_cz_ne q2": { - "duration": 80, - "cc": { - "ref_signal": "single-qubit-flux", - "static_codeword_override": [1] - } - }, - "sf_cz_ne q3": { - "duration": 80, - "cc": { - "ref_signal": "single-qubit-flux", - "static_codeword_override": [1] - } - }, - "sf_cz_se q0": { - "duration": 80, - "cc": { - "ref_signal": "single-qubit-flux", - "static_codeword_override": [2] - } - }, - "sf_cz_se q2": { - "duration": 80, - "cc": { - "ref_signal": "single-qubit-flux", - "static_codeword_override": [2] - } - }, - "sf_cz_sw q1": { - "duration": 80, - "cc": { - "ref_signal": "single-qubit-flux", - "static_codeword_override": [3] - } - }, - "sf_cz_sw q2": { - "duration": 80, - "cc": { - "ref_signal": "single-qubit-flux", - "static_codeword_override": [3] - } - }, - "sf_cz_nw q2": { - "duration": 80, - "cc": { - "ref_signal": "single-qubit-flux", - "static_codeword_override": [4] - } - }, - "sf_cz_nw q4": { - "duration": 80, - "cc": { - "ref_signal": "single-qubit-flux", - "static_codeword_override": [4] - } - }, - "sf_park q3": { - "duration": 80, - "cc": { - "ref_signal": "single-qubit-flux", - "static_codeword_override": [5] - } - }, - "sf_park q4": { - "duration": 80, - "cc": { - "ref_signal": "single-qubit-flux", - "static_codeword_override": [5] - } - }, - "sf_sp_park": { - "duration": 80, - "cc": { - "ref_signal": "single-qubit-flux", - "static_codeword_override": [5] - } - }, - "sf_square": { - "duration": 80, - "cc": { - "ref_signal": "single-qubit-flux", - "static_codeword_override": [6] - } - } - } // end of "instructions" -} +// do NOT EDIT, generated by generate_CC_cfg.py on 2020-03-25 09:59:18.525156. Parameters were: +// out_filename = d:\githubrepos\pycqed_py3\pycqed\measurement\openql_experiments\output_cc_s5_direct_iq\config_cc_s5_direct_iq.json +// mw_pulse_duration = 20 +// flux_pulse_duration = 80 +// ro_duration = 2000 +// init_duration = 200000 +// in_filename = d:\githubrepos\pycqed_py3\pycqed\measurement\openql_experiments\config_cc_s5_direct_iq.json.in +{ + // FIXME: proposed header, not used + //"file_type": "OpenQL-config", + //"file_version": "0.3", + //"min_version_openql": "0.7.1", + + "eqasm_compiler" : "cc", + + "hardware_settings": { + "qubit_number": 5, + "cycle_time" : 20, // in [ns] + + // FIXME: we put this key inside "hardware_settings" for now, but it should preferably be below "backend" or "eqasm_compiler" + "eqasm_backend_cc": { + // Immutable properties of instruments. + // Sub keys for "instrument_definitions": + // - a name which can be referred to from key 'instruments/[]/ref_instrument_definition' + // - /channels number of channels (either firmware (UHF-QC) or hardware) + // - /control_group_sizes possible arrangements of channels operating as a vector + // - /latency latency from trigger to output in [ns]. FIXME: where do we account for other latencies + // FIXME: introduce 'controller_definitions' for CC and friends? + "instrument_definitions": { + "qutech-qwg": { + "channels": 4, + "control_group_sizes": [1, 4], + "latency": 50 // FIXME: check + }, + "zi-hdawg": { + "channels": 8, + "control_group_sizes": [1, 2, 4, 8], // NB: size=1 needs special treatment of waveforms because one AWG unit drives 2 channels + "latency": 300 // FIXME: check. If latency depends on FW version, several definitions must be present + }, + "qutech-vsm": { + "channels": 32, + "control_group_sizes": [1], + "latency": 10 // FIXME: check + }, + "zi-uhfqa": { + "channels": 9, + "control_group_sizes": [1], + "latency": 150 // FIXME: check. FIXME: specify latency if trigger to output, also measurement latency + } + }, // instrument_definitions + + + + // Modes to control instruments. These define which bits are used to control groups of channels + // and/or get back measurement results. + // Sub keys for "control_modes": + // - a name which can be referred to from key 'instruments/[]/ref_control_mode' + // - /control_bits G groups of B bits: + // - G defines the 'instrument_definitions//control_group_sizes' used + // - B is an ordered list of bits (MSB to LSB) used for the code word + // - /trigger_bits vector of bits used to trigger the instrument. Must either be size 1 (common trigger) + // or size G (separate trigger per group) + // - /result_bits future + // - /data_valid_bits future + "control_modes": { + "awg8-mw-vsm-hack": { // ZI_HDAWG8.py::cfg_codeword_protocol() == 'microwave'. Old hack to skip DIO[8]. Doesn't support QWG + "control_bits": [ + [7,6,5,4,3,2,1,0], // group 0 + [16,15,14,13,12,11,10,9] // group 1 + ], + "trigger_bits": [31] + }, + "awg8-mw-vsm": { // the way the mode above should have been and support for QWG + "control_bits": [ + [7,6,5,4,3,2,1,0], // group 0 + [23,22,21,20,19,18,17,16] // group 1 + ], + "trigger_bits": [31] + }, + "awg8-mw-direct-iq": { // just I&Q to generate microwave without VSM. HDAWG8: "new_novsm_microwave" + "control_bits": [ + [6,5,4,3,2,1,0], // group 0 + [13,12,11,10,9,8,7], // group 1 + [22,21,20,19,18,17,16], // group 2. NB: starts at bit 16 so twin-QWG can also support it + [29,28,27,26,25,24,23] // group 4 + ], + "trigger_bits": [15,31] // FIXME: 15 is for dual QWG + }, + "awg8-flux": { // ZI_HDAWG8.py::cfg_codeword_protocol() == 'flux' + // NB: please note that internally one AWG unit handles 2 channels, which requires special handling of the waveforms + "control_bits": [ + [2,1,0], // group 0 + [5,4,3], + [8,7,6], + [11,10,9], + [18,17,16], // group 4. NB: starts at bit 16 so twin-QWG can also support it + [21,20,19], + [24,23,22], + [27,26,25] // group 7 + ], + "trigger_bits": [31] + }, + "awg8-flux-vector-8": { // single code word for 8 flux channels. FIXME: no official mode yet + "control_bits": [ + [7,6,5,4,3,2,1,0] // FIXME: how many bits are available + ], + "trigger_bits": [31] + }, + "dualqwg-mw-direct-iq": { // just I&Q to generate microwave without VSM + "control_bits": [ + [6,5,4,3,2,1,0], // group 0 + [13,12,11,10,9,8,7], // group 1 + [22,21,20,19,18,17,16], // group 2. NB: starts at bit 16 so twin-QWG can also support it + [29,28,27,26,25,24,23] // group 4 + ], + "trigger_bits": [15,31] + }, + "uhfqa-9ch": { + "control_bits": [[17],[18],[19],[20],[21],[22],[23],[24],[25]], // group[0:8] + "trigger_bits": [16], + "result_bits": [[1],[2],[3],[4],[5],[6],[7],[8],[9]], // group[0:8] + "data_valid_bits": [0] + }, + "vsm-32ch":{ + "control_bits": [ + [0],[1],[2],[3],[4],[5],[6],[7], // group[0:7] + [8],[9],[10],[11],[12],[13],[14],[15], // group[8:15] + [16],[17],[18],[19],[20],[21],[22],[23], // group[16:23] + [24],[25],[26],[27],[28],[28],[30],[31] // group[24:31] + ], + "trigger_bits": [] // no trigger + } + }, // control_modes + + + + // Signal library that gate definitions can refer to. + // Sub keys for "signals": + // - a name which can be referred to from key 'instructions/<>/cc/ref_signal' + // - /* see 'instructions/<>/cc/signal' + // NB: our JSON library does not yet support JSON pointers like: + // "signal": {"$ref": "#/hardware_settings/eqasm_backend_cc/signals/single-qubit-mw"} + "signals": { + "single-qubit-mw": [ + { "type": "mw", + "operand_idx": 0, + "value": [ + "{gateName}-{instrumentName}:{instrumentGroup}-i", + "{gateName}-{instrumentName}:{instrumentGroup}-q" + ] + } + ], + "two-qubit-flux": [ + { "type": "flux", + "operand_idx": 0, // control + "value": ["flux-0-{qubit}"] + }, + { "type": "flux", + "operand_idx": 1, // target + "value": ["flux-1-{qubit}"] + } + // FIXME: CZ(a,b) and CZ(a,c) requires different waveforms on a + ], + "single-qubit-flux": [ + { "type": "flux", + "operand_idx": 0, // control + "value": ["flux-0-{qubit}"] + } + ] + }, // signals + + + + // Instruments used in this setup, their configuration and connectivity. + "instruments": [ + // readout. + // FIXME: must match 'resources/meas_units' if resource constraint scheduler is used + { + "name": "ro_1", + "qubits": [[0], [2], [3], [4], [], [], [], [], []], + "signal_type": "measure", + "ref_instrument_definition": "zi-uhfqa", + "ref_control_mode": "uhfqa-9ch", + "controller": { + "name": "cc", // FIXME + "slot": 0, + "io_module": "CC-CONN-DIO" + } + }, + { + "name": "ro_2", + "qubits": [[1], [], [], [], [], [], [], [], []], + "signal_type": "measure", + "ref_instrument_definition": "zi-uhfqa", + "ref_control_mode": "uhfqa-9ch", + "controller": { + "name": "cc", // FIXME + "slot": 1, + "io_module": "CC-CONN-DIO" + } + }, + // microwave. + // FIXME: must match 'resources/qwgs' if resource constraint scheduler is used + { + "name": "mw_0", + "qubits": [ // data qubits: + [0], + [1], + [2], + [3] + ], + "signal_type": "mw", + "ref_instrument_definition": "zi-hdawg", + "ref_control_mode": "awg8-mw-direct-iq", + "controller": { + "name": "cc", // FIXME + "slot": 2, + "io_module": "CC-CONN-DIO-DIFF" + } + }, + { + "name": "mw_1", + "qubits": [ // data qubits: + [4], + [], + [], + [] + ], + "signal_type": "mw", + "ref_instrument_definition": "zi-hdawg", + "ref_control_mode": "awg8-mw-direct-iq", + "controller": { + "name": "cc", // FIXME + "slot": 3, + "io_module": "CC-CONN-DIO-DIFF" + } + }, + + // flux + { + "name": "flux_0", + "qubits": [[0], [1], [2], [3], [4], [], [], []], + "signal_type": "flux", + "ref_instrument_definition": "zi-hdawg", + "ref_control_mode": "awg8-flux", +// "ref_control_mode": "awg8-flux-vector-8", + "controller": { + "name": "cc", // FIXME + "slot": 4, + "io_module": "CC-CONN-DIO-DIFF" + } + } + ] // instruments + } + }, + + + + // extracted from PyqQED_py3 'generate_CCL_cfg.py' + "gate_decomposition": { + // necessary to support measz cQASM operation, using measure operation + "measz %0": ["measure %0"], + + // gate decompositions for quantum inspire starmon-5 + "x %0": ["rx180 %0"], + "y %0": ["ry180 %0"], + "h %0": ["ry90 %0", "ry180 %0"], + "z %0": ["rx180 %0","ry180 %0"], + + "t %0": ["ry90 %0","rx45 %0","rym90 %0"], + "tdag %0": ["ry90 %0","rxm45 %0","rym90 %0"], + + "s %0": ["ry90 %0","rx90 %0","rym90 %0"], + "sdag %0": ["ry90 %0","rxm90 %0","rym90 %0"], + + "cnot %0,%1": ["rym90 %1", "cz %0 %1", "ry90 %1"], + + "cz q0,q2": ["barrier q0,q2", "sf_cz_se q0", "sf_cz_nw q2", "barrier q0,q2"], + "cz q2,q0": ["barrier q0,q2", "sf_cz_se q0", "sf_cz_nw q2", "barrier q0,q2"], + + "cz q1,q2": ["barrier q1,q2", "sf_cz_sw q1", "sf_cz_ne q2", "barrier q1,q2"], + "cz q2,q1": ["barrier q1,q2", "sf_cz_sw q1", "sf_cz_ne q2", "barrier q1,q2"], + + "cz q3,q2": ["barrier q2,q3,q4", "sf_cz_sw q2", "sf_cz_ne q3", "sf_park q4", "barrier q2,q3,q4"], + "cz q2,q3": ["barrier q2,q3,q4", "sf_cz_sw q2", "sf_cz_ne q3", "sf_park q4", "barrier q2,q3,q4"], + + "cz q4,q2": ["barrier q2,q3,q4", "sf_cz_se q2", "sf_cz_nw q4", "sf_park q3", "barrier q2,q3,q4"], + "cz q2,q4": ["barrier q2,q3,q4", "sf_cz_se q2", "sf_cz_nw q4", "sf_park q3", "barrier q2,q3,q4"], + + // To support other forms of writing the same gates + "x180 %0": ["rx180 %0"], + "y180 %0": ["ry180 %0"], + "y90 %0": ["ry90 %0"], + "x90 %0": ["rx90 %0"], + "ym90 %0": ["rym90 %0"], + "xm90 %0": ["rxm90 %0"], + + // Clifford decomposition per Epstein et al. Phys. Rev. A 89, 062321 (2014) + "cl_0 %0": ["i %0"], + "cl_1 %0": ["ry90 %0", "rx90 %0"], + "cl_2 %0": ["rxm90 %0", "rym90 %0"], + "cl_3 %0": ["rx180 %0"], + "cl_4 %0": ["rym90 %0", "rxm90 %0"], + "cl_5 %0": ["rx90 %0", "rym90 %0"], + "cl_6 %0": ["ry180 %0"], + "cl_7 %0": ["rym90 %0", "rx90 %0"], + "cl_8 %0": ["rx90 %0", "ry90 %0"], + "cl_9 %0": ["rx180 %0", "ry180 %0"], + "cl_10 %0": ["ry90 %0", "rxm90 %0"], + "cl_11 %0": ["rxm90 %0", "ry90 %0"], + "cl_12 %0": ["ry90 %0", "rx180 %0"], + "cl_13 %0": ["rxm90 %0"], + "cl_14 %0": ["rx90 %0", "rym90 %0", "rxm90 %0"], + "cl_15 %0": ["rym90 %0"], + "cl_16 %0": ["rx90 %0"], + "cl_17 %0": ["rx90 %0", "ry90 %0", "rx90 %0"], + "cl_18 %0": ["rym90 %0", "rx180 %0"], + "cl_19 %0": ["rx90 %0", "ry180 %0"], + "cl_20 %0": ["rx90 %0", "rym90 %0", "rx90 %0"], + "cl_21 %0": ["ry90 %0"], + "cl_22 %0": ["rxm90 %0", "ry180 %0"], + "cl_23 %0": ["rx90 %0", "ry90 %0", "rxm90 %0"], + + // CC feedback + "measure_fb %0": ["measure %0", "_wait_uhfqa %0", "_dist_dsm %0", "_wait_dsm %0"] + }, + + + + // User defined instruction set. + // Sub keys for "instructions", standard OpenQL: + // - name for the instruction (NB: supports several naming schemes) + // - /duration duration in [ns] + // - /latency optional instruction latency (effect unclear) + // - /matrix required, but generally does not contain useful information + // + // The cc-light scheduler that we currently use requires the following sub keys: + // - /type + // Sub keys for "instructions", CC additions: + // - /cc/signal/type + // - /cc/signal/operand_idx + // - /cc/signal/value + // Supports the following macro expansions: + // * {gateName} + // * {instrumentName} + // * {instrumentGroup} + // * {qubit} + // - /cc/ref_signal reference to key 'signals/ instead of '/cc/signal' + // + // + // FIXME: allow AWG8 setPrecompClear with wave + + "instructions": { + // based on PyqQED_py3 'mw_lutman.py' and 'generate_CCL_cfg.py': + "i": { + "duration": 20, + "cc": { +// "ref_signal": "single-qubit-mw", + "signal": [], // no signal, to prevent conflicts with other gates (NB: will output nothing because VSM stays off) + "static_codeword_override": [0] + } + }, + "rx180": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", // NB: reference, instead of defining "signal" here + "static_codeword_override": [1] + } + }, + "ry180": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [2] + } + }, + "rx90": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [3] + } + }, + "ry90": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [4] + } + }, + "rxm90": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [5] + } + }, + "rym90": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [6] + } + }, + + ////////////////////////////////////////// + // Custom operations for Quantum Inspire + ////////////////////////////////////////// + "ry45": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [1] + } + }, + + "rym45": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [2] + } + }, + + "rx45": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [3] + } + }, + + "rxm45": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [4] + } + }, + ////////////////////////////////////////// + + "cz": { + "duration": 80, + "cc": { + "ref_signal": "two-qubit-flux", // NB: reference, instead of defining "signal" here + "static_codeword_override": [1,1] // FIXME + } + }, + "cz_park": { + "duration": 80, + "cc": { + "signal": [ + { "type": "flux", + "operand_idx": 0, // control + "value": ["flux-0-{qubit}"] + }, + { "type": "flux", + "operand_idx": 1, // target + "value": ["flux-1-{qubit}"] + }, + { "type": "flux", + "operand_idx": 2, // park + "value": ["park_cz-{qubit}"] + } + ], + "static_codeword_override": [0,0,0] // FIXME + } + }, + + // additions from 'CC-software-implementation.docx' + // flux pulses, see: + // - https://github.com/QuTech-Delft/OpenQL/issues/176 + // - https://github.com/QuTech-Delft/OpenQL/issues/224 + // - https://github.com/QuTech-Delft/OpenQL/pull/238 + + "park_cz" : { // park signal with same length as cz gate + "duration" : 80, + "cc": { + "signal": [ + { "type": "flux", + "operand_idx": 0, + "value": ["park_cz-{qubit}"] + } + ], + "static_codeword_override": [0] // FIXME + } + }, + + "park_measure" : { // park signal with same length as measurement + "duration" : 2000, + "cc": { + "signal": [ + { "type": "flux", + "operand_idx": 0, + "value": ["park_measure-{qubit}"] + } + ], + "static_codeword_override": [0] // FIXME + } + }, + + + // based on PyqQED_py3 'generate_CCL_cfg.py': + "prepz": { + "duration": 200000, + "cc": { +// "ref_signal": "single-qubit-mw" + "signal": [], // FIXME: no signal, pycQED::test_multi_qubit_oql_CC.py fails otherwise on scheduling issues + "static_codeword_override": [0] // FIXME + } + }, + + "measure": { + "duration": 2000, + "cc": { + "readout_mode": "", + "signal": [ + { "type": "measure", + "operand_idx": 0, + "value": ["dummy"], // Future extension: specify output, and generate code word. Use "" if no output is present + "weight": ["dummy"] // Future extension: specify weight (implies readout? How about INT_AVG) + } + ], + "static_codeword_override": [0] // FIXME + } + }, + + // additions for feedback + "_wait_uhfqa": { + "duration": 220, + "cc": { + "signal": [] + } + }, + "_dist_dsm": { + "duration": 20, + "cc": { + "readout_mode": "feedback", + "signal": [ + { "type": "measure", + "operand_idx": 0, + "value": [] + } + ] + } + }, + "_wait_dsm": { + "duration": 80, + "cc": { + "signal": [] + } + }, + + "if_0_break": { + "duration": 60, + "cc": { + "signal": [], + "pragma": { + "break": 0 + } + } + }, + + "if_1_break": { + "duration": 60, + "cc": { + "signal": [], + "pragma": { + "break": 1 + } + } + }, + + // additions for pycQED::test_single_qubit_oql_CC.py + // FIXME: contents untested + "square": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [0] + } + }, + "spec": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [0] + } + }, + "rx12": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [0] + } + }, + // ensure codewords to 32 for echo sequences generated + "cw_00": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [0] + } + }, + "cw_01": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [1] + } + }, + "cw_02": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [2] + } + }, + "cw_03": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [3] + } + }, + "cw_04": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [4] + } + }, + "cw_05": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [5] + } + }, + "cw_06": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [6] + } + }, + "cw_07": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [7] + } + }, + "cw_08": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [8] + } + }, + "cw_09": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [9] + } + }, + "cw_10": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [0] + } + }, + "cw_11": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [1] + } + }, + "cw_12": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [2] + } + }, + "cw_13": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [3] + } + }, + "cw_14": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [4] + } + }, + "cw_15": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [5] + } + }, + "cw_16": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [6] + } + }, + "cw_17": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [7] + } + }, + "cw_18": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [8] + } + }, + "cw_19": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [9] + } + }, + "cw_20": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [0] + } + }, + "cw_21": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [1] + } + }, + "cw_22": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [2] + } + }, + "cw_23": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [3] + } + }, + "cw_24": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [4] + } + }, + "cw_25": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [5] + } + }, + "cw_26": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [6] + } + }, + "cw_27": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [7] + } + }, + "cw_28": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [8] + } + }, + "cw_29": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [9] + } + }, + "cw_30": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [0] + } + }, + "cw_31": { + "duration": 20, + "cc": { + "ref_signal": "single-qubit-mw", + "static_codeword_override": [1] + } + }, + + + // fl_cw_00 .. fl_cw_07 + "fl_cw_00": { + "duration": 80, + "cc": { + "ref_signal": "two-qubit-flux", // FIXME + "static_codeword_override": [0] + } + }, + "fl_cw_01": { + "duration": 80, + "cc": { + "ref_signal": "two-qubit-flux", + "static_codeword_override": [1] + } + }, + "fl_cw_02": { + "duration": 80, + "cc": { + "ref_signal": "two-qubit-flux", + "static_codeword_override": [2] + } + }, + "fl_cw_03": { + "duration": 80, + "cc": { + "ref_signal": "two-qubit-flux", + "static_codeword_override": [3] + } + }, + "fl_cw_04": { + "duration": 80, + "cc": { + "ref_signal": "two-qubit-flux", + "static_codeword_override": [4] + } + }, + "fl_cw_05": { + "duration": 80, + "cc": { + "ref_signal": "two-qubit-flux", + "static_codeword_override": [5] + } + }, + "fl_cw_06": { + "duration": 80, + "cc": { + "ref_signal": "two-qubit-flux", + "static_codeword_override": [6] + } + }, + "fl_cw_07": { + "duration": 80, + "cc": { + "ref_signal": "two-qubit-flux", + "static_codeword_override": [7] + } + }, + + // single qubit flux hacks (compatible with QCC demo/flux lutman) + // (qubit numbers defined to allow cz decomposition to ne,nw,se,sw based + // on topology through gate decompositions defined above) + "sf_cz_ne q2": { + "duration": 80, + "cc": { + "ref_signal": "single-qubit-flux", + "static_codeword_override": [1] + } + }, + "sf_cz_ne q3": { + "duration": 80, + "cc": { + "ref_signal": "single-qubit-flux", + "static_codeword_override": [1] + } + }, + "sf_cz_se q0": { + "duration": 80, + "cc": { + "ref_signal": "single-qubit-flux", + "static_codeword_override": [2] + } + }, + "sf_cz_se q2": { + "duration": 80, + "cc": { + "ref_signal": "single-qubit-flux", + "static_codeword_override": [2] + } + }, + "sf_cz_sw q1": { + "duration": 80, + "cc": { + "ref_signal": "single-qubit-flux", + "static_codeword_override": [3] + } + }, + "sf_cz_sw q2": { + "duration": 80, + "cc": { + "ref_signal": "single-qubit-flux", + "static_codeword_override": [3] + } + }, + "sf_cz_nw q2": { + "duration": 80, + "cc": { + "ref_signal": "single-qubit-flux", + "static_codeword_override": [4] + } + }, + "sf_cz_nw q4": { + "duration": 80, + "cc": { + "ref_signal": "single-qubit-flux", + "static_codeword_override": [4] + } + }, + "sf_park q3": { + "duration": 80, + "cc": { + "ref_signal": "single-qubit-flux", + "static_codeword_override": [5] + } + }, + "sf_park q4": { + "duration": 80, + "cc": { + "ref_signal": "single-qubit-flux", + "static_codeword_override": [5] + } + }, + "sf_sp_park": { + "duration": 80, + "cc": { + "ref_signal": "single-qubit-flux", + "static_codeword_override": [5] + } + }, + "sf_square": { + "duration": 80, + "cc": { + "ref_signal": "single-qubit-flux", + "static_codeword_override": [6] + } + } + } // end of "instructions" +} diff --git a/tests/spin_demo_2811.json b/res/v1x/json/config_spin_demo_2811.json similarity index 100% rename from tests/spin_demo_2811.json rename to res/v1x/json/config_spin_demo_2811.json diff --git a/tests/test_179.json b/res/v1x/json/test_179.json similarity index 100% rename from tests/test_179.json rename to res/v1x/json/test_179.json diff --git a/tests/test_cfg_CCL_long_duration.json b/res/v1x/json/test_cfg_CCL_long_duration.json similarity index 100% rename from tests/test_cfg_CCL_long_duration.json rename to res/v1x/json/test_cfg_CCL_long_duration.json diff --git a/tests/cc/test_cfg_cc.json b/res/v1x/json/test_cfg_cc.json similarity index 100% rename from tests/cc/test_cfg_cc.json rename to res/v1x/json/test_cfg_cc.json diff --git a/tests/cc/test_cfg_cc_demo.json b/res/v1x/json/test_cfg_cc_demo.json similarity index 100% rename from tests/cc/test_cfg_cc_demo.json rename to res/v1x/json/test_cfg_cc_demo.json diff --git a/tests/test_cfg_cc_light_buffers_latencies.json b/res/v1x/json/test_cfg_cc_light_buffers_latencies.json similarity index 100% rename from tests/test_cfg_cc_light_buffers_latencies.json rename to res/v1x/json/test_cfg_cc_light_buffers_latencies.json diff --git a/tests/test_cfg_none.json b/res/v1x/json/test_cfg_none.json similarity index 100% rename from tests/test_cfg_none.json rename to res/v1x/json/test_cfg_none.json diff --git a/tests/test_cfg_none_s7.json b/res/v1x/json/test_cfg_none_s7.json similarity index 100% rename from tests/test_cfg_none_s7.json rename to res/v1x/json/test_cfg_none_s7.json diff --git a/tests/cc/test_cfg_none_simple.json b/res/v1x/json/test_cfg_none_simple.json similarity index 100% rename from tests/cc/test_cfg_none_simple.json rename to res/v1x/json/test_cfg_none_simple.json diff --git a/tests/test_config_default.json b/res/v1x/json/test_config_default.json similarity index 100% rename from tests/test_config_default.json rename to res/v1x/json/test_config_default.json diff --git a/tests/test_mapper_rig.json b/res/v1x/json/test_mapper_rig.json similarity index 100% rename from tests/test_mapper_rig.json rename to res/v1x/json/test_mapper_rig.json diff --git a/tests/test_multi_core_4x4_full.json b/res/v1x/json/test_multi_core_4x4_full.json similarity index 100% rename from tests/test_multi_core_4x4_full.json rename to res/v1x/json/test_multi_core_4x4_full.json diff --git a/tests/cc/test_multi_core_64x16_full.json b/res/v1x/json/test_multi_core_64x16_full.json similarity index 100% rename from tests/cc/test_multi_core_64x16_full.json rename to res/v1x/json/test_multi_core_64x16_full.json diff --git a/tests/test_multi_core_8x1024_full.json b/res/v1x/json/test_multi_core_8x1024_full.json similarity index 100% rename from tests/test_multi_core_8x1024_full.json rename to res/v1x/json/test_multi_core_8x1024_full.json diff --git a/tests/test_structure_decomposition_platform.json b/res/v1x/json/test_structure_decomposition_platform.json similarity index 100% rename from tests/test_structure_decomposition_platform.json rename to res/v1x/json/test_structure_decomposition_platform.json diff --git a/tests/visualizer/hardware_config_cc_light_visualizer.json b/res/v1x/json/visualizer/config_cc_light.json similarity index 100% rename from tests/visualizer/hardware_config_cc_light_visualizer.json rename to res/v1x/json/visualizer/config_cc_light.json diff --git a/tests/visualizer/hardware_config_cc_light_visualizer2.json b/res/v1x/json/visualizer/config_cc_light_2.json similarity index 100% rename from tests/visualizer/hardware_config_cc_light_visualizer2.json rename to res/v1x/json/visualizer/config_cc_light_2.json diff --git a/tests/visualizer/visualizer_config_example1.json b/res/v1x/json/visualizer/config_example_1.json similarity index 100% rename from tests/visualizer/visualizer_config_example1.json rename to res/v1x/json/visualizer/config_example_1.json diff --git a/tests/visualizer/visualizer_config_example2.json b/res/v1x/json/visualizer/config_example_2.json similarity index 100% rename from tests/visualizer/visualizer_config_example2.json rename to res/v1x/json/visualizer/config_example_2.json diff --git a/tests/visualizer/visualizer_config_example3.json b/res/v1x/json/visualizer/config_example_3.json similarity index 100% rename from tests/visualizer/visualizer_config_example3.json rename to res/v1x/json/visualizer/config_example_3.json diff --git a/tests/visualizer/visualizer_config_example4.json b/res/v1x/json/visualizer/config_example_4.json similarity index 100% rename from tests/visualizer/visualizer_config_example4.json rename to res/v1x/json/visualizer/config_example_4.json diff --git a/tests/visualizer/visualizer_config_example5.json b/res/v1x/json/visualizer/config_example_5.json similarity index 100% rename from tests/visualizer/visualizer_config_example5.json rename to res/v1x/json/visualizer/config_example_5.json diff --git a/tests/visualizer/test_s7.json b/res/v1x/json/visualizer/test_s7.json similarity index 100% rename from tests/visualizer/test_s7.json rename to res/v1x/json/visualizer/test_s7.json diff --git a/tests/visualizer/waveform_mapping.json b/res/v1x/json/visualizer/waveform_mapping.json similarity index 100% rename from tests/visualizer/waveform_mapping.json rename to res/v1x/json/visualizer/waveform_mapping.json diff --git a/examples/instructions.map b/res/v1x/map/example/instructions.map similarity index 100% rename from examples/instructions.map rename to res/v1x/map/example/instructions.map diff --git a/examples/notebooks/ccLightClassicalDemo.ipynb b/res/v1x/notebooks/ccLightClassicalDemo.ipynb similarity index 97% rename from examples/notebooks/ccLightClassicalDemo.ipynb rename to res/v1x/notebooks/ccLightClassicalDemo.ipynb index 25467f43e..23ac0ad03 100644 --- a/examples/notebooks/ccLightClassicalDemo.ipynb +++ b/res/v1x/notebooks/ccLightClassicalDemo.ipynb @@ -36,13 +36,14 @@ "metadata": {}, "outputs": [], "source": [ - "from openql import openql as ql\n", + "import openql as ql\n", "import os\n", "\n", - "curdir = '.'\n", - "output_dir = os.path.join(curdir, 'test_output')\n", + "from conftest import json_dir, output_dir\n", + "\n", + "\n", "ql.set_option('output_dir', output_dir)\n", - "config_fn = os.path.join(curdir, '../../tests/hardware_config_cc_light.json')\n", + "config_fn = os.path.join(json_dir, 'config_cc_light.json')\n", "platform = ql.Platform(\"myPlatform\", config_fn)" ] }, @@ -55,9 +56,9 @@ "# This is what we could do till last demo\n", "\n", "def test():\n", - " nqubits = 5\n", - " p = ql.Program(\"aProgram\", platform, nqubits)\n", - " k = ql.Kernel(\"aKernel\", platform, nqubits)\n", + " num_qubits = 5\n", + " p = ql.Program(\"aProgram\", platform, num_qubits)\n", + " k = ql.Kernel(\"aKernel\", platform, num_qubits)\n", "\n", " k.gate('x', [0])\n", " k.gate('h', [1])\n", diff --git a/tests/golden/AllXYLongDuration_last.qasm b/res/v1x/qasm/golden/AllXYLongDuration_last.qasm similarity index 100% rename from tests/golden/AllXYLongDuration_last.qasm rename to res/v1x/qasm/golden/AllXYLongDuration_last.qasm diff --git a/tests/golden/basic.qasm b/res/v1x/qasm/golden/basic.qasm similarity index 100% rename from tests/golden/basic.qasm rename to res/v1x/qasm/golden/basic.qasm diff --git a/tests/golden/basic_scheduled.qasm b/res/v1x/qasm/golden/basic_scheduled.qasm similarity index 100% rename from tests/golden/basic_scheduled.qasm rename to res/v1x/qasm/golden/basic_scheduled.qasm diff --git a/tests/golden/diamond_api_diamond_codegen.dqasm b/res/v1x/qasm/golden/diamond_api_diamond_codegen.dqasm similarity index 100% rename from tests/golden/diamond_api_diamond_codegen.dqasm rename to res/v1x/qasm/golden/diamond_api_diamond_codegen.dqasm diff --git a/tests/golden/diamond_api_scheduled.qasm b/res/v1x/qasm/golden/diamond_api_scheduled.qasm similarity index 100% rename from tests/golden/diamond_api_scheduled.qasm rename to res/v1x/qasm/golden/diamond_api_scheduled.qasm diff --git a/tests/golden/diamond_cqasm_diamond_codegen.dqasm b/res/v1x/qasm/golden/diamond_cqasm_diamond_codegen.dqasm similarity index 100% rename from tests/golden/diamond_cqasm_diamond_codegen.dqasm rename to res/v1x/qasm/golden/diamond_cqasm_diamond_codegen.dqasm diff --git a/tests/golden/diamond_cqasm_scheduled.qasm b/res/v1x/qasm/golden/diamond_cqasm_scheduled.qasm similarity index 100% rename from tests/golden/diamond_cqasm_scheduled.qasm rename to res/v1x/qasm/golden/diamond_cqasm_scheduled.qasm diff --git a/tests/golden/test_1_ALAP_last.qasm b/res/v1x/qasm/golden/test_1_ALAP_last.qasm similarity index 100% rename from tests/golden/test_1_ALAP_last.qasm rename to res/v1x/qasm/golden/test_1_ALAP_last.qasm diff --git a/tests/golden/test_1_qubit.qasm b/res/v1x/qasm/golden/test_1_qubit.qasm similarity index 100% rename from tests/golden/test_1_qubit.qasm rename to res/v1x/qasm/golden/test_1_qubit.qasm diff --git a/tests/golden/test_2_qubit.qasm b/res/v1x/qasm/golden/test_2_qubit.qasm similarity index 100% rename from tests/golden/test_2_qubit.qasm rename to res/v1x/qasm/golden/test_2_qubit.qasm diff --git a/tests/golden/test_3_qubit.qasm b/res/v1x/qasm/golden/test_3_qubit.qasm similarity index 100% rename from tests/golden/test_3_qubit.qasm rename to res/v1x/qasm/golden/test_3_qubit.qasm diff --git a/tests/golden/test_7_ALAP_last.qasm b/res/v1x/qasm/golden/test_7_ALAP_last.qasm similarity index 100% rename from tests/golden/test_7_ALAP_last.qasm rename to res/v1x/qasm/golden/test_7_ALAP_last.qasm diff --git a/tests/golden/test_RAR_Control_ASAP.qasm b/res/v1x/qasm/golden/test_RAR_Control_ASAP.qasm similarity index 100% rename from tests/golden/test_RAR_Control_ASAP.qasm rename to res/v1x/qasm/golden/test_RAR_Control_ASAP.qasm diff --git a/tests/golden/test_RAW_ASAP.qasm b/res/v1x/qasm/golden/test_RAW_ASAP.qasm similarity index 100% rename from tests/golden/test_RAW_ASAP.qasm rename to res/v1x/qasm/golden/test_RAW_ASAP.qasm diff --git a/tests/golden/test_WAR_ASAP.qasm b/res/v1x/qasm/golden/test_WAR_ASAP.qasm similarity index 100% rename from tests/golden/test_WAR_ASAP.qasm rename to res/v1x/qasm/golden/test_WAR_ASAP.qasm diff --git a/tests/golden/test_WAW_ASAP.qasm b/res/v1x/qasm/golden/test_WAW_ASAP.qasm similarity index 100% rename from tests/golden/test_WAW_ASAP.qasm rename to res/v1x/qasm/golden/test_WAW_ASAP.qasm diff --git a/tests/golden/test_adriaan_ALAP_last.qasm b/res/v1x/qasm/golden/test_adriaan_ALAP_last.qasm similarity index 100% rename from tests/golden/test_adriaan_ALAP_last.qasm rename to res/v1x/qasm/golden/test_adriaan_ALAP_last.qasm diff --git a/tests/golden/test_barrier_all.qasm b/res/v1x/qasm/golden/test_barrier_all.qasm similarity index 100% rename from tests/golden/test_barrier_all.qasm rename to res/v1x/qasm/golden/test_barrier_all.qasm diff --git a/tests/golden/test_barrier_last.qasm b/res/v1x/qasm/golden/test_barrier_last.qasm similarity index 100% rename from tests/golden/test_barrier_last.qasm rename to res/v1x/qasm/golden/test_barrier_last.qasm diff --git a/tests/golden/test_cnot_2N_controlcommute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_2N_control_commute_scheduled.qasm similarity index 71% rename from tests/golden/test_cnot_2N_controlcommute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_2N_control_commute_scheduled.qasm index b350482d1..0ab5dbfff 100644 --- a/tests/golden/test_cnot_2N_controlcommute_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cnot_2N_control_commute_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cnot_2N_controlcommute +# Generated by OpenQL 0.9.0 for program test_cnot_2N_control_commute version 1.2 -pragma @ql.name("test_cnot_2N_controlcommute") +pragma @ql.name("test_cnot_2N_control_commute") .aKernel diff --git a/tests/golden/test_cnot_2N_targetcommute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_2N_target_commute_scheduled.qasm similarity index 73% rename from tests/golden/test_cnot_2N_targetcommute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_2N_target_commute_scheduled.qasm index e9cab9c33..fb5c58b1e 100644 --- a/tests/golden/test_cnot_2N_targetcommute_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cnot_2N_target_commute_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cnot_2N_targetcommute +# Generated by OpenQL 0.9.0 for program test_cnot_2N_target_commute version 1.2 -pragma @ql.name("test_cnot_2N_targetcommute") +pragma @ql.name("test_cnot_2N_target_commute") .aKernel diff --git a/tests/golden/test_cnot_2R_controlcommute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_2R_control_commute_scheduled.qasm similarity index 66% rename from tests/golden/test_cnot_2R_controlcommute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_2R_control_commute_scheduled.qasm index 8abd52325..65e54bbbe 100644 --- a/tests/golden/test_cnot_2R_controlcommute_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cnot_2R_control_commute_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cnot_2R_controlcommute +# Generated by OpenQL 0.9.0 for program test_cnot_2R_control_commute version 1.2 -pragma @ql.name("test_cnot_2R_controlcommute") +pragma @ql.name("test_cnot_2R_control_commute") .aKernel diff --git a/tests/golden/test_cnot_2R_noncommute_DAR_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_2R_non_commute_DAR_scheduled.qasm similarity index 58% rename from tests/golden/test_cnot_2R_noncommute_DAR_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_2R_non_commute_DAR_scheduled.qasm index 079af16a8..1bf11a934 100644 --- a/tests/golden/test_cnot_2R_noncommute_DAR_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cnot_2R_non_commute_DAR_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cnot_2R_noncommute_DAR +# Generated by OpenQL 0.9.0 for program test_cnot_2R_non_commute_DAR version 1.2 -pragma @ql.name("test_cnot_2R_noncommute_DAR") +pragma @ql.name("test_cnot_2R_non_commute_DAR") .aKernel diff --git a/tests/golden/test_cnot_2R_noncommute_RAD_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_2R_non_commute_RAD_scheduled.qasm similarity index 57% rename from tests/golden/test_cnot_2R_noncommute_RAD_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_2R_non_commute_RAD_scheduled.qasm index 6ba90e7cf..f636585ee 100644 --- a/tests/golden/test_cnot_2R_noncommute_RAD_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cnot_2R_non_commute_RAD_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cnot_2R_noncommute_RAD +# Generated by OpenQL 0.9.0 for program test_cnot_2R_non_commute_RAD version 1.2 -pragma @ql.name("test_cnot_2R_noncommute_RAD") +pragma @ql.name("test_cnot_2R_non_commute_RAD") .aKernel diff --git a/tests/golden/test_cnot_2R_targetcommute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_2R_target_commute_scheduled.qasm similarity index 66% rename from tests/golden/test_cnot_2R_targetcommute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_2R_target_commute_scheduled.qasm index cf4148fe8..64f42bf5d 100644 --- a/tests/golden/test_cnot_2R_targetcommute_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cnot_2R_target_commute_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cnot_2R_targetcommute +# Generated by OpenQL 0.9.0 for program test_cnot_2R_target_commute version 1.2 -pragma @ql.name("test_cnot_2R_targetcommute") +pragma @ql.name("test_cnot_2R_target_commute") .aKernel diff --git a/tests/golden/test_cnot_NN_controlcommute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_NN_control_commute_scheduled.qasm similarity index 66% rename from tests/golden/test_cnot_NN_controlcommute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_NN_control_commute_scheduled.qasm index 56016016d..4e3f1e119 100644 --- a/tests/golden/test_cnot_NN_controlcommute_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cnot_NN_control_commute_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cnot_NN_controlcommute +# Generated by OpenQL 0.9.0 for program test_cnot_NN_control_commute version 1.2 -pragma @ql.name("test_cnot_NN_controlcommute") +pragma @ql.name("test_cnot_NN_control_commute") .aKernel diff --git a/tests/golden/test_cnot_NN_noncommute_DAR_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_NN_non_commute_DAR_scheduled.qasm similarity index 51% rename from tests/golden/test_cnot_NN_noncommute_DAR_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_NN_non_commute_DAR_scheduled.qasm index ce1aa14c7..5877c68b2 100644 --- a/tests/golden/test_cnot_NN_noncommute_DAR_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cnot_NN_non_commute_DAR_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cnot_NN_noncommute_DAR +# Generated by OpenQL 0.9.0 for program test_cnot_NN_non_commute_DAR version 1.2 -pragma @ql.name("test_cnot_NN_noncommute_DAR") +pragma @ql.name("test_cnot_NN_non_commute_DAR") .aKernel diff --git a/tests/golden/test_cnot_NN_noncommute_RAD_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_NN_non_commute_RAD_scheduled.qasm similarity index 52% rename from tests/golden/test_cnot_NN_noncommute_RAD_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_NN_non_commute_RAD_scheduled.qasm index a59354528..918fffeec 100644 --- a/tests/golden/test_cnot_NN_noncommute_RAD_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cnot_NN_non_commute_RAD_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cnot_NN_noncommute_RAD +# Generated by OpenQL 0.9.0 for program test_cnot_NN_non_commute_RAD version 1.2 -pragma @ql.name("test_cnot_NN_noncommute_RAD") +pragma @ql.name("test_cnot_NN_non_commute_RAD") .aKernel diff --git a/tests/golden/test_cnot_NN_targetcommute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_NN_target_commute_scheduled.qasm similarity index 69% rename from tests/golden/test_cnot_NN_targetcommute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_NN_target_commute_scheduled.qasm index 3ca8a1da4..541f05f79 100644 --- a/tests/golden/test_cnot_NN_targetcommute_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cnot_NN_target_commute_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cnot_NN_targetcommute +# Generated by OpenQL 0.9.0 for program test_cnot_NN_target_commute version 1.2 -pragma @ql.name("test_cnot_NN_targetcommute") +pragma @ql.name("test_cnot_NN_target_commute") .aKernel diff --git a/tests/golden/test_cnot_mixedcommute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_mixed_commute_scheduled.qasm similarity index 83% rename from tests/golden/test_cnot_mixedcommute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_mixed_commute_scheduled.qasm index 7c71b9c54..6b734dd92 100644 --- a/tests/golden/test_cnot_mixedcommute_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cnot_mixed_commute_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cnot_mixedcommute +# Generated by OpenQL 0.9.0 for program test_cnot_mixed_commute version 1.2 -pragma @ql.name("test_cnot_mixedcommute") +pragma @ql.name("test_cnot_mixed_commute") .aKernel diff --git a/tests/golden/test_cnot_variations_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_variations_scheduled.qasm similarity index 100% rename from tests/golden/test_cnot_variations_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_variations_scheduled.qasm diff --git a/tests/golden/test_cnot_x_2N_commute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_x_2N_commute_scheduled.qasm similarity index 100% rename from tests/golden/test_cnot_x_2N_commute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_x_2N_commute_scheduled.qasm diff --git a/tests/golden/test_cnot_x_2R_commute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_x_2R_commute_scheduled.qasm similarity index 100% rename from tests/golden/test_cnot_x_2R_commute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_x_2R_commute_scheduled.qasm diff --git a/tests/golden/test_cnot_x_NN_commute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_x_NN_commute_scheduled.qasm similarity index 100% rename from tests/golden/test_cnot_x_NN_commute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_x_NN_commute_scheduled.qasm diff --git a/tests/golden/test_cnot_z_2N_commute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_z_2N_commute_scheduled.qasm similarity index 100% rename from tests/golden/test_cnot_z_2N_commute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_z_2N_commute_scheduled.qasm diff --git a/tests/golden/test_cnot_z_2R_commute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_z_2R_commute_scheduled.qasm similarity index 100% rename from tests/golden/test_cnot_z_2R_commute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_z_2R_commute_scheduled.qasm diff --git a/tests/golden/test_cnot_z_NN_commute_scheduled.qasm b/res/v1x/qasm/golden/test_cnot_z_NN_commute_scheduled.qasm similarity index 100% rename from tests/golden/test_cnot_z_NN_commute_scheduled.qasm rename to res/v1x/qasm/golden/test_cnot_z_NN_commute_scheduled.qasm diff --git a/tests/golden/test_condex_basic_scheduled.qasm b/res/v1x/qasm/golden/test_condex_basic_scheduled.qasm similarity index 100% rename from tests/golden/test_condex_basic_scheduled.qasm rename to res/v1x/qasm/golden/test_condex_basic_scheduled.qasm diff --git a/tests/golden/test_condex_cnot_last.qasm b/res/v1x/qasm/golden/test_condex_cnot_last.qasm similarity index 100% rename from tests/golden/test_condex_cnot_last.qasm rename to res/v1x/qasm/golden/test_condex_cnot_last.qasm diff --git a/tests/golden/test_condex_measure_last.qasm b/res/v1x/qasm/golden/test_condex_measure_last.qasm similarity index 100% rename from tests/golden/test_condex_measure_last.qasm rename to res/v1x/qasm/golden/test_condex_measure_last.qasm diff --git a/tests/golden/test_condex_toffoli_composgate_last.qasm b/res/v1x/qasm/golden/test_condex_toffoli_compos_gate_last.qasm similarity index 98% rename from tests/golden/test_condex_toffoli_composgate_last.qasm rename to res/v1x/qasm/golden/test_condex_toffoli_compos_gate_last.qasm index 4680c6bd2..2766ca327 100644 --- a/tests/golden/test_condex_toffoli_composgate_last.qasm +++ b/res/v1x/qasm/golden/test_condex_toffoli_compos_gate_last.qasm @@ -1,10 +1,10 @@ -# Generated by OpenQL 0.10.5 for program test_condex_toffoli_composgate +# Generated by OpenQL 0.10.5 for program test_condex_toffoli_compos_gate version 1.2 -pragma @ql.name("test_condex_toffoli_composgate") +pragma @ql.name("test_condex_toffoli_compos_gate") -.kernel_toffoli_composgate +.kernel_toffoli_compos_gate y90 q[1] { # start at cycle 1 x q[5] diff --git a/tests/golden/test_conjugate.qasm b/res/v1x/qasm/golden/test_conjugate.qasm similarity index 96% rename from tests/golden/test_conjugate.qasm rename to res/v1x/qasm/golden/test_conjugate.qasm index ecee2f242..111fa3776 100644 --- a/tests/golden/test_conjugate.qasm +++ b/res/v1x/qasm/golden/test_conjugate.qasm @@ -4,7 +4,7 @@ version 1.2 pragma @ql.name("test_conjugate") -.kernel_orignal +.kernel_original x q[0] y q[0] z q[0] diff --git a/tests/golden/test_controlled_rotations_scheduled.qasm b/res/v1x/qasm/golden/test_controlled_rotations_scheduled.qasm similarity index 100% rename from tests/golden/test_controlled_rotations_scheduled.qasm rename to res/v1x/qasm/golden/test_controlled_rotations_scheduled.qasm diff --git a/tests/golden/test_controlled_single_qubit_gates_scheduled.qasm b/res/v1x/qasm/golden/test_controlled_single_qubit_gates_scheduled.qasm similarity index 100% rename from tests/golden/test_controlled_single_qubit_gates_scheduled.qasm rename to res/v1x/qasm/golden/test_controlled_single_qubit_gates_scheduled.qasm diff --git a/tests/golden/test_controlled_two_qubit_gates_scheduled.qasm b/res/v1x/qasm/golden/test_controlled_two_qubit_gates_scheduled.qasm similarity index 100% rename from tests/golden/test_controlled_two_qubit_gates_scheduled.qasm rename to res/v1x/qasm/golden/test_controlled_two_qubit_gates_scheduled.qasm diff --git a/tests/golden/test_cqasm_conditions.qasm b/res/v1x/qasm/golden/test_cqasm_conditions.qasm similarity index 100% rename from tests/golden/test_cqasm_conditions.qasm rename to res/v1x/qasm/golden/test_cqasm_conditions.qasm diff --git a/tests/golden/test_cqasm_custom_gates.qasm b/res/v1x/qasm/golden/test_cqasm_custom_gates.qasm similarity index 100% rename from tests/golden/test_cqasm_custom_gates.qasm rename to res/v1x/qasm/golden/test_cqasm_custom_gates.qasm diff --git a/tests/golden/test_cqasm_custom_gates_scheduled.qasm b/res/v1x/qasm/golden/test_cqasm_custom_gates_scheduled.qasm similarity index 100% rename from tests/golden/test_cqasm_custom_gates_scheduled.qasm rename to res/v1x/qasm/golden/test_cqasm_custom_gates_scheduled.qasm diff --git a/tests/golden/test_cqasm_default_gates.qasm b/res/v1x/qasm/golden/test_cqasm_default_gates.qasm similarity index 100% rename from tests/golden/test_cqasm_default_gates.qasm rename to res/v1x/qasm/golden/test_cqasm_default_gates.qasm diff --git a/tests/golden/test_cqasm_default_gates_scheduled.qasm b/res/v1x/qasm/golden/test_cqasm_default_gates_scheduled.qasm similarity index 100% rename from tests/golden/test_cqasm_default_gates_scheduled.qasm rename to res/v1x/qasm/golden/test_cqasm_default_gates_scheduled.qasm diff --git a/tests/golden/test_cqasm_real_numbers.qasm b/res/v1x/qasm/golden/test_cqasm_real_numbers.qasm similarity index 100% rename from tests/golden/test_cqasm_real_numbers.qasm rename to res/v1x/qasm/golden/test_cqasm_real_numbers.qasm diff --git a/tests/golden/test_cz_2N_anycommute_scheduled.qasm b/res/v1x/qasm/golden/test_cz_2N_any_commute_scheduled.qasm similarity index 75% rename from tests/golden/test_cz_2N_anycommute_scheduled.qasm rename to res/v1x/qasm/golden/test_cz_2N_any_commute_scheduled.qasm index de95f4b4e..d6c6e7aad 100644 --- a/tests/golden/test_cz_2N_anycommute_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cz_2N_any_commute_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cz_2N_anycommute +# Generated by OpenQL 0.9.0 for program test_cz_2N_any_commute version 1.2 -pragma @ql.name("test_cz_2N_anycommute") +pragma @ql.name("test_cz_2N_any_commute") .aKernel diff --git a/tests/golden/test_cz_2R_anycommute_scheduled.qasm b/res/v1x/qasm/golden/test_cz_2R_any_commute_scheduled.qasm similarity index 67% rename from tests/golden/test_cz_2R_anycommute_scheduled.qasm rename to res/v1x/qasm/golden/test_cz_2R_any_commute_scheduled.qasm index 7c41bbab9..83f4617a0 100644 --- a/tests/golden/test_cz_2R_anycommute_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cz_2R_any_commute_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cz_2R_anycommute +# Generated by OpenQL 0.9.0 for program test_cz_2R_any_commute version 1.2 -pragma @ql.name("test_cz_2R_anycommute") +pragma @ql.name("test_cz_2R_any_commute") .aKernel diff --git a/tests/golden/test_cz_NN_anycommute_scheduled.qasm b/res/v1x/qasm/golden/test_cz_NN_any_commute_scheduled.qasm similarity index 71% rename from tests/golden/test_cz_NN_anycommute_scheduled.qasm rename to res/v1x/qasm/golden/test_cz_NN_any_commute_scheduled.qasm index 9c630efc2..54bd93f72 100644 --- a/tests/golden/test_cz_NN_anycommute_scheduled.qasm +++ b/res/v1x/qasm/golden/test_cz_NN_any_commute_scheduled.qasm @@ -1,7 +1,7 @@ -# Generated by OpenQL 0.9.0 for program test_cz_NN_anycommute +# Generated by OpenQL 0.9.0 for program test_cz_NN_any_commute version 1.2 -pragma @ql.name("test_cz_NN_anycommute") +pragma @ql.name("test_cz_NN_any_commute") .aKernel diff --git a/tests/golden/test_decomposition_scheduled.qasm b/res/v1x/qasm/golden/test_decomposition_scheduled.qasm similarity index 100% rename from tests/golden/test_decomposition_scheduled.qasm rename to res/v1x/qasm/golden/test_decomposition_scheduled.qasm diff --git a/tests/golden/test_detuned2_ALAP_last.qasm b/res/v1x/qasm/golden/test_detuned_2_ALAP_last.qasm similarity index 64% rename from tests/golden/test_detuned2_ALAP_last.qasm rename to res/v1x/qasm/golden/test_detuned_2_ALAP_last.qasm index 52949e701..3ca673fcd 100644 --- a/tests/golden/test_detuned2_ALAP_last.qasm +++ b/res/v1x/qasm/golden/test_detuned_2_ALAP_last.qasm @@ -1,10 +1,10 @@ -# Generated by OpenQL 0.9.0 for program test_detuned2_ALAP +# Generated by OpenQL 0.9.0 for program test_detuned_2_ALAP version 1.2 -pragma @ql.name("test_detuned2_ALAP") +pragma @ql.name("test_detuned_2_ALAP") -.kernel_detuned2_ALAP +.kernel_detuned_2_ALAP { # start at cycle 0 cz q[0], q[2] cz q[1], q[4] diff --git a/tests/golden/test_detuned_ALAP_last.qasm b/res/v1x/qasm/golden/test_detuned_ALAP_last.qasm similarity index 100% rename from tests/golden/test_detuned_ALAP_last.qasm rename to res/v1x/qasm/golden/test_detuned_ALAP_last.qasm diff --git a/tests/golden/test_edge_ALAP_last.qasm b/res/v1x/qasm/golden/test_edge_ALAP_last.qasm similarity index 100% rename from tests/golden/test_edge_ALAP_last.qasm rename to res/v1x/qasm/golden/test_edge_ALAP_last.qasm diff --git a/tests/golden/test_edge_available_last.qasm b/res/v1x/qasm/golden/test_edge_available_last.qasm similarity index 100% rename from tests/golden/test_edge_available_last.qasm rename to res/v1x/qasm/golden/test_edge_available_last.qasm diff --git a/tests/golden/test_edge_busy_last.qasm b/res/v1x/qasm/golden/test_edge_busy_last.qasm similarity index 100% rename from tests/golden/test_edge_busy_last.qasm rename to res/v1x/qasm/golden/test_edge_busy_last.qasm diff --git a/tests/golden/test_fast_feedback_last.qasm b/res/v1x/qasm/golden/test_fast_feedback_last.qasm similarity index 100% rename from tests/golden/test_fast_feedback_last.qasm rename to res/v1x/qasm/golden/test_fast_feedback_last.qasm diff --git a/tests/golden/test_flux_all_last.qasm b/res/v1x/qasm/golden/test_flux_all_last.qasm similarity index 100% rename from tests/golden/test_flux_all_last.qasm rename to res/v1x/qasm/golden/test_flux_all_last.qasm diff --git a/tests/golden/test_independence.qasm b/res/v1x/qasm/golden/test_independence.qasm similarity index 100% rename from tests/golden/test_independence.qasm rename to res/v1x/qasm/golden/test_independence.qasm diff --git a/res/v1x/qasm/golden/test_issue_179_ALAP_last.qasm b/res/v1x/qasm/golden/test_issue_179_ALAP_last.qasm new file mode 100644 index 000000000..4138e14f4 --- /dev/null +++ b/res/v1x/qasm/golden/test_issue_179_ALAP_last.qasm @@ -0,0 +1,14 @@ +# Generated by OpenQL 0.9.0 for program test_issue_179_ALAP +version 1.2 + +pragma @ql.name("test_issue_179_ALAP") + + +.kernel_issue_179_ALAP + y q[3] + skip 1 + { # start at cycle 2 + x q[2] + x q[4] + } + skip 1 diff --git a/tests/golden/test_mapper_allD_last.qasm b/res/v1x/qasm/golden/test_mapper_all_D_last.qasm similarity index 95% rename from tests/golden/test_mapper_allD_last.qasm rename to res/v1x/qasm/golden/test_mapper_all_D_last.qasm index 4992c09dd..8320dd7e8 100644 --- a/tests/golden/test_mapper_allD_last.qasm +++ b/res/v1x/qasm/golden/test_mapper_all_D_last.qasm @@ -1,10 +1,10 @@ -# Generated by OpenQL 0.11.1 for program test_mapper_allD +# Generated by OpenQL 0.11.1 for program test_mapper_all_D version 1.2 -pragma @ql.name("test_mapper_allD") +pragma @ql.name("test_mapper_all_D") -.kernel_allD +.kernel_all_D { # start at cycle 0 x q[0] x q[3] diff --git a/tests/golden/test_mapper_allDopt_last.qasm b/res/v1x/qasm/golden/test_mapper_all_D_opt_last.qasm similarity index 94% rename from tests/golden/test_mapper_allDopt_last.qasm rename to res/v1x/qasm/golden/test_mapper_all_D_opt_last.qasm index 4a714e20a..00f744016 100644 --- a/tests/golden/test_mapper_allDopt_last.qasm +++ b/res/v1x/qasm/golden/test_mapper_all_D_opt_last.qasm @@ -1,10 +1,10 @@ -# Generated by OpenQL 0.11.1 for program test_mapper_allDopt +# Generated by OpenQL 0.11.1 for program test_mapper_all_D_opt version 1.2 -pragma @ql.name("test_mapper_allDopt") +pragma @ql.name("test_mapper_all_D_opt") -.kernel_allDopt +.kernel_all_D_opt { # start at cycle 0 x q[0] x q[3] diff --git a/tests/golden/test_mapper_allIP_last.qasm b/res/v1x/qasm/golden/test_mapper_all_IP_last.qasm similarity index 87% rename from tests/golden/test_mapper_allIP_last.qasm rename to res/v1x/qasm/golden/test_mapper_all_IP_last.qasm index c41ec1590..c046c00dd 100644 --- a/tests/golden/test_mapper_allIP_last.qasm +++ b/res/v1x/qasm/golden/test_mapper_all_IP_last.qasm @@ -1,10 +1,10 @@ -# Generated by OpenQL 0.11.1 for program test_mapper_allIP +# Generated by OpenQL 0.11.1 for program test_mapper_all_IP version 1.2 -pragma @ql.name("test_mapper_allIP") +pragma @ql.name("test_mapper_all_IP") -.kernel_allIP +.kernel_all_IP { # start at cycle 0 x q[1] x q[3] diff --git a/tests/golden/test_mapper_allNN_last.qasm b/res/v1x/qasm/golden/test_mapper_all_NN_last.qasm similarity index 89% rename from tests/golden/test_mapper_allNN_last.qasm rename to res/v1x/qasm/golden/test_mapper_all_NN_last.qasm index 548462da3..56c4d3322 100644 --- a/tests/golden/test_mapper_allNN_last.qasm +++ b/res/v1x/qasm/golden/test_mapper_all_NN_last.qasm @@ -1,10 +1,10 @@ -# Generated by OpenQL 0.11.1 for program test_mapper_allNN +# Generated by OpenQL 0.11.1 for program test_mapper_all_NN version 1.2 -pragma @ql.name("test_mapper_allNN") +pragma @ql.name("test_mapper_all_NN") -.kernel_allNN +.kernel_all_NN { # start at cycle 0 x q[0] x q[3] diff --git a/tests/golden/test_mapper_lingling5_last.qasm b/res/v1x/qasm/golden/test_mapper_ling_ling_5_last.qasm similarity index 95% rename from tests/golden/test_mapper_lingling5_last.qasm rename to res/v1x/qasm/golden/test_mapper_ling_ling_5_last.qasm index c8cf0df0f..a9c2f5f67 100644 --- a/tests/golden/test_mapper_lingling5_last.qasm +++ b/res/v1x/qasm/golden/test_mapper_ling_ling_5_last.qasm @@ -1,10 +1,10 @@ -# Generated by OpenQL 0.11.1 for program test_mapper_lingling5 +# Generated by OpenQL 0.11.1 for program test_mapper_ling_ling_5 version 1.2 -pragma @ql.name("test_mapper_lingling5") +pragma @ql.name("test_mapper_ling_ling_5") -.kernel_lingling5 +.kernel_ling_ling_5 { # start at cycle 0 prepz q[5] prepz q[6] diff --git a/tests/golden/test_mapper_lingling7_last.qasm b/res/v1x/qasm/golden/test_mapper_ling_ling_7_last.qasm similarity index 95% rename from tests/golden/test_mapper_lingling7_last.qasm rename to res/v1x/qasm/golden/test_mapper_ling_ling_7_last.qasm index 5f3107e69..f556edc71 100644 --- a/tests/golden/test_mapper_lingling7_last.qasm +++ b/res/v1x/qasm/golden/test_mapper_ling_ling_7_last.qasm @@ -1,10 +1,10 @@ -# Generated by OpenQL 0.11.1 for program test_mapper_lingling7 +# Generated by OpenQL 0.11.1 for program test_mapper_ling_ling_7 version 1.2 -pragma @ql.name("test_mapper_lingling7") +pragma @ql.name("test_mapper_ling_ling_7") -.kernel_lingling7 +.kernel_ling_ling_7 { # start at cycle 0 prepz q[8] prepz q[7] diff --git a/tests/golden/test_mapper_maxcut_last.qasm b/res/v1x/qasm/golden/test_mapper_max_cut_last.qasm similarity index 87% rename from tests/golden/test_mapper_maxcut_last.qasm rename to res/v1x/qasm/golden/test_mapper_max_cut_last.qasm index 820fc56a3..dc7f561b4 100644 --- a/tests/golden/test_mapper_maxcut_last.qasm +++ b/res/v1x/qasm/golden/test_mapper_max_cut_last.qasm @@ -1,10 +1,10 @@ -# Generated by OpenQL 0.11.1 for program test_mapper_maxcut +# Generated by OpenQL 0.11.1 for program test_mapper_max_cut version 1.2 -pragma @ql.name("test_mapper_maxcut") +pragma @ql.name("test_mapper_max_cut") -.kernel_maxcut +.kernel_max_cut { # start at cycle 0 x q[7] x q[6] diff --git a/tests/golden/test_mapper_oneD2_last.qasm b/res/v1x/qasm/golden/test_mapper_one_D2_last.qasm similarity index 58% rename from tests/golden/test_mapper_oneD2_last.qasm rename to res/v1x/qasm/golden/test_mapper_one_D2_last.qasm index 3f9a8fb3f..5a182ee1e 100644 --- a/tests/golden/test_mapper_oneD2_last.qasm +++ b/res/v1x/qasm/golden/test_mapper_one_D2_last.qasm @@ -1,10 +1,10 @@ -# Generated by OpenQL 0.11.1 for program test_mapper_oneD2 +# Generated by OpenQL 0.11.1 for program test_mapper_one_D2 version 1.2 -pragma @ql.name("test_mapper_oneD2") +pragma @ql.name("test_mapper_one_D2") -.kernel_oneD2 +.kernel_one_D2 y q[3] swap q[3], q[0] skip 9 diff --git a/tests/golden/test_mapper_oneD4_last.qasm b/res/v1x/qasm/golden/test_mapper_one_D4_last.qasm similarity index 68% rename from tests/golden/test_mapper_oneD4_last.qasm rename to res/v1x/qasm/golden/test_mapper_one_D4_last.qasm index 4b77602f9..db84e6e4c 100644 --- a/tests/golden/test_mapper_oneD4_last.qasm +++ b/res/v1x/qasm/golden/test_mapper_one_D4_last.qasm @@ -1,10 +1,10 @@ -# Generated by OpenQL 0.11.1 for program test_mapper_oneD4 +# Generated by OpenQL 0.11.1 for program test_mapper_one_D4 version 1.2 -pragma @ql.name("test_mapper_oneD4") +pragma @ql.name("test_mapper_one_D4") -.kernel_oneD4 +.kernel_one_D4 x q[2] y q[4] { # start at cycle 2 diff --git a/res/v1x/qasm/golden/test_mapper_one_NN_last.qasm b/res/v1x/qasm/golden/test_mapper_one_NN_last.qasm new file mode 100644 index 000000000..b8008ce15 --- /dev/null +++ b/res/v1x/qasm/golden/test_mapper_one_NN_last.qasm @@ -0,0 +1,11 @@ +# Generated by OpenQL 0.10.5 for program test_mapper_one_NN +version 1.2 + +pragma @ql.name("test_mapper_one_NN") + + +.kernel_one_NN + cnot q[2], q[5] + skip 1 + x q[0] + y q[1] diff --git a/tests/golden/test_mc_all_last.qasm b/res/v1x/qasm/golden/test_mc_all_last.qasm similarity index 100% rename from tests/golden/test_mc_all_last.qasm rename to res/v1x/qasm/golden/test_mc_all_last.qasm diff --git a/tests/golden/test_mc_all_saturate_last.qasm b/res/v1x/qasm/golden/test_mc_all_saturate_last.qasm similarity index 100% rename from tests/golden/test_mc_all_saturate_last.qasm rename to res/v1x/qasm/golden/test_mc_all_saturate_last.qasm diff --git a/tests/golden/test_mc_comms_last.qasm b/res/v1x/qasm/golden/test_mc_comms_last.qasm similarity index 100% rename from tests/golden/test_mc_comms_last.qasm rename to res/v1x/qasm/golden/test_mc_comms_last.qasm diff --git a/tests/golden/test_mc_locals_last.qasm b/res/v1x/qasm/golden/test_mc_locals_last.qasm similarity index 100% rename from tests/golden/test_mc_locals_last.qasm rename to res/v1x/qasm/golden/test_mc_locals_last.qasm diff --git a/res/v1x/qasm/golden/test_mc_non_comms_last.qasm b/res/v1x/qasm/golden/test_mc_non_comms_last.qasm new file mode 100644 index 000000000..988fbe0f4 --- /dev/null +++ b/res/v1x/qasm/golden/test_mc_non_comms_last.qasm @@ -0,0 +1,13 @@ +# Generated by OpenQL 0.11.1 for program test_mc_non_comms +version 1.2 + +pragma @ql.name("test_mc_non_comms") + + +.kernel_non_comms + x q[7] + tmove q[7], q[0] + skip 38 + x q[3] + cnot q[3], q[0] + skip 4 diff --git a/tests/golden/test_mc_wide_last.qasm b/res/v1x/qasm/golden/test_mc_wide_last.qasm similarity index 100% rename from tests/golden/test_mc_wide_last.qasm rename to res/v1x/qasm/golden/test_mc_wide_last.qasm diff --git a/res/v1x/qasm/golden/test_measure_available_01_last.qasm b/res/v1x/qasm/golden/test_measure_available_01_last.qasm new file mode 100644 index 000000000..1a4707d1d --- /dev/null +++ b/res/v1x/qasm/golden/test_measure_available_01_last.qasm @@ -0,0 +1,12 @@ +# Generated by OpenQL 0.9.0 for program test_measure_available_01 +version 1.2 + +pragma @ql.name("test_measure_available_01") + + +.aKernel + { # start at cycle 0 + measure q[0] + measure q[1] + } + skip 1 diff --git a/res/v1x/qasm/golden/test_measure_available_02_last.qasm b/res/v1x/qasm/golden/test_measure_available_02_last.qasm new file mode 100644 index 000000000..c3c80a573 --- /dev/null +++ b/res/v1x/qasm/golden/test_measure_available_02_last.qasm @@ -0,0 +1,12 @@ +# Generated by OpenQL 0.9.0 for program test_measure_available_02 +version 1.2 + +pragma @ql.name("test_measure_available_02") + + +.aKernel + { # start at cycle 0 + measure q[0] + measure q[2] + } + skip 1 diff --git a/tests/golden/test_measure_busy_last.qasm b/res/v1x/qasm/golden/test_measure_busy_last.qasm similarity index 100% rename from tests/golden/test_measure_busy_last.qasm rename to res/v1x/qasm/golden/test_measure_busy_last.qasm diff --git a/tests/golden/test_multi_controlled_scheduled.qasm b/res/v1x/qasm/golden/test_multi_controlled_scheduled.qasm similarity index 100% rename from tests/golden/test_multi_controlled_scheduled.qasm rename to res/v1x/qasm/golden/test_multi_controlled_scheduled.qasm diff --git a/tests/golden/test_multiple_programs.qasm b/res/v1x/qasm/golden/test_multiple_programs.qasm similarity index 100% rename from tests/golden/test_multiple_programs.qasm rename to res/v1x/qasm/golden/test_multiple_programs.qasm diff --git a/tests/golden/test_parallel_programs.qasm b/res/v1x/qasm/golden/test_parallel_programs.qasm similarity index 100% rename from tests/golden/test_parallel_programs.qasm rename to res/v1x/qasm/golden/test_parallel_programs.qasm diff --git a/tests/golden/test_platform_modified_in_place_last.qasm b/res/v1x/qasm/golden/test_platform_modified_in_place_last.qasm similarity index 100% rename from tests/golden/test_platform_modified_in_place_last.qasm rename to res/v1x/qasm/golden/test_platform_modified_in_place_last.qasm diff --git a/tests/golden/test_qubit_busy_last.qasm b/res/v1x/qasm/golden/test_qubit_busy_last.qasm similarity index 100% rename from tests/golden/test_qubit_busy_last.qasm rename to res/v1x/qasm/golden/test_qubit_busy_last.qasm diff --git a/tests/golden/test_qwg2_ALAP_last.qasm b/res/v1x/qasm/golden/test_qwg_2_ALAP_last.qasm similarity index 81% rename from tests/golden/test_qwg2_ALAP_last.qasm rename to res/v1x/qasm/golden/test_qwg_2_ALAP_last.qasm index ad47c00b1..868a3a477 100644 --- a/tests/golden/test_qwg2_ALAP_last.qasm +++ b/res/v1x/qasm/golden/test_qwg_2_ALAP_last.qasm @@ -1,10 +1,10 @@ -# Generated by OpenQL 0.9.0 for program test_qwg2_ALAP +# Generated by OpenQL 0.9.0 for program test_qwg_2_ALAP version 1.2 -pragma @ql.name("test_qwg2_ALAP") +pragma @ql.name("test_qwg_2_ALAP") -.kernel_qwg2_ALAP +.kernel_qwg_2_ALAP { # start at cycle 0 x q[0] x q[3] diff --git a/tests/golden/test_qwg_ALAP_last.qasm b/res/v1x/qasm/golden/test_qwg_ALAP_last.qasm similarity index 100% rename from tests/golden/test_qwg_ALAP_last.qasm rename to res/v1x/qasm/golden/test_qwg_ALAP_last.qasm diff --git a/tests/golden/test_qwg_available_01_last.qasm b/res/v1x/qasm/golden/test_qwg_available_01_last.qasm similarity index 100% rename from tests/golden/test_qwg_available_01_last.qasm rename to res/v1x/qasm/golden/test_qwg_available_01_last.qasm diff --git a/tests/golden/test_qwg_available_02_last.qasm b/res/v1x/qasm/golden/test_qwg_available_02_last.qasm similarity index 100% rename from tests/golden/test_qwg_available_02_last.qasm rename to res/v1x/qasm/golden/test_qwg_available_02_last.qasm diff --git a/tests/golden/test_qwg_busy_last.qasm b/res/v1x/qasm/golden/test_qwg_busy_last.qasm similarity index 100% rename from tests/golden/test_qwg_busy_last.qasm rename to res/v1x/qasm/golden/test_qwg_busy_last.qasm diff --git a/tests/golden/test_single_bit_kernel_operations.qasm b/res/v1x/qasm/golden/test_single_bit_kernel_operations.qasm similarity index 100% rename from tests/golden/test_single_bit_kernel_operations.qasm rename to res/v1x/qasm/golden/test_single_bit_kernel_operations.qasm diff --git a/tests/golden/test_skip_yes_scheduled.qasm b/res/v1x/qasm/golden/test_skip_yes_scheduled.qasm similarity index 100% rename from tests/golden/test_skip_yes_scheduled.qasm rename to res/v1x/qasm/golden/test_skip_yes_scheduled.qasm diff --git a/tests/golden/test_smis_all_bundled_last.qasm b/res/v1x/qasm/golden/test_smis_all_bundled_last.qasm similarity index 100% rename from tests/golden/test_smis_all_bundled_last.qasm rename to res/v1x/qasm/golden/test_smis_all_bundled_last.qasm diff --git a/tests/golden/test_smis_last.qasm b/res/v1x/qasm/golden/test_smis_last.qasm similarity index 100% rename from tests/golden/test_smis_last.qasm rename to res/v1x/qasm/golden/test_smis_last.qasm diff --git a/tests/golden/test_smis_multi_kernel_last.qasm b/res/v1x/qasm/golden/test_smis_multi_kernel_last.qasm similarity index 100% rename from tests/golden/test_smis_multi_kernel_last.qasm rename to res/v1x/qasm/golden/test_smis_multi_kernel_last.qasm diff --git a/tests/golden/test_smis_with_custom_gates_last.qasm b/res/v1x/qasm/golden/test_smis_with_custom_gates_last.qasm similarity index 100% rename from tests/golden/test_smis_with_custom_gates_last.qasm rename to res/v1x/qasm/golden/test_smis_with_custom_gates_last.qasm diff --git a/tests/golden/test_smit_all_bundled.qasm b/res/v1x/qasm/golden/test_smit_all_bundled.qasm similarity index 100% rename from tests/golden/test_smit_all_bundled.qasm rename to res/v1x/qasm/golden/test_smit_all_bundled.qasm diff --git a/tests/golden/test_smit_all_bundled_last.qasm b/res/v1x/qasm/golden/test_smit_all_bundled_last.qasm similarity index 100% rename from tests/golden/test_smit_all_bundled_last.qasm rename to res/v1x/qasm/golden/test_smit_all_bundled_last.qasm diff --git a/tests/golden/test_smit_last.qasm b/res/v1x/qasm/golden/test_smit_last.qasm similarity index 100% rename from tests/golden/test_smit_last.qasm rename to res/v1x/qasm/golden/test_smit_last.qasm diff --git a/tests/golden/test_sub_circuit_programs.qasm b/res/v1x/qasm/golden/test_sub_circuit_programs.qasm similarity index 100% rename from tests/golden/test_sub_circuit_programs.qasm rename to res/v1x/qasm/golden/test_sub_circuit_programs.qasm diff --git a/tests/golden/test_swap_multi_ASAP.qasm b/res/v1x/qasm/golden/test_swap_multi_ASAP.qasm similarity index 100% rename from tests/golden/test_swap_multi_ASAP.qasm rename to res/v1x/qasm/golden/test_swap_multi_ASAP.qasm diff --git a/tests/golden/test_swap_single_ASAP.qasm b/res/v1x/qasm/golden/test_swap_single_ASAP.qasm similarity index 100% rename from tests/golden/test_swap_single_ASAP.qasm rename to res/v1x/qasm/golden/test_swap_single_ASAP.qasm diff --git a/tests/golden/test_wait_barrier_last.qasm b/res/v1x/qasm/golden/test_wait_barrier_last.qasm similarity index 100% rename from tests/golden/test_wait_barrier_last.qasm rename to res/v1x/qasm/golden/test_wait_barrier_last.qasm diff --git a/tests/test_qi_example.initial.cq b/res/v1x/qasm/test_qi_example.initial.cq similarity index 100% rename from tests/test_qi_example.initial.cq rename to res/v1x/qasm/test_qi_example.initial.cq diff --git a/tests/test_qi_example.scheduled.cq b/res/v1x/qasm/test_qi_example.scheduled.cq similarity index 100% rename from tests/test_qi_example.scheduled.cq rename to res/v1x/qasm/test_qi_example.scheduled.cq diff --git a/setup.py b/setup.py index 583c17c29..6c62717b4 100755 --- a/setup.py +++ b/setup.py @@ -192,7 +192,6 @@ def run(self): cmd = cmd['--parallel'][nprocs] elif not sys.platform.startswith('win'): cmd = cmd['--']['-j'][nprocs] - cmd & FG # Run the C++ tests if requested. if 'OPENQL_BUILD_TESTS' in os.environ: diff --git a/src/ql/api/pass.cc b/src/ql/api/pass.cc index 47d8d6540..73d5753e6 100644 --- a/src/ql/api/pass.cc +++ b/src/ql/api/pass.cc @@ -18,7 +18,7 @@ namespace api { * Constructor used internally to build a pass object that belongs to * a compiler. */ -Pass::Pass(const ql::pmgr::PassRef &pass, bool dummy) : pass(pass) { +Pass::Pass(const ql::pmgr::PassRef &pass, bool) : pass(pass) { } /** diff --git a/src/ql/arch/cc/info.cc b/src/ql/arch/cc/info.cc index a2e239510..30de89891 100644 --- a/src/ql/arch/cc/info.cc +++ b/src/ql/arch/cc/info.cc @@ -487,9 +487,9 @@ utils::List Info::get_eqasm_compiler_names() const { * of this architecture. This JSON data will still be preprocessed by * preprocess_platform(). */ -utils::Str Info::get_default_platform(const utils::Str &variant) const { +utils::Str Info::get_default_platform(const utils::Str &) const { - // NOTE: based on tests/cc/cc_s5_direct_iq.json at the time of writing. + // NOTE: based on res/v1x/json/config_cc_s5_direct_iq.json at the time of writing. return HWCONF_DEFAULT_DATA; } @@ -500,7 +500,7 @@ utils::Str Info::get_default_platform(const utils::Str &variant) const { * platform, to save typing in the configuration file (and reduce the amount * of mistakes made). */ -void Info::preprocess_platform(utils::Json &data, const utils::Str &variant) const { +void Info::preprocess_platform(utils::Json &data, const utils::Str &) const { QL_IOUT("desugaring CC instructions"); @@ -657,7 +657,7 @@ void Info::post_process_platform( * code generation pass, but anything after prescheduling and optimization * is considered a backend pass. */ -void Info::populate_backend_passes(pmgr::Manager &manager, const utils::Str &variant) const { +void Info::populate_backend_passes(pmgr::Manager &manager, const utils::Str &) const { // Remove prescheduler if enabled implicitly (pointless since we add our own scheduling). // FIXME: bit of a hack, and invalidates https://openql.readthedocs.io/en/latest/gen/reference_architectures.html#default-pass-list utils::Str ps_name = "prescheduler"; diff --git a/src/ql/arch/cc/pass/gen/vq1asm/detail/backend.cc b/src/ql/arch/cc/pass/gen/vq1asm/detail/backend.cc index 08f3cee59..4c8a83de5 100644 --- a/src/ql/arch/cc/pass/gen/vq1asm/detail/backend.cc +++ b/src/ql/arch/cc/pass/gen/vq1asm/detail/backend.cc @@ -158,7 +158,7 @@ void Backend::codegen_block(const ir::BlockBaseRef &block, const Str &name, Int try { codegen.handle_set_instruction(*set_instruction, "conditional.set"); } catch (utils::Exception &e) { - e.add_context("in set_instruction '" + ir::describe(*set_instruction) + "'" , true); + e.add_context("in set_instruction '" + ir::describe(*set_instruction) + "'", true); throw; } diff --git a/src/ql/arch/cc/pass/gen/vq1asm/detail/codegen.cc b/src/ql/arch/cc/pass/gen/vq1asm/detail/codegen.cc index e46ed64ef..b258a5ef6 100644 --- a/src/ql/arch/cc/pass/gen/vq1asm/detail/codegen.cc +++ b/src/ql/arch/cc/pass/gen/vq1asm/detail/codegen.cc @@ -153,7 +153,7 @@ typedef struct { * Static helper function for bundle_finish() */ static CalcGroupDigOut calcGroupDigOut( - UInt instrIdx, + UInt, UInt group, UInt nrGroups, const Settings::InstrumentControl &ic, @@ -349,7 +349,7 @@ void Codegen::program_start(const Str &progName) { } -void Codegen::program_finish(const Str &progName) { +void Codegen::program_finish(const Str &) { emitProgramFinish(); dp.programFinish(); @@ -396,7 +396,7 @@ void Codegen::bundle_start(const Str &cmnt) { Codegen::CodeGenMap Codegen::collectCodeGenInfo( UInt startCycle, - UInt durationInCycles + UInt ) { CodeGenMap codeGenMap; @@ -418,7 +418,7 @@ Codegen::CodeGenMap Codegen::collectCodeGenInfo( // FIXME: the term 'group' is used in a diffused way: 1) index of signal vectors, 2) controlModeGroup - CodeGenInfo codeGenInfo = {false}; + CodeGenInfo codeGenInfo{}; // remind information needed for code generation codeGenInfo.instrumentName = ic.ii.instrumentName; diff --git a/src/ql/arch/cc/pass/gen/vq1asm/detail/datapath.cc b/src/ql/arch/cc/pass/gen/vq1asm/detail/datapath.cc index afd3c454b..2a0bd5b2e 100644 --- a/src/ql/arch/cc/pass/gen/vq1asm/detail/datapath.cc +++ b/src/ql/arch/cc/pass/gen/vq1asm/detail/datapath.cc @@ -88,7 +88,7 @@ UInt Datapath::getSmBit(UInt bit_operand) const { return smBit; } -UInt Datapath::getOrAssignMux(UInt instrIdx, const MeasResultRealTimeMap &measResultRealTimeMap) { +UInt Datapath::getOrAssignMux(UInt instrIdx, const MeasResultRealTimeMap &) { // We need a different MUX for every new combination of simultaneous readouts (per instrument) UInt mux = lastMux[instrIdx]++; // FIXME: no reuse of identical combinations yet if (mux == MUX_CNT) { @@ -99,7 +99,7 @@ UInt Datapath::getOrAssignMux(UInt instrIdx, const MeasResultRealTimeMap &measRe } -UInt Datapath::getOrAssignPl(UInt instrIdx, const CondGateMap &condGateMap) { +UInt Datapath::getOrAssignPl(UInt instrIdx, const CondGateMap &) { // We need a different PL for every new combination of simultaneous gate conditions (per instrument) UInt pl = lastPl[instrIdx]++; // FIXME: no reuse of identical combinations yet if (pl == PL_CNT) { @@ -173,7 +173,7 @@ UInt Datapath::getMuxSmAddr(const MeasResultRealTimeMap &measResultRealTimeMap) // FIXME: split like emitMux/getMuxSmAddr -UInt Datapath::emitPl(UInt pl, const CondGateMap &condGateMap, UInt instrIdx, Int slot) { +UInt Datapath::emitPl(UInt pl, const CondGateMap &condGateMap, UInt, Int slot) { Bool minMaxValid = false; // we might not access SM UInt minSmBit = MAX; UInt maxSmBit = 0; diff --git a/src/ql/arch/cc/pass/gen/vq1asm/detail/functions.cc b/src/ql/arch/cc/pass/gen/vq1asm/detail/functions.cc index 95a8d1acf..1cbf54324 100644 --- a/src/ql/arch/cc/pass/gen/vq1asm/detail/functions.cc +++ b/src/ql/arch/cc/pass/gen/vq1asm/detail/functions.cc @@ -66,8 +66,8 @@ void Functions::dispatch(const ir::FunctionCall *fn, const Str &label_if_false, } -UInt Functions::emit_bin_cast(utils::Vec bregs, Int expOpCnt) { - if(static_cast(bregs.size()) != expOpCnt) { +UInt Functions::emit_bin_cast(utils::Vec bregs, UInt expOpCnt) { + if(bregs.size() != expOpCnt) { QL_ICE("Expected " << expOpCnt << " breg operands, got " << bregs.size()); } @@ -276,19 +276,19 @@ void Functions::op_sub_iC(const FncArgs &a) { } #if OPT_CC_USER_FUNCTIONS -void Functions::rnd_seed_C(const FncArgs &a) { +void Functions::rnd_seed_C(const FncArgs &) { // FIXME } -void Functions::rnd_seed_i(const FncArgs &a) { +void Functions::rnd_seed_i(const FncArgs &) { // FIXME } -void Functions::rnd_C(const FncArgs &a) { +void Functions::rnd_C(const FncArgs &) { // FIXME } -void Functions::rnd_i(const FncArgs &a) { +void Functions::rnd_i(const FncArgs &) { // FIXME } #endif diff --git a/src/ql/arch/cc/pass/gen/vq1asm/detail/functions.h b/src/ql/arch/cc/pass/gen/vq1asm/detail/functions.h index de39e3394..7753b2fb3 100644 --- a/src/ql/arch/cc/pass/gen/vq1asm/detail/functions.h +++ b/src/ql/arch/cc/pass/gen/vq1asm/detail/functions.h @@ -36,7 +36,7 @@ class Functions { * FIXME: We don't have a matching quantum instruction for this cast (formerly, we had 'if_1_break' etc), but do * take up 'quantum' time, so the timeline is silently shifted */ - UInt emit_bin_cast(utils::Vec bregs, Int expOpCnt); + UInt emit_bin_cast(utils::Vec bregs, UInt expOpCnt); private: // types diff --git a/src/ql/arch/cc/pass/gen/vq1asm/detail/operands.cc b/src/ql/arch/cc/pass/gen/vq1asm/detail/operands.cc index e67bfd019..a3116ce07 100644 --- a/src/ql/arch/cc/pass/gen/vq1asm/detail/operands.cc +++ b/src/ql/arch/cc/pass/gen/vq1asm/detail/operands.cc @@ -5,6 +5,7 @@ #include "operands.h" +#include "ql/ir/ir_gen_ex.h" #include "ql/ir/ops.h" #include "ql/ir/describe.h" diff --git a/src/ql/arch/cc/pass/gen/vq1asm/detail/settings.cc b/src/ql/arch/cc/pass/gen/vq1asm/detail/settings.cc index f99f9ec6c..3fc08d93b 100644 --- a/src/ql/arch/cc/pass/gen/vq1asm/detail/settings.cc +++ b/src/ql/arch/cc/pass/gen/vq1asm/detail/settings.cc @@ -221,7 +221,7 @@ Settings::CalcSignalValue Settings::calcSignalValue( Settings::InstrumentInfo Settings::getInstrumentInfo(UInt instrIdx) const { - InstrumentInfo ret = {nullptr}; + InstrumentInfo ret{}; Str instrumentPath = QL_SS2S("instruments[" << instrIdx << "]"); // for JSON error reporting if (instrIdx >= jsonInstruments->size()) { diff --git a/src/ql/arch/cc/pass/gen/vq1asm/vq1asm.cc b/src/ql/arch/cc/pass/gen/vq1asm/vq1asm.cc index a4dec2daa..9c3fb7596 100644 --- a/src/ql/arch/cc/pass/gen/vq1asm/vq1asm.cc +++ b/src/ql/arch/cc/pass/gen/vq1asm/vq1asm.cc @@ -4,9 +4,10 @@ #include "ql/arch/cc/pass/gen/vq1asm/vq1asm.h" -#include "ql/pmgr/pass_types/base.h" #include "detail/backend.h" +#include "ql/ir/ir_gen_ex.h" #include "ql/pmgr/factory.h" +#include "ql/pmgr/pass_types/base.h" namespace ql { namespace arch { diff --git a/src/ql/arch/cc_light/info.cc b/src/ql/arch/cc_light/info.cc index fc6df4c8f..1d5a23e76 100644 --- a/src/ql/arch/cc_light/info.cc +++ b/src/ql/arch/cc_light/info.cc @@ -95,7 +95,7 @@ void Info::dump_variant_docs( if (variant == "default") { utils::dump_str(os, line_prefix, R"( This is the default CC-light configuration, based on what used to be - ``tests/hardware_config_cc_light.json``, which in turn is a simplified + ``config_cc_light.json``, which in turn is a simplified version of the surface-7 configuration (the instruction durations are comparatively short and uniform). )"); @@ -150,8 +150,7 @@ utils::Str Info::get_default_platform(const utils::Str &variant) const { * code generation pass, but anything after prescheduling and optimization * is considered a backend pass. */ -void Info::populate_backend_passes(pmgr::Manager &manager, const utils::Str &variant) const { - +void Info::populate_backend_passes(pmgr::Manager &manager, const utils::Str &) const { // Mapping. if (com::options::global["clifford_premapper"].as_bool()) { manager.append_pass( @@ -199,8 +198,7 @@ void Info::populate_backend_passes(pmgr::Manager &manager, const utils::Str &var } ); - // R.I.P. CC-light code generation. - + // CC-light code generation. } } // namespace cc_light diff --git a/src/ql/arch/diamond/info.cc b/src/ql/arch/diamond/info.cc index c1e1f9bd1..b2710d1e7 100644 --- a/src/ql/arch/diamond/info.cc +++ b/src/ql/arch/diamond/info.cc @@ -61,15 +61,12 @@ utils::List Info::get_eqasm_compiler_names() const { * be variations for surface-5, surface-7, and surface-17. This JSON data * will still be preprocessed by preprocess_platform(). */ -utils::Str Info::get_default_platform(const utils::Str &variant) const { - +utils::Str Info::get_default_platform(const utils::Str &) const { // NOTE: based on tests/hardware_config_qx.json at the time of writing. return HWCONF_DEFAULT_DATA; - } -void Info::populate_backend_passes(pmgr::Manager &manager, const utils::Str &variant) const { - +void Info::populate_backend_passes(pmgr::Manager &manager, const utils::Str &) const { // Add the microcode generator pass manager.append_pass("arch.diamond.gen.Microcode", "diamond_codegen"); } diff --git a/src/ql/arch/info_base.cc b/src/ql/arch/info_base.cc index 0245512bf..8027fa29e 100644 --- a/src/ql/arch/info_base.cc +++ b/src/ql/arch/info_base.cc @@ -52,8 +52,8 @@ void InfoBase::dump_variant_docs( * of mistakes made). */ void InfoBase::preprocess_platform( - utils::Json &data, - const utils::Str &variant + utils::Json &, + const utils::Str & ) const { } @@ -62,8 +62,8 @@ void InfoBase::preprocess_platform( * instance add annotations with architecture-specific configuration data. */ void InfoBase::post_process_platform( - const ir::compat::PlatformRef &platform, - const utils::Str &variant + const ir::compat::PlatformRef &, + const utils::Str & ) const { } @@ -74,7 +74,7 @@ void InfoBase::post_process_platform( * code generation pass, but anything after prescheduling and optimization * is considered a backend pass. */ -void InfoBase::populate_backend_passes(pmgr::Manager &manager, const utils::Str &variant) const { +void InfoBase::populate_backend_passes(pmgr::Manager &, const utils::Str &) const { } } // namespace arch diff --git a/src/ql/arch/none/info.cc b/src/ql/arch/none/info.cc index d36d35711..182d0d28f 100644 --- a/src/ql/arch/none/info.cc +++ b/src/ql/arch/none/info.cc @@ -64,11 +64,9 @@ utils::List Info::get_eqasm_compiler_names() const { * be variations for surface-5, surface-7, and surface-17. This JSON data * will still be preprocessed by preprocess_platform(). */ -utils::Str Info::get_default_platform(const utils::Str &variant) const { - +utils::Str Info::get_default_platform(const utils::Str &) const { // NOTE: based on tests/hardware_config_qx.json at the time of writing. return HWCONF_DEFAULT_DATA; - } } // namespace none diff --git a/src/ql/com/ana/interaction_matrix.cc b/src/ql/com/ana/interaction_matrix.cc index f38065692..369288b48 100644 --- a/src/ql/com/ana/interaction_matrix.cc +++ b/src/ql/com/ana/interaction_matrix.cc @@ -56,12 +56,12 @@ Str InteractionMatrix::get_string() const { ss << ALIGNMENT << " "; for (UInt c = 0; c < size; c++) { - ss << ALIGNMENT << "q" + to_string(c); + ss << ALIGNMENT << "q" << to_string(c); } ss << std::endl; for (UInt p = 0; p < size; p++) { - ss << ALIGNMENT << "q" + to_string(p); + ss << ALIGNMENT << "q" << to_string(p); for (UInt c = 0; c < size; c++) { ss << ALIGNMENT << matrix[p][c]; } diff --git a/src/ql/com/ana/metrics.cc b/src/ql/com/ana/metrics.cc index 7ff3f5a6b..81bc32d9b 100644 --- a/src/ql/com/ana/metrics.cc +++ b/src/ql/com/ana/metrics.cc @@ -5,6 +5,7 @@ #include "ql/com/ana/metrics.h" +#include "ql/ir/ir_gen_ex.h" #include "ql/ir/ops.h" namespace ql { @@ -15,7 +16,7 @@ namespace ana { * Classical operation counting metric. */ void ClassicalOperationCount::process_instruction( - const ir::Ref &ir, + const ir::Ref &, const ir::InstructionRef &instruction ) { if (instruction->as_set_instruction() || instruction->as_goto_instruction()) { @@ -27,7 +28,7 @@ void ClassicalOperationCount::process_instruction( * Quantum gate counting metric. */ void QuantumGateCount::process_instruction( - const ir::Ref &ir, + const ir::Ref &, const ir::InstructionRef &instruction ) { if (ir::get_number_of_qubits_involved(instruction)) { @@ -39,7 +40,7 @@ void QuantumGateCount::process_instruction( * Multi-qubit gate counting metric. */ void MultiQubitGateCount::process_instruction( - const ir::Ref &ir, + const ir::Ref &, const ir::InstructionRef &instruction ) { if (ir::get_number_of_qubits_involved(instruction) > 1) { @@ -95,7 +96,7 @@ void QubitUsedCycleCount::process_instruction( /** * Returns the duration of a scheduled block in cycles. */ -void Latency::process_block(const ir::Ref &ir, const ir::BlockBaseRef &block) { +void Latency::process_block(const ir::Ref &, const ir::BlockBaseRef &block) { value = ir::get_duration_of_block(block); } diff --git a/src/ql/com/dec/structure.cc b/src/ql/com/dec/structure.cc index ff4f155b3..e5ccae1cf 100644 --- a/src/ql/com/dec/structure.cc +++ b/src/ql/com/dec/structure.cc @@ -665,7 +665,7 @@ ir::ProgramRef StructureDecomposer::process_program(const ir::Ref &incoming_ir) new_program->blocks.add(block); } - return std::move(new_program); + return new_program; } /** diff --git a/src/ql/com/dec/unitary.cc b/src/ql/com/dec/unitary.cc index 8c0141441..9c8b9fa47 100644 --- a/src/ql/com/dec/unitary.cc +++ b/src/ql/com/dec/unitary.cc @@ -10,9 +10,6 @@ #ifndef WITHOUT_UNITARY_DECOMPOSITION #include #include -#define lapack_complex_float std::complex -#define lapack_complex_double std::complex -#include #endif #include @@ -61,7 +58,7 @@ Bool Unitary::is_decompose_support_enabled() { return false; } -#else +#else /* WITHOUT_UNITARY_DECOMPOSITION */ // JvS: this was originally the class "unitary" itself, but compile times of // Eigen are so excessive that I moved it into its own compile unit and @@ -115,6 +112,16 @@ class UnitaryDecomposer { return _matrix; } + Str to_string( + const complex_matrix &m, + [[maybe_unused]] const Str &vector_prefix = "", + [[maybe_unused]] const Str &elem_sep = ", " + ) { + StrStrm ss; + ss << m << "\n"; + return ss.str(); + } + void decompose() { QL_DOUT("decomposing Unitary: " << name); @@ -142,16 +149,6 @@ class UnitaryDecomposer { decomposed = true; } - Str to_string( - const complex_matrix &m, - const Str &vector_prefix = "", - const Str &elem_sep = ", " - ) { - StrStrm ss; - ss << m << "\n"; - return ss.str(); - } - void decomp_function(const Eigen::Ref& matrix, Int numberofbits) { QL_DOUT("decomp_function: \n" << to_string(matrix)); if(numberofbits == 1) { @@ -329,7 +326,7 @@ class UnitaryDecomposer { tmp.bottomRightCorner(p,p) = u2*c*v2; // Just to see if it kinda matches if (!tmp.isApprox(U, 10e-2)) { - throw utils::Exception("CSD of unitary '"+ name+"' is wrong! Failed at matrix: \n"+to_string(tmp) + "\nwhich should be: \n" + to_string(U)); + throw utils::Exception("CSD of unitary '" + name + "' is wrong! Failed at matrix: \n" + to_string(tmp) + "\nwhich should be: \n" + to_string(U)); } } @@ -407,7 +404,7 @@ class UnitaryDecomposer { complex_matrix Dtemp = D.asDiagonal(); if (!U1.isApprox(V*Dtemp*W, 10e-2) || !U2.isApprox(V*Dtemp.adjoint()*W, 10e-2)) { QL_EOUT("Demultiplexing not correct!"); - throw utils::Exception("Demultiplexing of unitary '"+ name+"' not correct! Failed at matrix U1: \n"+to_string(U1)+ "and matrix U2: \n" +to_string(U2) + "\nwhile they are: \n" + to_string(V*D.asDiagonal()*W) + "\nand \n" + to_string(V*D.conjugate().asDiagonal()*W)); + throw utils::Exception("Demultiplexing of unitary '" + name + "' not correct! Failed at matrix U1: \n" + to_string(U1) + "and matrix U2: \n" + to_string(U2) + "\nwhile they are: \n" + to_string(V*D.asDiagonal()*W) + "\nand \n" + to_string(V*D.conjugate().asDiagonal()*W)); } } @@ -458,7 +455,7 @@ class UnitaryDecomposer { // Check is very approximate to account for low-precision input matrices if (!temp.isApprox(genMk_lookuptable[uint64_log2(halfthesizeofthematrix)-1]*tr, 10e-2)) { QL_EOUT("Multicontrolled Y not correct!"); - throw utils::Exception("Demultiplexing of unitary '"+ name+"' not correct! Failed at demultiplexing of matrix ss: \n" + to_string(ss)); + throw utils::Exception("Demultiplexing of unitary '" + name + "' not correct! Failed at demultiplexing of matrix ss: \n" + to_string(ss)); } instruction_list.insert(instruction_list.end(), &tr[0], &tr[halfthesizeofthematrix]); @@ -471,7 +468,7 @@ class UnitaryDecomposer { // Check is very approximate to account for low-precision input matrices if (!temp.isApprox(genMk_lookuptable[uint64_log2(halfthesizeofthematrix)-1]*tr, 10e-2)) { QL_EOUT("Multicontrolled Z not correct!"); - throw utils::Exception("Demultiplexing of unitary '"+ name+"' not correct! Failed at demultiplexing of matrix D: \n"+ to_string(D)); + throw utils::Exception("Demultiplexing of unitary '" + name + "' not correct! Failed at demultiplexing of matrix D: \n" + to_string(D)); } instruction_list.insert(instruction_list.end(), &tr[0], &tr[halfthesizeofthematrix]); } @@ -504,8 +501,22 @@ Bool Unitary::is_decompose_support_enabled() { return true; } -#endif +#endif /* WITHOUT_UNITARY_DECOMPOSITION */ + +#ifdef WITHOUT_UNITARY_DECOMPOSITION + +/** + * Explicitly runs the matrix decomposition algorithm. Used to be required, + * nowadays is called implicitly by get_decomposition() if not done explicitly. + */ +ir::compat::GateRefs Unitary::prepare_state(const utils::Vec &) { + throw Exception("unitary decomposition, including state preparation, was explicitly disabled in this build!"); +} +ir::compat::GateRefs Unitary::get_decomposition(const utils::Vec &) { +throw Exception("unitary decomposition, including state preparation, was explicitly disabled in this build!"); +} +#else /* WITHOUT_UNITARY_DECOMPOSITION */ //controlled qubit is the first in the list. static void multicontrolled_rz( @@ -624,28 +635,13 @@ static Int recursiveRelationsForUnitaryDecomposition( } } - -#ifdef WITHOUT_UNITARY_DECOMPOSITION - -/** - * Explicitly runs the matrix decomposition algorithm. Used to be required, - * nowadays is called implicitly by get_decomposition() if not done explicitly. - */ -ir::compat::GateRefs Unitary::prepare_state(const utils::Vec &qubits) { - throw Exception("unitary decomposition, including state preparation, was explicitly disabled in this build!"); -} -ir::compat::GateRefs Unitary::get_decomposition(const utils::Vec &qubits) { -throw Exception("unitary decomposition, including state preparation, was explicitly disabled in this build!"); -} -#else - /** * Does state preparation, results in a circuit for which A|0> = |psi> for given state psi, stored as the array in Unitary */ ir::compat::GateRefs Unitary::prepare_state(const utils::Vec &qubits){ - UInt nqubits = qubits.size(); - if (((UInt) 1) << nqubits != array.size()){ - QL_FATAL("Length of state prepatation vector does not match number of qubits! Expected vector of size " << (1 << nqubits) << " but got vector of size " << array.size()); + UInt num_qubits = qubits.size(); + if (((UInt) 1) << num_qubits != array.size()){ + QL_FATAL("Length of state prepatation vector does not match number of qubits! Expected vector of size " << (1 << num_qubits) << " but got vector of size " << array.size()); } ir::compat::GateRefs c; Vec statevector = array; @@ -673,14 +669,14 @@ ir::compat::GateRefs Unitary::prepare_state(const utils::Vec &qubit QL_DOUT("Qubits: " << qubits << " qubits.size(): " << qubits.size() << " phi: " << phi << " theta: " << theta); c.emplace(qubits.back(), theta.back()); c.emplace(qubits.back(), phi.back()); - if (nqubits > 1){ + if (num_qubits > 1){ UInt start_i = phi.size() - 3; UInt ngates; decomposer.genMk(qubits.size()); Eigen::VectorXd temp; Eigen::VectorXd tr; UInt idx; - for (UInt i = 1; i < nqubits; i++) + for (UInt i = 1; i < num_qubits; i++) { ngates = 1 << i; QL_DOUT("Sending indices " << start_i << " until " << (start_i + ngates) << " to multicontrolled z and y. i=" << i); @@ -689,31 +685,31 @@ ir::compat::GateRefs Unitary::prepare_state(const utils::Vec &qubit tr = dec.solve(temp); // The first one is always controlled from the next qubit to the last qubit - c.emplace(qubits[nqubits-i-1], tr[0]); - c.emplace(qubits[nqubits-i], qubits[nqubits-i-1]); + c.emplace(qubits[num_qubits-i-1], tr[0]); + c.emplace(qubits[num_qubits-i], qubits[num_qubits-i-1]); for (UInt j = 1; j < (ngates - 1); j++){ idx = i - log2(((j)^((j)>>1))^((j+1)^((j+1)>>1))); - c.emplace(qubits[nqubits-i-1], tr[j]); - c.emplace(qubits[nqubits-idx], qubits[nqubits-i-1]); + c.emplace(qubits[num_qubits-i-1], tr[j]); + c.emplace(qubits[num_qubits-idx], qubits[num_qubits-i-1]); } //The last one is always controlled from the first to the last qubit. - c.emplace(qubits[nqubits-i-1], tr[ngates-1]); - c.emplace(qubits[nqubits-1], qubits[nqubits-i-1]); + c.emplace(qubits[num_qubits-i-1], tr[ngates-1]); + c.emplace(qubits[num_qubits-1], qubits[num_qubits-i-1]); temp = Eigen::Map(phi.data() + start_i, ngates); tr = dec.solve(temp); // The first one is always controlled from the next qubit to the last qubit - c.emplace(qubits[nqubits-i-1], tr[0]); - c.emplace(qubits[nqubits-i], qubits[nqubits-i-1]); + c.emplace(qubits[num_qubits-i-1], tr[0]); + c.emplace(qubits[num_qubits-i], qubits[num_qubits-i-1]); for (UInt j = 1; j < (ngates-1); j++) { idx = i - log2(((j)^((j)>>1))^((j+1)^((j+1)>>1))); - c.emplace(qubits[nqubits-i-1], tr[j]); - c.emplace(qubits[nqubits-idx], qubits[nqubits-i-1]); + c.emplace(qubits[num_qubits-i-1], tr[j]); + c.emplace(qubits[num_qubits-idx], qubits[num_qubits-i-1]); } //The last one is always controlled from the first to the last qubit. - c.emplace(qubits[nqubits-i-1], tr[ngates-1]); - c.emplace(qubits[nqubits-1], qubits[nqubits-i-1]); + c.emplace(qubits[num_qubits-i-1], tr[ngates-1]); + c.emplace(qubits[num_qubits-1], qubits[num_qubits-i-1]); start_i -= 2 << i; } @@ -721,7 +717,6 @@ ir::compat::GateRefs Unitary::prepare_state(const utils::Vec &qubit return c; } - /** * Returns the decomposed circuit. */ @@ -761,7 +756,8 @@ ir::compat::GateRefs Unitary::get_decomposition(const utils::Vec &q return c; } -#endif +#endif /* WITHOUT_UNITARY_DECOMPOSITION */ + } // namespace dec } // namespace com } // namespace ql diff --git a/src/ql/com/map/expression_mapper.cc b/src/ql/com/map/expression_mapper.cc index 921c6b09e..306f305aa 100644 --- a/src/ql/com/map/expression_mapper.cc +++ b/src/ql/com/map/expression_mapper.cc @@ -31,7 +31,7 @@ utils::Bool ExpressionMapper::on_expression(utils::Maybe &expr) * reference of some kind. The default implementation is no-op and just * returns false. */ -utils::Bool ExpressionMapper::on_reference(utils::Maybe &ref) { +utils::Bool ExpressionMapper::on_reference(utils::Maybe &) { return false; } diff --git a/src/ql/com/sch/heuristics.cc b/src/ql/com/sch/heuristics.cc index 912629c33..f15362951 100644 --- a/src/ql/com/sch/heuristics.cc +++ b/src/ql/com/sch/heuristics.cc @@ -14,8 +14,8 @@ namespace sch { * Comparator implementation for TrivialHeuristic. */ utils::Bool TrivialHeuristic::operator()( - const ir::StatementRef &lhs, - const ir::StatementRef &rhs + const ir::StatementRef &, + const ir::StatementRef & ) const { return false; } @@ -24,7 +24,7 @@ utils::Bool TrivialHeuristic::operator()( * String representation for TrivialHeuristic. */ utils::Str TrivialHeuristic::operator()( - const ir::StatementRef &val + const ir::StatementRef & ) const { return "-"; } diff --git a/src/ql/com/topology.cc b/src/ql/com/topology.cc index c025b3ac9..b4e5dcac8 100644 --- a/src/ql/com/topology.cc +++ b/src/ql/com/topology.cc @@ -646,7 +646,7 @@ utils::Bool Topology::is_comm_qubit(Qubit qubit) const { // Compute index of qubit local to core. utils::UInt qubit_local_index = qubit % num_qubits_per_core; - QL_ASSERT(0 <= qubit_local_index && qubit_local_index < num_qubits_per_core); + QL_ASSERT(qubit_local_index < num_qubits_per_core); // 0..ncommqpc-1 are comm qubits, ncommqpc..nq/ncores-1 are not comm qubits. return qubit_local_index < num_comm_qubits; @@ -787,8 +787,8 @@ void Topology::sort_neighbors_by_angle(Qubit src, Neighbors &nbl) const { } // find maxinx index in neighbor list before which largest angle difference occurs - utils::Int maxdiff = 0; // current maximum angle difference in loop search below - auto maxinx = nbl.begin(); // before which max diff occurs + utils::Int maxdiff = 0; // current maximum angle difference in loop search below + auto maxinx = nbl.begin(); // before which max diff occurs // for all indices in and its next one inx compute angle difference and find largest of these for (auto in = nbl.begin(); in != nbl.end(); in++) { diff --git a/src/ql/ir/compat/detail/cqasm_reader.h b/src/ql/ir/compat/detail/cqasm_reader.h index 1894e730d..b466e9574 100644 --- a/src/ql/ir/compat/detail/cqasm_reader.h +++ b/src/ql/ir/compat/detail/cqasm_reader.h @@ -19,12 +19,12 @@ namespace detail { // Shorthands for namespaces. namespace lqt { using namespace ::cqasm::tree; } -namespace lqs { using namespace ::cqasm::semantic; } -namespace lqv { using namespace ::cqasm::values; } -namespace lqtyp { using namespace ::cqasm::types; } -namespace lqi { using namespace ::cqasm::instruction; } -namespace lqa { using namespace ::cqasm::analyzer; } -namespace lqp { using namespace ::cqasm::parser; } +namespace lqs { using namespace ::cqasm::v1x::semantic; } +namespace lqv { using namespace ::cqasm::v1x::values; } +namespace lqtyp { using namespace ::cqasm::v1x::types; } +namespace lqi { using namespace ::cqasm::v1x::instruction; } +namespace lqa { using namespace ::cqasm::v1x::analyzer; } +namespace lqp { using namespace ::cqasm::v1x::parser; } using namespace utils; diff --git a/src/ql/ir/compat/kernel.cc b/src/ql/ir/compat/kernel.cc index 01ed69ab1..dba97d79b 100644 --- a/src/ql/ir/compat/kernel.cc +++ b/src/ql/ir/compat/kernel.cc @@ -4,9 +4,10 @@ #include "ql/ir/compat/kernel.h" -#include #include #include +#include +#include #include "ql/config.h" #include "ql/utils/json.h" @@ -1199,7 +1200,7 @@ void Kernel::controlled_h(UInt tq, UInt cq) { sdag(tq); } -void Kernel::controlled_i(UInt tq, UInt cq) { +void Kernel::controlled_i(UInt, UInt) { // well, basically you dont need to do anything for it :‑) } @@ -1577,11 +1578,11 @@ void Kernel::conjugate(const Kernel &k) { } else if (gtype == GateType::SWAP) { gate("swap", g->operands, {}, g->duration, g->angle, g->breg_operands); } else if (gtype == GateType::RX) { - gate("rx", g->operands, {}, g->duration, -(g->angle) , g->breg_operands); + gate("rx", g->operands, {}, g->duration, -(g->angle), g->breg_operands); } else if (gtype == GateType::RY) { - gate("ry", g->operands, {}, g->duration, -(g->angle) , g->breg_operands); + gate("ry", g->operands, {}, g->duration, -(g->angle), g->breg_operands); } else if (gtype == GateType::RZ) { - gate("rz", g->operands, {}, g->duration, -(g->angle) , g->breg_operands); + gate("rz", g->operands, {}, g->duration, -(g->angle), g->breg_operands); } else if (gtype == GateType::RX90) { gate("mrx90", g->operands, {}, g->duration, g->angle, g->breg_operands); } else if (gtype == GateType::MRX90) { diff --git a/src/ql/ir/consistency.cc b/src/ql/ir/consistency.cc index c0d34bf09..32b32bf94 100644 --- a/src/ql/ir/consistency.cc +++ b/src/ql/ir/consistency.cc @@ -138,7 +138,7 @@ class ConsistencyChecker : public RecursiveVisitor { * Behavior for unknown node types. Assume that means that no check is * needed. */ - void visit_node(Node &node) override { + void visit_node(Node &) override { } /** @@ -738,7 +738,7 @@ class ConsistencyChecker : public RecursiveVisitor { /** * Ensures that no sentinels have popped up in the IR. */ - void visit_sentinel_statement(SentinelStatement &node) override { + void visit_sentinel_statement(SentinelStatement &) override { QL_ASSERT(false); } diff --git a/src/ql/ir/cqasm/read.cc b/src/ql/ir/cqasm/read.cc index 039b3198d..1c8b6eb2e 100644 --- a/src/ql/ir/cqasm/read.cc +++ b/src/ql/ir/cqasm/read.cc @@ -11,17 +11,19 @@ #include "ql/ir/old_to_new.h" #include "ql/com/ddg/build.h" #include "cqasm.hpp" +#include "cqasm-version.hpp" namespace ql { namespace ir { namespace cqasm { -namespace cq = ::cqasm::v1; -namespace cqv = ::cqasm::v1::values; -namespace cqty = ::cqasm::v1::types; -namespace cqs = ::cqasm::semantic; +namespace cq1 = ::cqasm::v1x; +namespace cqv1 = ::cqasm::v1x::values; +namespace cqty1 = ::cqasm::v1x::types; +namespace cqs = ::cqasm::v1x::semantic; namespace cqt = ::cqasm::tree; namespace cqe = ::cqasm::error; +namespace cqver = ::cqasm::version; /** * Marker used on cQASM nodes when they have been successfully used by @@ -35,30 +37,30 @@ struct Used{}; * libqasm should allow values of this type to be assigned. For qubits this is * always true, for other types it defaults to false. */ -static cqty::Type make_cq_type( +static cqty1::Type make_cq_type( const DataTypeLink &ql_type, utils::Bool assignable = false ) { - cqty::Type cq_type; + cqty1::Type cq_type; if (ql_type->as_qubit_type()) { - cq_type.emplace(); + cq_type.emplace(); assignable = true; } else if (ql_type->as_bit_type()) { - cq_type.emplace(); + cq_type.emplace(); } else if (ql_type->as_int_type()) { - cq_type.emplace(); + cq_type.emplace(); } else if (ql_type->as_real_type()) { - cq_type.emplace(); + cq_type.emplace(); } else if (ql_type->as_complex_type()) { - cq_type.emplace(); + cq_type.emplace(); } else if (auto rmat = ql_type->as_real_matrix_type()) { - cq_type.emplace(rmat->num_rows, rmat->num_cols); + cq_type.emplace(rmat->num_rows, rmat->num_cols); } else if (auto cmat = ql_type->as_complex_matrix_type()) { - cq_type.emplace(cmat->num_rows, cmat->num_cols); + cq_type.emplace(cmat->num_rows, cmat->num_cols); } else if (ql_type->as_string_type()) { - cq_type.emplace(); + cq_type.emplace(); } else if (ql_type->as_json_type()) { - cq_type.emplace(); + cq_type.emplace(); } else { QL_ASSERT(false); } @@ -70,7 +72,7 @@ static cqty::Type make_cq_type( /** * Converts an operand type from the IR to a cQASM type. */ -static cqty::Type make_cq_op_type(const utils::One &ql_op_type) { +static cqty1::Type make_cq_op_type(const utils::One &ql_op_type) { switch (ql_op_type->mode) { case prim::OperandMode::READ: case prim::OperandMode::LITERAL: @@ -84,12 +86,12 @@ static cqty::Type make_cq_op_type(const utils::One &ql_op_type) { * Makes a reference to a register, modelled as a builtin function call with the * indices as its operands. */ -static cqv::Value make_cq_register_ref( +static cqv1::Value make_cq_register_ref( const ObjectLink &ql_obj, - const cqv::Values &cq_indices, + const cqv1::Values &cq_indices, utils::Bool assignable = true ) { - cqv::Value cq_val = cqt::make( + cqv1::Value cq_val = cqt::make( ql_obj->name, cq_indices, make_cq_type(ql_obj->data_type, assignable) @@ -103,9 +105,9 @@ static cqv::Value make_cq_register_ref( * Makes a reference to an operand, modelled as a builtin function call with the * operand index as its operand. */ -static cqv::Value make_cq_operand_ref( +static cqv1::Value make_cq_operand_ref( const utils::Vec> &ql_operands, - const cqv::Value &cq_index + const cqv1::Value &cq_index ) { // Select the operand based on the index. @@ -133,7 +135,7 @@ static cqv::Value make_cq_operand_ref( } // Return the appropriate reference. - return make_cq_register_ref(ql_obj, cqv::Values(), assignable); + return make_cq_register_ref(ql_obj, cqv1::Values(), assignable); } /** @@ -148,7 +150,7 @@ static cqt::Maybe find_pragma( public: utils::Str operation; cqt::Maybe data; - void visit_node(cqs::Node &node) override { + void visit_node(cqs::Node &) override { } void visit_instruction(cqs::Instruction &node) override { if (!data.empty()) return; @@ -173,13 +175,13 @@ static cqt::Maybe find_pragma( */ static utils::RawPtr find_annotation( const cqt::One &node, - const utils::Str &operation + const utils::Str & ) { class FindAnnotation : public cqs::RecursiveVisitor { public: utils::Str operation; utils::RawPtr data; - void visit_node(cqs::Node &node) override { + void visit_node(cqs::Node &) override { } void visit_annotation_data(cqs::AnnotationData &node) override { if (data) return; @@ -216,7 +218,7 @@ static utils::RawPtr find_annotation( static void check_all_annotations_used(const cqt::One &node) { class FindAnnotation : public cqs::RecursiveVisitor { public: - void visit_node(cqs::Node &node) override { + void visit_node(cqs::Node &) override { } void visit_annotation_data(cqs::AnnotationData &node) override { if (node.interface == "ql") { @@ -292,7 +294,7 @@ DataTypeLink parse_type_annotation( /** * Infers a matching OpenQL type for the given cQASM type. */ -DataTypeLink infer_ql_type(const Ref &ir, const cqty::Type &cq_type) { +DataTypeLink infer_ql_type(const Ref &ir, const cqty1::Type &cq_type) { if (cq_type->as_qubit()) { return ir->platform->qubits->data_type; } else if (cq_type->as_bool()) { @@ -359,7 +361,7 @@ find_last_goto_instruction(const cqt::One &subcircuit) { public: utils::RawPtr goto_insn; utils::Bool only_insn = true; - void visit_node(cqs::Node &node) override { + void visit_node(cqs::Node &) override { } void visit_instruction_base(cqs::InstructionBase &node) override { if (auto insn = node.as_instruction()) { @@ -377,7 +379,7 @@ find_last_goto_instruction(const cqt::One &subcircuit) { only_insn = false; goto_insn.reset(); } - void visit_structured(cqs::Structured &node) override { + void visit_structured(cqs::Structured &) override { only_insn = false; goto_insn.reset(); } @@ -402,7 +404,7 @@ find_last_goto_instruction(const cqt::One &subcircuit) { * Converts a qubit/bit index to a static unsigned integer. */ static utils::UInt convert_index( - const cqv::Value &cq_expr + const cqv1::Value &cq_expr ) { if (auto ci = cq_expr->as_const_int()) { if (ci->value < 0) { @@ -424,7 +426,7 @@ static utils::UInt convert_index( */ static ExpressionRef convert_expression( const Ref &ir, - const cqv::Value &cq_expr, + const cqv1::Value &cq_expr, utils::UInt sgmq_size = 1, utils::UInt sgmq_index = 0 ) { @@ -445,7 +447,7 @@ static ExpressionRef convert_expression( return make_int_lit(ir, ci->value, as_type); } else if (auto cr = cq_expr->as_const_real()) { if (as_type.empty()) { - as_type = infer_ql_type(ir, cqv::type_of(cq_expr)); + as_type = infer_ql_type(ir, cqv1::type_of(cq_expr)); } if (!as_type->as_real_type()) { QL_USER_ERROR("cannot cast real number to type " << as_type->name); @@ -453,7 +455,7 @@ static ExpressionRef convert_expression( return utils::make(cr->value, as_type); } else if (auto cc = cq_expr->as_const_complex()) { if (as_type.empty()) { - as_type = infer_ql_type(ir, cqv::type_of(cq_expr)); + as_type = infer_ql_type(ir, cqv1::type_of(cq_expr)); } if (!as_type->as_complex_type()) { QL_USER_ERROR("cannot cast complex number to type " << as_type->name); @@ -461,7 +463,7 @@ static ExpressionRef convert_expression( return utils::make(cc->value, as_type); } else if (auto crm = cq_expr->as_const_real_matrix()) { if (as_type.empty()) { - as_type = infer_ql_type(ir, cqv::type_of(cq_expr)); + as_type = infer_ql_type(ir, cqv1::type_of(cq_expr)); } if (auto rmt = as_type->as_real_matrix_type()) { if (rmt->num_rows != crm->value.size_rows() || rmt->num_cols != crm->value.size_cols()) { @@ -476,7 +478,7 @@ static ExpressionRef convert_expression( ); } else if (auto ccm = cq_expr->as_const_complex_matrix()) { if (as_type.empty()) { - as_type = infer_ql_type(ir, cqv::type_of(cq_expr)); + as_type = infer_ql_type(ir, cqv1::type_of(cq_expr)); } if (auto cmt = as_type->as_complex_matrix_type()) { if (cmt->num_rows != ccm->value.size_rows() || cmt->num_cols != ccm->value.size_cols()) { @@ -491,7 +493,7 @@ static ExpressionRef convert_expression( ); } else if (auto cs = cq_expr->as_const_string()) { if (as_type.empty()) { - as_type = infer_ql_type(ir, cqv::type_of(cq_expr)); + as_type = infer_ql_type(ir, cqv1::type_of(cq_expr)); } if (!as_type->as_string_type()) { QL_USER_ERROR("cannot cast string to type " << as_type->name); @@ -499,7 +501,7 @@ static ExpressionRef convert_expression( return utils::make(cs->value, as_type); } else if (auto cj = cq_expr->as_const_json()) { if (as_type.empty()) { - as_type = infer_ql_type(ir, cqv::type_of(cq_expr)); + as_type = infer_ql_type(ir, cqv1::type_of(cq_expr)); } if (!as_type->as_json_type()) { QL_USER_ERROR("cannot cast JSON to type " << as_type->name); @@ -563,7 +565,7 @@ static ExpressionRef convert_expression( if (auto ql_type = fn->get_annotation_ptr()) { ref->data_type = *ql_type; } - return std::move(ref); + return ref; } else { @@ -1052,10 +1054,10 @@ static void convert_block( * Loads a platform from the `@ql.platform` annotation in the given parse * result. */ -static ir::compat::PlatformRef load_platform(const cq::parser::ParseResult &pres) { +static ir::compat::PlatformRef load_platform(const cq1::parser::ParseResult &pres) { // Look for the annotation. - cqt::One platform_annot_operands; + cqt::One platform_annot_operands; if (auto prog = pres.root->as_program()) { for (const auto &stmt : prog->statements->items) { auto bun = stmt->as_bundle(); @@ -1119,7 +1121,7 @@ static ir::compat::PlatformRef load_platform(const cq::parser::ParseResult &pres * the filename if one exists for the purpose of generating better error * messages. */ -void read( +void read_v1( const Ref &ir, const utils::Str &data, const utils::Str &fname, @@ -1127,10 +1129,10 @@ void read( ) { // Start by parsing the file without analysis. - auto pres = cq::parser::parse_string(data, fname); + auto pres = cq1::parser::parse_string(data, fname); if (!pres.errors.empty()) { utils::StrStrm errors; - errors << "failed to parse " << fname << " for the following reasons:"; + errors << "failed to parse '" << data << "' for the following reasons:"; for (const auto &error : pres.errors) { QL_EOUT(error); errors << "\n " << error; @@ -1147,7 +1149,7 @@ void read( } // Create an analyzer for files with a version up to cQASM 1.2. - cq::analyzer::Analyzer a{"1.2"}; + cq1::analyzer::Analyzer a{"1.2"}; // Add the default constant-propagation functions and mappings such as true // and false. @@ -1164,7 +1166,7 @@ void read( a.register_function( dt->name, {make_cq_type(dt)}, - [dt](const cqv::Values &ops) -> cqv::Value { + [dt](const cqv1::Values &ops) -> cqv1::Value { ops[0]->set_annotation(dt); return ops[0]; } @@ -1175,12 +1177,12 @@ void read( a.register_function( ir->platform->default_bit_type->name, {make_cq_type(ir->platform->qubits->data_type)}, - [ir](const cqv::Values &ops) -> cqv::Value { + [ir](const cqv1::Values &ops) -> cqv1::Value { if (auto qrefs = ops[0]->as_qubit_refs()) { - auto brefs = cqt::make(); + auto brefs = cqt::make(); brefs->index = qrefs->index; brefs->set_annotation(ir->platform->default_bit_type); - return std::move(brefs); + return brefs; } else if (auto fun = ops[0]->as_function()) { fun->return_type = make_cq_type(ir->platform->default_bit_type); ops[0]->set_annotation(ir->platform->default_bit_type); @@ -1202,11 +1204,11 @@ void read( if (obj->shape.size() != 1) { QL_ICE("main qubit register must be one-dimensional"); } - auto q = cqt::make(); - auto b = cqt::make(); + auto q = cqt::make(); + auto b = cqt::make(); for (utils::UInt i = 0; i < obj->shape[0]; i++) { - q->index.add(cqt::make(i)); - b->index.add(cqt::make(i)); + q->index.add(cqt::make(i)); + b->index.add(cqt::make(i)); } a.register_mapping("q", q); a.register_mapping("b", b); @@ -1217,11 +1219,11 @@ void read( // for each index dimension. The function always returns a builtin // function call object, which we'll convert to the appropriate // register reference after libqasm's analysis. - cqty::Types types; + cqty1::Types types; for (utils::UInt i = 0; i < obj->shape.size(); i++) { - types.emplace(); + types.emplace(); } - a.register_function(obj->name, types, [obj](const cqv::Values &ops) -> cqv::Value { + a.register_function(obj->name, types, [obj](const cqv1::Values &ops) -> cqv1::Value { return make_cq_register_ref(obj, ops); }); @@ -1238,9 +1240,9 @@ void read( // NB: this is to support new style instruction decomposition, where op(n) refers // to the actual operands of an instruction. if (!options.operands.empty()) { - cqty::Types types; - types.emplace(); - a.register_function("op", types, [options](const cqv::Values &ops) -> cqv::Value { + cqty1::Types types; + types.emplace(); + a.register_function("op", types, [options](const cqv1::Values &ops) -> cqv1::Value { return make_cq_operand_ref(options.operands, ops[0]); }); } @@ -1256,12 +1258,12 @@ void read( // Note: these functions are added using calls to 'add_function_type()' in // 'Ref convert_old_to_new(const compat::PlatformRef &old)' for (const auto &fun : ir->platform->functions) { - cqty::Types cq_types; + cqty1::Types cq_types; for (const auto &ql_op_type : fun->operand_types) { cq_types.add(make_cq_op_type(ql_op_type)); } - a.register_function(fun->name, cq_types, [fun](const cqv::Values &ops) -> cqv::Value { - cqv::Value cq_val = cqt::make( + a.register_function(fun->name, cq_types, [fun](const cqv1::Values &ops) -> cqv1::Value { + cqv1::Value cq_val = cqt::make( fun->name, ops, make_cq_type(fun->return_type) @@ -1279,7 +1281,7 @@ void read( auto res = a.analyze(pres); if (!res.errors.empty()) { utils::StrStrm errors; - errors << "failed to analyze " << fname << " for the following reasons:"; + errors << "failed to analyze '" << data << "' for the following reasons:"; for (const auto &error : res.errors) { QL_EOUT(error); errors << "\n " << error; @@ -1514,6 +1516,24 @@ void read( } +/** + * Reads a cQASM file into the IR. + * If reading is successful, ir->program is completely replaced. + * data represents the cQASM file contents, + * fname specifies the filename if one exists for the purpose of generating better error messages. + */ +void read( + const Ref &ir, + const utils::Str &data, + const utils::Str &fname, + const ReadOptions &options +) { + auto pres = cqver::parse_string(data, fname); + if (auto version = cqver::parse_string(data, fname); version <= cqver::Version("1.2")) { + read_v1(ir, data, fname, options); + } +} + /** * Same as read(), but given a file to load, rather than loading from a string. */ @@ -1537,7 +1557,7 @@ ir::compat::PlatformRef read_platform( ) { // Read the file without analyzing it. - auto pres = cq::parser::parse_string(data, fname); + auto pres = cq1::parser::parse_string(data, fname); if (!pres.errors.empty()) { utils::StrStrm errors; errors << "failed to parse " << fname << " for the following reasons:"; diff --git a/src/ql/ir/cqasm/write.cc b/src/ql/ir/cqasm/write.cc index 9fbad84dd..de01beec2 100644 --- a/src/ql/ir/cqasm/write.cc +++ b/src/ql/ir/cqasm/write.cc @@ -4,11 +4,12 @@ #include "ql/ir/cqasm/write.h" -#include "ql/version.h" -#include "ql/ir/ops.h" #include "ql/ir/describe.h" +#include "ql/ir/ir_gen_ex.h" #include "ql/ir/operator_info.h" +#include "ql/ir/ops.h" #include "ql/pass/ana/statistics/report.h" +#include "ql/version.h" namespace ql { namespace ir { @@ -813,7 +814,7 @@ class Writer : public Visitor { /** * Visitor function for `BreakStatement` nodes. */ - void visit_break_statement(BreakStatement &node) override { + void visit_break_statement(BreakStatement &) override { if (!version_at_least({1, 2})) { QL_USER_ERROR("control-flow is not supported until cQASM 1.2"); } @@ -823,7 +824,7 @@ class Writer : public Visitor { /** * Visitor function for `ContinueStatement` nodes. */ - void visit_continue_statement(ContinueStatement &node) override { + void visit_continue_statement(ContinueStatement &) override { if (!version_at_least({1, 2})) { QL_USER_ERROR("control-flow is not supported until cQASM 1.2"); } diff --git a/src/ql/ir/describe.cc b/src/ql/ir/describe.cc index 74c943342..d11dd0af6 100644 --- a/src/ql/ir/describe.cc +++ b/src/ql/ir/describe.cc @@ -51,7 +51,7 @@ class DescribingVisitor : public Visitor { */ explicit DescribingVisitor(std::ostream &ss) : ss(ss) {}; - void visit_node(Node &node) override { + void visit_node(Node &) override { ss << ""; } @@ -243,19 +243,19 @@ class DescribingVisitor : public Visitor { ss << ") ..."; } - void visit_loop(Loop &loop) override { + void visit_loop(Loop &) override { ss << "loop ..."; } - void visit_break_statement(BreakStatement &break_statement) override { + void visit_break_statement(BreakStatement &) override { ss << "break"; } - void visit_continue_statement(ContinueStatement &continue_statementn) override { + void visit_continue_statement(ContinueStatement &) override { ss << "continue"; } - void visit_sentinel_statement(SentinelStatement &source_instruction) override { + void visit_sentinel_statement(SentinelStatement &) override { ss << "SENTINEL"; } diff --git a/src/ql/ir/ir_gen_ex.cc b/src/ql/ir/ir_gen_ex.cc new file mode 100644 index 000000000..9290f4e45 --- /dev/null +++ b/src/ql/ir/ir_gen_ex.cc @@ -0,0 +1,30 @@ +#include "ql/ir/ir_gen_ex.h" + +// These set of functions are used to disambiguate in cases where the compiler cannot decide +// between the operator== implementation and the synthesized version with reverse parameter order + +namespace ql { +namespace ir { + +bool operator==(const utils::Link &lhs, const utils::Link &rhs) { + return (lhs->name == rhs->name && + lhs->data_type == rhs->data_type && + lhs->shape == rhs->shape); +} + +bool operator==(const utils::Link &lhs, const utils::Link &rhs) { + return (lhs->name == rhs->name && + lhs->data_type == rhs->data_type && + lhs->shape == rhs->shape); +} + +bool operator==(const utils::tree::base::One &lhs, const utils::tree::base::One &rhs) { + return lhs.get_ptr() == rhs.get_ptr(); +} + +bool operator==(const utils::tree::base::One &lhs, const utils::tree::base::One &rhs) { + return lhs.get_ptr() == rhs.get_ptr(); +} + +} // namespace ir +} // namespace ql diff --git a/src/ql/ir/new_to_old.cc b/src/ql/ir/new_to_old.cc index 8c8282e5f..efcb91d9c 100644 --- a/src/ql/ir/new_to_old.cc +++ b/src/ql/ir/new_to_old.cc @@ -5,10 +5,11 @@ #include "ql/ir/new_to_old.h" +#include "ql/arch/diamond/annotations.h" +#include "ql/ir/describe.h" +#include "ql/ir/ir_gen_ex.h" #include "ql/ir/old_to_new.h" #include "ql/ir/ops.h" -#include "ql/ir/describe.h" -#include "ql/arch/diamond/annotations.h" // uncomment next line to enable multi-line dumping // #define MULTI_LINE_LOG_DEBUG diff --git a/src/ql/ir/old_to_new.cc b/src/ql/ir/old_to_new.cc index 3722270ad..b9e629ace 100644 --- a/src/ql/ir/old_to_new.cc +++ b/src/ql/ir/old_to_new.cc @@ -193,7 +193,7 @@ static void parse_decomposition_rule( cqasm::ReadOptions read_options; read_options.schedule_mode = cqasm::ScheduleMode::KEEP; for (const auto &operand_type : ityp->operand_types) { - utils::Bool assignable; + utils::Bool assignable{ false }; switch (operand_type->mode) { case prim::OperandMode::BARRIER: case prim::OperandMode::WRITE: @@ -218,7 +218,7 @@ static void parse_decomposition_rule( // for the result. Obviously, we don't want that. So we make our own root // tree with the platform half shared, and nothing in the program node. auto rule_ir = utils::make(ir->platform); - cqasm::read(rule_ir, cqasm.str(), "<" + description.str() + ">", read_options); + cqasm::read_v1(rule_ir, cqasm.str(), "<" + description.str() + ">", read_options); // Copy the temporary variables declared in the cQASM program to the // decomposition rule. diff --git a/src/ql/ir/ops.cc b/src/ql/ir/ops.cc index bd7366a61..e284fdcb9 100644 --- a/src/ql/ir/ops.cc +++ b/src/ql/ir/ops.cc @@ -927,7 +927,7 @@ ObjectLink make_temporary( ) { auto obj = utils::make("", data_type, shape); ir->program->objects.add(obj); - return std::move(obj); + return obj; } /** diff --git a/src/ql/ir/prim.cc b/src/ql/ir/prim.cc index 5d6b78ffc..454414671 100644 --- a/src/ql/ir/prim.cc +++ b/src/ql/ir/prim.cc @@ -355,11 +355,11 @@ std::ostream &operator<<(std::ostream &os, const Architecture &arch) { //============================================================================== template <> -void serialize(const ResourceManager &obj, utils::tree::cbor::MapWriter &map) { +void serialize(const ResourceManager &, utils::tree::cbor::MapWriter &) { } template <> -ResourceManager deserialize(const utils::tree::cbor::MapReader &map) { +ResourceManager deserialize(const utils::tree::cbor::MapReader &) { return ResourceManager(); } diff --git a/src/ql/pass/ana/statistics/clean.cc b/src/ql/pass/ana/statistics/clean.cc index 1841ef8e4..c00b50d86 100644 --- a/src/ql/pass/ana/statistics/clean.cc +++ b/src/ql/pass/ana/statistics/clean.cc @@ -49,7 +49,7 @@ CleanStatisticsPass::CleanStatisticsPass( */ utils::Int CleanStatisticsPass::run( const ir::Ref &ir, - const pmgr::pass_types::Context &context + const pmgr::pass_types::Context & ) const { if (!ir->program.empty()) { for (const auto &kernel : ir->program->blocks) { diff --git a/src/ql/pass/ana/visualize/circuit.cc b/src/ql/pass/ana/visualize/circuit.cc index 39e5c4533..9db61af5e 100644 --- a/src/ql/pass/ana/visualize/circuit.cc +++ b/src/ql/pass/ana/visualize/circuit.cc @@ -363,12 +363,12 @@ VisualizeCircuitPass::VisualizeCircuitPass( /** * Runs the circuit visualizer. */ +#ifdef WITH_VISUALIZER + utils::Int VisualizeCircuitPass::run( const ir::Ref &ir, const pmgr::pass_types::Context &context ) const { - -#ifdef WITH_VISUALIZER detail::visualizeCircuit( ir, { "CIRCUIT", @@ -380,7 +380,14 @@ utils::Int VisualizeCircuitPass::run( } ); return 0; -#else +} + +#else /* WITH_VISUALIZER */ + +utils::Int VisualizeCircuitPass::run( + const ir::Ref &, + const pmgr::pass_types::Context & +) const { QL_EOUT( "The visualizer was disabled during compilation of OpenQL. If this was " "not intended, and OpenQL is running on Linux or Mac, the X11 library " @@ -388,9 +395,10 @@ utils::Int VisualizeCircuitPass::run( "itself." ); return -1; -#endif } +#endif /* WITH_VISUALIZER */ + } // namespace circuit } // namespace visualize } // namespace ana diff --git a/src/ql/pass/ana/visualize/detail/circuit.cc b/src/ql/pass/ana/visualize/detail/circuit.cc index f1cb61e38..1b71f4470 100644 --- a/src/ql/pass/ana/visualize/detail/circuit.cc +++ b/src/ql/pass/ana/visualize/detail/circuit.cc @@ -38,7 +38,7 @@ Vec CircuitData::generateCycles(Vec &gates) const { // Calculate the amount of cycles. If there are gates with undefined cycle // indices, visualize the circuit sequentially. - Vec cycles; + Vec cycles{}; Int amountOfCycles = calculateAmountOfCycles(gates); // Generate the cycles. @@ -50,7 +50,7 @@ Vec CircuitData::generateCycles(Vec &gates) const { const Vec> firstChunk; partition.push_back(firstChunk); - cycles.push_back({i, true, false, partition}); + cycles.emplace_back(i, true, false, partition); } // Mark non-empty cycles and add gates to their corresponding cycles. for (GateProperties &gate : gates) { @@ -294,7 +294,7 @@ Int Structure::calculateCellHeight(const CircuitLayout &layout) const { } } -Int Structure::calculateImageWidth(const CircuitData &circuitData) const { +Int Structure::calculateImageWidth(const CircuitData &) const { QL_DOUT("Calculating image width..."); const Int amountOfCells = utoi(qbitCellPositions.size()); @@ -1466,7 +1466,7 @@ void drawBitLine(Image &image, const CircuitLayout &layout, const BitType bitType, const Int row, - const CircuitData &circuitData, + const CircuitData &, const Structure &structure) { Color bitLineColor; Color bitLabelColor; @@ -1801,7 +1801,7 @@ void drawGate(Image &image, } void drawGateNode(Image &image, - const CircuitLayout &layout, + const CircuitLayout &, const Structure &structure, const Node &node, const Cell &cell) { @@ -1827,7 +1827,7 @@ void drawGateNode(Image &image, } void drawControlNode(Image &image, - const CircuitLayout &layout, + const CircuitLayout &, const Structure &structure, const Node &node, const Cell &cell) { @@ -1841,7 +1841,7 @@ void drawControlNode(Image &image, } void drawNotNode(Image &image, - const CircuitLayout &layout, + const CircuitLayout &, const Structure &structure, const Node &node, const Cell &cell) { @@ -1870,7 +1870,7 @@ void drawNotNode(Image &image, } void drawCrossNode(Image &image, - const CircuitLayout &layout, + const CircuitLayout &, const Structure &structure, const Node &node, const Cell &cell) { diff --git a/src/ql/pass/ana/visualize/detail/circuit.h b/src/ql/pass/ana/visualize/detail/circuit.h index 853267326..39eca49a1 100644 --- a/src/ql/pass/ana/visualize/detail/circuit.h +++ b/src/ql/pass/ana/visualize/detail/circuit.h @@ -23,12 +23,16 @@ namespace visualize { namespace detail { struct Cycle { + using GatePropertiesMatrix = utils::Vec>>; + utils::Int index; utils::Bool empty; utils::Bool cut; - utils::Vec>> gates; + GatePropertiesMatrix gates; - Cycle() = delete; + Cycle(utils::Int i, utils::Bool e, utils::Bool c, GatePropertiesMatrix g) + : index{ i }, empty{ e }, cut{ c }, gates{ std::move(g) } + {} }; struct Cell { @@ -67,7 +71,9 @@ struct GatePulses { utils::Vec flux; utils::Vec readout; - GatePulses() = delete; + GatePulses(utils::Vec m, utils::Vec f, utils::Vec r) + : microwave{ std::move(m) }, flux{ std::move(f) }, readout{ std::move(r) } + {} }; struct PulseVisualization { diff --git a/src/ql/pass/ana/visualize/detail/common.cc b/src/ql/pass/ana/visualize/detail/common.cc index b2e092cb4..d694904c3 100644 --- a/src/ql/pass/ana/visualize/detail/common.cc +++ b/src/ql/pass/ana/visualize/detail/common.cc @@ -6,10 +6,12 @@ #include "common.h" -#include -#include "ql/utils/json.h" #include "ql/com/options.h" #include "ql/ir/ir.h" +#include "ql/ir/ir_gen_ex.h" +#include "ql/utils/json.h" + +#include namespace ql { namespace pass { @@ -23,9 +25,9 @@ class GateCollector : public ir::RecursiveVisitor { public: GateCollector(const ir::PlatformRef& platform, Vec& gates) : ir::RecursiveVisitor(), platform(platform), gates(gates) {} - void visit_node(ir::Node &node) override {} + void visit_node(ir::Node &) override {} - void visit_platform(ir::Platform &platform) override {} + void visit_platform(ir::Platform &) override {} void visit_conditional_instruction(ir::ConditionalInstruction &cond_instr) override { if (!cond_instr.condition->as_bit_literal() || !cond_instr.condition->as_bit_literal()->value) { @@ -36,7 +38,7 @@ class GateCollector : public ir::RecursiveVisitor { ir::RecursiveVisitor::visit_conditional_instruction(cond_instr); } - void visit_structured(ir::Structured &structured) override { + void visit_structured(ir::Structured &) override { QL_FATAL("Visualizer doesn't support structured blocks (loops, if/else)"); } diff --git a/src/ql/pass/ana/visualize/detail/mapping.h b/src/ql/pass/ana/visualize/detail/mapping.h index 39335c3be..c50545daf 100644 --- a/src/ql/pass/ana/visualize/detail/mapping.h +++ b/src/ql/pass/ana/visualize/detail/mapping.h @@ -23,6 +23,10 @@ struct Edge { utils::Int dst; Edge() = delete; + Edge(utils::Int src_, utils::Int dst_) + : src{ src_ } + , dst{ dst_ } + {} }; struct Topology { diff --git a/src/ql/pass/ana/visualize/detail/types.h b/src/ql/pass/ana/visualize/detail/types.h index 60215e7a2..193810f81 100644 --- a/src/ql/pass/ana/visualize/detail/types.h +++ b/src/ql/pass/ana/visualize/detail/types.h @@ -70,6 +70,12 @@ struct Position4 { utils::Int y1; Position4() = delete; + Position4(utils::Int x0_, utils::Int y0_, utils::Int x1_, utils::Int y1_) + : x0{ x0_ } + , y0{ y0_ } + , x1{ x1_ } + , y1{ y1_ } + {} }; struct Position2 { @@ -77,6 +83,10 @@ struct Position2 { utils::Int y; Position2() = delete; + Position2(utils::Int x_, utils::Int y_) + : x{ x_ } + , y{ y_ } + {} }; struct EndPoints { @@ -84,6 +94,10 @@ struct EndPoints { utils::Int end; EndPoints() = delete; + EndPoints(utils::Int start_, utils::Int end_) + : start{ start_ } + , end{ end_ } + {} }; struct Dimensions { @@ -91,6 +105,10 @@ struct Dimensions { utils::Int height; Dimensions() = delete; + Dimensions(utils::Int width_, utils::Int height_) + : width{ width_ } + , height{ height_ } + {} }; struct GateOperand { @@ -108,6 +126,10 @@ struct GateOperand { friend utils::Bool operator>=(const GateOperand &lhs, const GateOperand &rhs) {return !operator<(lhs, rhs);} GateOperand() = delete; + GateOperand(BitType bitType_, utils::Int index_) + : bitType{ bitType_ } + , index{ index_ } + {} }; struct GateProperties { @@ -121,6 +143,25 @@ struct GateProperties { utils::Str visual_type; GateProperties() = delete; + GateProperties( + utils::Str name_, + utils::Vec operands_, + utils::Vec creg_operands_, + ir::SwapParameters swap_params_, + utils::Int durationInCycles_, + utils::Int cycle_, + utils::Vec codewords_, + utils::Str visual_type_) + + : name{ std::move(name_) } + , operands{ std::move(operands_) } + , creg_operands{ std::move(creg_operands_) } + , swap_params{ std::move(swap_params_) } + , durationInCycles{ durationInCycles_ } + , cycle{ cycle_ } + , codewords{ std::move(codewords_) } + , visual_type{ std::move(visual_type_) } + {} }; // ------------- Layout declaration -------------- // diff --git a/src/ql/pass/ana/visualize/interaction.cc b/src/ql/pass/ana/visualize/interaction.cc index 9fa42f40d..a3d0a09b0 100644 --- a/src/ql/pass/ana/visualize/interaction.cc +++ b/src/ql/pass/ana/visualize/interaction.cc @@ -112,12 +112,12 @@ VisualizeInteractionPass::VisualizeInteractionPass( /** * Runs the interaction graph visualizer. */ +#ifdef WITH_VISUALIZER + utils::Int VisualizeInteractionPass::run( const ir::Ref &ir, const pmgr::pass_types::Context &context ) const { - -#ifdef WITH_VISUALIZER detail::visualizeInteractionGraph( ir, { "INTERACTION_GRAPH", @@ -129,7 +129,14 @@ utils::Int VisualizeInteractionPass::run( } ); return 0; -#else +} + +#else /* WITH_VISUALIZER */ + +utils::Int VisualizeInteractionPass::run( + const ir::Ref &, + const pmgr::pass_types::Context & +) const { QL_EOUT( "The visualizer was disabled during compilation of OpenQL. If this was " "not intended, and OpenQL is running on Linux or Mac, the X11 library " @@ -137,9 +144,10 @@ utils::Int VisualizeInteractionPass::run( "itself." ); return -1; -#endif } +#endif /* WITH_VISUALIZER */ + } // namespace interaction } // namespace visualize } // namespace ana diff --git a/src/ql/pass/ana/visualize/mapping.cc b/src/ql/pass/ana/visualize/mapping.cc index ecc2182d4..5cd4b297a 100644 --- a/src/ql/pass/ana/visualize/mapping.cc +++ b/src/ql/pass/ana/visualize/mapping.cc @@ -123,12 +123,12 @@ VisualizeMappingPass::VisualizeMappingPass( /** * Runs the mapping graph visualizer. */ +#ifdef WITH_VISUALIZER + utils::Int VisualizeMappingPass::run( const ir::Ref &ir, const pmgr::pass_types::Context &context ) const { - -#ifdef WITH_VISUALIZER detail::visualizeMappingGraph( ir, { "MAPPING_GRAPH", @@ -140,7 +140,14 @@ utils::Int VisualizeMappingPass::run( } ); return 0; -#else +} + +#else /* WITH_VISUALIZER */ + +utils::Int VisualizeMappingPass::run( + const ir::Ref &, + const pmgr::pass_types::Context & +) const { QL_EOUT( "The visualizer was disabled during compilation of OpenQL. If this was " "not intended, and OpenQL is running on Linux or Mac, the X11 library " @@ -148,9 +155,10 @@ utils::Int VisualizeMappingPass::run( "itself." ); return -1; -#endif } +#endif /* WITH_VISUALIZER */ + } // namespace mapping } // namespace visualize } // namespace ana diff --git a/src/ql/pass/dec/generalize/generalize.cc b/src/ql/pass/dec/generalize/generalize.cc index 6cb203050..05cbd8877 100644 --- a/src/ql/pass/dec/generalize/generalize.cc +++ b/src/ql/pass/dec/generalize/generalize.cc @@ -78,7 +78,7 @@ void GeneralizeInstructionsPass::run_on_block( */ utils::Int GeneralizeInstructionsPass::run( const ir::Ref &ir, - const pmgr::pass_types::Context &context + const pmgr::pass_types::Context &/* context */ ) const { if (!ir->program.empty()) { for (const auto &block : ir->program->blocks) { diff --git a/src/ql/pass/dec/instructions/instructions.cc b/src/ql/pass/dec/instructions/instructions.cc index 0c5fa30f0..5650c290d 100644 --- a/src/ql/pass/dec/instructions/instructions.cc +++ b/src/ql/pass/dec/instructions/instructions.cc @@ -226,7 +226,7 @@ utils::UInt DecomposeInstructionsPass::run_on_block( */ utils::Int DecomposeInstructionsPass::run( const ir::Ref &ir, - const pmgr::pass_types::Context &context + const pmgr::pass_types::Context &/* context */ ) const { // Parse options. diff --git a/src/ql/pass/dec/specialize/specialize.cc b/src/ql/pass/dec/specialize/specialize.cc index e8b5d5000..e53e97079 100644 --- a/src/ql/pass/dec/specialize/specialize.cc +++ b/src/ql/pass/dec/specialize/specialize.cc @@ -78,7 +78,7 @@ void SpecializeInstructionsPass::run_on_block( */ utils::Int SpecializeInstructionsPass::run( const ir::Ref &ir, - const pmgr::pass_types::Context &context + const pmgr::pass_types::Context & ) const { if (!ir->program.empty()) { for (const auto &block : ir->program->blocks) { diff --git a/src/ql/pass/io/cqasm/read.cc b/src/ql/pass/io/cqasm/read.cc index b612887b0..fd25ff043 100644 --- a/src/ql/pass/io/cqasm/read.cc +++ b/src/ql/pass/io/cqasm/read.cc @@ -215,7 +215,7 @@ ReadCQasmPass::ReadCQasmPass( */ utils::Int ReadCQasmPass::run( const ir::Ref &ir, - const pmgr::pass_types::Context &context + const pmgr::pass_types::Context &/* context */ ) const { ir::cqasm::ReadOptions read_options; diff --git a/src/ql/pass/map/qubits/map/detail/alter.cc b/src/ql/pass/map/qubits/map/detail/alter.cc index d40dfb528..0202b6c42 100644 --- a/src/ql/pass/map/qubits/map/detail/alter.cc +++ b/src/ql/pass/map/qubits/map/detail/alter.cc @@ -21,7 +21,7 @@ void Alter::add_swaps(Past &past, utils::Any *output_circuit) con const auto& mode = options->swap_selection_mode; if (mode == SwapSelectionMode::ONE || mode == SwapSelectionMode::ALL) { utils::UInt max_num_to_add = (mode == SwapSelectionMode::ONE ? 1 : utils::MAX); - + // Add a maximum of max_num_to_add swaps to "past" from the 2 paths represented by this (split) Alter. // So a maximum of 2 * max_num_to_add swaps are added to "past". // It stops when the paths are completely covered, or when the max number of swaps is reached. @@ -71,13 +71,13 @@ utils::List Alter::create_from_path(const ir::PlatformRef &platform, cons std::shared_ptr> shared_path(new std::list(path)); QL_ASSERT (shared_path->size() >= 2); - + auto leftOpIt = shared_path->begin(); auto rightOpIt = std::prev(std::prev(shared_path->rend())); while (leftOpIt != std::prev(shared_path->end())) { QL_ASSERT(*std::next(leftOpIt) == *rightOpIt); QL_ASSERT(platform->topology->get_distance(*leftOpIt, *rightOpIt) == 1); - + // An inter-core hop cannot execute a two-qubit gate, so is not a valid alternative. if (!platform->topology->is_inter_core_hop(*leftOpIt, *rightOpIt)) { result.push_back(Alter(platform, block, options, gate, shared_path, leftOpIt, rightOpIt)); diff --git a/src/ql/pass/map/qubits/map/detail/future.cc b/src/ql/pass/map/qubits/map/detail/future.cc index b10497763..2e8e9c869 100644 --- a/src/ql/pass/map/qubits/map/detail/future.cc +++ b/src/ql/pass/map/qubits/map/detail/future.cc @@ -65,7 +65,7 @@ class CircuitOrderGateIterator : public GateIterator { return { asCustomInstruction }; } - virtual std::unique_ptr clone() { + virtual std::unique_ptr clone() override { return std::unique_ptr(new CircuitOrderGateIterator(*this)); } @@ -158,7 +158,7 @@ class TopologicalOrderGateIterator : public GateIterator { } } - virtual std::unique_ptr clone() { + virtual std::unique_ptr clone() override { return std::unique_ptr(new TopologicalOrderGateIterator(*this)); } diff --git a/src/ql/pass/map/qubits/map/detail/mapper.cc b/src/ql/pass/map/qubits/map/detail/mapper.cc index 1fa5510ff..f1d233fdb 100644 --- a/src/ql/pass/map/qubits/map/detail/mapper.cc +++ b/src/ql/pass/map/qubits/map/detail/mapper.cc @@ -53,7 +53,7 @@ List Mapper::gen_shortest_paths( ) { QL_ASSERT(path.empty() || path.back() != src); path.push_back(src); - + if (src == tgt) { return Alter::create_from_path(platform, block, options, gate, path); } @@ -148,11 +148,11 @@ List Mapper::gen_shortest_paths(const ir::CustomInstructionRef &gate, UIn if (options->path_selection_mode == PathSelectionMode::ALL) { return compute(PathStrategy::ALL); } - + if (options->path_selection_mode == PathSelectionMode::BORDERS) { return compute(PathStrategy::LEFT_RIGHT); } - + if (options->path_selection_mode == PathSelectionMode::RANDOM) { return compute(PathStrategy::RANDOM); } @@ -204,7 +204,7 @@ Alter Mapper::tie_break_alter(List &alters, Future &future) { return a; } } - + QL_FATAL("This should not happen"); } @@ -278,7 +278,7 @@ List Mapper::map_mappable_gates( return available_gates; } } - + return {}; } @@ -301,7 +301,7 @@ Alter Mapper::select_alter( for (auto &a : alters) { a.extend(past, base_past); // This fills a.score. } - alters.sort([this](const Alter &a1, const Alter &a2) { return a1.get_score() < a2.get_score(); }); + alters.sort([](const Alter &a1, const Alter &a2) { return a1.get_score() < a2.get_score(); }); auto factor = options->recursion_width_factor * utils::pow(options->recursion_width_exponent, recursion_depth); auto keep_real = utils::max(1.0, utils::ceil(factor * alters.size())); @@ -327,7 +327,7 @@ Alter Mapper::select_alter( // Copy of current state for recursion. Future sub_future = future; Past sub_past = past; - + commit_alter(a, sub_future, sub_past); Bool also_nn_two_qubit_gates = options->recurse_on_nn_two_qubit @@ -349,7 +349,7 @@ Alter Mapper::select_alter( } } - alters.sort([this](const Alter &a1, const Alter &a2) { return a1.get_score() < a2.get_score(); }); + alters.sort([](const Alter &a1, const Alter &a2) { return a1.get_score() < a2.get_score(); }); while (alters.back().get_score() > alters.front().get_score()) { alters.pop_back(); @@ -397,7 +397,7 @@ Mapper::RoutingStatistics Mapper::route(ir::BlockBaseRef block, com::map::QubitM past.export_mapping(v2r_out); Mapper::RoutingStatistics stats; - + stats.num_swaps_added = past.get_num_swaps_added(); stats.num_moves_added = past.get_num_moves_added(); diff --git a/src/ql/pass/map/qubits/place_mip/detail/impl.cc b/src/ql/pass/map/qubits/place_mip/detail/impl.cc index ccee7250e..2a44b54e9 100644 --- a/src/ql/pass/map/qubits/place_mip/detail/impl.cc +++ b/src/ql/pass/map/qubits/place_mip/detail/impl.cc @@ -22,7 +22,7 @@ bool isPermutation(const utils::Vec &v2r) { std::set image; for(auto x: v2r) { - if (x < 0 || x >= v2r.size() || image.count(x) > 0) { + if (x >= v2r.size() || image.count(x) > 0) { return false; } image.insert(x); @@ -408,9 +408,9 @@ Impl::TwoQGatesCount inventorize2QGates(ir::Ref ir) { public: Inventorize2QGates(ir::Ref aIr, Impl::TwoQGatesCount &m) : ir(aIr), twoQGatesCount(m) {} - void visit_node(ir::Node &node) override {} + void visit_node(ir::Node &/* node */) override {} - void visit_instruction_decomposition(ir::InstructionDecomposition &instruction_decomposition) override {} + void visit_instruction_decomposition(ir::InstructionDecomposition &/* instruction_decomposition */) override {} void visit_custom_instruction(ir::CustomInstruction &instr) override { std::pair qubit_operands; diff --git a/src/ql/pass/map/qubits/place_mip/detail/impl.h b/src/ql/pass/map/qubits/place_mip/detail/impl.h index 1659851fa..65e11efde 100644 --- a/src/ql/pass/map/qubits/place_mip/detail/impl.h +++ b/src/ql/pass/map/qubits/place_mip/detail/impl.h @@ -30,7 +30,7 @@ struct Options { /** * Whether to write the MPS model to a file. */ - utils::Bool write_model_to_file = true; + utils::Bool write_model_to_file = false; /** * Timeout for the MIP algorithm in seconds, or 0 to disable timeout. diff --git a/src/ql/pass/map/qubits/place_mip/place_mip.cc b/src/ql/pass/map/qubits/place_mip/place_mip.cc index 8326aece7..9c6495195 100644 --- a/src/ql/pass/map/qubits/place_mip/place_mip.cc +++ b/src/ql/pass/map/qubits/place_mip/place_mip.cc @@ -4,10 +4,11 @@ #include "ql/pass/map/qubits/place_mip/place_mip.h" -#include "ql/pass/ana/statistics/annotations.h" #include "detail/impl.h" -#include "ql/pmgr/factory.h" #include "ql/com/map/reference_updater.h" +#include "ql/ir/ir_gen_ex.h" +#include "ql/pass/ana/statistics/annotations.h" +#include "ql/pmgr/factory.h" namespace ql { namespace pass { @@ -133,7 +134,7 @@ PlaceQubitsPass::PlaceQubitsPass( */ utils::Int PlaceQubitsPass::run( const ir::Ref &ir, - const pmgr::pass_types::Context &context + const pmgr::pass_types::Context &/* context */ ) const { detail::Options opts; opts.timeout = options["timeout"].as_real(); diff --git a/src/ql/pass/map/qubits/place_mip/tests/ip_test.cc b/src/ql/pass/map/qubits/place_mip/tests/ip_test.cc deleted file mode 100644 index ee2c437a8..000000000 --- a/src/ql/pass/map/qubits/place_mip/tests/ip_test.cc +++ /dev/null @@ -1,431 +0,0 @@ -#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -#include "doctest/doctest.h" - -#include "ql/pass/map/qubits/place_mip/detail/impl.h" - -namespace ql { -namespace pass { -namespace map { -namespace qubits { -namespace place_mip { -namespace detail { - -class IpTest { -protected: - IpTest() { - ql::utils::logger::set_log_level("LOG_INFO"); - } - - void computeAndCheckResultType(Result expected) { - REQUIRE_GE(qubitsCount, 0); - - Impl impl{qubitsCount, twoQGatesCount, [this](utils::UInt q1, utils::UInt q2) { - REQUIRE_LE(q1, utils::MAX); - REQUIRE_LE(q2, utils::MAX); - return q1 == q2 ? 0 : distances[q1][q2]; - }, {}}; - - auto actual = impl.run(mapping); - - CHECK_EQ(expected, actual); - } - - void setupClique() { - init(5); - - for (utils::UInt i = 0; i < distances.size(); ++i) { - for (utils::UInt j = 0; j < distances[i].size(); ++j) { - if (i != j) { - distances[i][j] = 1; - } - } - } - } - - void setupStar() { - init(5); - - /* - - 2 - | - | - 1-------0-------3 - | - | - 4 - - */ - - for (utils::UInt i = 1; i < qubitsCount; ++i) { - distances[0][i] = 1; - distances[i][0] = 1; - } - - for (utils::UInt i = 1; i < qubitsCount; ++i) { - for (utils::UInt j = 1; j < qubitsCount; ++j) { - if (i == j) { - continue; - } - - distances[i][j] = 2; - distances[j][i] = 2; - } - } - } - - void setupLine(utils::UInt qubitsCount = 3) { - init(qubitsCount); - - /* - - 0-------1-------2----- .... -----(n-1)------n - - */ - - for (utils::UInt i = 0; i < qubitsCount; ++i) { - for (utils::UInt j = i + 1; j < qubitsCount; ++j) { - distances[i][j] = j - i; - distances[j][i] = j - i; - } - } - } - - void setupGrid() { - init(6); - - /* - - 0------1------2 - | | | - | | | - 3------4------5 - - */ - - auto setDistance = [this](utils::UInt q1, utils::UInt q2, utils::UInt d) { distances[q1][q2] = d; distances[q2][q1] = d; }; - setDistance(0, 1, 1); - setDistance(1, 2, 1); - setDistance(2, 5, 1); - setDistance(5, 4, 1); - setDistance(4, 3, 1); - setDistance(3, 0, 1); - setDistance(1, 4, 1); - - setDistance(0, 2, 2); - setDistance(0, 4, 2); - setDistance(1, 3, 2); - setDistance(1, 5, 2); - setDistance(2, 4, 2); - setDistance(3, 5, 2); - - setDistance(0, 5, 3); - setDistance(2, 3, 3); - } - - void add2QGate(utils::UInt q1, utils::UInt q2, utils::UInt n = 1) { - REQUIRE_GE(qubitsCount, 0); - REQUIRE_LE(q1, qubitsCount); - REQUIRE_LE(q2, qubitsCount); - - twoQGatesCount[std::make_pair(q1, q2)] += n; - } - - void checkPermutation(std::vector expected) { - REQUIRE_EQ(expected.size(), qubitsCount); - REQUIRE_EQ(mapping.size(), qubitsCount); - - for (utils::UInt i = 0; i < qubitsCount; ++i) { - INFO("Failure happens because virtual qubit ", i, " is expected to map to" - " real qubit ", expected[i], ", but the result shows that it actually maps to real qubit ", mapping[i]); - CHECK_EQ(expected[i], mapping[i]); - } - } - - void checkAllMappedGatesAreNearestNeighbors() { - for (const auto& kv: twoQGatesCount) { - INFO("Gate between operands ", kv.first.first, " and ", kv.first.second, " and occurrence count ", kv.second, " is not between nearest neighbors after mapping."); - REQUIRE_NE(kv.first.first, kv.first.second); - CHECK_EQ(distances[mapping[kv.first.first]][mapping[kv.first.second]], 1); - } - } - - void checkAtLeastOneMappedGateIsNonNN() { - utils::UInt nonNNGateCount = 0; - for (const auto& kv: twoQGatesCount) { - if (distances[mapping[kv.first.first]][mapping[kv.first.second]] > 1) { - ++nonNNGateCount; - }; - } - - CHECK_GE(nonNNGateCount, 1); - } - - utils::UInt getQubitsCount() { - return qubitsCount; - } - -private: - void init(utils::UInt aQubitsCount) { - REQUIRE_EQ(qubitsCount, 0); - qubitsCount = aQubitsCount; - mapping = utils::Vec(qubitsCount, UNDEFINED_QUBIT); - - distances.resize(qubitsCount); - for (auto &ds: distances) { - ds.resize(qubitsCount, utils::MAX); - } - } - - utils::UInt qubitsCount = 0; - std::vector> distances; - Impl::TwoQGatesCount twoQGatesCount{}; - utils::Vec mapping; -}; - -TEST_CASE_FIXTURE(IpTest, "Star with no 2Q gate") { - setupStar(); - - computeAndCheckResultType(Result::ANY); -} - -TEST_CASE_FIXTURE(IpTest, "Clique with no 2Q gate") { - setupClique(); - - computeAndCheckResultType(Result::ANY); -} - -TEST_CASE_FIXTURE(IpTest, "Line with 2Q gate") { - setupLine(); - - add2QGate(0, 2); - - computeAndCheckResultType(Result::NEW_MAP); - - checkPermutation({1, 0, 2}); - checkAllMappedGatesAreNearestNeighbors(); -} - -TEST_CASE_FIXTURE(IpTest, "Clique with 2Q gate") { - setupClique(); - - add2QGate(1, 3); - - computeAndCheckResultType(Result::CURRENT); -} - -TEST_CASE_FIXTURE(IpTest, "Star with 2Q gate") { - setupStar(); - - SUBCASE("One 2q gate") { - add2QGate(1, 3); - - computeAndCheckResultType(Result::NEW_MAP); - - // This is not the most straightforward mapping (swapping 2 and 3 is useless) but it works. - checkPermutation({1, 0, 3, 2, 4}); - checkAllMappedGatesAreNearestNeighbors(); - } - - SUBCASE("Force change of center") { - add2QGate(1, 3); - add2QGate(1, 2); - - computeAndCheckResultType(Result::NEW_MAP); - - // Swapping 2 and 3 is useless... - checkPermutation({1, 0, 3, 2, 4}); - checkAllMappedGatesAreNearestNeighbors(); - } - - SUBCASE("All possible interactions between properly mapped qubits") { - add2QGate(0, 1); - add2QGate(0, 2); - add2QGate(0, 3); - add2QGate(0, 4); - - computeAndCheckResultType(Result::CURRENT); - } - - SUBCASE("All possible interactions with new center") { - add2QGate(1, 0); - add2QGate(1, 2); - add2QGate(1, 3); - add2QGate(1, 4); - - computeAndCheckResultType(Result::NEW_MAP); - - // Virtual qubit 1 maps to center. - checkPermutation({1, 0, 4, 2, 3}); - checkAllMappedGatesAreNearestNeighbors(); - } - - SUBCASE("No perfect solution") { - add2QGate(1, 2, 5); - add2QGate(3, 4, 10); - - computeAndCheckResultType(Result::NEW_MAP); - - // Virtual qubit 4 maps to center. - checkPermutation({4, 3, 2, 1, 0}); - checkAtLeastOneMappedGateIsNonNN(); - } - - SUBCASE("No perfect solution, same gates, counts swapped => better center is chosen") { - add2QGate(1, 2, 10); - add2QGate(3, 4, 5); - - computeAndCheckResultType(Result::NEW_MAP); - - // Virtual qubit 1 maps to center. - checkPermutation({3, 0, 1, 4, 2}); - checkAtLeastOneMappedGateIsNonNN(); - } -} - -TEST_CASE_FIXTURE(IpTest, "Grid") { - setupGrid(); - - SUBCASE("Preserve non-used virtual qubit indices") { - add2QGate(0, 2); - - computeAndCheckResultType(Result::NEW_MAP); - - checkPermutation({1, 2, 0, 3, 4, 5}); - checkAllMappedGatesAreNearestNeighbors(); - } - - SUBCASE("Make extremes closer") { - add2QGate(0, 5); - add2QGate(3, 2); - - computeAndCheckResultType(Result::NEW_MAP); - - checkPermutation({5, 2, 0, 1, 3, 4}); - checkAllMappedGatesAreNearestNeighbors(); - } - - SUBCASE("Find complex permutation") { - /* - - This test case adds all possible nearest neighboring gates in the following topology: - - 3------5------0 - | | | - | | | - 2------1------4 - - */ - - add2QGate(3, 5); - add2QGate(5, 0); - add2QGate(0, 4); - add2QGate(4, 1); - add2QGate(5, 1); - add2QGate(1, 2); - add2QGate(2, 3); - - computeAndCheckResultType(Result::NEW_MAP); - - checkPermutation({2, 4, 3, 0, 5, 1}); - - checkAllMappedGatesAreNearestNeighbors(); - } -} - -// The following test case can take some time to complete, -// especially when compiler optimizations are disabled (DEBUG build). -TEST_CASE_FIXTURE(IpTest, "Very long line, find permutation of N qubits") { -#ifdef NDEBUG - utils::UInt lineSize = 10; -#else - utils::UInt lineSize = 6; -#endif - - setupLine(lineSize); - REQUIRE_EQ(getQubitsCount() % 2, 0); - - // n = qubitsCount - // 0 ------ (n - 1) ------ 1 ------ (n - 2) ----- 2 ------ (n - 3) ------ ... ------- (n / 2 - 2) ------ (n / 2 + 1) ------ (n / 2 - 1) ------- (n / 2) - - for (utils::UInt i = 0; i <= getQubitsCount() / 2 - 2; ++i) { - add2QGate(i, getQubitsCount() - 1 - i, 2 + i % 5); - add2QGate(getQubitsCount() - 1 - i, i + 1, 3 + i % 5); - } - add2QGate(getQubitsCount() / 2 - 1, getQubitsCount() / 2, 4); - - // There are two possible perfect permutations that make these 2q gates - // executable on a line (since the line has symmetry). - // Which one is output by the algorithm depends on HiGHS implementation details, - // so should be considered to be random. - std::vector expectedPermutation1(getQubitsCount(), 0); - for (utils::UInt i = 0; i < getQubitsCount() / 2; ++i) { - expectedPermutation1[i] = 2 * i; - expectedPermutation1[getQubitsCount() - 1 - i] = 2 * i + 1; - } - - std::vector expectedPermutation2(getQubitsCount(), 0); - for (utils::UInt i = 0; i < getQubitsCount() / 2; ++i) { - expectedPermutation2[i] = getQubitsCount() - 1 - 2 * i; - expectedPermutation2[getQubitsCount() - 1 - i] = getQubitsCount() - 2 * (i + 1); - } - (void)expectedPermutation2; - - SUBCASE("Perfect mapping") { - computeAndCheckResultType(Result::NEW_MAP); - - checkPermutation(expectedPermutation1); - checkAllMappedGatesAreNearestNeighbors(); - } - - SUBCASE("Imperfect mapping") { - add2QGate(0, 1); // This gate is not NN in the optimal case. - - computeAndCheckResultType(Result::NEW_MAP); - - checkPermutation(expectedPermutation1); - checkAtLeastOneMappedGateIsNonNN(); - } -} - -TEST_CASE("Horizon") { - Impl::TwoQGatesCount twoQGatesCount{}; - - twoQGatesCount[std::make_pair(0, 1)] = 10; - twoQGatesCount[std::make_pair(3, 4)] = 5; - twoQGatesCount[std::make_pair(3, 5)] = 3; - twoQGatesCount[std::make_pair(5, 3)] = 3; - twoQGatesCount[std::make_pair(1, 2)] = 9; - twoQGatesCount[std::make_pair(1, 0)] = 2; - - auto originalTwoQGatesCount = twoQGatesCount; - - SUBCASE("Horizon smaller than # of different 2q gates, pick most important 2q gate types") { - applyHorizon(2, twoQGatesCount); - - CHECK_EQ(twoQGatesCount.size(), 2); - CHECK_EQ(twoQGatesCount.at(std::make_pair(0, 1)), 10); - CHECK_EQ(twoQGatesCount.at(std::make_pair(1, 2)), 9); - } - - SUBCASE("Horizon greater than # of different 2q gates") { - applyHorizon(20, twoQGatesCount); - - CHECK_EQ(twoQGatesCount.size(), 6); - CHECK_EQ(originalTwoQGatesCount, twoQGatesCount); - } - - SUBCASE("Horizon is 0") { - applyHorizon(0, twoQGatesCount); - - CHECK_EQ(twoQGatesCount.size(), 6); - CHECK_EQ(originalTwoQGatesCount, twoQGatesCount); - } -} - -} -} -} -} -} -} \ No newline at end of file diff --git a/src/ql/pass/opt/clifford/optimize.cc b/src/ql/pass/opt/clifford/optimize.cc index ae4484df9..e0c1d4c6a 100644 --- a/src/ql/pass/opt/clifford/optimize.cc +++ b/src/ql/pass/opt/clifford/optimize.cc @@ -56,7 +56,7 @@ CliffordOptimizePass::CliffordOptimizePass( * Runs the Clifford optimizer. */ utils::Int CliffordOptimizePass::run( - const ir::compat::ProgramRef &program, + const ir::compat::ProgramRef &/* program */, const ir::compat::KernelRef &kernel, const pmgr::pass_types::Context &context ) const { diff --git a/src/ql/pass/opt/const_prop/const_prop.cc b/src/ql/pass/opt/const_prop/const_prop.cc index afb08a30a..e1382eb52 100644 --- a/src/ql/pass/opt/const_prop/const_prop.cc +++ b/src/ql/pass/opt/const_prop/const_prop.cc @@ -35,7 +35,7 @@ utils::Str ConstantPropagationPass::get_friendly_type() const { */ utils::Int ConstantPropagationPass::run( const ir::Ref &ir, - const pmgr::pass_types::Context &context + const pmgr::pass_types::Context &/* context */ ) const { // perform constant propagation if (!ir->program.empty()) { diff --git a/src/ql/pass/opt/dead_code_elim/dead_code_elim.cc b/src/ql/pass/opt/dead_code_elim/dead_code_elim.cc index d0a8be544..295b7c05d 100644 --- a/src/ql/pass/opt/dead_code_elim/dead_code_elim.cc +++ b/src/ql/pass/opt/dead_code_elim/dead_code_elim.cc @@ -150,7 +150,7 @@ void DeadCodeEliminationPass::run_on_block( */ utils::Int DeadCodeEliminationPass::run( const ir::Ref &ir, - const pmgr::pass_types::Context &context + const pmgr::pass_types::Context &/* context */ ) const { // perform dead code elimination if (!ir->program.empty()) { diff --git a/src/ql/pass/sch/schedule/detail/scheduler.cc b/src/ql/pass/sch/schedule/detail/scheduler.cc index ebf287145..1a2008a93 100644 --- a/src/ql/pass/sch/schedule/detail/scheduler.cc +++ b/src/ql/pass/sch/schedule/detail/scheduler.cc @@ -614,7 +614,7 @@ void Scheduler::init( } // print depgraph for debugging with string parameter identifying where -void Scheduler::dprint_depgraph(const Str &s) const { +void Scheduler::dprint_depgraph(const Str &/* s */) const { #ifdef MULTI_LINE_LOG_DEBUG QL_IF_LOG_DEBUG { QL_DOUT("dependence graph dump: "); diff --git a/src/ql/pass/sch/schedule/schedule.cc b/src/ql/pass/sch/schedule/schedule.cc index 6def2da71..9dee5b26b 100644 --- a/src/ql/pass/sch/schedule/schedule.cc +++ b/src/ql/pass/sch/schedule/schedule.cc @@ -105,7 +105,7 @@ SchedulePass::SchedulePass( * Runs the scheduler. */ utils::Int SchedulePass::run( - const ir::compat::ProgramRef &program, + const ir::compat::ProgramRef &/* program */, const ir::compat::KernelRef &kernel, const pmgr::pass_types::Context &context ) const { diff --git a/src/ql/pmgr/group.cc b/src/ql/pmgr/group.cc index 81c1cc09f..c3a87b037 100644 --- a/src/ql/pmgr/group.cc +++ b/src/ql/pmgr/group.cc @@ -26,8 +26,8 @@ Group::Group( * pass group. */ void Group::get_passes( - const utils::Ptr &factory, - utils::List &passes + const utils::Ptr &/* factory */, + utils::List &/* passes */ ) { } diff --git a/src/ql/pmgr/manager.cc b/src/ql/pmgr/manager.cc index 5a4a116b6..92ec84085 100644 --- a/src/ql/pmgr/manager.cc +++ b/src/ql/pmgr/manager.cc @@ -447,7 +447,7 @@ static utils::Map convert_global_to_pass_options() { */ Manager Manager::from_json( const utils::Json &json, - const Factory &factory + const Factory &/* factory */ ) { // Shorthand. diff --git a/src/ql/pmgr/pass_types/specializations.cc b/src/ql/pmgr/pass_types/specializations.cc index 93b9c0534..8da9ba738 100644 --- a/src/ql/pmgr/pass_types/specializations.cc +++ b/src/ql/pmgr/pass_types/specializations.cc @@ -30,7 +30,7 @@ Group::Group( NodeType Group::on_construct( const utils::Ptr &factory, utils::List &passes, - condition::Ref &condition + condition::Ref &/* condition */ ) { get_passes(factory, passes); return NodeType::GROUP; @@ -42,8 +42,8 @@ NodeType Group::on_construct( * exception. */ utils::Int Group::run_internal( - const ir::Ref &ir, - const Context &context + const ir::Ref &/* ir */, + const Context &/* context */ ) const { QL_ASSERT(false); } @@ -65,9 +65,9 @@ Normal::Normal( * based on its options. */ NodeType Normal::on_construct( - const utils::Ptr &factory, - utils::List &passes, - condition::Ref &condition + const utils::Ptr &/* factory */, + utils::List &/* passes */, + condition::Ref &/* condition */ ) { return NodeType::NORMAL; } diff --git a/src/ql/rmgr/resource_types/base.cc b/src/ql/rmgr/resource_types/base.cc index 0447d0cdc..9acb86912 100644 --- a/src/ql/rmgr/resource_types/base.cc +++ b/src/ql/rmgr/resource_types/base.cc @@ -4,8 +4,9 @@ #include "ql/rmgr/resource_types/base.h" -#include "ql/ir/ops.h" #include "ql/ir/describe.h" +#include "ql/ir/ir_gen_ex.h" +#include "ql/ir/ops.h" namespace ql { namespace rmgr { diff --git a/src/ql/utils/rangemap.cc b/src/ql/utils/rangemap.cc index 30327206b..bbff79c24 100644 --- a/src/ql/utils/rangemap.cc +++ b/src/ql/utils/rangemap.cc @@ -10,7 +10,7 @@ namespace utils { /** * String conversion for Empty. */ -std::ostream &operator<<(std::ostream &os, const Nothing &e) { +std::ostream &operator<<(std::ostream &os, const Nothing &) { return os; } diff --git a/src/ql/utils/vcd.cc b/src/ql/utils/vcd.cc index 9ceb441ab..136d24c98 100644 --- a/src/ql/utils/vcd.cc +++ b/src/ql/utils/vcd.cc @@ -22,13 +22,13 @@ void Vcd::start() { } -void Vcd::scope(Scope type, const Str &name) { +void Vcd::scope(Scope, const Str &name) { // FIXME: handle type vcd << "$scope " << "module" << " " << name << " $end" << std::endl; } -int Vcd::registerVar(const Str &name, VarType type, Scope scope) { +int Vcd::registerVar(const Str &name, VarType, Scope) { // FIXME: incomplete const Int width = 20; @@ -83,7 +83,7 @@ void Vcd::change(Int var, Int timestamp, const Str &value) } -void Vcd::change(Int var, Int timestamp, Int value) { +void Vcd::change(Int /* var */, Int /* timestamp */, Int /* value */) { throw Exception("not yet implemented"); // FIXME } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 000000000..e8f2c4856 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,50 @@ +# Packages +include(FetchContent) + +message(STATUS "Fetching googletest") +FetchContent_Declare(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG "f014396910d397b4f408c0c867aa8ca6a000ef7f" +) +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +# Test executable +add_executable(${PROJECT_NAME}_test) + +# Subdirectories +add_subdirectory(ql) +add_subdirectory(v1x) + +# Test sources +target_sources(${PROJECT_NAME}_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") + +# Target options +target_link_libraries(${PROJECT_NAME}_test + PRIVATE ql + PUBLIC GTest::gmock + PUBLIC GTest::gtest +) +if(CMAKE_COMPILER_IS_GNUCXX) + target_compile_options(${PROJECT_NAME}_test PRIVATE + -Wall -Wextra -Werror -Wfatal-errors + -Wno-error=restrict + -Wno-error=deprecated-declarations + ) +elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + target_compile_options(${PROJECT_NAME}_test PRIVATE + -Wall -Wextra -Werror -Wfatal-errors + -Wno-error=unused-private-field + -Wno-error=unused-but-set-variable + ) +elseif(MSVC) + target_compile_options(${PROJECT_NAME}_test PRIVATE + /MP /D_USE_MATH_DEFINES /EHsc /bigobj + ) +else() + message(SEND_ERROR "Unknown compiler!") +endif() + +gtest_discover_tests(${PROJECT_NAME}_test + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} +) diff --git a/test/main.cpp b/test/main.cpp new file mode 100644 index 000000000..6ad44728d --- /dev/null +++ b/test/main.cpp @@ -0,0 +1,12 @@ +#include +#include + +int main_impl(int argc, char** argv, std::ostream&) { + ::testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +} + +int main(int argc, char** argv) { + return main_impl(argc, argv, std::cout); +} diff --git a/test/ql/CMakeLists.txt b/test/ql/CMakeLists.txt new file mode 100644 index 000000000..99bd44a28 --- /dev/null +++ b/test/ql/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(com) +add_subdirectory(ir) +add_subdirectory(pass) +add_subdirectory(utils) diff --git a/test/ql/com/CMakeLists.txt b/test/ql/com/CMakeLists.txt new file mode 100644 index 000000000..b4c2c8cb0 --- /dev/null +++ b/test/ql/com/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(ddg) diff --git a/test/ql/com/ddg/CMakeLists.txt b/test/ql/com/ddg/CMakeLists.txt new file mode 100644 index 000000000..af067c822 --- /dev/null +++ b/test/ql/com/ddg/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${PROJECT_NAME}_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/ddg.cc") diff --git a/src/ql/com/ddg/tests/ddg.cc b/test/ql/com/ddg/ddg.cc similarity index 95% rename from src/ql/com/ddg/tests/ddg.cc rename to test/ql/com/ddg/ddg.cc index 24c3ab413..7c52ffd7a 100644 --- a/src/ql/com/ddg/tests/ddg.cc +++ b/test/ql/com/ddg/ddg.cc @@ -1,13 +1,16 @@ -#include "ql/ir/compat/compat.h" -#include "ql/ir/old_to_new.h" #include "ql/com/ddg/build.h" -#include "ql/com/ddg/ops.h" #include "ql/com/ddg/consistency.h" #include "ql/com/ddg/dot.h" +#include "ql/com/ddg/ops.h" +#include "ql/ir/compat/compat.h" +#include "ql/ir/old_to_new.h" + +#include using namespace ql; -int main() { + +TEST(ql_com_ddg, ddg) { auto plat = ir::compat::Platform::build("test_plat", utils::Str("cc_light")); auto program = utils::make("test_prog", plat, 7, 32, 10); @@ -34,6 +37,4 @@ int main() { com::ddg::reverse(ir->program->blocks[0]); com::ddg::check_consistency(ir->program->blocks[0]); com::ddg::dump_dot(ir->program->blocks[0]); - - return 0; } diff --git a/test/ql/ir/CMakeLists.txt b/test/ql/ir/CMakeLists.txt new file mode 100644 index 000000000..4b8e884e7 --- /dev/null +++ b/test/ql/ir/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(cqasm) diff --git a/test/ql/ir/cqasm/CMakeLists.txt b/test/ql/ir/cqasm/CMakeLists.txt new file mode 100644 index 000000000..7f95d11b9 --- /dev/null +++ b/test/ql/ir/cqasm/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${PROJECT_NAME}_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/read.cc") diff --git a/test/ql/ir/cqasm/read.cc b/test/ql/ir/cqasm/read.cc new file mode 100644 index 000000000..6e6eb1776 --- /dev/null +++ b/test/ql/ir/cqasm/read.cc @@ -0,0 +1,165 @@ +#include "ql/arch/factory.h" +#include "ql/arch/none/info.h" +#include "ql/ir/ir.gen.h" +#include "ql/ir/compat/platform.h" +#include "ql/ir/cqasm/read.h" +#include "ql/rmgr/manager.h" + +#include +#include + + +struct CompatPlatformFake : public ql::ir::compat::Platform {}; + +struct FactoryFake : public ql::rmgr::Factory {}; + +struct ResourceManagerFake : public ql::rmgr::Manager { + explicit ResourceManagerFake( + const ql::ir::compat::PlatformRef &platform, + const ql::utils::Str &architecture = "", + const ql::utils::Set &dnu = {}, + const ql::rmgr::Factory &factory = {}, + const ql::ir::Ref &ir = {} + ) : ql::rmgr::Manager{ platform, architecture, dnu, factory, ir } {} +}; + +struct PlatformFake : public ql::ir::Platform { + PlatformFake() { + name = "platform_fake"; + + auto creg_count = 1; + auto qubit_count = 1; + + // Notice data_types and objects vectors have to be sorted + // Thus, adding elements in order: bit, int and qubit; and creg and q, respectively + auto bit_type = ql::utils::make("bit").template as(); + data_types.get_vec().push_back(bit_type); + + auto int_type = ql::utils::make("int", true, 32).template as(); + data_types.get_vec().push_back(int_type); + auto physical_object = ql::utils::make("creg", int_type, ql::ir::prim::UIntVec(creg_count)); + objects.get_vec().push_back(physical_object); + + auto qubit_type = ql::utils::make("qubit").template as(); + data_types.get_vec().push_back(qubit_type); + physical_object = ql::utils::make("q", qubit_type, ql::ir::prim::UIntVec(qubit_count)); + objects.get_vec().push_back(physical_object); + qubits = physical_object; + + implicit_bit_type = bit_type; + default_bit_type = bit_type; + default_int_type = int_type; + + auto top = ql::com::Topology(qubit_count, ql::utils::Json{ R"({ + "number_of_cores": 1, + "connectivity": "full", + "form": "irregular", + "comm_qubits_per_core": 4 + })" }); + topology.populate(top); + + auto arch = ql::arch::Factory().build_from_namespace("none"); + architecture.populate(arch); + + auto rmgr_fake = ResourceManagerFake{ ql::utils::One{}, "", {}, FactoryFake{}, {}}; + resources.populate(rmgr_fake); + } +}; + +TEST(read, version_1_0) { + const ql::utils::Str data{ "version 1.0; qubits 2" }; + const ql::utils::Str fname{}; + ql::ir::Ref ir{}; + ir.emplace(); + ir->platform = ql::utils::make(); + ql::ir::cqasm::ReadOptions options{}; + ql::ir::cqasm::read(ir, data, fname, options); + EXPECT_THAT(ir->program->name, "program"); +} +TEST(read, version_1_1) { + const ql::utils::Str data{ "version 1.1" }; + const ql::utils::Str fname{}; + ql::ir::Ref ir{}; + ir.emplace(); + ir->platform = ql::utils::make(); + ql::ir::cqasm::ReadOptions options{}; + ql::ir::cqasm::read(ir, data, fname, options); + EXPECT_THAT(ir->program->name, "program"); +} +TEST(read, version_1_1_1) { + const ql::utils::Str data{ "version 1.1.1" }; + const ql::utils::Str fname{}; + ql::ir::Ref ir{}; + ir.emplace(); + ir->platform = ql::utils::make(); + ql::ir::cqasm::ReadOptions options{}; + ql::ir::cqasm::read(ir, data, fname, options); + EXPECT_THAT(ir->program->name, "program"); +} +TEST(read, version_1_2) { + const ql::utils::Str data{ "version 1.2" }; + const ql::utils::Str fname{}; + ql::ir::Ref ir{}; + ir.emplace(); + ir->platform = ql::utils::make(); + ql::ir::cqasm::ReadOptions options{}; + ql::ir::cqasm::read(ir, data, fname, options); + EXPECT_THAT(ir->program->name, "program"); +} +TEST(read, version_1_3) { + const ql::utils::Str data{ "version 1.3" }; + const ql::utils::Str fname{}; + ql::ir::Ref ir{}; + ir.emplace(); + ir->platform = ql::utils::make(); + ql::ir::cqasm::ReadOptions options{}; + ql::ir::cqasm::read(ir, data, fname, options); + EXPECT_THROW((void) ir->program->name, std::runtime_error); +} +TEST(read, version_2_0) { + const ql::utils::Str data{ "version 2.0" }; + const ql::utils::Str fname{}; + ql::ir::Ref ir{}; + ir.emplace(); + ir->platform = ql::utils::make(); + ql::ir::cqasm::ReadOptions options{}; + ql::ir::cqasm::read(ir, data, fname, options); + EXPECT_THROW((void) ir->program->name, std::runtime_error); +} +TEST(read, version_3_0) { + const ql::utils::Str data{ "version 3.0" }; + const ql::utils::Str fname{}; + ql::ir::Ref ir{}; + ir.emplace(); + ir->platform = ql::utils::make(); + ql::ir::cqasm::ReadOptions options{}; + ql::ir::cqasm::read(ir, data, fname, options); + EXPECT_THROW((void) ir->program->name, std::runtime_error); +} +TEST(read, no_version) { + const ql::utils::Str data{}; + const ql::utils::Str fname{}; + ql::ir::Ref ir{}; + ir.emplace(); + ir->platform = ql::utils::make(); + ql::ir::cqasm::ReadOptions options{}; + EXPECT_THROW(ql::ir::cqasm::read(ir, data, fname, options), std::runtime_error); +} +TEST(read, version_abc) { + const ql::utils::Str data{ "version abc" }; + const ql::utils::Str fname{}; + ql::ir::Ref ir{}; + ir.emplace(); + ir->platform = ql::utils::make(); + ql::ir::cqasm::ReadOptions options{}; + EXPECT_THROW(ql::ir::cqasm::read(ir, data, fname, options), std::runtime_error); +} +TEST(read, version_1_1_abc) { + const ql::utils::Str data{ "version 1.1.abc" }; + const ql::utils::Str fname{}; + ql::ir::Ref ir{}; + ir.emplace(); + ir->platform = ql::utils::make(); + ql::ir::cqasm::ReadOptions options{}; + EXPECT_THROW(ql::ir::cqasm::read(ir, data, fname, options), std::runtime_error); +} diff --git a/src/ql/ir/tests/ir.cc b/test/ql/ir/ir.cc similarity index 98% rename from src/ql/ir/tests/ir.cc rename to test/ql/ir/ir.cc index 81a792313..a884b2971 100644 --- a/src/ql/ir/tests/ir.cc +++ b/test/ql/ir/ir.cc @@ -1,22 +1,25 @@ -#include "ql/utils/filesystem.h" -#include "ql/ir/ir.h" -#include "ql/ir/describe.h" -#include "ql/ir/old_to_new.h" -#include "ql/ir/new_to_old.h" -#include "ql/ir/ops.h" -#include "ql/ir/cqasm/write.h" -#include "ql/ir/cqasm/read.h" -#include "ql/com/ddg/types.h" -#include "ql/com/ddg/ops.h" #include "ql/com/ddg/build.h" #include "ql/com/ddg/dot.h" +#include "ql/com/ddg/ops.h" +#include "ql/com/ddg/types.h" #include "ql/com/sch/scheduler.h" +#include "ql/ir/cqasm/read.h" +#include "ql/ir/cqasm/write.h" +#include "ql/ir/describe.h" +#include "ql/ir/ir.h" +#include "ql/ir/new_to_old.h" +#include "ql/ir/old_to_new.h" +#include "ql/ir/ops.h" #include "ql/pass/io/cqasm/report.h" #include "ql/rmgr/manager.h" +#include "ql/utils/filesystem.h" + +#include using namespace ql; -int main() { + +TEST(ql_ir, ir) { auto plat = ir::compat::Platform::build("test_plat", utils::Str("cc_light")); auto program = utils::make("test_prog", plat, 7, 32, 10); @@ -77,6 +80,4 @@ int main() { //ir::cqasm::write(ir, {}, ss); std::cout << ss.str() << std::endl; - - return 0; } diff --git a/test/ql/pass/CMakeLists.txt b/test/ql/pass/CMakeLists.txt new file mode 100644 index 000000000..7953a82ac --- /dev/null +++ b/test/ql/pass/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(map) \ No newline at end of file diff --git a/test/ql/pass/map/CMakeLists.txt b/test/ql/pass/map/CMakeLists.txt new file mode 100644 index 000000000..ba8eb8fde --- /dev/null +++ b/test/ql/pass/map/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(qubits) diff --git a/test/ql/pass/map/qubits/CMakeLists.txt b/test/ql/pass/map/qubits/CMakeLists.txt new file mode 100644 index 000000000..ed82f365e --- /dev/null +++ b/test/ql/pass/map/qubits/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(place_mip) diff --git a/test/ql/pass/map/qubits/place_mip/CMakeLists.txt b/test/ql/pass/map/qubits/place_mip/CMakeLists.txt new file mode 100644 index 000000000..7fdecea4f --- /dev/null +++ b/test/ql/pass/map/qubits/place_mip/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${PROJECT_NAME}_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/ip_test.cc") diff --git a/test/ql/pass/map/qubits/place_mip/ip_test.cc b/test/ql/pass/map/qubits/place_mip/ip_test.cc new file mode 100644 index 000000000..cf25ba0f3 --- /dev/null +++ b/test/ql/pass/map/qubits/place_mip/ip_test.cc @@ -0,0 +1,451 @@ +#include "ql/pass/map/qubits/place_mip/detail/impl.h" + +#include + + +namespace ql::pass::map::qubits::place_mip::detail { + +class IpTest : public ::testing::Test { +protected: + IpTest() { + ql::utils::logger::set_log_level("LOG_INFO"); + } + + void computeAndCheckResultType(Result expected) { + ASSERT_GE(qubitsCount, 0); + + Impl impl{qubitsCount, twoQGatesCount, [this](utils::UInt q1, utils::UInt q2) -> utils::UInt { + return (q1 == q2) ? 0 : distances[q1][q2]; + }, {}}; + + auto actual = impl.run(mapping); + + EXPECT_EQ(expected, actual); + } + + void setupClique() { + init(5); + + for (utils::UInt i = 0; i < distances.size(); ++i) { + for (utils::UInt j = 0; j < distances[i].size(); ++j) { + if (i != j) { + distances[i][j] = 1; + } + } + } + } + + void setupStar() { + init(5); + + /* + + 2 + | + | + 1-------0-------3 + | + | + 4 + + */ + + for (utils::UInt i = 1; i < qubitsCount; ++i) { + distances[0][i] = 1; + distances[i][0] = 1; + } + + for (utils::UInt i = 1; i < qubitsCount; ++i) { + for (utils::UInt j = 1; j < qubitsCount; ++j) { + if (i == j) { + continue; + } + + distances[i][j] = 2; + distances[j][i] = 2; + } + } + } + + void setupLine(utils::UInt qubits_count = 3) { + init(qubits_count); + + /* + + 0-------1-------2----- .... -----(n-1)------n + + */ + + for (utils::UInt i = 0; i < qubits_count; ++i) { + for (utils::UInt j = i + 1; j < qubits_count; ++j) { + distances[i][j] = j - i; + distances[j][i] = j - i; + } + } + } + + void setupGrid() { + init(6); + + /* + + 0------1------2 + | | | + | | | + 3------4------5 + + */ + + auto setDistance = [this](utils::UInt q1, utils::UInt q2, utils::UInt d) { distances[q1][q2] = d; distances[q2][q1] = d; }; + setDistance(0, 1, 1); + setDistance(1, 2, 1); + setDistance(2, 5, 1); + setDistance(5, 4, 1); + setDistance(4, 3, 1); + setDistance(3, 0, 1); + setDistance(1, 4, 1); + + setDistance(0, 2, 2); + setDistance(0, 4, 2); + setDistance(1, 3, 2); + setDistance(1, 5, 2); + setDistance(2, 4, 2); + setDistance(3, 5, 2); + + setDistance(0, 5, 3); + setDistance(2, 3, 3); + } + + void add2QGate(utils::UInt q1, utils::UInt q2, utils::UInt n = 1) { + ASSERT_GE(qubitsCount, 0); + ASSERT_LE(q1, qubitsCount); + ASSERT_LE(q2, qubitsCount); + + twoQGatesCount[std::make_pair(q1, q2)] += n; + } + + void checkPermutation(std::vector expected) { + ASSERT_EQ(expected.size(), qubitsCount); + ASSERT_EQ(mapping.size(), qubitsCount); + + for (utils::UInt i = 0; i < qubitsCount; ++i) { + std::ostringstream info; + info << "Failure happens because virtual qubit " << i << " is expected to map to real qubit " << expected[i] + << ", but the result shows that it actually maps to real qubit " << mapping[i]; + EXPECT_EQ(expected[i], mapping[i]) << info.str(); + } + } + + void checkAllMappedGatesAreNearestNeighbors() { + for (const auto& kv: twoQGatesCount) { + std::ostringstream info; + info << "Gate between operands " << kv.first.first << " and " << kv.first.second + << " and occurrence count " << kv.second << " is not between nearest neighbors after mapping."; + ASSERT_NE(kv.first.first, kv.first.second) << info.str(); + EXPECT_EQ(distances[mapping[kv.first.first]][mapping[kv.first.second]], 1) << info.str(); + } + } + + void checkAtLeastOneMappedGateIsNonNN() { + utils::UInt nonNNGateCount = 0; + for (const auto& kv: twoQGatesCount) { + if (distances[mapping[kv.first.first]][mapping[kv.first.second]] > 1) { + ++nonNNGateCount; + } + } + + EXPECT_GE(nonNNGateCount, 1); + } + + void checkIndividualMapping(size_t mapping_index, size_t qubit_index) { + EXPECT_EQ(mapping[mapping_index], qubit_index); + } + + utils::UInt getQubitsCount() const { + return qubitsCount; + } + +private: + void init(utils::UInt aQubitsCount) { + ASSERT_EQ(qubitsCount, 0); + qubitsCount = aQubitsCount; + mapping = utils::Vec(qubitsCount, UNDEFINED_QUBIT); + + distances.resize(qubitsCount); + for (auto &ds: distances) { + ds.resize(qubitsCount, utils::MAX); + } + } + + utils::UInt qubitsCount = 0; + std::vector> distances; + Impl::TwoQGatesCount twoQGatesCount{}; + utils::Vec mapping; +}; + +class IpStarTest : public IpTest { +protected: + void SetUp() override { + setupStar(); + } +}; + +class IpCliqueTest : public IpTest { +protected: + void SetUp() override { + setupClique(); + } +}; + +class IpLineTest : public IpTest { +protected: + void SetUp() override { + setupLine(); + } +}; + +class IpGridTest : public IpTest { +protected: + void SetUp() override { + setupGrid(); + } +}; + +TEST_F(IpStarTest, star_with_no_2q_gate) { + computeAndCheckResultType(Result::ANY); +} + +TEST_F(IpCliqueTest, clique_with_no_2q_gate) { + computeAndCheckResultType(Result::ANY); +} + +TEST_F(IpLineTest, line_with_2q_gate) { + add2QGate(0, 2); + + computeAndCheckResultType(Result::NEW_MAP); + + checkPermutation({1, 0, 2}); + checkAllMappedGatesAreNearestNeighbors(); +} + +TEST_F(IpCliqueTest, clique_with_2q_gate) { + add2QGate(1, 3); + + computeAndCheckResultType(Result::CURRENT); +} + +TEST_F(IpStarTest, star_with_2q_gate__one_2q_gate) { + add2QGate(1, 3); + + computeAndCheckResultType(Result::NEW_MAP); + + // This is not the most straightforward mapping (swapping 2 and 3 is useless) but it works. + checkPermutation({1, 0, 3, 2, 4}); + checkAllMappedGatesAreNearestNeighbors(); +} + +TEST_F(IpStarTest, star_with_2q_gate__force_change_of_center) { + add2QGate(1, 3); + add2QGate(1, 2); + + computeAndCheckResultType(Result::NEW_MAP); + + // Swapping 2 and 3 is useless... + checkPermutation({1, 0, 3, 2, 4}); + checkAllMappedGatesAreNearestNeighbors(); +} + +TEST_F(IpStarTest, star_with_2q_gate__all_possible_interactions_between_properly_mapped_qubits) { + add2QGate(0, 1); + add2QGate(0, 2); + add2QGate(0, 3); + add2QGate(0, 4); + + computeAndCheckResultType(Result::CURRENT); +} + +TEST_F(IpStarTest, star_with_2q_gate__all_possible_interactions_with_new_center) { + add2QGate(1, 0); + add2QGate(1, 2); + add2QGate(1, 3); + add2QGate(1, 4); + + computeAndCheckResultType(Result::NEW_MAP); + + // Virtual qubit 1 maps to center. + checkPermutation({1, 0, 4, 2, 3}); + checkAllMappedGatesAreNearestNeighbors(); +} + +TEST_F(IpStarTest, star_with_2q_gate__no_perfect_solution) { + add2QGate(1, 2, 5); + add2QGate(3, 4, 10); + + computeAndCheckResultType(Result::NEW_MAP); + + // Virtual qubit 4 maps to center. + checkIndividualMapping(4, 0); + // We don't check a given permutation here because there are at least two valid ones + // E.g. {4, 3, 2, 1, 0} and {4, 2, 3, 1, 0} + checkAtLeastOneMappedGateIsNonNN(); +} + +TEST_F(IpStarTest, star_with_2q_gate__no_perfect_solution__same_gates__counts_swapped__better_center_is_chosen) { + add2QGate(1, 2, 10); + add2QGate(3, 4, 5); + + computeAndCheckResultType(Result::NEW_MAP); + + // Virtual qubit 1 maps to center. + checkPermutation({3, 0, 1, 4, 2}); + checkAtLeastOneMappedGateIsNonNN(); +} + +TEST_F(IpGridTest, grid__preserve_non_used_virtual_qubit_indices) { + add2QGate(0, 2); + + computeAndCheckResultType(Result::NEW_MAP); + + checkPermutation({1, 2, 0, 3, 4, 5}); + checkAllMappedGatesAreNearestNeighbors(); +} + +TEST_F(IpGridTest, grid__make_extremes_closer) { + add2QGate(0, 5); + add2QGate(3, 2); + + computeAndCheckResultType(Result::NEW_MAP); + + checkPermutation({5, 2, 0, 1, 3, 4}); + checkAllMappedGatesAreNearestNeighbors(); +} + +TEST_F(IpGridTest, grid__find_complex_permutation) { + /* + + This test case adds all possible nearest neighboring gates in the following topology: + + 3------5------0 + | | | + | | | + 2------1------4 + + */ + + add2QGate(3, 5); + add2QGate(5, 0); + add2QGate(0, 4); + add2QGate(4, 1); + add2QGate(5, 1); + add2QGate(1, 2); + add2QGate(2, 3); + + computeAndCheckResultType(Result::NEW_MAP); + + // We don't check a given permutation here because there are at least two valid ones + // E.g. {2, 4, 3, 0, 5, 1} and {0, 4, 5, 2, 3, 1} + checkAllMappedGatesAreNearestNeighbors(); +} + +class IpVeryLongLineFindPermutationOfNQubitsTest : public IpTest { +protected: + void SetUp() override { +#ifdef NDEBUG + utils::UInt lineSize = 10; +#else + utils::UInt lineSize = 6; +#endif + + setupLine(lineSize); + ASSERT_EQ(getQubitsCount() % 2, 0); + + // n = qubitsCount + // 0 ------ (n - 1) ------ 1 ------ (n - 2) ----- 2 ------ (n - 3) ------ ... ------- (n / 2 - 2) ------ (n / 2 + 1) ------ (n / 2 - 1) ------- (n / 2) + + for (utils::UInt i = 0; i <= getQubitsCount() / 2 - 2; ++i) { + add2QGate(i, getQubitsCount() - 1 - i, 2 + i % 5); + add2QGate(getQubitsCount() - 1 - i, i + 1, 3 + i % 5); + } + add2QGate(getQubitsCount() / 2 - 1, getQubitsCount() / 2, 4); + + // There are two possible perfect permutations that make these 2q gates + // executable on a line (since the line has symmetry). + // Which one is output by the algorithm depends on HiGHS implementation details, + // so should be considered to be random. + expectedPermutation1 = std::vector(getQubitsCount(), 0); + for (utils::UInt i = 0; i < getQubitsCount() / 2; ++i) { + expectedPermutation1[i] = 2 * i; + expectedPermutation1[getQubitsCount() - 1 - i] = 2 * i + 1; + } + + std::vector expectedPermutation2(getQubitsCount(), 0); + for (utils::UInt i = 0; i < getQubitsCount() / 2; ++i) { + expectedPermutation2[i] = getQubitsCount() - 1 - 2 * i; + expectedPermutation2[getQubitsCount() - 1 - i] = getQubitsCount() - 2 * (i + 1); + } + (void) expectedPermutation2; + } + +protected: + std::vector expectedPermutation1; +}; + +// The following test case can take some time to complete, +// especially when compiler optimizations are disabled (DEBUG build). +TEST_F(IpVeryLongLineFindPermutationOfNQubitsTest, perfect_mapping) { + computeAndCheckResultType(Result::NEW_MAP); + + checkPermutation(expectedPermutation1); + checkAllMappedGatesAreNearestNeighbors(); +} + +TEST_F(IpVeryLongLineFindPermutationOfNQubitsTest, imperfect_mapping) { + add2QGate(0, 1); // This gate is not NN in the optimal case. + + computeAndCheckResultType(Result::NEW_MAP); + + checkPermutation(expectedPermutation1); + checkAtLeastOneMappedGateIsNonNN(); +} + +class IpHorizonTest : public ::testing::Test { +protected: + void SetUp() override { + twoQGatesCount[std::make_pair(0, 1)] = 10; + twoQGatesCount[std::make_pair(3, 4)] = 5; + twoQGatesCount[std::make_pair(3, 5)] = 3; + twoQGatesCount[std::make_pair(5, 3)] = 3; + twoQGatesCount[std::make_pair(1, 2)] = 9; + twoQGatesCount[std::make_pair(1, 0)] = 2; + + originalTwoQGatesCount = twoQGatesCount; + } + +protected: + Impl::TwoQGatesCount twoQGatesCount{}; + Impl::TwoQGatesCount originalTwoQGatesCount{}; +}; + +TEST_F(IpHorizonTest, horizon_smaller_than_number_of_different_2q_gates__pick_most_important_2q_gate_types) { + applyHorizon(2, twoQGatesCount); + + EXPECT_EQ(twoQGatesCount.size(), 2); + EXPECT_EQ(twoQGatesCount.at(std::make_pair(0, 1)), 10); + EXPECT_EQ(twoQGatesCount.at(std::make_pair(1, 2)), 9); +} + +TEST_F(IpHorizonTest, horizon_greater_than_number_of_different_2q_gates) { + applyHorizon(20, twoQGatesCount); + + EXPECT_EQ(twoQGatesCount.size(), 6); + EXPECT_EQ(originalTwoQGatesCount, twoQGatesCount); +} + +TEST_F(IpHorizonTest, horizon_is_0) { + applyHorizon(0, twoQGatesCount); + + EXPECT_EQ(twoQGatesCount.size(), 6); + EXPECT_EQ(originalTwoQGatesCount, twoQGatesCount); +} + +} // namespace ql::pass::map::qubits::place_mip::detail diff --git a/test/ql/utils/CMakeLists.txt b/test/ql/utils/CMakeLists.txt new file mode 100644 index 000000000..47b9e4e38 --- /dev/null +++ b/test/ql/utils/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${PROJECT_NAME}_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/rangemap.cc") diff --git a/src/ql/utils/tests/rangemap.cc b/test/ql/utils/rangemap.cc similarity index 97% rename from src/ql/utils/tests/rangemap.cc rename to test/ql/utils/rangemap.cc index 31e1db9e0..794af2a71 100644 --- a/src/ql/utils/tests/rangemap.cc +++ b/test/ql/utils/rangemap.cc @@ -1,10 +1,12 @@ -#include - #include "ql/utils/rangemap.h" +#include +#include + using namespace ql::utils; -int main() { + +TEST(ql_utils, rangemap) { RangeMap map([](const UInt &a, const UInt &b) { return a == b; }); QL_ASSERT(map.key_lt(10, 20)); @@ -124,7 +126,7 @@ int main() { QL_ASSERT_EQ(map.to_string(), "{[10..12): 10, [12..14): 6, [14..16): 2, [16..18): 6, [18..20): 10}"); QL_ASSERT_RAISES(map.at({10, 11})); - QL_ASSERT_EQ(map.at({10, 12}), 10); + QL_ASSERT_EQ(map.at({10, 12}), 10ul); QL_ASSERT_EQ(map.find(9), map.end()); QL_ASSERT_EQ(map.find(10), map.begin()); @@ -153,7 +155,7 @@ int main() { map.set({8, 10}, 10); map.check_consistency(); QL_ASSERT_EQ(map.to_string(), "{[8..21): 10}"); - map.set({10, 15}, 10, [](const UInt &a, const UInt &b) { return false; }); + map.set({10, 15}, 10, [](const UInt &, const UInt &) { return false; }); map.check_consistency(); QL_ASSERT_EQ(map.to_string(), "{[8..10): 10, [10..15): 10, [15..21): 10}"); QL_ASSERT_RAISES(map.set({20, 10}, 3)); @@ -172,6 +174,4 @@ int main() { map.erase({8, 10}); map.check_consistency(); QL_ASSERT_EQ(map.to_string(), "{[10..13): 10, [17..21): 10}"); - - return 0; } diff --git a/test/v1x/CMakeLists.txt b/test/v1x/CMakeLists.txt new file mode 100644 index 000000000..2322a85f7 --- /dev/null +++ b/test/v1x/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(cpp) diff --git a/test/v1x/cpp/CMakeLists.txt b/test/v1x/cpp/CMakeLists.txt new file mode 100644 index 000000000..89665ca87 --- /dev/null +++ b/test/v1x/cpp/CMakeLists.txt @@ -0,0 +1,11 @@ +add_subdirectory(example) + +target_sources(${PROJECT_NAME}_test PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/test_179.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/test_cc.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/test_cqasm_reader.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/test_mapper.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/test_multi_core_4_4.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/test_program.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/test_unitary.cc" +) diff --git a/test/v1x/cpp/example/CMakeLists.txt b/test/v1x/cpp/example/CMakeLists.txt new file mode 100644 index 000000000..3f9f7a9e7 --- /dev/null +++ b/test/v1x/cpp/example/CMakeLists.txt @@ -0,0 +1,7 @@ +target_sources(${PROJECT_NAME}_test PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/cpp_standalone.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/multi_qubits_randomized_benchmarking.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/randomized_benchmarking.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/rb_single.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/simple.cc" +) diff --git a/test/v1x/cpp/example/cpp_standalone.cc b/test/v1x/cpp/example/cpp_standalone.cc new file mode 100644 index 000000000..6ea22b00d --- /dev/null +++ b/test/v1x/cpp/example/cpp_standalone.cc @@ -0,0 +1,31 @@ +#include + +#include +#include + + +TEST(v1x_example, cpp_standalone) { + // create platform + auto platform = ql::Platform("seven_qubits_chip", "cc_light"); + + // create program + auto program = ql::Program("aProgram", platform, 2); + + // create kernel + auto kernel = ql::Kernel("aKernel", platform, 2); + + kernel.gate("prepz", 0); + kernel.gate("prepz", 1); + kernel.gate("x", 0); + kernel.gate("y", 1); + kernel.measure(0); + kernel.measure(1); + + // add kernel to program + program.add_kernel(kernel); + + // compile the program + program.compile(); + + std::cout << "Seems good to me!" << std::endl; +} diff --git a/examples/multi_qubits_randomized_benchmarking.cc b/test/v1x/cpp/example/multi_qubits_randomized_benchmarking.cc similarity index 91% rename from examples/multi_qubits_randomized_benchmarking.cc rename to test/v1x/cpp/example/multi_qubits_randomized_benchmarking.cc index 330228faa..235949421 100644 --- a/examples/multi_qubits_randomized_benchmarking.cc +++ b/test/v1x/cpp/example/multi_qubits_randomized_benchmarking.cc @@ -1,14 +1,14 @@ -#include -#include +#include + +#include +#include +#include #include -#include -#include #include -#include +#include -#include -#include +namespace example_multi_qubits_randomized_benchmarking { // clifford inverse lookup table for grounded state const size_t inv_clifford_lut_gs[] = {0, 2, 1, 3, 8, 10, 6, 11, 4, 9, 5, 7, 12, 16, 23, 21, 13, 17, 18, 19, 20, 15, 22, 14}; @@ -74,7 +74,12 @@ void build_rb(int num_cliffords, ql::Kernel &k, int qubits=1, bool different=fal } } -int main(int argc, char **argv) { +} // namespace example_multi_qubits_randomized_benchmarking + + +TEST(v1x_example, multi_qubits_randomized_benchmarking) { + using namespace example_multi_qubits_randomized_benchmarking; + srand(clock()); // initialize openql @@ -92,12 +97,12 @@ int main(int argc, char **argv) { int num_cliffords = 4096; bool different = false; + /* if (argc == 3) { num_qubits = atoi(argv[1]); different = (argv[2][0] == 'd'); } - - int num_circuits = 1; + */ std::cout << "[+] num_qubits : " << num_qubits << std::endl; std::cout << "[+] num_cliffords : " << num_cliffords<< std::endl; @@ -117,6 +122,4 @@ int main(int argc, char **argv) { // compile the program rb.compile(); - - return 0; } diff --git a/examples/randomized_benchmarking.cc b/test/v1x/cpp/example/randomized_benchmarking.cc similarity index 85% rename from examples/randomized_benchmarking.cc rename to test/v1x/cpp/example/randomized_benchmarking.cc index a27464948..f8307ad62 100644 --- a/examples/randomized_benchmarking.cc +++ b/test/v1x/cpp/example/randomized_benchmarking.cc @@ -1,16 +1,17 @@ +#include - -#include -#include -#include -#include #include -#include #include +#include +#include +#include +#include +#include +#include +#include -#include -#include +namespace example_randomized_benchmarking { // clifford inverse lookup table for grounded state const size_t inv_clifford_lut_gs[] = {0, 2, 1, 3, 8, 10, 6, 11, 4, 9, 5, 7, 12, 16, 23, 21, 13, 17, 18, 19, 20, 15, 22, 14}; @@ -45,7 +46,12 @@ void build_rb(int num_cliffords, ql::Kernel &k) { k.measure(0); } -int main(int argc, char **argv) { +} // namespace example_randomized_benchmarking + + +TEST(v1x_example, randomized_benchmarking) { + using namespace example_randomized_benchmarking; + srand(0); // create platform @@ -54,12 +60,11 @@ int main(int argc, char **argv) { // print info qx_platform.print_info(); - int num_randomizations = 3; - int num_circuits = 13; + int num_randomizations = 3; + int num_circuits = 13; std::vector sizes = { 2, 4, 8, 16, 32, 64, 128, 256, 512, 512.25, 512.75, 513.25, 513.75 }; // sizes of the clifford circuits per randomization - for (int r=0; r - -#include -#include -#include -#include #include -#include #include +#include +#include +#include +#include +#include +#include +#include -#include -#include +namespace example_rb_single { // clifford inverse lookup table for grounded state const size_t inv_clifford_lut_gs[] = {0, 2, 1, 3, 8, 10, 6, 11, 4, 9, 5, 7, 12, 16, 23, 21, 13, 17, 18, 19, 20, 15, 22, 14}; @@ -45,8 +46,12 @@ void build_rb(int num_cliffords, ql::Kernel &k) { k.measure(0); } +} // namespace example_rb_single + + +TEST(v1_example, rb_single) { + using namespace example_rb_single; -int main(int argc, char **argv) { srand(0); // create platform @@ -66,6 +71,4 @@ int main(int argc, char **argv) { // std::cout<< rb.qasm() << std::endl; // std::cout << rb.qasm() << std::endl; - - return 0; } diff --git a/test/v1x/cpp/example/simple.cc b/test/v1x/cpp/example/simple.cc new file mode 100644 index 000000000..5ddb8a752 --- /dev/null +++ b/test/v1x/cpp/example/simple.cc @@ -0,0 +1,29 @@ +#include + +#include +#include + + +TEST(v1x_example, simple) { + // create platform + auto platform = ql::Platform("seven_qubits_chip", "cc_light"); + + // create program + auto program = ql::Program("aProgram", platform, 2); + + // create kernel + auto kernel = ql::Kernel("aKernel", platform, 2); + + kernel.gate("prepz", 0); + kernel.gate("prepz", 1); + kernel.gate("x", 0); + kernel.gate("y", 1); + kernel.measure(0); + kernel.measure(1); + + // add kernel to program + program.add_kernel(kernel); + + // compile the program + program.compile(); +} diff --git a/examples/scaffCC/square_root.cc b/test/v1x/cpp/example/square_root.cc similarity index 97% rename from examples/scaffCC/square_root.cc rename to test/v1x/cpp/example/square_root.cc index 1e0580f02..da72ebedd 100644 --- a/examples/scaffCC/square_root.cc +++ b/test/v1x/cpp/example/square_root.cc @@ -1,12 +1,12 @@ -#include -#include -#include -#include +#include + #include -#include #include - -#include "src/openql.h" +#include +#include +#include +#include +#include #define n 6 // problem size (log of database size) #define pi 3.141592653589793238462643383279502884197 @@ -113,7 +113,7 @@ int main(int argc, char ** argv) { srand(0); - ql::init(ql::transmon_platform, "instructions.map"); + ql::init(ql::transmon_platform, "res/map/v1x/example/instructions.map"); // create program ql::quantum_program prog("prog", n*3+1); diff --git a/tests/test_179.cc b/test/v1x/cpp/test_179.cc similarity index 53% rename from tests/test_179.cc rename to test/v1x/cpp/test_179.cc index 1d9259cfb..f19eff99c 100644 --- a/tests/test_179.cc +++ b/test/v1x/cpp/test_179.cc @@ -1,25 +1,18 @@ -#include -#include -#include -#include -#include -#include -#include - -#include - #include +#include +#include +#include // all cnots with operands that are neighbors in s7 // no or hardly any significant difference between pre179 and post179 scheduling -void test_cnot_mixedcommute(std::string v, std::string schedopt, std::string sched_post179opt) { +void test_cnot_mixed_commute(const std::string &v, const std::string &sched_opt, const std::string &sched_post179opt) { int n = 7; - std::string prog_name = "test_" + v + "_schedopt=" + schedopt + "_sched_post179opt=" + sched_post179opt; - std::string kernel_name = "test_" + v + "_schedopt=" + schedopt + "_sched_post179opt=" + sched_post179opt; + std::string prog_name = "test_" + v + "_sched_opt=" + sched_opt + "_sched_post179opt=" + sched_post179opt; + std::string kernel_name = "test_" + v + "_sched_opt=" + sched_opt + "_sched_post179opt=" + sched_post179opt; - auto starmon = ql::Platform("starmon", "test_179.json"); + auto starmon = ql::Platform("starmon", "res/v1x/json/test_179.json"); auto prog = ql::Program(prog_name, starmon, n, 0); auto k = ql::Kernel(kernel_name, starmon, n, 0); @@ -47,19 +40,19 @@ void test_cnot_mixedcommute(std::string v, std::string schedopt, std::string sch prog.add_kernel(k); - ql::set_option("scheduler", schedopt); + ql::set_option("scheduler", sched_opt); ql::set_option("scheduler_post179", sched_post179opt); - prog.compile( ); + prog.compile(); } // test cnot control operand commutativity // i.e. best result is the reverse original order -void test_cnot_controlcommute(std::string v, std::string schedopt, std::string sched_post179opt) { +void test_cnot_control_commute(const std::string &v, const std::string &sched_opt, const std::string &sched_post179opt) { int n = 7; - std::string prog_name = "test_" + v + "_schedopt=" + schedopt + "_sched_post179opt=" + sched_post179opt; - std::string kernel_name = "test_" + v + "_schedopt=" + schedopt + "_sched_post179opt=" + sched_post179opt; + std::string prog_name = "test_" + v + "_sched_opt=" + sched_opt + "_sched_post179opt=" + sched_post179opt; + std::string kernel_name = "test_" + v + "_sched_opt=" + sched_opt + "_sched_post179opt=" + sched_post179opt; - auto starmon = ql::Platform("starmon", "test_179.json"); + auto starmon = ql::Platform("starmon", "res/v1x/json/test_179.json"); auto prog = ql::Program(prog_name, starmon, n, 0); auto k = ql::Kernel(kernel_name, starmon, n, 0); @@ -82,19 +75,19 @@ void test_cnot_controlcommute(std::string v, std::string schedopt, std::string s prog.add_kernel(k); - ql::set_option("scheduler", schedopt); + ql::set_option("scheduler", sched_opt); ql::set_option("scheduler_post179", sched_post179opt); prog.compile(); } // test cnot target operand commutativity // i.e. best result is the reverse original order -void test_cnot_targetcommute(std::string v, std::string schedopt, std::string sched_post179opt) { +void test_cnot_target_commute(const std::string &v, const std::string &sched_opt, const std::string &sched_post179opt) { int n = 7; - std::string prog_name = "test_" + v + "_schedopt=" + schedopt + "_sched_post179opt=" + sched_post179opt; - std::string kernel_name = "test_" + v + "_schedopt=" + schedopt + "_sched_post179opt=" + sched_post179opt; + std::string prog_name = "test_" + v + "_sched_opt=" + sched_opt + "_sched_post179opt=" + sched_post179opt; + std::string kernel_name = "test_" + v + "_sched_opt=" + sched_opt + "_sched_post179opt=" + sched_post179opt; - auto starmon = ql::Platform("starmon", "test_179.json"); + auto starmon = ql::Platform("starmon", "res/v1x/json/test_179.json"); auto prog = ql::Program(prog_name, starmon, n, 0); auto k = ql::Kernel(kernel_name, starmon, n, 0); @@ -117,19 +110,19 @@ void test_cnot_targetcommute(std::string v, std::string schedopt, std::string sc prog.add_kernel(k); - ql::set_option("scheduler", schedopt); + ql::set_option("scheduler", sched_opt); ql::set_option("scheduler_post179", sched_post179opt); - prog.compile( ); + prog.compile(); } // test cz any operand commutativity // i.e. best result is the reverse original order -void test_cz_anycommute(std::string v, std::string schedopt, std::string sched_post179opt) { +void test_cz_any_commute(const std::string &v, const std::string &sched_opt, const std::string &sched_post179opt) { int n = 7; - std::string prog_name = "test_" + v + "_schedopt=" + schedopt + "_sched_post179opt=" + sched_post179opt; - std::string kernel_name = "test_" + v + "_schedopt=" + schedopt + "_sched_post179opt=" + sched_post179opt; + std::string prog_name = "test_" + v + "_sched_opt=" + sched_opt + "_sched_post179opt=" + sched_post179opt; + std::string kernel_name = "test_" + v + "_sched_opt=" + sched_opt + "_sched_post179opt=" + sched_post179opt; - auto starmon = ql::Platform("starmon", "test_179.json"); + auto starmon = ql::Platform("starmon", "res/v1x/json/test_179.json"); auto prog = ql::Program(prog_name, starmon, n, 0); auto k = ql::Kernel(kernel_name, starmon, n, 0); @@ -152,30 +145,28 @@ void test_cz_anycommute(std::string v, std::string schedopt, std::string sched_p prog.add_kernel(k); - ql::set_option("scheduler", schedopt); + ql::set_option("scheduler", sched_opt); ql::set_option("scheduler_post179", sched_post179opt); - prog.compile( ); + prog.compile(); } -int main(int argc, char **argv) { +TEST(v1x, test_179) { ql::utils::logger::set_log_level("LOG_DEBUG"); - test_cnot_controlcommute("cnot_controlcommute", "ASAP", "no"); - test_cnot_controlcommute("cnot_controlcommute", "ASAP", "yes"); - test_cnot_controlcommute("cnot_controlcommute", "ALAP", "no"); - test_cnot_controlcommute("cnot_controlcommute", "ALAP", "yes"); - test_cnot_targetcommute("cnot_targetcommute", "ASAP", "no"); - test_cnot_targetcommute("cnot_targetcommute", "ASAP", "yes"); - test_cnot_targetcommute("cnot_targetcommute", "ALAP", "no"); - test_cnot_targetcommute("cnot_targetcommute", "ALAP", "yes"); - test_cz_anycommute("cz_anycommute", "ASAP", "no"); - test_cz_anycommute("cz_anycommute", "ASAP", "yes"); - test_cz_anycommute("cz_anycommute", "ALAP", "no"); - test_cz_anycommute("cz_anycommute", "ALAP", "yes"); - test_cnot_mixedcommute("cnot_mixedcommute", "ASAP", "no"); - test_cnot_mixedcommute("cnot_mixedcommute", "ASAP", "yes"); - test_cnot_mixedcommute("cnot_mixedcommute", "ALAP", "no"); - test_cnot_mixedcommute("cnot_mixedcommute", "ALAP", "yes"); - - return 0; + test_cnot_control_commute("cnot_control_commute", "ASAP", "no"); + test_cnot_control_commute("cnot_control_commute", "ASAP", "yes"); + test_cnot_control_commute("cnot_control_commute", "ALAP", "no"); + test_cnot_control_commute("cnot_control_commute", "ALAP", "yes"); + test_cnot_target_commute("cnot_target_commute", "ASAP", "no"); + test_cnot_target_commute("cnot_target_commute", "ASAP", "yes"); + test_cnot_target_commute("cnot_target_commute", "ALAP", "no"); + test_cnot_target_commute("cnot_target_commute", "ALAP", "yes"); + test_cz_any_commute("cz_any_commute", "ASAP", "no"); + test_cz_any_commute("cz_any_commute", "ASAP", "yes"); + test_cz_any_commute("cz_any_commute", "ALAP", "no"); + test_cz_any_commute("cz_any_commute", "ALAP", "yes"); + test_cnot_mixed_commute("cnot_mixed_commute", "ASAP", "no"); + test_cnot_mixed_commute("cnot_mixed_commute", "ASAP", "yes"); + test_cnot_mixed_commute("cnot_mixed_commute", "ALAP", "no"); + test_cnot_mixed_commute("cnot_mixed_commute", "ALAP", "yes"); } diff --git a/tests/cc/test_cc.cc b/test/v1x/cpp/test_cc.cc similarity index 95% rename from tests/cc/test_cc.cc rename to test/v1x/cpp/test_cc.cc index 7799051e7..b2d09a1bc 100644 --- a/tests/cc/test_cc.cc +++ b/test/v1x/cpp/test_cc.cc @@ -8,14 +8,17 @@ #include -#include #include +#include +#include using namespace ql::utils; -#define CFG_FILE_JSON "test_cfg_cc.json" +#define CFG_FILE_JSON "res/v1x/json/test_cfg_cc.json" +namespace test_cc { + // based on tests/test_hybrid.py void test_classical() { const int num_qubits = 17; @@ -235,7 +238,7 @@ void test_do_while_nested_for() { void test_rabi() { // create and set platform - auto s17 = ql::Platform("s17", "test_cfg_cc_demo.json"); + auto s17 = ql::Platform("s17", "res/v1x/json/test_cfg_cc_demo.json"); const int num_qubits = 17; const int num_cregs = 3; @@ -284,7 +287,7 @@ void test_wait() { // FIXME: test to find quantum inspire problems 20200325 void test_qi_example() { // create and set platform - auto s17 = ql::Platform("s17", "config_cc_s17_direct_iq_openql_0_10.json"); + auto s17 = ql::Platform("s17", "res/v1x/json/config_cc_s17_direct_iq_openql_0_10.json"); const int num_qubits = 17; const int num_cregs = 17; @@ -320,7 +323,7 @@ void test_qi_example() { #if 0 // FIXME: if_1_break deprecated in CC backend void test_break() { // create and set platform - auto s5 = ql::Platform("s5", "cc_s5_direct_iq.json"); + auto s5 = ql::Platform("s5", "res/v1x/json/config_cc_s5_direct_iq.json"); ql::set_option("write_qasm_files", "yes"); // so we can see bundles const int num_qubits = 5; @@ -342,7 +345,7 @@ void test_break() { void test_condex() { // create and set platform - auto s5 = ql::Platform("s5", "cc_s5_direct_iq.json"); + auto s5 = ql::Platform("s5", "res/v1x/json/config_cc_s5_direct_iq.json"); ql::set_option("write_qasm_files", "yes"); // so we can see bundles const int num_qubits = 5; @@ -385,7 +388,7 @@ void test_condex() { void test_cqasm_condex() { // create platform - auto platform = ql::Platform("s5", "cc_s5_direct_iq.json"); + auto platform = ql::Platform("s5", "res/v1x/json/config_cc_s5_direct_iq.json"); size_t num_qubits = platform.get_qubit_number(); // create program auto program = ql::Program("qasm_qi_example", platform, num_qubits); @@ -406,7 +409,12 @@ void test_cqasm_condex() { program.compile(); } -int main(int argc, char **argv) { +} // namespace test_cc + + +TEST(v1x, test_cc) { + using namespace test_cc; + ql::initialize(); ql::utils::logger::set_log_level("LOG_INFO"); // LOG_DEBUG, LOG_INFO @@ -422,6 +430,4 @@ int main(int argc, char **argv) { // test_break(); // test_condex(); // FIXME: fails on for loop // test_cqasm_condex(); - - return 0; } diff --git a/tests/test_cqasm_reader.cc b/test/v1x/cpp/test_cqasm_reader.cc similarity index 59% rename from tests/test_cqasm_reader.cc rename to test/v1x/cpp/test_cqasm_reader.cc index 9bad8653c..9e3aed1d4 100644 --- a/tests/test_cqasm_reader.cc +++ b/test/v1x/cpp/test_cqasm_reader.cc @@ -1,18 +1,23 @@ +#include +#include + +#include #include -#include -#include +using namespace ql::utils; + + +namespace test_cqasm_reader { -void test_single_bit_kernel_operations() -{ - IOUT("test_single_bit_kernel_operations"); +void test_single_bit_kernel_operations() { + QL_IOUT("test_single_bit_kernel_operations"); // create platform - ql::quantum_platform platform("seven_qubits_chip", "hardware_config_cc_light.json"); + ql::Platform platform("seven_qubits_chip", "res/v1x/json/config_cc_light.json"); size_t num_qubits = platform.get_qubit_number(); // create program - ql::quantum_program program("qasm_single_bit_kernel_operations", platform, num_qubits); + ql::Program program("qasm_single_bit_kernel_operations", platform, num_qubits); - ql::cqasm_reader cqasm_rdr(platform, program); + ql::cQasmReader cqasm_rdr(platform, program); cqasm_rdr.string2circuit( "version 1.0\n" "qubits 6\n" @@ -43,16 +48,15 @@ void test_single_bit_kernel_operations() program.compile(); } -void test_parameterized_single_bit_kernel_operations() -{ - IOUT("test_parameterized_single_bit_kernel_operations"); +void test_parameterized_single_bit_kernel_operations() { + QL_IOUT("test_parameterized_single_bit_kernel_operations"); // create platform - ql::quantum_platform platform("seven_qubits_chip", "hardware_config_cc_light.json"); + ql::Platform platform("seven_qubits_chip", "res/v1x/json/config_cc_light.json"); size_t num_qubits = platform.get_qubit_number(); // create program - ql::quantum_program program("qasm_parameterized_single_bit_kernel_operations", platform, num_qubits); + ql::Program program("qasm_parameterized_single_bit_kernel_operations", platform, num_qubits); - ql::cqasm_reader cqasm_rdr(platform, program); + ql::cQasmReader cqasm_rdr(platform, program); cqasm_rdr.string2circuit( "version 1.0\n" "qubits 6\n" @@ -68,16 +72,15 @@ void test_parameterized_single_bit_kernel_operations() program.compile(); } -void test_dual_bit_kernel_operations() -{ - IOUT("test_dual_bit_kernel_operations"); +void test_dual_bit_kernel_operations() { + QL_IOUT("test_dual_bit_kernel_operations"); // create platform - ql::quantum_platform platform("seven_qubits_chip", "hardware_config_cc_light.json"); + ql::Platform platform("seven_qubits_chip", "res/v1x/json/config_cc_light.json"); size_t num_qubits = platform.get_qubit_number(); // create program - ql::quantum_program program("qasm_dual_bit_kernel_operations", platform, num_qubits); + ql::Program program("qasm_dual_bit_kernel_operations", platform, num_qubits); - ql::cqasm_reader cqasm_rdr(platform, program); + ql::cQasmReader cqasm_rdr(platform, program); cqasm_rdr.string2circuit( "version 1.0\n" "qubits 6\n" @@ -93,16 +96,15 @@ void test_dual_bit_kernel_operations() program.compile(); } -void test_parameterized_dual_bit_kernel_operations() -{ - IOUT("test_parameterized_dual_bit_kernel_operations"); +void test_parameterized_dual_bit_kernel_operations() { + QL_IOUT("test_parameterized_dual_bit_kernel_operations"); // create platform - ql::quantum_platform platform("seven_qubits_chip", "hardware_config_cc_light.json"); + ql::Platform platform("seven_qubits_chip", "res/v1x/json/config_cc_light.json"); size_t num_qubits = platform.get_qubit_number(); // create program - ql::quantum_program program("qasm_parameterized_dual_bit_kernel_operations", platform, num_qubits); + ql::Program program("qasm_parameterized_dual_bit_kernel_operations", platform, num_qubits); - ql::cqasm_reader cqasm_rdr(platform, program); + ql::cQasmReader cqasm_rdr(platform, program); cqasm_rdr.string2circuit( "version 1.0\n" "qubits 6\n" @@ -116,18 +118,17 @@ void test_parameterized_dual_bit_kernel_operations() program.compile(); } -void test_triple_bit_kernel_operations() -{ - IOUT("test_triple_bit_kernel_operations"); +void test_triple_bit_kernel_operations() { + QL_IOUT("test_triple_bit_kernel_operations"); - ql::options::set("decompose_toffoli", "AM"); + ql::set_option("decompose_toffoli", "AM"); // create platform - ql::quantum_platform platform("seven_qubits_chip", "hardware_config_cc_light.json"); + ql::Platform platform("seven_qubits_chip", "res/v1x/json/config_cc_light.json"); size_t num_qubits = platform.get_qubit_number(); // create program - ql::quantum_program program("qasm_triple_bit_kernel_operations", platform, num_qubits); + ql::Program program("qasm_triple_bit_kernel_operations", platform, num_qubits); - ql::cqasm_reader cqasm_rdr(platform, program); + ql::cQasmReader cqasm_rdr(platform, program); cqasm_rdr.string2circuit( "version 1.0\n" "qubits 6\n" @@ -141,16 +142,15 @@ void test_triple_bit_kernel_operations() program.compile(); } -void test_sub_circuit_program() -{ - IOUT("test_sub_circuit_program"); +void test_sub_circuit_program() { + QL_IOUT("test_sub_circuit_program"); // create platform - ql::quantum_platform platform("seven_qubits_chip", "hardware_config_cc_light.json"); + ql::Platform platform("seven_qubits_chip", "res/v1x/json/config_cc_light.json"); size_t num_qubits = platform.get_qubit_number(); // create program - ql::quantum_program program("qasm_sub_circuit_program", platform, num_qubits); + ql::Program program("qasm_sub_circuit_program", platform, num_qubits); - ql::cqasm_reader cqasm_rdr(platform, program); + ql::cQasmReader cqasm_rdr(platform, program); cqasm_rdr.string2circuit( "version 1.0\n" "qubits 6\n" @@ -167,16 +167,15 @@ void test_sub_circuit_program() program.compile(); } -void test_parallel_program() -{ - IOUT("test_parallel_program"); +void test_parallel_program() { + QL_IOUT("test_parallel_program"); // create platform - ql::quantum_platform platform("seven_qubits_chip", "hardware_config_cc_light.json"); + ql::Platform platform("seven_qubits_chip", "res/v1x/json/config_cc_light.json"); size_t num_qubits = platform.get_qubit_number(); // create program - ql::quantum_program program("qasm_parallel_program", platform, num_qubits); + ql::Program program("qasm_parallel_program", platform, num_qubits); - ql::cqasm_reader cqasm_rdr(platform, program); + ql::cQasmReader cqasm_rdr(platform, program); cqasm_rdr.string2circuit( "version 1.0\n" "qubits 6\n" @@ -191,17 +190,16 @@ void test_parallel_program() program.compile(); } -void test_special_gates() -{ - IOUT("test_special_gates"); - IOUT("test_parallel_programs"); +void test_special_gates() { + QL_IOUT("test_special_gates"); + QL_IOUT("test_parallel_programs"); // create platform - ql::quantum_platform platform("seven_qubits_chip", "hardware_config_cc_light.json"); + ql::Platform platform("seven_qubits_chip", "res/v1x/json/config_cc_light.json"); size_t num_qubits = platform.get_qubit_number(); // create program - ql::quantum_program program("qasm_special_gates", platform, num_qubits); + ql::Program program("qasm_special_gates", platform, num_qubits); - ql::cqasm_reader cqasm_rdr(platform, program); + ql::cQasmReader cqasm_rdr(platform, program); cqasm_rdr.string2circuit( "version 1.0\n" "qubits 6\n" @@ -222,16 +220,15 @@ void test_special_gates() program.compile(); } -void test_add_multiple_parts_of_cqasm() -{ - IOUT("test_add_multiple_programs"); +void test_add_multiple_parts_of_cqasm() { + QL_IOUT("test_add_multiple_programs"); // create platform - ql::quantum_platform platform("seven_qubits_chip", "hardware_config_cc_light.json"); + ql::Platform platform("seven_qubits_chip", "res/v1x/json/config_cc_light.json"); size_t num_qubits = platform.get_qubit_number(); // create program - ql::quantum_program program("qasm_add_multiple_programs", platform, num_qubits); + ql::Program program("qasm_add_multiple_programs", platform, num_qubits); - ql::cqasm_reader cqasm_rdr(platform, program); + ql::cQasmReader cqasm_rdr(platform, program); cqasm_rdr.string2circuit( "version 1.0\n" "qubits 6\n" @@ -257,16 +254,15 @@ void test_add_multiple_parts_of_cqasm() program.compile(); } -void test_qi_example() -{ - IOUT("test_qi_example"); +void test_qi_example() { + QL_IOUT("test_qi_example"); // create platform - ql::quantum_platform platform("seven_qubits_chip", "hardware_config_cc_light.json"); + ql::Platform platform("seven_qubits_chip", "res/v1x/json/config_cc_light.json"); size_t num_qubits = platform.get_qubit_number(); // create program - ql::quantum_program program("qasm_qi_example", platform, num_qubits); + ql::Program program("qasm_qi_example", platform, num_qubits); - ql::cqasm_reader cqasm_rdr(platform, program); + ql::cQasmReader cqasm_rdr(platform, program); cqasm_rdr.string2circuit( "version 1.0\n" "qubits 5\n" @@ -280,39 +276,34 @@ void test_qi_example() program.compile(); } -int main(int argc, char ** argv) -{ +} // namespace test_cqasm_reader + + +TEST(v1x, test_cqasm_reader) { + using namespace test_cqasm_reader; + //ql::utils::logger::set_log_level("LOG_NOTHING"); ql::utils::logger::set_log_level("LOG_WARNING"); - ql::options::set("write_qasm_files", "yes"); + ql::set_option("write_qasm_files", "yes"); try { - COUT("Testing cqasm_reader"); - //the following tests run successfully for configuration hardware_config_cc_light.json + QL_COUT("Testing cqasm_reader"); + //the following tests run successfully for configuration config_cc_light.json test_qi_example(); test_add_multiple_parts_of_cqasm(); test_single_bit_kernel_operations(); test_sub_circuit_program(); test_parallel_program(); - //the following tests are not suitable for configuration hardware_config_cc_light.json + //the following tests are not suitable for configuration config_cc_light.json //test_parameterized_single_bit_kernel_operations(); //test_dual_bit_kernel_operations(); //test_parameterized_dual_bit_kernel_operations(); //test_triple_bit_kernel_operations(); //test_special_gates(); - } - catch (const std::runtime_error& e) - { - EOUT(e.what()); - std::cerr << e.what() << std::endl; - std::cerr << std::flush; - } - catch (const ql::exception& e) - { - EOUT(e.what()); + } catch (const std::runtime_error& e) { + QL_EOUT(e.what()); std::cerr << e.what() << std::endl; std::cerr << std::flush; } - return 0; } diff --git a/tests/test_mapper.cc b/test/v1x/cpp/test_mapper.cc similarity index 98% rename from tests/test_mapper.cc rename to test/v1x/cpp/test_mapper.cc index e4e597524..fc8dfc0ca 100644 --- a/tests/test_mapper.cc +++ b/test/v1x/cpp/test_mapper.cc @@ -1,5 +1,10 @@ #include +#include + + +namespace test_mapper { + void test_dpt( std::string v, std::string param1, @@ -168,7 +173,7 @@ void test_recursion( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } // simple program to test (post179) dot printing by the scheduler @@ -203,7 +208,7 @@ void test_dot( ql::set_option("scheduler_post179", param1); ql::set_option("scheduler", param2); - prog.compile( ); + prog.compile(); } // resource constraint presence test @@ -236,7 +241,7 @@ void test_rc( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } // all cnots (in both directions) with operands that are neighbors in s7 @@ -286,7 +291,7 @@ void test_someNN( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } // one cnot with operands that are at distance 2 in s7 @@ -328,7 +333,7 @@ void test_oneD2( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } // one cnot with operands that are at distance 4 in s7 @@ -369,7 +374,7 @@ void test_oneD4( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } // longest string of cnots with operands that could be at distance 1 in s7 when initially placed correctly @@ -417,7 +422,7 @@ void test_string( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } // all possible cnots in s7, avoiding collisions: @@ -517,7 +522,7 @@ void test_allDopt( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } // all possible cnots in s7, in lexicographic order @@ -555,7 +560,7 @@ void test_allD( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } void test_allD2( @@ -637,7 +642,7 @@ void test_allD2( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } // actual test kernel of daniel that failed once @@ -906,7 +911,7 @@ void test_daniel2( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } // real code with 5-qubit short error code checkers in 4 variations next to eachother @@ -1066,7 +1071,7 @@ void test_lingling5esm( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } // real code with 7-qubit short error code checkers in 3 variations next to eachother @@ -1210,7 +1215,7 @@ void test_lingling7esm( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } // real code with 7-qubit short error code checkers in 3 variations next to eachother @@ -1363,7 +1368,7 @@ void test_lingling7sub( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } // a maxcut QAOA algorithm inspired by the one in Venturelli et al [2017]'s paper @@ -1384,7 +1389,7 @@ void test_maxcut( std::string prog_name = "test_" + v + "_maplookahead=" + param1 + "_maprecNN2q=" + param2 + "_mapselectmaxlevel=" + param3 + "_mapselectmaxwidth=" + param4; std::string kernel_name = "test_" + v + "_maplookahead=" + param1 + "_maprecNN2q=" + param2 + "_mapselectmaxlevel=" + param3 + "_mapselectmaxwidth=" + param4; - auto starmon = ql::Platform("starmon", "test_mapper_rig.json"); + auto starmon = ql::Platform("starmon", "res/v1x/json/test_mapper_rig.json"); //ql::set_platform(starmon); auto prog = ql::Program(prog_name, starmon, n, 0); auto k = ql::Kernel(kernel_name, starmon, n, 0); @@ -1423,11 +1428,15 @@ void test_maxcut( ql::set_option("mapselectmaxlevel", param3); ql::set_option("mapselectmaxwidth", param4); - prog.compile( ); + prog.compile(); } +} // namespace test_mapper + + +TEST(v1x, test_mapper) { + using namespace test_mapper; -int main(int argc, char ** argv) { ql::utils::logger::set_log_level("LOG_DEBUG"); // ql::utils::logger::set_log_level("LOG_NOTHING"); ql::set_option("unique_output", "no"); @@ -1462,6 +1471,4 @@ int main(int argc, char ** argv) { test_dpt("dpt", "noroutingfirst", "no", "0", "min"); // test_recursion("recursion", "noroutingfirst", "no", "0", "min"); - - return 0; } diff --git a/tests/test_multi_core.cc b/test/v1x/cpp/test_multi_core_4_4.cc similarity index 88% rename from tests/test_multi_core.cc rename to test/v1x/cpp/test_multi_core_4_4.cc index baaf74a60..1d12fafb8 100644 --- a/tests/test_multi_core.cc +++ b/test/v1x/cpp/test_multi_core_4_4.cc @@ -1,13 +1,18 @@ #include -void test_mc(std::string v, std::string param1, std::string param2, std::string param3, std::string param4) { +#include + + +namespace test_multi_core { + +void test_mc(std::string v, std::string, std::string, std::string, std::string) { int n = 16; // std::string prog_name = "test_" + v + "_maplookahead=" + param1 + "_maprecNN2q=" + param2 + "_mapselectmaxlevel=" + param3 + "_mapselectmaxwidth=" + param4; std::string prog_name = "test_" + v; // std::string kernel_name = "test_" + v + "_maplookahead=" + param1 + "_maprecNN2q=" + param2 + "_mapselectmaxlevel=" + param3 + "_mapselectmaxwidth=" + param4; std::string kernel_name = "test_" + v; - auto starmon = ql::Platform("mc4x4full", "test_multi_core_4x4_full.json"); + auto starmon = ql::Platform("mc4x4full", "res/v1x/json/test_multi_core_4x4_full.json"); //ql::set_platform(starmon); auto prog = ql::Program(prog_name, starmon, n, 0); auto k = ql::Kernel(kernel_name, starmon, n, 0); @@ -37,9 +42,12 @@ void test_mc(std::string v, std::string param1, std::string param2, std::string prog.compile(); } +} // namespace test_multi_core -int main(int argc, char **argv) { +TEST(v1x, test_multi_core_4_4) { + using namespace test_multi_core; + ql::utils::logger::set_log_level("LOG_DEBUG"); // ql::utils::logger::set_log_level("LOG_NOTHING"); ql::set_option("unique_output", "no"); @@ -73,6 +81,4 @@ int main(int argc, char **argv) { ql::set_option("prescheduler", "yes"); test_mc("mc", "noroutingfirst", "no", "0", "min"); - - return 0; } diff --git a/tests/cc/debug.cc b/test/v1x/cpp/test_multi_core_64_16.cc similarity index 90% rename from tests/cc/debug.cc rename to test/v1x/cpp/test_multi_core_64_16.cc index 235ecda2c..66cd1cba7 100644 --- a/tests/cc/debug.cc +++ b/test/v1x/cpp/test_multi_core_64_16.cc @@ -1,6 +1,9 @@ #include -int main(int, char **) { +#include + + +TEST(v1x, test_multi_core_64_16) { ql::initialize(); ql::utils::logger::set_log_level("LOG_INFO"); ql::set_option("log_level", "LOG_INFO"); @@ -34,11 +37,11 @@ int main(int, char **) { ql::set_option("write_qasm_files", "yes"); ql::set_option("write_report_files", "yes"); - auto platform = ql::Platform("mctests", "test_multi_core_64x16_full.json"); + auto platform = ql::Platform("mctests", "res/v1x/json/test_multi_core_64x16_full.json"); auto num_qubits = 18; auto p = ql::Program("qaoa_q1024", platform, num_qubits); auto k = ql::Kernel("qaoa_q1024", platform, num_qubits); k.gate("cnot", 0, 17); p.add_kernel(k); p.compile(); -} \ No newline at end of file +} diff --git a/test/v1x/cpp/test_program.cc b/test/v1x/cpp/test_program.cc new file mode 100644 index 000000000..1a9cb5dfc --- /dev/null +++ b/test/v1x/cpp/test_program.cc @@ -0,0 +1,34 @@ +#include + +#include +#include + + +TEST(v1x, test_program) { + size_t num_qubits = 5; + + // create platform + auto qplatform = ql::Platform("target_platform", "cc_light"); + + // create program + auto prog = ql::Program("prog", qplatform, num_qubits); + + // create a kernel + auto kernel = ql::Kernel("my_kernel", qplatform, num_qubits); + + // add gates to kernel + kernel.gate("prepz", std::vector{0}); + kernel.gate("prepz", std::vector{1}); + kernel.gate("x", std::vector{0}); + kernel.gate("y", std::vector{2}); + kernel.gate("cnot", std::vector{0, 2}); + kernel.gate("measure", std::vector{0}); + kernel.gate("measure", std::vector{1}); + kernel.gate("measure", std::vector{2}); + + // add kernel to prog + prog.add_kernel(kernel); + + // compile the program + prog.compile(); +} diff --git a/test/v1x/cpp/test_unitary.cc b/test/v1x/cpp/test_unitary.cc new file mode 100644 index 000000000..b7f8c616b --- /dev/null +++ b/test/v1x/cpp/test_unitary.cc @@ -0,0 +1,56 @@ +#include + +#include +#include + + +// Fails in CI on some platforms. +TEST(v1x, decomposition_controlled_u) { + if (!ql::Unitary::is_decompose_support_enabled()) { + GTEST_SKIP(); + } + + auto platform = ql::Platform("platform_none", "res/v1x/json/test_cfg_none_simple.json"); + auto num_qubits = 3; + auto p = ql::Program("test_using_qx_toffoli", platform, num_qubits); + auto k = ql::Kernel("aKernel", platform, num_qubits); + + std::vector> matrix = { + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, std::complex(0.30279949, -0.60010283), std::complex(-0.58058628, -0.45946559), + 0, 0, 0, 0, 0 ,0, std::complex(0.04481146, -0.73904059), std::complex(0.64910478, 0.17456782)}; + + auto u1 = ql::Unitary("using_qx_toffoli", matrix); + u1.decompose(); + k.hadamard(0); + k.hadamard(1); + k.hadamard(2); + k.gate(u1, { 0, 1, 2 }); + + p.add_kernel(k); + p.get_compiler().set_option("initialqasmwriter.cqasm_version", "1.0"); + p.get_compiler().set_option("initialqasmwriter.with_metadata", "no"); + p.compile(); + + EXPECT_DOUBLE_EQ(0.125 * std::norm(std::accumulate(std::begin(matrix), std::begin(matrix) + 7, std::complex{0.0, 0.0})), + std::norm(std::complex(0.03708885276142243, 0.3516026407762626))); + EXPECT_DOUBLE_EQ(0.125 * std::norm(std::accumulate(std::begin(matrix) + 8, std::begin(matrix) + 15, std::complex{0.0, 0.0})), + std::norm(std::complex(0.03708885276142243, 0.3516026407762626))); + EXPECT_DOUBLE_EQ(0.125 * std::norm(std::accumulate(std::begin(matrix) + 16, std::begin(matrix) + 23, std::complex{0.0, 0.0})), + std::norm(std::complex(0.03708885276142243, 0.3516026407762626))); + EXPECT_DOUBLE_EQ(0.125 * std::norm(std::accumulate(std::begin(matrix) + 24, std::begin(matrix) + 31, std::complex{0.0, 0.0})), + std::norm(std::complex(0.03708885276142243, 0.3516026407762626))); + EXPECT_DOUBLE_EQ(0.125 * std::norm(std::accumulate(std::begin(matrix) + 32, std::begin(matrix) + 39, std::complex{0.0, 0.0})), + std::norm(std::complex(0.03708885276142243, 0.3516026407762626))); + EXPECT_DOUBLE_EQ(0.125 * std::norm(std::accumulate(std::begin(matrix) + 40, std::begin(matrix) + 47, std::complex{0.0, 0.0})), + std::norm(std::complex(0.03708885276142243, 0.3516026407762626))); + EXPECT_DOUBLE_EQ(0.125 * std::norm(std::accumulate(std::begin(matrix) + 48, std::begin(matrix) + 55, std::complex{0.0, 0.0})), + std::norm(std::complex(-0.38284984896211677, 0.058372391728338066))); + EXPECT_DOUBLE_EQ(0.125 * std::norm(std::accumulate(std::begin(matrix) + 56, std::begin(matrix) + 63, std::complex{0.0, 0.0})), + std::norm(std::complex(-0.17273355873910606, -0.2649184303119007))); +} diff --git a/test/v1x/python/config.py b/test/v1x/python/config.py new file mode 100644 index 000000000..4e7258ec8 --- /dev/null +++ b/test/v1x/python/config.py @@ -0,0 +1,15 @@ +import os + +cur_dir = os.path.dirname(os.path.realpath(__file__)) +root_dir = os.path.join(cur_dir, '..', '..', '..') +res_dir = os.path.join(root_dir, 'res', 'v1x') + +cq_dir = os.path.join(res_dir, 'cq') +cq_golden_dir = os.path.join(cq_dir, 'golden') + +json_dir = os.path.join(res_dir, 'json') + +qasm_dir = os.path.join(res_dir, 'qasm') +qasm_golden_dir = os.path.join(qasm_dir, 'golden') + +output_dir = "test_output" diff --git a/test/v1x/python/example/config.py b/test/v1x/python/example/config.py new file mode 100644 index 000000000..74eb3340a --- /dev/null +++ b/test/v1x/python/example/config.py @@ -0,0 +1,16 @@ +import os + +cur_dir = os.path.dirname(os.path.realpath(__file__)) +root_dir = os.path.join(cur_dir, '..', '..', '..', '..') +res_dir = os.path.join(root_dir, 'res', 'v1x') + +cq_dir = os.path.join(res_dir, 'cq') +cq_example_dir = os.path.join(cq_dir, 'example') +cq_golden_dir = os.path.join(cq_dir, 'golden') + +json_dir = os.path.join(res_dir, 'json') + +qasm_dir = os.path.join(res_dir, 'qasm') +qasm_golden_dir = os.path.join(qasm_dir, 'golden') + +output_dir = "example_output" diff --git a/test/v1x/python/example/diamond.py b/test/v1x/python/example/diamond.py new file mode 100644 index 000000000..384f32059 --- /dev/null +++ b/test/v1x/python/example/diamond.py @@ -0,0 +1,86 @@ +import openql as ql +# import os + +# from config import cq_example_dir + + +# turn off automatic scheduling by OpenQL to preserve instruction order +ql.set_option('prescheduler', 'no') + +# Specify the platform +platform = ql.Platform("diamond_test", "diamond") + +# Put a cQASM reader before the diamond pass, so a cQASM file is read instead of the python code +# platform.get_compiler().prefix_pass( +# 'io.cqasm.Read', '', +# {'cqasm_file': os.path.join(cq_example_dir, 'diamond.cq'), 'measure_all_target': 'measure_z'}) + +num_qubits = 3 +p = ql.Program("testProgram", platform, num_qubits) +k = ql.Kernel("testKernel", platform, num_qubits) + +# Below follow examples for all gates that are supported, arranged by category: + +# Initialization +# k.gate('prep_z', [0]) +# k.gate('prep_x', [0]) +# k.gate('prep_y', [0]) +# k.gate('initialize', [0]) + +# Measurement +# k.gate('measure', [0]) +# k.gate('measure_z', [0]) +# k.gate('measure_x', [0]) +# k.gate('measure_y', [0]) + +# single qubit gates +# k.x(0) +# k.y(0) +# k.z(0) +# k.s(0) +# k.t(0) + +# two qubit gates +# k.gate('cnot', [0, 1]) # only between color center - nuclear spin qubit +# k.gate('cz', [0, 1]) + +# three qubit gate +# k.gate('toffoli', [0, 1, 2]) + +# calibration +# k.gate('cal_measure', [0]) +# k.gate('cal_pi', [0]) +# k.gate('cal_halfpi', [0]) +# k.gate('decouple', [0]) + +# custom rotations +# k.gate('rx', [0], 0, 1.57) +# k.gate('ry', [0], 0, 1.57) +# k.gate('crk', [0, 1], 0, 1) +# k.gate('cr', [0, 1], 0, 3.14) + +# diamond protocols/sequences +# k.diamond_crc(0, 30, 5) +# k.diamond_rabi_check(0, 100, 2, 3) # qubit, duration, measurement, t_max +# k.diamond_excite_mw(1, 100, 200, 0, 60, 0) # envelope, duration, frequency, phase, amplitude, qubit +# k.diamond_qentangle(0, 15) # qubit, nuclear qubit +# k.gate('nventangle', [0, 1]) +# k.diamond_memswap(0,1) # qubit, nuclear qubit +# k.diamond_sweep_bias(0, 10, 0, 0, 10, 100, 0) # qubit, value, dacreg, start, step, max, memaddress + +# timing +# k.gate('wait', [], 200) +# k.gate('qnop', [0]) # qubit, mandatory from openQL + +# calculate bias +# k.gate('calculate_current', [0]) + +# calculate voltage +# k.gate('calculate_voltage', [0]) + +# magnetic bias check +# k.diamond_sweep_bias(0, 10, 0, 0, 10, 100, 0) +# k.gate('calculate_voltage', [0]) + +p.add_kernel(k) +p.compile() diff --git a/examples/dice.py b/test/v1x/python/example/dice.py similarity index 52% rename from examples/dice.py rename to test/v1x/python/example/dice.py index a7154e8a5..7201c7f1e 100644 --- a/examples/dice.py +++ b/test/v1x/python/example/dice.py @@ -1,66 +1,74 @@ -from openql import openql as ql +import matplotlib.pyplot as plt +import openql as ql +import os import qxelarator + +from config import output_dir from functools import reduce -import os -import matplotlib.pyplot as plt -ql.set_option('output_dir', 'output') + +ql.set_option('output_dir', output_dir) ql.set_option('log_level', 'LOG_INFO') -nqubits = 3 +num_qubits = 3 + def dice_compile(): print('compiling 8-face dice program by openql') platform = ql.Platform('myPlatform', 'none') - p = ql.Program('dice', platform, nqubits) - k = ql.Kernel('aKernel', platform, nqubits) + p = ql.Program('dice', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) - for q in range(nqubits): + for q in range(num_qubits): k.gate('h', [q]) - for q in range(nqubits): + for q in range(num_qubits): k.gate('measure', [q]) p.add_kernel(k) p.compile() + def plot_histogram(dice_faces): - plt.hist(dice_faces, bins=8, color='#0504aa',alpha=0.7, rwidth=0.85) + plt.hist(dice_faces, bins=8, color='#0504aa', alpha=0.7, rwidth=0.85) plt.grid(axis='y', alpha=0.75) - plt.xlabel('Dice Face',fontsize=15) - plt.ylabel('Frequency',fontsize=15) + plt.xlabel('Dice Face', fontsize=15) + plt.ylabel('Frequency', fontsize=15) plt.xticks(fontsize=15) plt.yticks(fontsize=15) - plt.ylabel('Frequency',fontsize=15) - plt.title('Histogram',fontsize=15) + plt.ylabel('Frequency', fontsize=15) + plt.title('Histogram', fontsize=15) plt.show() plt.savefig('hist.png') -def dice_execute_singleshot(): + +def dice_execute_single_shot(): print('executing 8-face dice program on qxelarator') qx = qxelarator.QX() - qx.set('output/dice.qasm') + qx.set(os.path.join(output_dir, 'dice.qasm')) qx.execute() - res = [int(qx.get_measurement_outcome(q)) for q in range(nqubits)] + res = [int(qx.get_measurement_outcome(q)) for q in range(num_qubits)] dice_face = reduce(lambda x, y: 2*x+y, res, 0) + 1 print('Dice face : {}'.format(dice_face)) -def dice_execute_multishot(): + +def dice_execute_multi_shot(): print('executing 8-face dice program on qxelarator') qx = qxelarator.QX() - qx.set('output/dice.qasm') + qx.set(os.path.join(output_dir, 'dice.qasm')) dice_faces = [] - ntests = 100 - for i in range(ntests): + num_tests = 100 + for i in range(num_tests): qx.execute() - res = [int(qx.get_measurement_outcome(q)) for q in range(nqubits)] - dice_face = reduce(lambda x, y: 2*x+y, res, 0) +1 + res = [int(qx.get_measurement_outcome(q)) for q in range(num_qubits)] + dice_face = reduce(lambda x, y: 2*x+y, res, 0) + 1 dice_faces.append(dice_face) plot_histogram(dice_faces) + if __name__ == '__main__': dice_compile() - dice_execute_singleshot() - dice_execute_multishot() + dice_execute_single_shot() + dice_execute_multi_shot() diff --git a/examples/getting_started.py b/test/v1x/python/example/getting_started.py similarity index 71% rename from examples/getting_started.py rename to test/v1x/python/example/getting_started.py index 3fb958552..2c7b7cba2 100644 --- a/examples/getting_started.py +++ b/test/v1x/python/example/getting_started.py @@ -1,8 +1,8 @@ -from openql import openql as ql +import openql as ql import os -curdir = os.path.dirname(__file__) -output_dir = os.path.join(curdir, 'test_output') +from config import json_dir, output_dir + ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') @@ -10,23 +10,24 @@ ql.set_option('log_level', 'LOG_WARNING') ql.set_option('write_qasm_files', 'yes') + def hello_openql(): # if you copy this example somewhere else, make sure to provide # correct path of configuration file copy the configuration file # to the same directory and update the path - config_fn = os.path.join(curdir, '../tests/hardware_config_cc_light.json') + config_fn = os.path.join(json_dir, 'config_cc_light.json') platform = ql.Platform("myPlatform", config_fn) - nqubits = 3 + num_qubits = 3 # create a program - p = ql.Program("aProgram", platform, nqubits) + p = ql.Program("aProgram", platform, num_qubits) # create a kernel - k = ql.Kernel("aKernel", platform, nqubits) + k = ql.Kernel("aKernel", platform, num_qubits) # populate kernel using default and custom gates - for i in range(nqubits): + for i in range(num_qubits): k.gate('prepz', [i]) k.gate('x', [0]) @@ -41,5 +42,6 @@ def hello_openql(): # compile the program p.compile() + if __name__ == '__main__': hello_openql() diff --git a/test/v1x/python/example/grover.py b/test/v1x/python/example/grover.py new file mode 100644 index 000000000..7e0ce82a3 --- /dev/null +++ b/test/v1x/python/example/grover.py @@ -0,0 +1,128 @@ +""" + grover algorithm implementation +""" + +import openql as ql +import os + +from config import json_dir, output_dir + + +num_qubits = 9 + + +def init(platform): + init_k = ql.Kernel('init', platform, num_qubits) + + # oracle qubit + oracle = 4 + + # init + init_k.x(oracle) + init_k.hadamard(oracle) + + # Hn search space + for i in range(4): + init_k.hadamard(i) + + return init_k + + +def grover(platform): + grover_k = ql.Kernel('grover', platform, num_qubits) + # oracle qubit + oracle = 4 + # name search space + s0 = 0 + s1 = 1 + s2 = 2 + s3 = 3 + + # oracle + grover_k.x(s0) + grover_k.x(s1) + grover_k.toffoli(s0, s1, 5) + grover_k.toffoli(s1, 5, 6) + grover_k.toffoli(s2, 6, 7) + grover_k.toffoli(s3, 7, 8) + grover_k.cnot(8, oracle) + grover_k.toffoli(s3, 7, 8) + grover_k.toffoli(s2, 6, 7) + grover_k.toffoli(s1, 5, 6) + grover_k.toffoli(s0, 1, 5) + + # restore ss + grover_k.x(s0) + grover_k.x(s1) + + # diffusion + for i in range(4): + grover_k.hadamard(i) + + for i in range(4): + grover_k.x(i) + + # controlled-phase shift + grover_k.hadamard(s3) + grover_k.toffoli(s0, s1, 5) + grover_k.toffoli(s1, 5, 6) + grover_k.toffoli(s2, 6, 7) + grover_k.cnot(7, s3) + grover_k.toffoli(s2, 6, 7) + grover_k.toffoli(s1, 5, 6) + grover_k.toffoli(s0, s1, 5) + grover_k.hadamard(s3) + + # restore search space + for i in range(4): + grover_k.x(i) + for i in range(4): + grover_k.hadamard(i) + + grover_k.gate('display', []) + + return grover_k + + +def grover_algorithm(): + ql.set_option('output_dir', output_dir) + ql.set_option('optimize', 'no') + ql.set_option('scheduler', 'ASAP') + ql.set_option('log_level', 'LOG_CRITICAL') + ql.set_option('write_qasm_files', 'yes') + + config_fn = os.path.join(json_dir, 'config_qx.json') + platform = ql.Platform('platform_none', config_fn) + # num_qubits = 9 + # oracle qubit + oracle = 4 + + # create a grover program + p = ql.Program('test_grover', platform, num_qubits, 0) + + # kernels + init_k = init(platform) + grover_k = grover(platform) + result_k = ql.Kernel('result', platform, num_qubits) + + # result + result_k.hadamard(oracle) + result_k.measure(oracle) + result_k.gate("display", []) + + result_k.measure(0) + result_k.measure(1) + result_k.measure(2) + result_k.measure(3) + result_k.gate("display_binary", []) + + # build the program + p.add_kernel(init_k) + p.add_kernel(grover_k) + p.add_kernel(result_k) + ql.set_option('decompose_toffoli', 'NC') + p.compile() + + +if __name__ == '__main__': + grover_algorithm() diff --git a/examples/rb_single.py b/test/v1x/python/example/rb_single.py similarity index 54% rename from examples/rb_single.py rename to test/v1x/python/example/rb_single.py index 9c71c9c8a..c9d01f673 100644 --- a/examples/rb_single.py +++ b/test/v1x/python/example/rb_single.py @@ -1,12 +1,9 @@ +import openql as ql import os import random -from openql import openql as ql +from config import json_dir, output_dir -rootDir = os.path.dirname(os.path.realpath(__file__)) - -curdir = os.path.dirname(__file__) -output_dir = os.path.join(curdir, 'test_output') ql.set_option('output_dir', output_dir) ql.set_option('write_qasm_files', 'yes') @@ -15,23 +12,21 @@ ql.set_option('log_level', 'LOG_INFO') -def build_rb(qubit, num_cliffords, kernel): - inv_clifford_lut_gs = [0, 2, 1, 3, 8, 10, 6, 11, 4, 9, 5, 7, 12, 16, - 23, 21, 13, 17, 18, 19, 20, 15, 22, 14] +def build_rb(qubit): + inv_clifford_lut_gs = [0, 2, 1, 3, 8, 10, 6, 11, 4, 9, 5, 7, 12, 16, 23, 21, 13, 17, 18, 19, 20, 15, 22, 14] - cl = random.sample( range(0, len(inv_clifford_lut_gs) ), - int(num_cliffords/2) ) + cl = random.sample(range(0, len(inv_clifford_lut_gs)), int(num_cliffords/2)) inv_cl = cl[::-1] cliffords = inv_cl + cl kernel.prepz(qubit) for c in cliffords: - kernel.clifford(c, qubit); + kernel.clifford(c, qubit) kernel.measure(qubit) -config_fn = os.path.join(curdir, '../tests/hardware_config_qx.json') -platform = ql.Platform('platform_none', config_fn) +config_fn = os.path.join(json_dir, 'config_qx.json') +platform = ql.Platform('platform_none', config_fn) num_qubits = 1 # create a grover program @@ -41,7 +36,7 @@ def build_rb(qubit, num_cliffords, kernel): num_cliffords = 32 for q in range(num_qubits): - build_rb(q, num_cliffords, kernel) + build_rb(q) p.add_kernel(kernel) p.compile() diff --git a/examples/simple.py b/test/v1x/python/example/simple.py similarity index 55% rename from examples/simple.py rename to test/v1x/python/example/simple.py index 88a7c088c..e11b77308 100644 --- a/examples/simple.py +++ b/test/v1x/python/example/simple.py @@ -1,17 +1,20 @@ import openql as ql +from config import output_dir + + ql.initialize() -ql.set_option('output_dir', 'output') +ql.set_option('output_dir', output_dir) ql.set_option('log_level', 'LOG_INFO') platform = ql.Platform('my_platform', 'none') -nqubits = 3 -program = ql.Program('my_program', platform, nqubits) -kernel = ql.Kernel('my_kernel', platform, nqubits) +num_qubits = 3 +program = ql.Program('my_program', platform, num_qubits) +kernel = ql.Kernel('my_kernel', platform, num_qubits) -for i in range(nqubits): +for i in range(num_qubits): kernel.prepz(i) kernel.x(0) diff --git a/tests/test_Kernel.py b/test/v1x/python/test_Kernel.py similarity index 68% rename from tests/test_Kernel.py rename to test/v1x/python/test_Kernel.py index 181143255..118788dca 100644 --- a/tests/test_Kernel.py +++ b/test/v1x/python/test_Kernel.py @@ -1,17 +1,17 @@ +import openql as ql import os import unittest -from openql import openql as ql -curdir = os.path.dirname(os.path.realpath(__file__)) -config_fn = os.path.join(curdir, 'test_config_default.json') -platf = ql.Platform("starmon", config_fn) +from config import json_dir, output_dir -output_dir = os.path.join(curdir, 'test_output') -class Test_kernel(unittest.TestCase): +config_fn = os.path.join(json_dir, "test_config_default.json") +platform = ql.Platform("starmon", config_fn) + +class TestKernel(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') @@ -20,27 +20,26 @@ def setUp(self): def test_kernel_name(self): name = "kernel1" - nqubits = 3 - k = ql.Kernel(name, platf, nqubits) + num_qubits = 3 + k = ql.Kernel(name, platform, num_qubits) self.assertEqual(k.name, name) def test_kernel_qubit_count(self): name = "kernel1" - nqubits=3 - k = ql.Kernel(name, platf, nqubits) - self.assertEqual(k.qubit_count, nqubits) + num_qubits = 3 + k = ql.Kernel(name, platform, num_qubits) + self.assertEqual(k.qubit_count, num_qubits) def test_kernel_creg_count(self): name = "kernel1" - nqubits=2 - ncreg = 3 - k = ql.Kernel(name, platf, nqubits, ncreg) - self.assertEqual(k.creg_count, ncreg) - + num_qubits = 2 + num_cregs = 3 + k = ql.Kernel(name, platform, num_qubits, num_cregs) + self.assertEqual(k.creg_count, num_cregs) def test_allowed_operations(self): - nqubits = 3 - k = ql.Kernel("kernel1", platf, nqubits) + num_qubits = 3 + k = ql.Kernel("kernel1", platform, num_qubits) # The following operations can be executed using a kernel operations = [ # SPAM @@ -59,13 +58,13 @@ def test_allowed_operations(self): 'rx', 'ry', 'rz', # synchronization 'wait', 'barrier' - ] + ] # Test that these operations exist as methods of the kernel self.assertTrue(set(operations).issubset(dir(k))) def test_simple_kernel(self): - nqubits = 3 - k = ql.Kernel("kernel1", platf, nqubits) + num_qubits = 3 + k = ql.Kernel("kernel1", platform, num_qubits) k.prepz(0) k.prepz(1) k.x(0) @@ -80,9 +79,9 @@ def test_simple_kernel(self): # to the qubits. However, it is not clear how to view this def test_multi_kernel(self): - nqubits = 3 + num_qubits = 3 - k1 = ql.Kernel("kernel1", platf, nqubits) + k1 = ql.Kernel("kernel1", platform, num_qubits) k1.prepz(0) k1.prepz(1) k1.x(0) @@ -93,7 +92,7 @@ def test_multi_kernel(self): k1.clifford(2, 0) k1.measure(2) - k2 = ql.Kernel("kernel2", platf, nqubits) + k2 = ql.Kernel("kernel2", platform, num_qubits) k2.prepz(0) k2.prepz(1) k2.x(0) @@ -104,19 +103,19 @@ def test_multi_kernel(self): k2.clifford(2, 0) k2.measure(2) - p = ql.Program("test_multi_kernel", platf, nqubits) + p = ql.Program("test_multi_kernel", platform, num_qubits) p.add_kernel(k1) p.add_kernel(k2) p.compile() def test_duplicate_kernel_name(self): - nqubits = 3 + num_qubits = 3 - p = ql.Program("test_duplicate_kernel_name", platf, nqubits) - k1 = ql.Kernel("aKernel1", platf, nqubits) - k2 = ql.Kernel("aKernel2", platf, nqubits) - k3 = ql.Kernel("aKernel1", platf, nqubits) + p = ql.Program("test_duplicate_kernel_name", platform, num_qubits) + k1 = ql.Kernel("aKernel1", platform, num_qubits) + k2 = ql.Kernel("aKernel2", platform, num_qubits) + k3 = ql.Kernel("aKernel1", platform, num_qubits) k1.gate('x', [0]) k2.gate('x', [0]) diff --git a/tests/test_Platform.py b/test/v1x/python/test_Platform.py similarity index 54% rename from tests/test_Platform.py rename to test/v1x/python/test_Platform.py index a54a1761e..a52a15575 100644 --- a/tests/test_Platform.py +++ b/test/v1x/python/test_Platform.py @@ -1,15 +1,14 @@ +import openql as ql import os import unittest -from openql import openql as ql -from utils import file_compare -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare -class Test_platform(unittest.TestCase): +class TestPlatform(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') @@ -18,8 +17,8 @@ def setUp(self): def test_platform_name(self): platf_name = 'starmon_platform' - platf = ql.Platform(platf_name, 'none') - self.assertEqual(platf.name, platf_name) + platform = ql.Platform(platf_name, 'none') + self.assertEqual(platform.name, platf_name) def test_platform_architectures(self): ql.Platform('x', 'cc_light') @@ -29,33 +28,34 @@ def test_platform_architectures(self): ql.Platform('x', 'cc') def test_platform_simple_constructor(self): - platf = ql.Platform('cc_light') - self.assertEqual(platf.name, 'cc_light') - self.assertEqual(platf.config_file, 'cc_light') - platf = ql.Platform() - self.assertEqual(platf.name, 'none') - self.assertEqual(platf.config_file, 'none') + platform = ql.Platform('cc_light') + self.assertEqual(platform.name, 'cc_light') + self.assertEqual(platform.config_file, 'cc_light') + platform = ql.Platform() + self.assertEqual(platform.name, 'none') + self.assertEqual(platform.config_file, 'none') def test_platform_from_config(self): - platf_name = 'starmon_platform' - config_fn = os.path.join(curdir, 'test_cfg_none.json') - platf = ql.Platform(platf_name, config_fn) - self.assertEqual(platf.config_file, config_fn) + platform_name = 'starmon_platform' + config_fn = os.path.join(json_dir, 'test_cfg_none.json') + platform = ql.Platform(platform_name, config_fn) + self.assertEqual(platform.config_file, config_fn) def test_platform_modified_in_place(self): name = 'test_platform_modified_in_place' data = ql.Platform.get_platform_json('cc_light') data['instructions']['my_custom_instruction'] = {'duration': 20} - platf = ql.Platform.from_json(name, data) - k = ql.Kernel('test', platf) + platform = ql.Platform.from_json(name, data) + k = ql.Kernel('test', platform) k.gate('my_custom_instruction', 0) - p = ql.Program(name, platf) + p = ql.Program(name, platform) p.add_kernel(k) p.compile() self.assertTrue(file_compare( os.path.join(output_dir, name + '_last.qasm'), - os.path.join(curdir, 'golden', name + '_last.qasm') + os.path.join(qasm_golden_dir, name + '_last.qasm') )) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_Program.py b/test/v1x/python/test_Program.py similarity index 68% rename from tests/test_Program.py rename to test/v1x/python/test_Program.py index 5f0bfc532..bbb83a209 100644 --- a/tests/test_Program.py +++ b/test/v1x/python/test_Program.py @@ -1,17 +1,16 @@ +import openql as ql import os import unittest -from openql import openql as ql -curdir = os.path.dirname(os.path.realpath(__file__)) -config_fn = os.path.join(curdir, 'test_config_default.json') -platf = ql.Platform("starmon", config_fn) +from config import json_dir, output_dir -output_dir = os.path.join(curdir, 'test_output') +config_fn = os.path.join(json_dir, 'test_config_default.json') +platform = ql.Platform("starmon", config_fn) -class Test_program(unittest.TestCase): +class TestProgram(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') @@ -21,28 +20,28 @@ def setUp(self): def test_program_name(self): name = "program1" - nqubits=1 - p = ql.Program(name, platf, nqubits) + num_qubits = 1 + p = ql.Program(name, platform, num_qubits) self.assertEqual(p.name, name) def test_program_qubit_count(self): name = "program1" - nqubits=3 - p = ql.Program(name, platf, nqubits) - self.assertEqual(p.qubit_count, nqubits) + num_qubits = 3 + p = ql.Program(name, platform, num_qubits) + self.assertEqual(p.qubit_count, num_qubits) def test_program_creg_count(self): name = "program1" - nqubits=2 + num_qubits = 2 ncreg = 3 - p = ql.Program(name, platf, nqubits, ncreg) + p = ql.Program(name, platform, num_qubits, ncreg) self.assertEqual(p.creg_count, ncreg) def test_add_kernel(self): # test that this does not raise any error - nqubits=5 - k = ql.Kernel("kernel1", platf, nqubits) - p = ql.Program('program1', platf, nqubits) + num_qubits = 5 + k = ql.Kernel("kernel1", platform, num_qubits) + p = ql.Program('program1', platform, num_qubits) p.add_kernel(k) # there should be a check here to see if k was indeed added @@ -50,8 +49,8 @@ def test_add_kernel(self): def test_program_methods(self): # This tests for the existence of the right methods in the wrapping - nqubits=5 - p = ql.Program('program1', platf, nqubits) + num_qubits = 5 + p = ql.Program('program1', platform, num_qubits) program_methods = [ 'add_kernel', 'add_program', @@ -65,8 +64,8 @@ def test_program_methods(self): self.assertTrue(set(program_methods).issubset(dir(p))) def test_simple_program(self): - nqubits = 2 - k = ql.Kernel("kernel1", platf, nqubits) + num_qubits = 2 + k = ql.Kernel("kernel1", platform, num_qubits) k.prepz(0) k.prepz(1) k.x(0) @@ -75,16 +74,15 @@ def test_simple_program(self): k.clifford(1, 0) k.measure(0) - p = ql.Program("rb_program", platf, nqubits) + p = ql.Program("rb_program", platform, num_qubits) p.add_kernel(k) # print( p.qasm() ) p.compile() - - def test_5qubit_program(self): - nqubits=5 - p = ql.Program("a_program", platf, nqubits) - k = ql.Kernel("a_kernel", platf, nqubits) + def test_5_qubit_program(self): + num_qubits = 5 + p = ql.Program("aProgram", platform, num_qubits) + k = ql.Kernel("aKernel", platform, num_qubits) # populate kernel for i in range(2): @@ -98,12 +96,11 @@ def test_5qubit_program(self): p.add_kernel(k) # add kernel to program p.compile() - # @unittest.skip('Gate by name not implemented') - def test_allxy_program(self): - nqubits=7 - p = ql.Program('AllXY', platf, nqubits) - k = ql.Kernel('AllXY_q0', platf, nqubits) + def test_all_xy_program(self): + num_qubits = 7 + p = ql.Program('AllXY', platform, num_qubits) + k = ql.Kernel('AllXY_q0', platform, num_qubits) q = 0 # target qubit @@ -115,8 +112,8 @@ def test_allxy_program(self): ['rx180', 'ry90'], ['ry180', 'rx90'], ['rx90', 'rx180'], ['rx180', 'rx90'], ['ry90', 'ry180'], ['ry180', 'ry90'], ['rx180', 'I'], ['ry180', 'I'], ['rx90', 'rx90'], - ['ry90', 'ry90']] - + ['ry90', 'ry90'] + ] for pulse_comb in pulse_combinations: k.prepz(q) diff --git a/tests/test_alap_rc_schedule.py b/test/v1x/python/test_alap_rc_schedule.py similarity index 69% rename from tests/test_alap_rc_schedule.py rename to test/v1x/python/test_alap_rc_schedule.py index a0c47bfbe..259c21e8e 100644 --- a/tests/test_alap_rc_schedule.py +++ b/test/v1x/python/test_alap_rc_schedule.py @@ -1,20 +1,18 @@ -from openql import openql as ql +import openql as ql import os import unittest -from utils import file_compare - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import output_dir, qasm_golden_dir +from utils import file_compare -class Test_Alap_Rc_Schedule(unittest.TestCase): - _SCHEDULER = 'ALAP' - config = 'cc_light' +class TestAlapRcSchedule(unittest.TestCase): + _scheduler = 'ALAP' + config_fn = 'cc_light' def setUp(self): ql.initialize() - ql.set_option('scheduler', self._SCHEDULER) + ql.set_option('scheduler', self._scheduler) ql.set_option('output_dir', output_dir) ql.set_option('log_level', "LOG_NOTHING") @@ -23,10 +21,10 @@ def test_qwg(self): v = 'qwg' # create and set platform - prog_name = "test_" + v + "_" + self._SCHEDULER - kernel_name = "kernel_" + v + "_" + self._SCHEDULER + prog_name = "test_" + v + "_" + self._scheduler + kernel_name = "kernel_" + v + "_" + self._scheduler - starmon = ql.Platform("starmon", self.config) + starmon = ql.Platform("starmon", self.config_fn) prog = ql.Program(prog_name, starmon, 7, 0) k = ql.Kernel(kernel_name, starmon, 7, 0) @@ -37,21 +35,21 @@ def test_qwg(self): prog.add_kernel(k) prog.compile() - GOLD_fn = os.path.join(curdir, 'golden', prog.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, prog.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, prog.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_qwg2(self): # parameters - v = 'qwg2' - scheduler = self._SCHEDULER + v = 'qwg_2' + scheduler = self._scheduler # create and set platform prog_name = "test_" + v + "_" + scheduler kernel_name = "kernel_" + v + "_" + scheduler - starmon = ql.Platform("starmon", self.config) + starmon = ql.Platform("starmon", self.config_fn) prog = ql.Program(prog_name, starmon, 7, 0) k = ql.Kernel(kernel_name, starmon, 7, 0) @@ -71,27 +69,27 @@ def test_qwg2(self): ql.set_option("scheduler", scheduler) prog.compile() - GOLD_fn = os.path.join(curdir, 'golden', prog.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, prog.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, prog.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) - def test_issue179(self): + def test_issue_179(self): # parameters - v = 'issue179' - scheduler = self._SCHEDULER + v = 'issue_179' + scheduler = self._scheduler # create and set platform prog_name = "test_" + v + '_' + scheduler kernel_name = "kernel_" + v + '_' + scheduler - starmon = ql.Platform("starmon", self.config) + starmon = ql.Platform("starmon", self.config_fn) prog = ql.Program(prog_name, starmon, 7, 0) k = ql.Kernel(kernel_name, starmon, 7, 0) # independent gates but stacking qwg unit use # in s7, q2, q3 and q4 all use qwg1 - # the y q3 must be in an other cycle than the x's because x conflicts with y in qwg1 + # the y q3 must be in another cycle than the x's because x conflicts with y in qwg1 # the x q2 and x q4 can be in parallel but the y q3 in between prohibits this # because the qwg1 resource in single dimensional: # after x q2 it is busy on x in cycle 0, @@ -107,21 +105,21 @@ def test_issue179(self): ql.set_option("scheduler", scheduler) prog.compile() - GOLD_fn = os.path.join(curdir, 'golden', prog.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, prog.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, prog.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_edge(self): # parameters v = 'edge' - scheduler = self._SCHEDULER + scheduler = self._scheduler # create and set platform prog_name = "test_" + v + '_' + scheduler kernel_name = "kernel_" + v + '_' + scheduler - starmon = ql.Platform("starmon", self.config) + starmon = ql.Platform("starmon", self.config_fn) prog = ql.Program(prog_name, starmon, 7, 0) k = ql.Kernel(kernel_name, starmon, 7, 0) @@ -134,21 +132,21 @@ def test_edge(self): ql.set_option("scheduler", scheduler) prog.compile() - GOLD_fn = os.path.join(curdir, 'golden', prog.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, prog.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, prog.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_detuned(self): # parameters v = 'detuned' - scheduler = self._SCHEDULER + scheduler = self._scheduler # create and set platform prog_name = "test_" + v + '_' + scheduler kernel_name = "kernel_" + v + '_' + scheduler - starmon = ql.Platform("starmon", self.config) + starmon = ql.Platform("starmon", self.config_fn) prog = ql.Program(prog_name, starmon, 7, 0) k = ql.Kernel(kernel_name, starmon, 7, 0) @@ -166,21 +164,21 @@ def test_detuned(self): ql.set_option("scheduler", scheduler) prog.compile() - GOLD_fn = os.path.join(curdir, 'golden', prog.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, prog.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, prog.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) - def test_detuned2(self): + def test_detuned_2(self): # parameters - v = 'detuned2' - scheduler = self._SCHEDULER + v = 'detuned_2' + scheduler = self._scheduler # create and set platform prog_name = "test_" + v + '_' + scheduler kernel_name = "kernel_" + v + '_' + scheduler - starmon = ql.Platform("starmon", self.config) + starmon = ql.Platform("starmon", self.config_fn) prog = ql.Program(prog_name, starmon, 7, 0) k = ql.Kernel(kernel_name, starmon, 7, 0) @@ -198,21 +196,21 @@ def test_detuned2(self): ql.set_option("scheduler", scheduler) prog.compile() - GOLD_fn = os.path.join(curdir, 'golden', prog.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, prog.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, prog.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_adriaan(self): # parameters v = 'adriaan' - scheduler = self._SCHEDULER + scheduler = self._scheduler # create and set platform prog_name = "test_" + v + '_' + scheduler kernel_name = "kernel_" + v + '_' + scheduler - starmon = ql.Platform("starmon", self.config) + starmon = ql.Platform("starmon", self.config_fn) prog = ql.Program(prog_name, starmon, 7, 0) k = ql.Kernel(kernel_name, starmon, 7, 0) @@ -230,21 +228,21 @@ def test_adriaan(self): ql.set_option("scheduler", scheduler) prog.compile() - GOLD_fn = os.path.join(curdir, 'golden', prog.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, prog.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, prog.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_1(self): # parameters v = '1' - scheduler = self._SCHEDULER + scheduler = self._scheduler # create and set platform prog_name = "test_" + v + '_' + scheduler kernel_name = "kernel_" + v + '_' + scheduler - starmon = ql.Platform("starmon", self.config) + starmon = ql.Platform("starmon", self.config_fn) prog = ql.Program(prog_name, starmon, 7, 0) k = ql.Kernel(kernel_name, starmon, 7, 0) @@ -274,21 +272,21 @@ def test_1(self): ql.set_option("scheduler", scheduler) prog.compile() - GOLD_fn = os.path.join(curdir, 'golden', prog.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, prog.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, prog.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_7(self): # parameters v = '7' - scheduler = self._SCHEDULER + scheduler = self._scheduler # create and set platform prog_name = "test_" + v + '_' + scheduler kernel_name = "kernel_" + v + '_' + scheduler - starmon = ql.Platform("starmon", self.config) + starmon = ql.Platform("starmon", self.config_fn) prog = ql.Program(prog_name, starmon, 7, 0) k = ql.Kernel(kernel_name, starmon, 7, 0) @@ -326,10 +324,10 @@ def test_7(self): ql.set_option("scheduler", scheduler) prog.compile() - GOLD_fn = os.path.join(curdir, 'golden', prog.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, prog.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, prog.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) if __name__ == '__main__': diff --git a/tests/test_barrier.py b/test/v1x/python/test_barrier.py similarity index 82% rename from tests/test_barrier.py rename to test/v1x/python/test_barrier.py index e668adfbe..53dde1764 100644 --- a/tests/test_barrier.py +++ b/test/v1x/python/test_barrier.py @@ -1,14 +1,12 @@ +import openql as ql import os import unittest -from openql import openql as ql -from utils import file_compare - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import output_dir, qasm_golden_dir +from utils import file_compare -class Test_barrier(unittest.TestCase): +class TestBarrier(unittest.TestCase): def setUp(self): ql.initialize() ql.set_option('output_dir', output_dir) @@ -19,7 +17,6 @@ def setUp(self): ql.set_option("scheduler_commute", 'no') ql.set_option('use_default_gates', 'yes') # ql.set_option('write_qasm_files', 'yes') - # barrier on specified qubits def test_barrier(self): @@ -43,8 +40,8 @@ def test_barrier(self): p.add_kernel(k) p.compile() - qasm_fn = os.path.join(output_dir, p.name+'_last.qasm') - gold_fn = curdir + '/golden/test_barrier_last.qasm' + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, 'test_barrier_last.qasm') self.assertTrue(file_compare(qasm_fn, gold_fn)) # barrier on specified qubits with 'wait' and duration = 0 @@ -66,11 +63,10 @@ def test_wait_barrier(self): ql.print_options() p.compile() - qasm_fn = os.path.join(output_dir, p.name+'_last.qasm') - gold_fn = curdir + '/golden/test_wait_barrier_last.qasm' + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, 'test_wait_barrier_last.qasm') self.assertTrue(file_compare(qasm_fn, gold_fn)) - # barrier on all qubits with barrier def test_barrier_all_1(self): platform = ql.Platform('seven_qubits_chip', 'cc_light') @@ -107,11 +103,9 @@ def test_barrier_all_1(self): p.add_kernel(k) p.compile() - - QASM_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - gold_fn = curdir + '/golden/test_barrier_all.qasm' - self.assertTrue(file_compare(QASM_fn, gold_fn)) - + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + gold_fn = os.path.join(qasm_golden_dir, 'test_barrier_all.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) # barrier on all qubits with generalized gate API using 'barrier' def test_barrier_all_2(self): @@ -149,10 +143,9 @@ def test_barrier_all_2(self): p.add_kernel(k) p.compile() - QASM_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - gold_fn = curdir + '/golden/test_barrier_all.qasm' - self.assertTrue(file_compare(QASM_fn, gold_fn)) - + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + gold_fn = os.path.join(qasm_golden_dir, 'test_barrier_all.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) # barrier on all qubits with generalized gate API using wait with duration 0 def test_barrier_all_3(self): @@ -190,9 +183,10 @@ def test_barrier_all_3(self): p.add_kernel(k) p.compile() - QASM_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - gold_fn = curdir + '/golden/test_barrier_all.qasm' - self.assertTrue(file_compare(QASM_fn, gold_fn)) + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + gold_fn = os.path.join(qasm_golden_dir, 'test_barrier_all.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_basics.py b/test/v1x/python/test_basics.py similarity index 64% rename from tests/test_basics.py rename to test/v1x/python/test_basics.py index f2afe6c44..dfa4dd977 100644 --- a/tests/test_basics.py +++ b/test/v1x/python/test_basics.py @@ -1,15 +1,14 @@ -from openql import openql as ql -import unittest +import openql as ql import os -from utils import file_compare +import unittest -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import output_dir, qasm_golden_dir +from utils import file_compare -class Test_basic(unittest.TestCase): +class TestBasic(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) @@ -23,14 +22,13 @@ def setUp(self): ql.set_option('scheduler_post179', 'yes') def test_compilation(self): - - print('output dir : {}'.format( ql.get_option('output_dir') ) ) - platf = ql.Platform("starmon", 'none') - nqubits = 2 - p = ql.Program("basic", platf, nqubits, nqubits) + print('output dir : {}'.format(ql.get_option('output_dir'))) + platform = ql.Platform("starmon", 'none') + num_qubits = 2 + p = ql.Program("basic", platform, num_qubits, num_qubits) # populate kernel - k = ql.Kernel("first_kernel", platf, nqubits, nqubits) + k = ql.Kernel("first_kernel", platform, num_qubits, num_qubits) k.gate('prep_z', [0]) k.gate('x', [0]) @@ -38,7 +36,7 @@ def test_compilation(self): k.gate('measure', [0]) p.add_kernel(k) - k = ql.Kernel("second_kernel", platf, nqubits, nqubits) + k = ql.Kernel("second_kernel", platform, num_qubits, num_qubits) k.gate('prep_z', [0]) k.gate('x90', [0]) k.gate('cz', [0, 1]) @@ -49,7 +47,8 @@ def test_compilation(self): p.compile() for name in ('basic.qasm', 'basic_scheduled.qasm'): - self.assertTrue(file_compare(os.path.join(output_dir, name), os.path.join(curdir, 'golden', name))) + self.assertTrue(file_compare(os.path.join(output_dir, name), os.path.join(qasm_golden_dir, name))) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_bugs.py b/test/v1x/python/test_bugs.py similarity index 56% rename from tests/test_bugs.py rename to test/v1x/python/test_bugs.py index 746901ea6..358b3b2d6 100644 --- a/tests/test_bugs.py +++ b/test/v1x/python/test_bugs.py @@ -1,30 +1,29 @@ +import numpy as np +import openql as ql import os -import filecmp import unittest -import numpy as np -from openql import openql as ql + +from config import cq_dir, cq_golden_dir, output_dir from utils import file_compare -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') -class Test_bugs(unittest.TestCase): +class TestBugs(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('use_default_gates', 'yes') ql.set_option('log_level', 'LOG_WARNING') - os.chdir(curdir) # test_empty_infinite_loop uses relative paths for test_output + cur_dir = os.path.dirname(os.path.realpath(__file__)) + os.chdir(cur_dir) # test_empty_infinite_loop uses relative paths for test_output # @unittest.expectedFailure # @unittest.skip def test_typecast(self): - num_circuits = 1 num_qubits = 2 - platf = ql.Platform("starmon", 'cc_light') - p = ql.Program('test_bug', platf, num_qubits) - k = ql.Kernel('kernel1', platf, num_qubits) + platform = ql.Platform("starmon", 'cc_light') + p = ql.Program('test_bug', platform, num_qubits) + k = ql.Kernel('kernel1', platform, num_qubits) qubit = 1 @@ -39,10 +38,9 @@ def test_typecast(self): # add the kernel to the program p.add_kernel(k) - # relates to https://github.com/QuTech-Delft/OpenQL/issues/171 # various runs of compiles were generating different results or in the best - # case strange errors. So multiple (NCOMPILES) runs of compile are executed + # case strange errors. So multiple (num_compilations) runs of compile are executed # to make sure there is no error and output generated in all these runs is same # JvS: more likely, it also had to do with the classical register allocator # depending on stuff like Python's garbage collection to free a register. @@ -53,11 +51,11 @@ def test_stateful_behavior(self): platform = ql.Platform("myPlatform", 'cc_light') - nqubits = 3 - nregs = 3 + num_qubits = 3 + num_regs = 3 - p = ql.Program("statelessProgram", platform, nqubits, nregs) - k = ql.Kernel("aKernel", platform, nqubits, nregs) + p = ql.Program("statelessProgram", platform, num_qubits, num_regs) + k = ql.Kernel("aKernel", platform, num_qubits, num_regs) k.prepz(0) k.gate('rx180', [0]) @@ -73,28 +71,29 @@ def test_stateful_behavior(self): p.add_kernel(k) - NCOMPILES=50 - QISA_fn = os.path.join(output_dir, p.name+'_last.qasm') - for i in range(NCOMPILES): + num_compilations = 50 + qisa_fn = os.path.join(output_dir, p.name + '_last.qasm') + for i in range(num_compilations): p.compile() self.setUpClass() - QISA_fn_i = os.path.join(output_dir, p.name+'_'+str(i)+'_last.qasm') - os.rename(QISA_fn, QISA_fn_i) + qisa_fn_i = os.path.join(output_dir, p.name + '_' + str(i) + '_last.qasm') + os.rename(qisa_fn, qisa_fn_i) - for i in range(NCOMPILES-1): - QISA_fn_1 = os.path.join(output_dir, p.name+'_'+str(i)+'_last.qasm') - QISA_fn_2 = os.path.join(output_dir, p.name+'_'+str(i+1)+'_last.qasm') - self.assertTrue( file_compare(QISA_fn_1, QISA_fn_2)) + for i in range(num_compilations - 1): + qisa_fn_1 = os.path.join(output_dir, p.name + '_' + str(i) + '_last.qasm') + qisa_fn_2 = os.path.join(output_dir, p.name + '_' + str(i + 1) + '_last.qasm') + self.assertTrue(file_compare(qisa_fn_1, qisa_fn_2)) def test_empty_infinite_loop(self): name = 'empty_infinite_loop' - in_fn = 'test_' + name + '.cq' - out_fn = 'test_output/' + name + '_out.cq' # must match path set inside in_fn - gold_fn = 'golden/' + name + '_out.cq' + in_fn = os.path.join(cq_dir, 'test_' + name + '.cq') + out_fn = os.path.join(output_dir, name + '_out.cq') # must match path set inside in_fn + gold_fn = os.path.join(cq_golden_dir, name + '_out.cq') ql.initialize() # note that output path is set inside file in_fn, so output_dir is not respected - #ql.set_option('log_level', 'LOG_DEBUG') + # ql.set_option('log_level', 'LOG_DEBUG') ql.compile(in_fn) self.assertTrue(file_compare(out_fn, gold_fn)) + if __name__ == '__main__': unittest.main() diff --git a/tests/cc/test_cc.py b/test/v1x/python/test_cc.py similarity index 68% rename from tests/cc/test_cc.py rename to test/v1x/python/test_cc.py index 6bc395811..07d8713b0 100644 --- a/tests/cc/test_cc.py +++ b/test/v1x/python/test_cc.py @@ -2,34 +2,33 @@ # Purpose: test the central controller backend # Based on: ../test_hybrid.py, ../test_uniform_sched.py +import openql as ql import os import unittest -import openql as ql + +from config import json_dir, output_dir from typing import List, Tuple -rootDir = os.path.dirname(os.path.realpath(__file__)) -curdir = os.path.dirname(__file__) -output_dir = os.path.join(curdir, 'test_output') -config_fn = os.path.join(curdir, 'test_cfg_cc.json') -platform_name = 's-17' -num_qubits = 17 -num_cregs = 32 -num_bregs = 32 -all_qubits = range(0, num_qubits) +config_fn = os.path.join(json_dir, 'test_cfg_cc.json') +platform_name = 's-17' +default_num_qubits = 17 +default_num_cregs = 32 +default_num_bregs = 32 +all_qubits = range(0, default_num_qubits) -class Test_central_controller(unittest.TestCase): +class TestCentralController(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('scheduler', 'ALAP') ql.set_option('log_level', 'LOG_WARNING') # NB: based on PycQED::openql_helpers.py + @staticmethod def _configure_compiler( - self, platform: ql.Platform, cqasm_src_filename: str = "", extra_pass_options: List[Tuple[str, str]] = None @@ -39,7 +38,6 @@ def _configure_compiler( c = platform.get_compiler() - # remove default pass list (this also removes support for most *global* options as defined in # https://openql.readthedocs.io/en/latest/gen/reference_options.html, except for 'log_level') # NB: this defeats automatic backend selection by OpenQL based on key "eqasm_compiler" @@ -128,10 +126,10 @@ def _configure_compiler( return c def test_gate_decomposition_cz(self): - platform = ql.Platform(platform_name, os.path.join(curdir, 'config_cc_s17_direct_iq_openql_0_10.json')) + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s17_direct_iq_openql_0_10.json')) - p = ql.Program('test_gate_decomposition_cz', platform, 17, num_cregs, num_bregs) - k = ql.Kernel('kernel_0', platform, 17, num_cregs, num_bregs) + p = ql.Program('test_gate_decomposition_cz', platform, 17, default_num_cregs, default_num_bregs) + k = ql.Kernel('kernel_0', platform, 17, default_num_cregs, default_num_bregs) k.gate("cz", [8, 10]) k.gate("cz", [10, 8]) @@ -157,10 +155,10 @@ def test_gate_decomposition_cz(self): c.compile(p) def test_native_instructions(self): - platform = ql.Platform(platform_name, os.path.join(curdir, 'config_cc_s17_direct_iq_openql_0_10.json')) + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s17_direct_iq_openql_0_10.json')) - p = ql.Program('test_native_instructions', platform, 17, num_cregs, num_bregs) - k = ql.Kernel('kernel_0', platform, 17, num_cregs, num_bregs) + p = ql.Program('test_native_instructions', platform, 17, default_num_cregs, default_num_bregs) + k = ql.Kernel('kernel_0', platform, 17, default_num_cregs, default_num_bregs) k.gate("prepz", [0]) k.gate("i", [0]) @@ -177,10 +175,10 @@ def test_native_instructions(self): p.compile() def test_special_instructions(self): - platform = ql.Platform(platform_name, os.path.join(curdir, 'config_cc_s17_direct_iq_openql_0_10.json')) + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s17_direct_iq_openql_0_10.json')) - p = ql.Program('test_special_instructions', platform, 17, num_cregs, num_bregs) - k = ql.Kernel('kernel_0', platform, 17, num_cregs, num_bregs) + p = ql.Program('test_special_instructions', platform, 17, default_num_cregs, default_num_bregs) + k = ql.Kernel('kernel_0', platform, 17, default_num_cregs, default_num_bregs) k.gate("spec", [0]) k.gate("rx12", [0]) @@ -206,10 +204,10 @@ def test_special_instructions(self): p.compile() def test_gate_decompositions_alias(self): - platform = ql.Platform(platform_name, os.path.join(curdir, 'config_cc_s17_direct_iq_openql_0_10.json')) + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s17_direct_iq_openql_0_10.json')) - p = ql.Program('test_gate_decompositions_alias', platform, 17, num_cregs, num_bregs) - k = ql.Kernel('kernel_0', platform, 17, num_cregs, num_bregs) + p = ql.Program('test_gate_decompositions_alias', platform, 17, default_num_cregs, default_num_bregs) + k = ql.Kernel('kernel_0', platform, 17, default_num_cregs, default_num_bregs) k.gate("x", [0]) k.gate("y", [0]) @@ -228,68 +226,70 @@ def test_gate_decompositions_alias(self): def test_qec(self): platform = ql.Platform(platform_name, config_fn) - p = ql.Program('test_qec', platform, num_qubits, num_cregs, num_bregs) - k = ql.Kernel('kernel_0', platform, num_qubits, num_cregs, num_bregs) + p = ql.Program('test_qec', platform, default_num_qubits, default_num_cregs, default_num_bregs) + k = ql.Kernel('kernel_0', platform, default_num_qubits, default_num_cregs, default_num_bregs) # pipelined QEC: [ # see: R. Versluis et al., Phys. Rev. A 8, 034021 (2017) # - nw, ne, sw, se] -> [n, e, w, s] because we rotate grid # - H -> rym90, ry90, see Fig 2 of reference # - # class SurfaceCode, qubits, tiles, width, getNeighbourN, getNeighbourE, getNeighbourW, getNeighbourS, getX, getZ, getData + # class SurfaceCode, qubits, tiles, width, getNeighbourN, getNeighbourE, getNeighbourW, getNeighbourS, + # getX, getZ, getData # define qubit aliases: # FIXME: neighbours make no sense anymore x = 7 - xN = x-5 - xE = x+1 - xS = x+5 - xW = x-1 + x_n = x - 5 + x_e = x + 1 + x_s = x + 5 + x_w = x - 1 z = 11 - zN = z-5 - zE = z+1 - zS = z+5 - zW = z-1 + z_n = z - 5 + z_e = z + 1 + z_s = z + 5 + z_w = z - 1 # create classical registers - if 0: # FIXME: deprecated by branch condex - rdX = ql.CReg(1) - rdZ = ql.CReg(2) + # FIXME: deprecated by branch condex + # if 0: + # rdx = ql.CReg(1) + # rdz = ql.CReg(2) # X stabilizers k.gate("rym90", [x]) - k.gate("rym90", [xN]) - k.gate("rym90", [xE]) - k.gate("rym90", [xW]) - k.gate("rym90", [xS]) + k.gate("rym90", [x_n]) + k.gate("rym90", [x_e]) + k.gate("rym90", [x_w]) + k.gate("rym90", [x_s]) k.barrier([]) - k.gate("cz", [x, xE]) - k.gate("cz", [x, xN]) - k.gate("cz", [x, xS]) - k.gate("cz", [x, xW]) + k.gate("cz", [x, x_e]) + k.gate("cz", [x, x_n]) + k.gate("cz", [x, x_s]) + k.gate("cz", [x, x_w]) k.barrier([]) k.gate("ry90", [x]) - k.gate("ry90", [xN]) - k.gate("ry90", [xE]) - k.gate("ry90", [xW]) - k.gate("ry90", [xS]) + k.gate("ry90", [x_n]) + k.gate("ry90", [x_e]) + k.gate("ry90", [x_w]) + k.gate("ry90", [x_s]) k.barrier([]) -# k.gate("measure", [x], rdX) - k.gate('measure', [x], 0,0.0, [0]) + # k.gate("measure", [x], rdX) + k.gate('measure', [x], 0, 0.0, [0]) k.barrier([]) # Z stabilizers k.gate("rym90", [z]) k.barrier([]) - k.gate("cz", [z, zE]) - k.gate("cz", [z, zS]) - k.gate("cz", [z, zN]) - k.gate("cz", [z, zW]) + k.gate("cz", [z, z_e]) + k.gate("cz", [z, z_s]) + k.gate("cz", [z, z_n]) + k.gate("cz", [z, z_w]) k.barrier([]) k.gate("ry90", [z]) @@ -302,8 +302,8 @@ def test_qec(self): def test_angle(self): platform = ql.Platform(platform_name, config_fn) - p = ql.Program('test_angle', platform, num_qubits, num_cregs, num_bregs) - k = ql.Kernel('kernel_0', platform, num_qubits, num_cregs, num_bregs) + p = ql.Program('test_angle', platform, default_num_qubits, default_num_cregs, default_num_bregs) + k = ql.Kernel('kernel_0', platform, default_num_qubits, default_num_cregs, default_num_bregs) k.gate("rx180", [6], 0, 1.2345) # NB: Python interface lacks classical parameter @@ -311,10 +311,10 @@ def test_angle(self): p.compile() def test_qi_example(self): - platform = ql.Platform(platform_name, os.path.join(curdir, 'config_cc_s17_direct_iq_openql_0_10.json')) + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s17_direct_iq_openql_0_10.json')) - p = ql.Program('test_qi_example', platform, 17, num_cregs, num_bregs) - k = ql.Kernel('kernel_0', platform, 17, num_cregs, num_bregs) + p = ql.Program('test_qi_example', platform, 17, default_num_cregs, default_num_bregs) + k = ql.Kernel('kernel_0', platform, 17, default_num_cregs, default_num_bregs) k.barrier([]) for q in [0, 1, 2, 3, 4]: @@ -339,8 +339,8 @@ def test_qi_example(self): # based on ../test_cqasm_reader.py::test_conditions # FIXME: uses old cqasm_reader def test_cqasm_conditions(self): - cqasm_config_fn = os.path.join(curdir, 'cqasm_config_cc.json') - platform = ql.Platform(platform_name, os.path.join(curdir, 'cc_s5_direct_iq.json')) + cqasm_config_fn = os.path.join(json_dir, 'config_cc.json') + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s5_direct_iq.json')) number_qubits = platform.get_qubit_number() name = 'test_cqasm_conditions' program = ql.Program(name, platform, number_qubits) @@ -411,12 +411,12 @@ def test_cqasm_conditions(self): qasm_rdr.string2circuit(qasm_str) ql.set_option('log_level', 'LOG_INFO') program.compile() - #self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), os.path.join(curdir, 'golden', name + '.qasm'))) - + # self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), + # os.path.join(qasm_golden_dir, name + '.qasm'))) def test_cqasm_gate_decomposition(self): - cqasm_config_fn = os.path.join(curdir, 'cqasm_config_cc.json') - platform = ql.Platform(platform_name, os.path.join(curdir, 'cc_s5_direct_iq.json')) + cqasm_config_fn = os.path.join(json_dir, 'config_cc.json') + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s5_direct_iq.json')) number_qubits = platform.get_qubit_number() name = 'test_cqasm_gate_decomposition' program = ql.Program(name, platform, number_qubits) @@ -434,34 +434,36 @@ def test_cqasm_gate_decomposition(self): program.compile() # based on test_hybrid.py::test_do_while_nested_for() - @unittest.skip("fails on sf_cz_sw") # FIXME: now fails with "in repeat-until loop body: expected creg reference, but got something else" + # FIXME: now fails with "in repeat-until loop body: expected creg reference, but got something else" + @unittest.skip("fails on sf_cz_sw") # additionally, we don't support if_?_break anymore def test_nested_rus(self): num_qubits = 5 - qidx = 0 + q_idx = 0 - platform = ql.Platform(platform_name, os.path.join(curdir, 'config_cc_s17_direct_iq_openql_0_10.json')) - p = ql.Program('test_nested_rus', platform, num_qubits, num_cregs, num_bregs) + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s17_direct_iq_openql_0_10.json')) + p = ql.Program('test_nested_rus', platform, num_qubits, default_num_cregs, default_num_bregs) - outer_program = ql.Program('outer_program', platform, num_qubits, num_cregs, num_bregs) - outer_kernel = ql.Kernel('outer_kernel', platform, num_qubits, num_cregs) - outer_kernel.gate("measure_fb", [qidx]) - outer_kernel.gate("if_1_break", [qidx]) # FIXME: uses incorrect label + outer_program = ql.Program('outer_program', platform, num_qubits, default_num_cregs, default_num_bregs) + outer_kernel = ql.Kernel('outer_kernel', platform, num_qubits, default_num_cregs) + outer_kernel.gate("measure_fb", [q_idx]) + outer_kernel.gate("if_1_break", [q_idx]) # FIXME: uses incorrect label outer_program.add_kernel(outer_kernel) - inner_program = ql.Program('inner_program', platform, num_qubits, num_cregs, num_bregs) - inner_kernel = ql.Kernel('inner_kernel', platform, num_qubits, num_cregs) - inner_kernel.gate("measure_fb", [qidx]) - inner_kernel.gate("if_0_break", [qidx]) - inner_kernel.gate("rx180", [qidx]) - inner_program.add_for(inner_kernel, 1000000) # NB: loops *kernel* + inner_program = ql.Program('inner_program', platform, num_qubits, default_num_cregs, default_num_bregs) + inner_kernel = ql.Kernel('inner_kernel', platform, num_qubits, default_num_cregs) + inner_kernel.gate("measure_fb", [q_idx]) + inner_kernel.gate("if_0_break", [q_idx]) + inner_kernel.gate("rx180", [q_idx]) + inner_program.add_for(inner_kernel, 1000000) # NB: loops *kernel* outer_program.add_program(inner_program) + # NB: loops *program*, CC backend interprets all conditions as true foo = ql.CReg(0) - p.add_do_while(outer_program, ql.Operation(foo, '==', foo)) # NB: loops *program*, CC backend interprets all conditions as true + p.add_do_while(outer_program, ql.Operation(foo, '==', foo)) - ql.set_option('log_level', 'LOG_INFO') # override log level + ql.set_option('log_level', 'LOG_INFO') # override log level p.compile() # based on DCL test program @@ -472,109 +474,109 @@ def test_nested_rus_angle_0(self): ancilla1idx = 10 ancilla2idx = 8 - dataidx = 11 + data_idx = 11 angle = 0 echo_delay_inner_rus = 1 echo_delay_inner_rus_data = 1 echo_delay_outer_rus = 1 - platform = ql.Platform(platform_name, os.path.join(curdir, 'config_cc_s17_direct_iq.json')) - p = ql.Program('test_nested_rus_angle_0', platform, num_qubits, num_cregs, num_bregs) + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s17_direct_iq.json')) + p = ql.Program('test_nested_rus_angle_0', platform, num_qubits, default_num_cregs, default_num_bregs) - init_kernel = ql.Kernel('initKernel', platform, num_qubits, num_cregs) + init_kernel = ql.Kernel('initKernel', platform, num_qubits, default_num_cregs) init_kernel.prepz(ancilla1idx) init_kernel.prepz(ancilla2idx) - init_kernel.prepz(dataidx) - init_kernel.gate('cw_{:02}'.format(int(angle) // 20 + 9), [dataidx]) + init_kernel.prepz(data_idx) + init_kernel.gate('cw_{:02}'.format(int(angle) // 20 + 9), [data_idx]) init_kernel.gate("wait", [], 0) p.add_kernel(init_kernel) - outer_program = ql.Program('outerProgram', platform, num_qubits, num_cregs, num_bregs) - rus_program_1 = ql.Program('rusProgram1', platform, num_qubits, num_cregs, num_bregs) - rus_kernel_1 = ql.Kernel('rusKernel1', platform, num_qubits, num_cregs) + outer_program = ql.Program('outerProgram', platform, num_qubits, default_num_cregs, default_num_bregs) + rus_program_1 = ql.Program('rusProgram1', platform, num_qubits, default_num_cregs, default_num_bregs) + rus_kernel_1 = ql.Kernel('rusKernel1', platform, num_qubits, default_num_cregs) rus_kernel_1.gate("rx2theta", [ancilla1idx]) rus_kernel_1.gate("rYm90", [ancilla2idx]) rus_kernel_1.gate("cz", [ancilla1idx, ancilla2idx]) rus_kernel_1.gate("rXm2theta", [ancilla1idx]) rus_kernel_1.gate("ry90beta", [ancilla2idx]) - rus_kernel_1.gate("wait", [ancilla1idx,ancilla2idx], 0) - rus_kernel_1.gate("rphi180", [dataidx]) + rus_kernel_1.gate("wait", [ancilla1idx, ancilla2idx], 0) + rus_kernel_1.gate("rphi180", [data_idx]) rus_kernel_1.gate("measure_fb", [ancilla1idx]) rus_kernel_1.gate("wait", [ancilla2idx], echo_delay_inner_rus) rus_kernel_1.gate("rphi180", [ancilla2idx]) rus_kernel_1.gate("wait", [ancilla2idx], 1860-echo_delay_inner_rus) - rus_kernel_1.gate("wait", [dataidx], echo_delay_inner_rus_data) - rus_kernel_1.gate("wait", [ancilla1idx,ancilla2idx,dataidx], 0) + rus_kernel_1.gate("wait", [data_idx], echo_delay_inner_rus_data) + rus_kernel_1.gate("wait", [ancilla1idx, ancilla2idx, data_idx], 0) rus_kernel_1.gate("if_0_break", [ancilla1idx]) - rus_kernel_1.gate("wait", [ancilla1idx,ancilla2idx,dataidx], 0) + rus_kernel_1.gate("wait", [ancilla1idx, ancilla2idx, data_idx], 0) rus_kernel_1.gate("rx180", [ancilla1idx]) rus_kernel_1.gate("rxm90", [ancilla2idx]) - rus_kernel_1.gate("rx180", [dataidx]) - rus_kernel_1.gate("wait", [ancilla1idx,ancilla2idx,dataidx], 0) + rus_kernel_1.gate("rx180", [data_idx]) + rus_kernel_1.gate("wait", [ancilla1idx, ancilla2idx, data_idx], 0) rus_program_1.add_for(rus_kernel_1, 1000000) outer_program.add_program(rus_program_1) - interm_program = ql.Program('intermProgram', platform, num_qubits, num_cregs, num_bregs) - interm_kernel = ql.Kernel('intermKernel', platform, num_qubits, num_cregs) + interm_program = ql.Program('intermProgram', platform, num_qubits, default_num_cregs, default_num_bregs) + interm_kernel = ql.Kernel('intermKernel', platform, num_qubits, default_num_cregs) interm_kernel.gate("rx180", [ancilla2idx]) - interm_kernel.gate("rx180", [dataidx]) - interm_kernel.gate("rYm90", [dataidx]) - interm_kernel.gate("cz", [ancilla2idx, dataidx]) - interm_kernel.gate("rY90", [dataidx]) + interm_kernel.gate("rx180", [data_idx]) + interm_kernel.gate("rYm90", [data_idx]) + interm_kernel.gate("cz", [ancilla2idx, data_idx]) + interm_kernel.gate("rY90", [data_idx]) interm_program.add_kernel(interm_kernel) outer_program.add_program(interm_program) - rus_program_2 = ql.Program('rusProgram2', platform, num_qubits, num_cregs, num_bregs) - rus_kernel_2 = ql.Kernel('rusKernel2', platform, num_qubits, num_cregs) + rus_program_2 = ql.Program('rusProgram2', platform, num_qubits, default_num_cregs, default_num_bregs) + rus_kernel_2 = ql.Kernel('rusKernel2', platform, num_qubits, default_num_cregs) rus_kernel_2.gate("rX2theta", [ancilla1idx]) rus_kernel_2.gate("rYm90alpha", [ancilla2idx]) rus_kernel_2.gate("cz", [ancilla1idx, ancilla2idx]) rus_kernel_2.gate("rX2thetaalpha", [ancilla1idx]) rus_kernel_2.gate("rY90betapi", [ancilla2idx]) - rus_kernel_2.gate("wait", [ancilla1idx,ancilla2idx], 0) - rus_kernel_2.gate("rphi180beta", [dataidx]) + rus_kernel_2.gate("wait", [ancilla1idx, ancilla2idx], 0) + rus_kernel_2.gate("rphi180beta", [data_idx]) rus_kernel_2.gate("measure_fb", [ancilla1idx]) rus_kernel_2.gate("wait", [ancilla2idx], echo_delay_inner_rus) rus_kernel_2.gate("rphi180alpha", [ancilla2idx]) rus_kernel_2.gate("wait", [ancilla2idx], 1860-echo_delay_inner_rus) - rus_kernel_2.gate("wait", [dataidx], echo_delay_inner_rus_data) - rus_kernel_2.gate("wait", [ancilla1idx,ancilla2idx,dataidx], 0) + rus_kernel_2.gate("wait", [data_idx], echo_delay_inner_rus_data) + rus_kernel_2.gate("wait", [ancilla1idx, ancilla2idx, data_idx], 0) rus_kernel_2.gate("if_0_break", [ancilla1idx]) - rus_kernel_2.gate("wait", [ancilla1idx,ancilla2idx,dataidx], 0) + rus_kernel_2.gate("wait", [ancilla1idx, ancilla2idx, data_idx], 0) rus_kernel_2.gate("rx180", [ancilla1idx]) rus_kernel_2.gate("rx90alpha", [ancilla2idx]) - rus_kernel_2.gate("rx180beta", [dataidx]) - rus_kernel_2.gate("wait", [ancilla1idx,ancilla2idx,dataidx], 0) + rus_kernel_2.gate("rx180beta", [data_idx]) + rus_kernel_2.gate("wait", [ancilla1idx, ancilla2idx, data_idx], 0) rus_program_2.add_for(rus_kernel_2, 1000000) outer_program.add_program(rus_program_2) - end_kernel = ql.Kernel('outerKernel', platform, num_qubits, num_cregs) - end_kernel.gate("wait", [ancilla2idx,dataidx], 0) + end_kernel = ql.Kernel('outerKernel', platform, num_qubits, default_num_cregs) + end_kernel.gate("wait", [ancilla2idx, data_idx], 0) end_kernel.gate("rx180alpha2", [ancilla2idx]) end_kernel.gate("measure_fb", [ancilla2idx]) - end_kernel.gate("wait", [dataidx], echo_delay_outer_rus) - end_kernel.gate("rphi180beta2", [dataidx]) - end_kernel.gate("wait", [dataidx], 1880-echo_delay_outer_rus) - end_kernel.gate("wait", [ancilla2idx,dataidx], 0) + end_kernel.gate("wait", [data_idx], echo_delay_outer_rus) + end_kernel.gate("rphi180beta2", [data_idx]) + end_kernel.gate("wait", [data_idx], 1880-echo_delay_outer_rus) + end_kernel.gate("wait", [ancilla2idx, data_idx], 0) end_kernel.gate("if_0_break", [ancilla2idx]) outer_program.add_kernel(end_kernel) foo = ql.CReg(0) p.add_do_while(outer_program, ql.Operation(foo, '==', foo)) - measure_kernel = ql.Kernel('measureKernel', platform, num_qubits, num_cregs) - measure_kernel.gate("measure_fb", [dataidx]) + measure_kernel = ql.Kernel('measureKernel', platform, num_qubits, default_num_cregs) + measure_kernel.gate("measure_fb", [data_idx]) p.add_kernel(measure_kernel) - ql.set_option('log_level', 'LOG_INFO') # override log level + ql.set_option('log_level', 'LOG_INFO') # override log level p.compile() def test_rc_sched_measure(self): - platform = ql.Platform(platform_name, os.path.join(curdir, 'cc_s5_direct_iq.json')) + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s5_direct_iq.json')) - p = ql.Program('test_rc_sched_measure', platform, 5, num_cregs, num_bregs) - k = ql.Kernel('kernel_0', platform, 5, num_cregs, num_bregs) + p = ql.Program('test_rc_sched_measure', platform, 5, default_num_cregs, default_num_bregs) + k = ql.Kernel('kernel_0', platform, 5, default_num_cregs, default_num_bregs) for q in [0, 1, 2, 3, 4]: k.gate("measure", [q]) @@ -586,12 +588,13 @@ def test_rc_sched_measure(self): p.add_kernel(k) p.compile() - @unittest.skip("fails with: 'Inconsistency detected in bundle contents: time travel not yet possible in this version'") # FIXME: solve for real + # FIXME: solve for real + @unittest.skip("fails: 'Inconsistency detected in bundle contents: time travel not yet possible in this version'") def test_rc_sched_measure_asap(self): - platform = ql.Platform(platform_name, os.path.join(curdir, 'cc_s5_direct_iq.json')) + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s5_direct_iq.json')) - p = ql.Program('test_rc_sched_measure_asap', platform, 5, num_cregs, num_bregs) - k = ql.Kernel('kernel_0', platform, 5, num_cregs, num_bregs) + p = ql.Program('test_rc_sched_measure_asap', platform, 5, default_num_cregs, default_num_bregs) + k = ql.Kernel('kernel_0', platform, 5, default_num_cregs, default_num_bregs) k.gate('x', [2]) for q in [0, 1, 2, 3, 4]: @@ -606,10 +609,10 @@ def test_rc_sched_measure_asap(self): p.compile() def test_rc_sched_measure_barrier(self): - platform = ql.Platform(platform_name, os.path.join(curdir, 'cc_s5_direct_iq.json')) + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s5_direct_iq.json')) - p = ql.Program('test_rc_sched_measure_barrier', platform, 5, num_cregs, num_bregs) - k = ql.Kernel('kernel_0', platform, 5, num_cregs, num_bregs) + p = ql.Program('test_rc_sched_measure_barrier', platform, 5, default_num_cregs, default_num_bregs) + k = ql.Kernel('kernel_0', platform, 5, default_num_cregs, default_num_bregs) for q in [0, 1, 2, 3, 4]: k.gate("measure", [q]) @@ -624,14 +627,15 @@ def test_rc_sched_measure_barrier(self): p.add_kernel(k) p.compile() - @unittest.skip("fails with new IR") # FIXME: solve for real + # FIXME: solve for real + @unittest.skip("fails with new IR") def test_rc_sched_cz(self): num_qubits = 17 - platform = ql.Platform(platform_name, os.path.join(curdir, 'config_cc_s17_direct_iq.json')) + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s17_direct_iq.json')) - p = ql.Program('test_rc_sched_cz', platform, num_qubits, num_cregs, num_bregs) - k = ql.Kernel('kernel_0', platform, num_qubits, num_cregs, num_bregs) + p = ql.Program('test_rc_sched_cz', platform, num_qubits, default_num_cregs, default_num_bregs) + k = ql.Kernel('kernel_0', platform, num_qubits, default_num_cregs, default_num_bregs) # NB: requires resource to manage fluxing k.gate("cz", [10, 14]) # no associated park @@ -639,31 +643,29 @@ def test_rc_sched_cz(self): k.gate('x', [10]) p.add_kernel(k) - ql.set_option('log_level', 'LOG_DEBUG') # override log level + ql.set_option('log_level', 'LOG_DEBUG') # override log level p.compile() def test_rc_sched_prepz(self): num_qubits = 17 - platform = ql.Platform(platform_name, os.path.join(curdir, 'config_cc_s17_direct_iq.json')) + platform = ql.Platform(platform_name, os.path.join(json_dir, 'config_cc_s17_direct_iq.json')) - p = ql.Program('test_rc_sched_prepz', platform, num_qubits, num_cregs, num_bregs) - k = ql.Kernel('kernel_0', platform, num_qubits, num_cregs, num_bregs) + p = ql.Program('test_rc_sched_prepz', platform, num_qubits, default_num_cregs, default_num_bregs) + k = ql.Kernel('kernel_0', platform, num_qubits, default_num_cregs, default_num_bregs) k.gate('x', [2]) - k.gate('prepz', [1,2]) + k.gate('prepz', [1, 2]) k.gate('x', [1]) p.add_kernel(k) - ql.set_option('log_level', 'LOG_DEBUG') # override log level + ql.set_option('log_level', 'LOG_DEBUG') # override log level p.compile() - # FIXME: add: # - qec_pipelined # - long program (RB) - if __name__ == '__main__': unittest.main() diff --git a/tests/cc/test_cc_cqasm.py b/test/v1x/python/test_cc_cqasm.py similarity index 73% rename from tests/cc/test_cc_cqasm.py rename to test/v1x/python/test_cc_cqasm.py index df4a1a501..53dd92578 100644 --- a/tests/cc/test_cc_cqasm.py +++ b/test/v1x/python/test_cc_cqasm.py @@ -2,29 +2,24 @@ # Purpose: test CC using cQASM1.2 # Based on: test_structure_decomposition.py -import os -import unittest -import pathlib import inspect -#from utils import file_compare - import openql as ql +import os +import pathlib +import unittest +from config import cq_dir, json_dir, output_dir -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') - - -class Test_cQASM(unittest.TestCase): - def run_test_case(self, name): +class TestCqasm(unittest.TestCase): + @staticmethod + def run_test_case(name): old_wd = os.getcwd() try: - os.chdir(curdir) + cur_dir = os.path.dirname(os.path.realpath(__file__)) + os.chdir(cur_dir) - in_fn = 'test_' + name + '.cq' - out_fn = 'test_output/' + name + '_out.cq' - gold_fn = 'golden/' + name + '_out.cq' + in_fn = os.path.join(cq_dir, 'test_' + name + '.cq') ql.initialize() ql.set_option('log_level', 'LOG_INFO') @@ -33,7 +28,7 @@ def run_test_case(self, name): if 1: # use pass manager - pl = ql.Platform("cc", "config_cc_s17_direct_iq_openql_0_10.json") + pl = ql.Platform("cc", os.path.join(json_dir, "config_cc_s17_direct_iq_openql_0_10.json")) c = pl.get_compiler() # insert passes at front (in reverse run order) @@ -43,7 +38,7 @@ def run_test_case(self, name): 'opt.DeadCodeElim', 'dead_code_elim', { - 'output_prefix': 'test_output/%N.%P', + 'output_prefix': output_dir + '/%N.%P', 'debug': 'yes' } ) @@ -53,19 +48,18 @@ def run_test_case(self, name): 'opt.ConstProp', 'const_prop', { - 'output_prefix': 'test_output/%N.%P', + 'output_prefix': output_dir + '/%N.%P', 'debug': 'yes' } ) - # insert decomposer for legacy decompositions (FIXME: and new style decompositions) # See: see https://openql.readthedocs.io/en/latest/gen/reference_passes.html#instruction-decomposer c.prefix_pass( 'dec.Instructions', 'legacy', # sets predicate key to use legacy decompositions (FIXME: TBC) { - 'output_prefix': 'test_output/%N.%P', + 'output_prefix': output_dir + '/%N.%P', 'debug': 'yes' } ) @@ -76,7 +70,7 @@ def run_test_case(self, name): 'reader', { 'cqasm_file': in_fn, - 'output_prefix': 'test_output/%N.%P', + 'output_prefix': output_dir + '/%N.%P', 'debug': 'yes' } ) @@ -84,21 +78,20 @@ def run_test_case(self, name): # set scheduler options # sch = c.get_pass('scheduler') # sch.set_option('scheduler_target', 'asap') -# c.set_option('scheduler.debug', 'yes') -# c.set_option('scheduler.scheduler_target', 'asap') -# c.set_option('scheduler.scheduler_heuristic', 'none') + # c.set_option('scheduler.debug', 'yes') + # c.set_option('scheduler.scheduler_target', 'asap') + # c.set_option('scheduler.scheduler_heuristic', 'none') c.print_strategy() c.compile_with_frontend(pl) - -# self.assertTrue(file_compare(out_fn, gold_fn)) + # self.assertTrue(file_compare(out_fn, gold_fn)) finally: os.chdir(old_wd) def run_test_case_string(self, name: str, src: str): - pathlib.Path(curdir+"/test_"+name+".cq").write_text(inspect.cleandoc(src)) + pathlib.Path(os.path.join(cq_dir, "test_" + name + ".cq")).write_text(inspect.cleandoc(src)) self.run_test_case(name) def test_rus_elements(self): @@ -122,5 +115,6 @@ def test_const_prop(self): def test_rus_private(self): self.run_test_case('rus_private') + if __name__ == '__main__': unittest.main() diff --git a/tests/test_cc_light.py b/test/v1x/python/test_cc_light.py similarity index 64% rename from tests/test_cc_light.py rename to test/v1x/python/test_cc_light.py index 5955ff5d5..2307e4a9d 100644 --- a/tests/test_cc_light.py +++ b/test/v1x/python/test_cc_light.py @@ -1,23 +1,22 @@ +import openql as ql import os import unittest -from openql import openql as ql -from utils import file_compare -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare -class Test_basic(unittest.TestCase): +class TestBasic(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') # TODO cleanup - ql.set_option('scheduler', 'ASAP'); - ql.set_option('scheduler_post179', 'yes'); + ql.set_option('scheduler', 'ASAP') + ql.set_option('scheduler_post179', 'yes') ql.set_option('log_level', 'LOG_WARNING') @@ -49,14 +48,13 @@ def test_smis(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) # single qubit mask generation test with custom gates def test_smis_with_custom_gates(self): - # You can specify a config location, here we use a default config platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 @@ -78,16 +76,13 @@ def test_smis_with_custom_gates(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) - - # single qubit mask generation multi-kernel test (custom with non-custom - # gates) + # single qubit mask generation multi-kernel test (custom with non-custom gates) def test_smis_multi_kernel(self): - # You can specify a config location, here we use a default config platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 @@ -125,14 +120,12 @@ def test_smis_multi_kernel(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') - - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_smis_all_bundled(self): - # You can specify a config location, here we use a default config platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = platform.get_qubit_number() @@ -152,15 +145,13 @@ def test_smis_all_bundled(self): # compile the program p.compile() - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') - GOLD_fn = curdir + '/golden/test_smis_all_bundled_last.qasm' - - self.assertTrue( file_compare(QASM_fn, GOLD_fn) ) + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, 'test_smis_all_bundled_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) # two qubit mask generation test def test_smit(self): - # You can specify a config location, here we use a default config platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 @@ -190,14 +181,12 @@ def test_smit(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') - - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_smit_all_bundled(self): - # You can specify a config location, here we use a default config platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = platform.get_qubit_number() @@ -222,20 +211,20 @@ def test_smit_all_bundled(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) -class Test_advance(unittest.TestCase): +class TestAdvance(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() def test_qubit_busy(self): ql.set_option('output_dir', output_dir) - platform = ql.Platform('seven_qubits_chip', 'cc_light') + platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 p = ql.Program('test_qubit_busy', platform, num_qubits) @@ -251,15 +240,14 @@ def test_qubit_busy(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') - - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_qwg_available_01(self): ql.set_option('output_dir', output_dir) - platform = ql.Platform('seven_qubits_chip', 'cc_light') + platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 p = ql.Program('test_qwg_available_01', platform, num_qubits) @@ -275,15 +263,14 @@ def test_qwg_available_01(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') - - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_qwg_available_02(self): ql.set_option('output_dir', output_dir) - platform = ql.Platform('seven_qubits_chip', 'cc_light') + platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 p = ql.Program('test_qwg_available_02', platform, num_qubits) @@ -299,15 +286,14 @@ def test_qwg_available_02(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') - - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_qwg_busy(self): ql.set_option('output_dir', output_dir) - platform = ql.Platform('seven_qubits_chip', 'cc_light') + platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 p = ql.Program('test_qwg_busy', platform, num_qubits) @@ -323,17 +309,16 @@ def test_qwg_busy(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) - - def test_measure_available01(self): + def test_measure_available_01(self): ql.set_option('output_dir', output_dir) - platform = ql.Platform('seven_qubits_chip', 'cc_light') + platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 - p = ql.Program('test_measure_available01', platform, num_qubits) + p = ql.Program('test_measure_available_01', platform, num_qubits) k = ql.Kernel('aKernel', platform, num_qubits) @@ -348,17 +333,16 @@ def test_measure_available01(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') - - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) - def test_measure_available02(self): + def test_measure_available_02(self): ql.set_option('output_dir', output_dir) - platform = ql.Platform('seven_qubits_chip', 'cc_light') + platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 - p = ql.Program('test_measure_available02', platform, num_qubits) + p = ql.Program('test_measure_available_02', platform, num_qubits) # populate kernel using default gates k = ql.Kernel('aKernel', platform, num_qubits) @@ -374,15 +358,14 @@ def test_measure_available02(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') - - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_measure_busy(self): ql.set_option('output_dir', output_dir) - platform = ql.Platform('seven_qubits_chip', 'cc_light') + platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 p = ql.Program('test_measure_busy', platform, num_qubits) @@ -401,15 +384,14 @@ def test_measure_busy(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') - - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_edge_available(self): ql.set_option('output_dir', output_dir) - platform = ql.Platform('seven_qubits_chip', 'cc_light') + platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 p = ql.Program('test_edge_available', platform, num_qubits) @@ -425,15 +407,14 @@ def test_edge_available(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') - - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_edge_busy(self): ql.set_option('output_dir', output_dir) - platform = ql.Platform('seven_qubits_chip', 'cc_light') + platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 p = ql.Program('test_edge_busy', platform, num_qubits) @@ -449,15 +430,14 @@ def test_edge_busy(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') - - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_edge_illegal(self): ql.set_option('output_dir', output_dir) - platform = ql.Platform('seven_qubits_chip', 'cc_light') + platform = ql.Platform('seven_qubits_chip', 'cc_light') num_qubits = 7 p = ql.Program('test_edge_illegal', platform, num_qubits) @@ -477,10 +457,8 @@ def test_edge_illegal(self): except: pass - # fast feedback test def test_fast_feedback(self): - # You can specify a config location, here we use a default config ql.set_option('output_dir', output_dir) platform = ql.Platform('seven_qubits_chip', 'cc_light') @@ -500,46 +478,45 @@ def test_fast_feedback(self): # compile the program p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) @unittest.skip def test_ccl_buffers(self): - tests = [ - # mw - mw buffer (same qubit and of course same awg channel is involved) - (0, [ ("x",[0]), ("y",[0]) ]), - # mw - mw buffer (different qubit but same awg channel is involved) - (1, [ ("x",[0]), ("y",[1]) ]), - # mw - mw buffer (different qubit and different awg channel) - (2, [ ("x",[0]), ("y",[2]) ]), - # mw - flux - (3, [ ("x",[2]), ("cnot", [0,2]) ]), - # mw - readout - (4, [ ("x",[0]), ("measure", [0]) ]), - # flux - flux - (5, [ ("cnot", [0,2]), ("cnot", [0,2]) ]), - # flux - mw - (6, [ ("cnot", [0,2]), ("x", [2]) ]), - # flux - readout - (7, [("cnot", [0,2]), ("measure", [2])]), - # readout - readout - (8, [("measure", [0]), ("measure", [0])]), - # readout - mw - (9, [("measure", [0]), ("x", [0])]), - # readout - flux - (10, [("measure", [0]), ("cnot", [0,2]) ]) - ] + # mw - mw buffer (same qubit and of course same awg channel is involved) + (0, [("x", [0]), ("y", [0])]), + # mw - mw buffer (different qubit but same awg channel is involved) + (1, [("x", [0]), ("y", [1])]), + # mw - mw buffer (different qubit and different awg channel) + (2, [("x", [0]), ("y", [2])]), + # mw - flux + (3, [("x", [2]), ("cnot", [0, 2])]), + # mw - readout + (4, [("x", [0]), ("measure", [0])]), + # flux - flux + (5, [("cnot", [0, 2]), ("cnot", [0, 2])]), + # flux - mw + (6, [("cnot", [0, 2]), ("x", [2])]), + # flux - readout + (7, [("cnot", [0, 2]), ("measure", [2])]), + # readout - readout + (8, [("measure", [0]), ("measure", [0])]), + # readout - mw + (9, [("measure", [0]), ("x", [0])]), + # readout - flux + (10, [("measure", [0]), ("cnot", [0, 2])]) + ] for testNo, testKernel in tests: ql.set_option('output_dir', output_dir) print('Running test_ccl_buffers No: {}'.format(testNo)) - config_fn = os.path.join(curdir, 'test_cfg_cc_light_buffers_latencies.json') - platform = ql.Platform('seven_qubits_chip', config_fn) + config_fn = os.path.join(json_dir, 'test_cfg_cc_light_buffers_latencies.json') + platform = ql.Platform('seven_qubits_chip', config_fn) num_qubits = 7 - p = ql.Program('test_ccl_buffers'+str(testNo), platform, num_qubits) + p = ql.Program('test_ccl_buffers' + str(testNo), platform, num_qubits) k = ql.Kernel('aKernel', platform, num_qubits) for gate, qubits in testKernel: @@ -548,17 +525,16 @@ def test_ccl_buffers(self): p.add_kernel(k) p.compile() - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') - - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) # def test_single_qubit_flux_manual01(self): # ql.set_option('output_dir', output_dir) # ql.set_option('cz_mode', 'manual') -# config_fn = os.path.join(curdir, 'hardware_config_cc_light.json') -# platform = ql.Platform('seven_qubits_chip', config_fn) +# config_fn = os.path.join(json_dir, 'config_cc_light.json') +# platform = ql.Platform('seven_qubits_chip', config_fn) # num_qubits = platform.get_qubit_number() # # p = ql.Program('test_single_qubit_flux_manual01', platform, num_qubits) @@ -570,16 +546,16 @@ def test_ccl_buffers(self): # p.add_kernel(k) # p.compile() # -# GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') -# QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') +# gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') +# qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') # -# self.assertTrue(file_compare(QASM_fn, GOLD_fn)) +# self.assertTrue(file_compare(qasm_fn, gold_fn)) # # def test_single_qubit_flux_manual02(self): # ql.set_option('output_dir', output_dir) # ql.set_option('cz_mode', 'manual') -# config_fn = os.path.join(curdir, 'hardware_config_cc_light.json') -# platform = ql.Platform('seven_qubits_chip', config_fn) +# config_fn = os.path.join(json_dir, 'config_cc_light.json') +# platform = ql.Platform('seven_qubits_chip', config_fn) # num_qubits = platform.get_qubit_number() # # p = ql.Program('test_single_qubit_flux_manual02', platform, num_qubits) @@ -596,16 +572,16 @@ def test_ccl_buffers(self): # p.add_kernel(k) # p.compile() # -# GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') -# QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') +# gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') +# qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') # -# self.assertTrue(file_compare(QASM_fn, GOLD_fn)) +# self.assertTrue(file_compare(qasm_fn, gold_fn)) # # def test_single_qubit_flux_auto(self): # ql.set_option('output_dir', output_dir) # ql.set_option('cz_mode', 'auto') -# config_fn = os.path.join(curdir, 'hardware_config_cc_light.json') -# platform = ql.Platform('seven_qubits_chip', config_fn) +# config_fn = os.path.join(json_dir, 'config_cc_light.json') +# platform = ql.Platform('seven_qubits_chip', config_fn) # num_qubits = platform.get_qubit_number() # # p = ql.Program('test_single_qubit_flux_auto', platform, num_qubits) @@ -620,10 +596,11 @@ def test_ccl_buffers(self): # p.add_kernel(k) # p.compile() # -# GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') -# QASM_fn = os.path.join(output_dir, p.name+'_last.qasm') +# gold_fn = os.path.join(qasm_golden_dir, p.name + '_last.qasm') +# qasm_fn = os.path.join(output_dir, p.name + '_last.qasm') # -# self.assertTrue(file_compare(QASM_fn, GOLD_fn)) +# self.assertTrue(file_compare(qasm_fn, gold_fn)) + if __name__ == '__main__': unittest.main() diff --git a/test/v1x/python/test_cc_light_long_duration.py b/test/v1x/python/test_cc_light_long_duration.py new file mode 100644 index 000000000..b45bb3bd9 --- /dev/null +++ b/test/v1x/python/test_cc_light_long_duration.py @@ -0,0 +1,60 @@ +import openql as ql +import os +import unittest + +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare + + +class TestCclLongDuration(unittest.TestCase): + @classmethod + def setUp(cls): + ql.initialize() + + def test_all_xy(self): + """ + Single qubit AllXY sequence. + Writes output files to the directory specified in openql. + Output directory is set as an attribute to the program for convenience. + + Input pars: + qubit_idx: int specifying the target qubit (starting at 0) + platf_cfg: filename of the platform config file + double_points: if true repeats every element twice + Returns: + p: OpenQL Program object containing + """ + ql.set_option('output_dir', output_dir) + config_fn = os.path.join(json_dir, 'test_cfg_CCL_long_duration.json') + platform = ql.Platform('seven_qubits_chip', config_fn) + program = ql.Program("AllXYLongDuration", platform, platform.get_qubit_number()) + + all_xy = [['i', 'i'], ['rx180', 'ry180'], ['ry180', 'rx180']] + # , + # ['rx180', 'ry180'], ['ry180', 'rx180'], + # ['rx90', 'i'], ['ry90', 'i'], ['rx90', 'ry90'], + # ['ry90', 'rx90'], ['rx90', 'ry180'], ['ry90', 'rx180'], + # ['rx180', 'ry90'], ['ry180', 'rx90'], ['rx90', 'rx180'], + # ['rx180', 'rx90'], ['ry90', 'ry180'], ['ry180', 'ry90'], + # ['rx180', 'i'], ['ry180', 'i'], ['rx90', 'rx90'], + # ['ry90', 'ry90']] + + qubit_idx = 0 + for i, xy in enumerate(all_xy): + k = ql.Kernel("AllXY_" + str(i), platform, platform.get_qubit_number()) + k.prepz(qubit_idx) + k.gate(xy[0], [qubit_idx]) + k.gate(xy[1], [qubit_idx]) + k.measure(qubit_idx) + program.add_kernel(k) + + program.compile() + + gold_fn = os.path.join(qasm_golden_dir, program.name + '_last.qasm') + qisa_fn = os.path.join(output_dir, program.name + '_last.qasm') + + self.assertTrue(file_compare(qisa_fn, gold_fn)) + + +if __name__ == '__main__': + unittest.main() diff --git a/test/v1x/python/test_commutation.py b/test/v1x/python/test_commutation.py new file mode 100644 index 000000000..9298470f4 --- /dev/null +++ b/test/v1x/python/test_commutation.py @@ -0,0 +1,698 @@ +import openql as ql +import os +import unittest + +from config import qasm_golden_dir, output_dir +from utils import file_compare + + +# s5 would do as well +# cnot, t, z, etc. must not have been decomposed to exploit their commute properties +config_fn = 'cc_light.s7' + + +class TestCommutation(unittest.TestCase): + def setUp(self): + ql.initialize() + ql.set_option('output_dir', output_dir) + ql.set_option('log_level', 'LOG_WARNING') + + # ASAP is easier to construct and verify the tests + ql.set_option('scheduler', 'ASAP') + + # don't optimize since gates are used by the tests to create 'latency' + # to enforce schedules that make a difference with/without commutation + ql.set_option('clifford_prescheduler', 'no') + ql.set_option('clifford_postscheduler', 'no') + ql.set_option('clifford_premapper', 'no') + ql.set_option('clifford_postmapper', 'no') + + def test_cnot_z_nn_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'no') + ql.set_option("scheduler_commute_rotations", 'no') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on z operand of CNOT/T/Z/... + # gates on q0 commute with gates on q3 and could even be in parallel + # q3 is cnot control and thus z-commuting operand i.e. with t q3 and z q3 + # q0 is cnot target and thus x-commuting operand, of which there are none + # so: cnot commutes with later t q3 and z q3, making t q3 and z q3 available in parallel to q0 gates, + + # while cnot has to be after t q0 and z q0, so intended result is that t q3 and z q3 get before cnot + # + # both commutation options are 'no' so input order must be kept + k.gate("t", [0]) + k.gate("z", [0]) + k.gate("cnot", [3, 0]) + k.gate("t", [3]) + k.gate("z", [3]) + + p = ql.Program("test_cnot_z_NN_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_z_2n_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'no') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on z operand of CNOT/T/Z/... + # gates on q0 commute with gates on q3 and could even be in parallel + # q3 is cnot control and thus z-commuting operand i.e. with t q3 and z q3 + # q0 is cnot target and thus x-commuting operand, of which there are none + # so: cnot commutes with later t q3 and z q3, making t q3 and z q3 available in parallel to q0 gates, + # while cnot has to be after t q0 and z q0, so intended result is that t q3 and z q3 get before cnot + # + # only cnot/cz commutation is enabled so input order must be kept + k.gate("t", [0]) + k.gate("z", [0]) + k.gate("cnot", [3, 0]) + k.gate("t", [3]) + k.gate("z", [3]) + + p = ql.Program("test_cnot_z_2N_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_z_2r_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'yes') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on z operand of CNOT/T/Z/... + # gates on q0 commute with gates on q3 and could even be in parallel + # q3 is cnot control and thus z-commuting operand i.e. with t q3 and z q3 + # q0 is cnot target and thus x-commuting operand, of which there are none + # so: cnot commutes with later t q3 and z q3, making t q3 and z q3 available in parallel to q0 gates, + # while cnot has to be after t q0 and z q0, so intended result is that t q3 and z q3 get before cnot + # + # also rotation commutation is enabled so intended result as above should be result + k.gate("t", [0]) + k.gate("z", [0]) + k.gate("cnot", [3, 0]) + k.gate("t", [3]) + k.gate("z", [3]) + + p = ql.Program("test_cnot_z_2R_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_x_nn_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'no') + ql.set_option("scheduler_commute_rotations", 'no') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on x operand of CNOT/X/X45/... + # gates on q0 commute with gates on q3 and could even be in parallel + # q3 is cnot control and thus z-commuting operand, of which there are none + # q0 is cnot target and thus x-commuting operand, i.e. x q0 and x45 q0 + # so: cnot commutes with later x q0 and x45 q0, making x q0 and x45 q0 available in parallel to q3 gates, + # while cnot has to be after x q3 and x45 q3, so intended result is that x q0 and x45 q0 get before cnot + # + # both commutation options are 'no' so input order must be kept + k.gate("x", [3]) + k.gate("x45", [3]) + k.gate("cnot", [3, 0]) + k.gate("x", [0]) + k.gate("x45", [0]) + + p = ql.Program("test_cnot_x_NN_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_x_2n_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'no') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on x operand of CNOT/X/X45/... + # gates on q0 commute with gates on q3 and could even be in parallel + # q3 is cnot control and thus z-commuting operand, of which there are none + # q0 is cnot target and thus x-commuting operand, i.e. x q0 and x45 q0 + # so: cnot commutes with later x q0 and x45 q0, making x q0 and x45 q0 available in parallel to q3 gates, + # while cnot has to be after x q3 and x45 q3, so intended result is that x q0 and x45 q0 get before cnot + # + # only cnot/cz commutation is enabled so input order must be kept + k.gate("x", [3]) + k.gate("x45", [3]) + k.gate("cnot", [3, 0]) + k.gate("x", [0]) + k.gate("x45", [0]) + + p = ql.Program("test_cnot_x_2N_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_x_2r_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'yes') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on x operand of CNOT/X/X45/... + # gates on q0 commute with gates on q3 and could even be in parallel + # q3 is cnot control and thus z-commuting operand, of which there are none + # q0 is cnot target and thus x-commuting operand, i.e. x q0 and x45 q0 + # so: cnot commutes with later x q0 and x45 q0, making x q0 and x45 q0 available in parallel to q3 gates, + # while cnot has to be after x q3 and x45 q3, so intended result is that x q0 and x45 q0 get before cnot + # + # also rotation commutation is enabled so intended result as above should be result + k.gate("x", [3]) + k.gate("x45", [3]) + k.gate("cnot", [3, 0]) + k.gate("x", [0]) + k.gate("x45", [0]) + + p = ql.Program("test_cnot_x_2R_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_nn_non_commute_rad(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'no') + ql.set_option("scheduler_commute_rotations", 'no') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # the 2 cnots don't commute although a commute would shorten the circuit's latency + # the common qubit is q3 and it is target (x position) of the first and control (z position) of the second cnot + # this is a RAD (or ZAX) dependence between the cnots + # + # gates on q5 commute with cnot q0,q3 and could be in parallel + # but cnot q3,q5 doesn't commute with first cnot and q5 gates depend on it (and don't commute) + # so: shortening circuit is blocked by 2nd cnot not commuting with first and with gates + # + # commute options are both off + # circuit will be as input + k.gate("cnot", [0, 3]) + k.gate("cnot", [3, 5]) + k.gate("t", [5]) + k.gate("z", [5]) + + p = ql.Program("test_cnot_NN_non_commute_RAD", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_2r_non_commute_rad(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'yes') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # the 2 cnots don't commute although a commute would shorten the circuit's latency + # the common qubit is q3 and it is target (x position) of the first and control (z position) of the second cnot + # this is a RAD (or ZAX) dependence between the cnots + # + # gates on q5 commute with cnot q0,q3 and could be in parallel + # but cnot q3,q5 doesn't commute with first cnot and q5 gates depend on it (and don't commute) + # so: shortening circuit is blocked by 2nd cnot not commuting with first and with gates + # + # commute options are both on + # circuit will be as input + k.gate("cnot", [0, 3]) + k.gate("cnot", [3, 5]) + k.gate("t", [5]) + k.gate("z", [5]) + + p = ql.Program("test_cnot_2R_non_commute_RAD", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_nn_non_commute_dar(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'no') + ql.set_option("scheduler_commute_rotations", 'no') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # the 2 cnots don't commute although a commute would shorten the circuit's latency + # the common qubit is q3 and it is control (z position) of the first and target (x position) of the second cnot + # this is a DAR (or XAZ) dependence between the cnots + # + # gates on q0 commute with cnot q3,q5 and could be in parallel + # but cnot q0,q3 doesn't commute with first cnot and q0 gates depend on it (and don't commute) + # so: shortening circuit is blocked by 2nd cnot not commuting with first and with gates + # + # commute options are both off + # circuit will be as input + k.gate("cnot", [3, 5]) + k.gate("cnot", [0, 3]) + k.gate("x45", [0]) + k.gate("x", [0]) + k.gate("x45", [0]) + + p = ql.Program("test_cnot_NN_non_commute_DAR", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_2r_non_commute_dar(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'yes') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # the 2 cnots don't commute although a commute would shorten the circuit's latency + # the common qubit is q3, and it is control (z position) of the first and target (x position) of the second cnot + # this is a DAR (or XAZ) dependence between the cnots + # + # gates on q0 commute with cnot q3,q5 and could be in parallel + # but cnot q0,q3 doesn't commute with first cnot and q0 gates depend on it (and don't commute) + # so: shortening circuit is blocked by 2nd cnot not commuting with first and with gates + # + # commute options are both on + # circuit will be as input + k.gate("cnot", [3, 5]) + k.gate("cnot", [0, 3]) + k.gate("x45", [0]) + k.gate("x", [0]) + k.gate("x45", [0]) + + p = ql.Program("test_cnot_2R_non_commute_DAR", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_nn_control_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'no') + ql.set_option("scheduler_commute_rotations", 'no') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on control operand of CNOT + # without any commutation, the order is kept + k.gate("cnot", [3, 0]) + k.gate("cnot", [3, 6]) + k.gate("x45", [6]) + k.gate("x", [6]) + k.gate("cnot", [3, 1]) + k.gate("x45", [1]) + k.gate("x", [1]) + k.gate("x45", [1]) + k.gate("x", [1]) + + p = ql.Program("test_cnot_NN_control_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_2n_control_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'no') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on control operand of CNOT + # without rotation commutation, last one is most critical so cnot order is reversed wrt input order + k.gate("cnot", [3, 0]) + k.gate("cnot", [3, 6]) + k.gate("x45", [6]) + k.gate("x", [6]) + k.gate("cnot", [3, 1]) + k.gate("x45", [1]) + k.gate("x", [1]) + k.gate("x45", [1]) + k.gate("x", [1]) + + p = ql.Program("test_cnot_2N_control_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_2r_control_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'yes') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on control operand of CNOT + # with all commutation, all gates commute, so any result order is ok + k.gate("cnot", [3, 0]) + k.gate("cnot", [3, 6]) + k.gate("x45", [6]) + k.gate("x", [6]) + k.gate("cnot", [3, 1]) + k.gate("x45", [1]) + k.gate("x", [1]) + k.gate("x45", [1]) + k.gate("x", [1]) + + p = ql.Program("test_cnot_2R_control_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_nn_target_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'no') + ql.set_option("scheduler_commute_rotations", 'no') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on target operand of CNOT + # without any commutation, the order is kept + k.gate("cnot", [0, 3]) + k.gate("cnot", [6, 3]) + k.gate("t", [6]) + k.gate("z", [6]) + k.gate("cnot", [1, 3]) + k.gate("t", [1]) + k.gate("z", [1]) + k.gate("t", [1]) + k.gate("z", [1]) + + p = ql.Program("test_cnot_NN_target_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_2n_target_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'no') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on target operand of CNOT + # without rotation commutation, last one is most critical so cnot order is reversed wrt input order + k.gate("cnot", [0, 3]) + k.gate("cnot", [6, 3]) + k.gate("t", [6]) + k.gate("z", [6]) + k.gate("cnot", [1, 3]) + k.gate("t", [1]) + k.gate("z", [1]) + k.gate("t", [1]) + k.gate("z", [1]) + + p = ql.Program("test_cnot_2N_target_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_2r_target_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'yes') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on target operand of CNOT + # with all commutation, all gates commute, so any result order is ok + k.gate("cnot", [0, 3]) + k.gate("cnot", [6, 3]) + k.gate("t", [6]) + k.gate("z", [6]) + k.gate("cnot", [1, 3]) + k.gate("t", [1]) + k.gate("z", [1]) + k.gate("t", [1]) + k.gate("z", [1]) + + p = ql.Program("test_cnot_2R_target_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cz_nn_any_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'no') + ql.set_option("scheduler_commute_rotations", 'no') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on both operands of CZ + # without any commutation, order is kept + k.gate("cz", [0, 3]) + k.gate("cz", [3, 6]) + k.gate("t", [6]) + k.gate("z", [6]) + k.gate("cz", [1, 3]) + k.gate("t", [1]) + k.gate("z", [1]) + k.gate("t", [1]) + k.gate("z", [1]) + + p = ql.Program("test_cz_NN_any_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cz_2n_any_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'no') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on both operands of CZ + # without rotation commutation, cz order is reversed wrt input because last one is most critical + k.gate("cz", [0, 3]) + k.gate("cz", [3, 6]) + k.gate("t", [6]) + k.gate("z", [6]) + k.gate("cz", [1, 3]) + k.gate("t", [1]) + k.gate("z", [1]) + k.gate("t", [1]) + k.gate("z", [1]) + + p = ql.Program("test_cz_2N_any_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cz_2r_any_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'yes') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on both operands of CZ + # with all commutation, all gates commute, so any result order is ok + k.gate("cz", [0, 3]) + k.gate("cz", [3, 6]) + k.gate("t", [6]) + k.gate("z", [6]) + k.gate("cz", [1, 3]) + k.gate("t", [1]) + k.gate("z", [1]) + k.gate("t", [1]) + k.gate("z", [1]) + + p = ql.Program("test_cz_2R_any_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_cnot_mixed_commute(self): + platform = ql.Platform("starmon", config_fn) + + ql.set_option("scheduler_commute", 'yes') + ql.set_option("scheduler_commute_rotations", 'yes') + + num_qubits = 7 + k = ql.Kernel("aKernel", platform, num_qubits) + + # commute on mixture of operands of many CNOTs: + # the only dependencies are those reflecting that + # each CNOT(a,b) must be before CNOT(b,c), since b is in common but in different positions (RAD), + # each CNOT(a,b) must be before CNOT(c,a), since a is in common but in different positions (DAR), + # all dep chains have length 3: + # cnot[0,*] -> cnot[2,*] -> cnot[5,*] + # cnot[0,*] -> cnot[3,*] -> cnot[6,*] + # cnot[1,*] -> cnot[3,*] -> cnot[6,*] + # cnot[1,*] -> cnot[4,*] -> cnot[6,*] + # so the end result should reflect those 3 bundles with cnots, one for each column above + # but after rc scheduling, the middle ones because of classical control constraints, causing 4 bundles + k.gate("cnot", [0, 2]) + k.gate("cnot", [0, 3]) + k.gate("cnot", [1, 3]) + k.gate("cnot", [1, 4]) + k.gate("cnot", [2, 0]) + k.gate("cnot", [2, 5]) + k.gate("cnot", [3, 0]) + k.gate("cnot", [3, 1]) + k.gate("cnot", [3, 5]) + k.gate("cnot", [3, 6]) + k.gate("cnot", [4, 1]) + k.gate("cnot", [4, 6]) + k.gate("cnot", [5, 2]) + k.gate("cnot", [5, 3]) + k.gate("cnot", [6, 3]) + k.gate("cnot", [6, 4]) + + p = ql.Program("test_cnot_mixed_commute", platform, num_qubits) + p.add_kernel(k) + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + +# def test_cnot_variations(self): +# platform = ql.Platform("starmon", config_fn) +# ql.set_option("scheduler", 'ALAP') +# ql.set_option("scheduler_commute", 'yes') +# ql.set_option("vary_commutations", 'yes') +# +# num_qubits = 7 +# k = ql.Kernel("aKernel", platform, num_qubits) +# +# for j in range(7): +# k.gate("x", [j]) +# # commute on mixture of operands of many CNOTs +# # basically, each CNOT(a,b) must ultimately be before CNOT(b,a) +# # in between, CNOT(a,b) commutes with CNOT(a,c) and CNOT(d,b) +# # there will be several commutation sets +# k.gate("cnot", [0, 2]) +# k.gate("cnot", [0, 3]) +# k.gate("cnot", [1, 3]) +# k.gate("cnot", [1, 4]) +# k.gate("cnot", [2, 0]) +# k.gate("cnot", [2, 5]) +# k.gate("cnot", [3, 0]) +# k.gate("cnot", [3, 1]) +# k.gate("cnot", [3, 5]) +# k.gate("cnot", [3, 6]) +# k.gate("cnot", [4, 1]) +# k.gate("cnot", [4, 6]) +# # k.gate("cnot", [5, 2]) +# # k.gate("cnot", [5, 3]) +# # k.gate("cnot", [6, 3]) +# # k.gate("cnot", [6, 4]) +# for j in range(7): +# k.gate("x", [j]) +# +# +# p = ql.Program("test_cnot_variations", platform, num_qubits) +# p.add_kernel(k) +# p.compile() +# +# gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') +# qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') +# self.assertTrue(file_compare(qasm_fn, gold_fn)) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_compiler_api.py b/test/v1x/python/test_compiler_api.py similarity index 97% rename from tests/test_compiler_api.py rename to test/v1x/python/test_compiler_api.py index ff7eb8701..b5e031b66 100644 --- a/tests/test_compiler_api.py +++ b/test/v1x/python/test_compiler_api.py @@ -1,14 +1,10 @@ import openql as ql import os -import unittest -from utils import file_compare import tempfile +import unittest -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') - -class test_compiler_api(unittest.TestCase): +class TestCompilerApi(unittest.TestCase): def setUp(self): ql.initialize() self.maxDiff = None @@ -378,8 +374,8 @@ def test_compiler_json_5(self): def test_compiler_json_6(self): with tempfile.TemporaryDirectory() as d: - fname = os.path.join(d, 'test.json') - with open(fname, 'w') as f: + file_name = os.path.join(d, 'test.json') + with open(file_name, 'w') as f: f.write(""" { "eqasm_compiler": { @@ -397,7 +393,7 @@ def test_compiler_json_6(self): "instructions": {} } """) - self.assertEqual(ql.Platform('compiler', fname).get_compiler().dump_strategy().strip(), """ + self.assertEqual(ql.Platform('compiler', file_name).get_compiler().dump_strategy().strip(), """ - io_cqasm_report: io.cqasm.Report |- no options to dump """.strip()) @@ -406,4 +402,3 @@ def test_compiler_json_6(self): if __name__ == '__main__': # ql.set_option('log_level', 'LOG_DEBUG') unittest.main() - diff --git a/tests/test_condex.py b/test/v1x/python/test_condex.py similarity index 74% rename from tests/test_condex.py rename to test/v1x/python/test_condex.py index 1997c8bf0..875ceff8a 100644 --- a/tests/test_condex.py +++ b/test/v1x/python/test_condex.py @@ -5,20 +5,18 @@ # assumes config files: test_mapper_s7.json # -from openql import openql as ql +import openql as ql import os import unittest -from utils import file_compare - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import output_dir, qasm_golden_dir +from utils import file_compare -class Test_condex(unittest.TestCase): +class TestCondex(unittest.TestCase): def setUp(self): ql.initialize() - ql.set_option('output_dir', output_dir) # this uses output_dir set above + ql.set_option('output_dir', output_dir) # this uses output_dir set above ql.set_option('log_level', 'LOG_NOTHING') ql.set_option('write_qasm_files', 'no') @@ -70,19 +68,19 @@ def test_condex_basic(self): # measure q0 and q1 and then x conditionally on b0 OP b1 on q0 k.gate("measure", [0]) k.gate("measure", [1]) - k.condgate("x", [0], 'COND_AND', [0,1]) - k.condgate("x", [0], 'COND_NAND', [0,1]) - k.condgate("x", [0], 'COND_OR', [0,1]) - k.condgate("x", [0], 'COND_NOR', [0,1]) - k.condgate("x", [0], 'COND_XOR', [0,1]) - k.condgate("x", [0], 'COND_NXOR', [0,1]) + k.condgate("x", [0], 'COND_AND', [0, 1]) + k.condgate("x", [0], 'COND_NAND', [0, 1]) + k.condgate("x", [0], 'COND_OR', [0, 1]) + k.condgate("x", [0], 'COND_NOR', [0, 1]) + k.condgate("x", [0], 'COND_XOR', [0, 1]) + k.condgate("x", [0], 'COND_NXOR', [0, 1]) prog.add_kernel(k) prog.compile() - gold_fn = curdir + '/golden/' + prog_name +'_scheduled.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) ql.set_option('use_default_gates', 'no') @@ -109,9 +107,9 @@ def test_condex_measure(self): prog.add_kernel(k) prog.compile() - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_condex_cnot(self): # check whether condex works with conditional cnot gate which is to be decomposed by mapper @@ -134,32 +132,32 @@ def test_condex_cnot(self): ql.set_option('mappathselect', 'all') ql.set_option('maptiebreak', 'first') - k.gate("cnot", [0,1]) + k.gate("cnot", [0, 1]) k.gate("measure", [2]) - k.gate("cnot", [0,2], 0, 0.0, [], 'COND_UNARY', [2]) + k.gate("cnot", [0, 2], 0, 0.0, [], 'COND_UNARY', [2]) k.gate("measure", [2]) - k.condgate("cnot", [0,5], 'COND_UNARY', [2]) + k.condgate("cnot", [0, 5], 'COND_UNARY', [2]) k.gate("measure", [2]) k.gate_preset_condition('COND_UNARY', [2]) - k.gate("cnot", [0,6]) + k.gate("cnot", [0, 6]) k.gate_clear_condition() prog.add_kernel(k) prog.compile() - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) ql.set_option('mapper', 'no') - def test_condex_toffoli_composgate(self): + def test_condex_toffoli_compos_gate(self): # check whether condex works with conditional toffoli gate which is to be decomposed by toffoli decomposition # parameters - v = 'toffoli_composgate' + v = 'toffoli_compos_gate' num_qubits = 7 num_bregs = num_qubits @@ -177,28 +175,29 @@ def test_condex_toffoli_composgate(self): ql.set_option('mappathselect', 'all') ql.set_option('maptiebreak', 'first') - k.gate("toffoli_decomp", [0,1,5]) + k.gate("toffoli_decomp", [0, 1, 5]) k.gate("measure", [0]) - k.gate("toffoli_decomp", [0,1,5], 0, 0.0, [], 'COND_UNARY', [0]) + k.gate("toffoli_decomp", [0, 1, 5], 0, 0.0, [], 'COND_UNARY', [0]) k.gate("measure", [0]) - k.condgate("toffoli_decomp", [0,1,5], 'COND_UNARY', [0]) + k.condgate("toffoli_decomp", [0, 1, 5], 'COND_UNARY', [0]) k.gate("measure", [0]) k.gate_preset_condition('COND_UNARY', [0]) - k.gate("toffoli_decomp", [0,1,5]) + k.gate("toffoli_decomp", [0, 1, 5]) k.gate_clear_condition() prog.add_kernel(k) prog.compile() - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) ql.set_option('mapper', 'no') + if __name__ == '__main__': # ql.set_option('log_level', 'LOG_DEBUG') unittest.main() diff --git a/tests/test_configuration.py b/test/v1x/python/test_configuration.py similarity index 74% rename from tests/test_configuration.py rename to test/v1x/python/test_configuration.py index c1f47885b..64d041f26 100644 --- a/tests/test_configuration.py +++ b/test/v1x/python/test_configuration.py @@ -1,15 +1,13 @@ -import numpy as np +import openql as ql import os import unittest -from openql import openql as ql -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import json_dir, output_dir -class Test_Configuration(unittest.TestCase): +class TestConfiguration(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') @@ -18,14 +16,14 @@ def setUp(self): # ql.set_option('write_qasm_files', 'yes') def test_case_insensitivity(self): - config_fn = os.path.join(curdir, 'test_cfg_CCL_long_duration.json') - platform = ql.Platform('seven_qubits_chip', config_fn) + config_fn = os.path.join(json_dir, 'test_cfg_CCL_long_duration.json') + platform = ql.Platform('seven_qubits_chip', config_fn) p = ql.Program("test_case_insensitivity", platform, platform.get_qubit_number()) k = ql.Kernel('aKernel', platform, platform.get_qubit_number()) - k.gate('Rx180', [0]) # in the configuartion its name is rx180 q0 - k.gate('rX180', [2]) # in the configuartion its name is rx180 q2 - k.gate('CZ', [2, 0]) # in the configuartion its name is cz q2, q0 + k.gate('Rx180', [0]) # in the configuration its name is rx180 q0 + k.gate('rX180', [2]) # in the configuration its name is rx180 q2 + k.gate('CZ', [2, 0]) # in the configuration its name is cz q2, q0 # add the kernel to the program p.add_kernel(k) @@ -43,11 +41,9 @@ def test_case_insensitivity(self): # errors = qasm_reader.load() # self.assertTrue(errors == 0) - - def test_missing_instr(self): - config_fn = os.path.join(curdir, 'test_cfg_CCL_long_duration.json') - platform = ql.Platform('seven_qubits_chip', config_fn) + config_fn = os.path.join(json_dir, 'test_cfg_CCL_long_duration.json') + platform = ql.Platform('seven_qubits_chip', config_fn) p = ql.Program("test_missing_instr", platform, platform.get_qubit_number()) k = ql.Kernel('aKernel', platform, platform.get_qubit_number()) diff --git a/tests/test_conjugate.py b/test/v1x/python/test_conjugate.py similarity index 72% rename from tests/test_conjugate.py rename to test/v1x/python/test_conjugate.py index fecdaadc6..73655673d 100644 --- a/tests/test_conjugate.py +++ b/test/v1x/python/test_conjugate.py @@ -1,16 +1,14 @@ +import openql as ql import os import unittest -from openql import openql as ql -from utils import file_compare - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare -class Test_conjugated_kernel(unittest.TestCase): +class TestConjugatedKernel(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') @@ -19,12 +17,12 @@ def setUp(self): # ql.set_option('write_qasm_files', 'yes') def test_conjugate(self): - config_fn = os.path.join(curdir, 'test_cfg_none_simple.json') + config_fn = os.path.join(json_dir, 'test_cfg_none_simple.json') platform = ql.Platform('platform_none', config_fn) num_qubits = 3 p = ql.Program('test_conjugate', platform, num_qubits) - k = ql.Kernel('kernel_orignal', platform, num_qubits) + k = ql.Kernel('kernel_original', platform, num_qubits) ck = ql.Kernel('kernel_conjugate', platform, num_qubits) k.gate("x", [0]) @@ -51,8 +49,8 @@ def test_conjugate(self): p.compile() - gold_fn = curdir + '/golden/test_conjugate.qasm' - qasm_fn = os.path.join(output_dir, p.name+'.qasm') + gold_fn = os.path.join(qasm_golden_dir, 'test_conjugate.qasm') + qasm_fn = os.path.join(output_dir, p.name + '.qasm') self.assertTrue(file_compare(qasm_fn, gold_fn)) diff --git a/tests/test_controlled_kernel.py b/test/v1x/python/test_controlled_kernel.py similarity index 66% rename from tests/test_controlled_kernel.py rename to test/v1x/python/test_controlled_kernel.py index e9f9f7564..5b1a8853a 100644 --- a/tests/test_controlled_kernel.py +++ b/test/v1x/python/test_controlled_kernel.py @@ -1,17 +1,15 @@ +import numpy as np +import openql as ql import os import unittest -from openql import openql as ql -import numpy as np -from utils import file_compare - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare -class Test_controlled_kernel(unittest.TestCase): +class TestControlledKernel(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') @@ -19,8 +17,8 @@ def setUp(self): ql.set_option('log_level', 'LOG_WARNING') def test_controlled_single_qubit_gates(self): - config_fn = os.path.join(curdir, 'test_cfg_none_simple.json') - platform = ql.Platform('platform_none', config_fn) + config_fn = os.path.join(json_dir, 'test_cfg_none_simple.json') + platform = ql.Platform('platform_none', config_fn) num_qubits = 3 p = ql.Program('test_controlled_single_qubit_gates', platform, num_qubits) @@ -45,22 +43,22 @@ def test_controlled_single_qubit_gates(self): p.compile() - gold_fn = curdir + '/golden/' + p.name +'_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_controlled_rotations(self): - config_fn = os.path.join(curdir, 'test_cfg_none_simple.json') - platform = ql.Platform('platform_none', config_fn) + config_fn = os.path.join(json_dir, 'test_cfg_none_simple.json') + platform = ql.Platform('platform_none', config_fn) num_qubits = 3 p = ql.Program('test_controlled_rotations', platform, num_qubits) k = ql.Kernel('kernel1', platform, num_qubits) ck = ql.Kernel('controlled_kernel1', platform, num_qubits) - k.gate("rx", [0], 0, (np.pi)/4 ) # duration = 0 uses default value of duration - k.gate("ry", [0], 0, (np.pi)/4 ) # duration = 0 uses default value of duration - k.gate("rz", [0], 0, (np.pi)/4 ) # duration = 0 uses default value of duration + k.gate("rx", [0], 0, np.pi/4) # duration = 0 uses default value of duration + k.gate("ry", [0], 0, np.pi/4) # duration = 0 uses default value of duration + k.gate("rz", [0], 0, np.pi/4) # duration = 0 uses default value of duration # generate controlled version of k. # qubit 1 is used as control qubit @@ -72,13 +70,13 @@ def test_controlled_rotations(self): p.compile() - gold_fn = curdir + '/golden/' + p.name +'_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_controlled_two_qubit_gates(self): - config_fn = os.path.join(curdir, 'test_cfg_none_simple.json') - platform = ql.Platform('platform_none', config_fn) + config_fn = os.path.join(json_dir, 'test_cfg_none_simple.json') + platform = ql.Platform('platform_none', config_fn) num_qubits = 4 p = ql.Program('test_controlled_two_qubit_gates', platform, num_qubits) @@ -97,13 +95,13 @@ def test_controlled_two_qubit_gates(self): p.compile() - gold_fn = curdir + '/golden/' + p.name +'_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_multi_controlled(self): - config_fn = os.path.join(curdir, 'test_cfg_none_simple.json') - platform = ql.Platform('platform_none', config_fn) + config_fn = os.path.join(json_dir, 'test_cfg_none_simple.json') + platform = ql.Platform('platform_none', config_fn) num_qubits = 12 p = ql.Program('test_multi_controlled', platform, num_qubits) @@ -126,9 +124,10 @@ def test_multi_controlled(self): p.compile() - gold_fn = curdir + '/golden/' + p.name +'_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') self.assertTrue(file_compare(qasm_fn, gold_fn)) + if __name__ == '__main__': unittest.main() diff --git a/tests/test_cqasm.py b/test/v1x/python/test_cqasm.py similarity index 70% rename from tests/test_cqasm.py rename to test/v1x/python/test_cqasm.py index 39a340455..8d6ec16c4 100644 --- a/tests/test_cqasm.py +++ b/test/v1x/python/test_cqasm.py @@ -1,18 +1,17 @@ +import openql as ql import os -import filecmp import unittest + +from config import output_dir, qasm_golden_dir from utils import file_compare -from openql import openql as ql -curdir = os.path.dirname(os.path.realpath(__file__)) -platf = ql.Platform("starmon", "none") -output_dir = os.path.join(curdir, 'test_output') +platform = ql.Platform("starmon", "none") -class Test_cqasm(unittest.TestCase): +class TestCqasm(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') @@ -20,13 +19,12 @@ def setUp(self): ql.set_option('log_level', 'LOG_INFO') # ql.set_option('write_qasm_files', 'yes') - def test_cqasm_default_gates(self): ql.set_option('use_default_gates', 'yes') - nqubits = 4 + num_qubits = 4 - k = ql.Kernel("aKernel", platf, nqubits) + k = ql.Kernel("aKernel", platform, num_qubits) k.gate('prep_z', [0]) k.gate('identity', [0]) k.gate('hadamard', [0]) @@ -51,24 +49,23 @@ def test_cqasm_default_gates(self): k.gate('measure', [0]) k.gate('measure', [1]) - - p = ql.Program('test_cqasm_default_gates', platf, nqubits) + p = ql.Program('test_cqasm_default_gates', platform, num_qubits) p.add_kernel(k) p.compile() for ext in ('.qasm', '_scheduled.qasm'): - GOLD_fn = os.path.join(curdir, 'golden', p.name + ext) - QISA_fn = os.path.join(output_dir, p.name + ext) + gold_fn = os.path.join(qasm_golden_dir, p.name + ext) + qisa_fn = os.path.join(output_dir, p.name + ext) - self.assertTrue(file_compare(QISA_fn, GOLD_fn)) + self.assertTrue(file_compare(qisa_fn, gold_fn)) # @unittest.skip def test_cqasm_custom_gates(self): ql.set_option('use_default_gates', 'no') - nqubits = 4 + num_qubits = 4 - k = ql.Kernel("aKernel", platf, nqubits) + k = ql.Kernel("aKernel", platform, num_qubits) k.gate('prep_z', [0]) k.gate('i', [0]) k.gate('h', [0]) @@ -93,16 +90,16 @@ def test_cqasm_custom_gates(self): k.gate('measure', [0]) k.gate('measure', [1]) - - p = ql.Program('test_cqasm_custom_gates', platf, nqubits) + p = ql.Program('test_cqasm_custom_gates', platform, num_qubits) p.add_kernel(k) p.compile() for ext in ('.qasm', '_scheduled.qasm'): - GOLD_fn = os.path.join(curdir, 'golden', p.name + ext) - QISA_fn = os.path.join(output_dir, p.name + ext) + gold_fn = os.path.join(qasm_golden_dir, p.name + ext) + qisa_fn = os.path.join(output_dir, p.name + ext) + + self.assertTrue(file_compare(qisa_fn, gold_fn)) - self.assertTrue(file_compare(QISA_fn, GOLD_fn)) if __name__ == '__main__': unittest.main() diff --git a/tests/test_cqasm_reader.py b/test/v1x/python/test_cqasm_reader.py similarity index 90% rename from tests/test_cqasm_reader.py rename to test/v1x/python/test_cqasm_reader.py index eeb0be0fb..c349583cc 100644 --- a/tests/test_cqasm_reader.py +++ b/test/v1x/python/test_cqasm_reader.py @@ -1,17 +1,14 @@ -from openql import openql as ql -import unittest +import openql as ql import os -from utils import file_compare - - -curdir = os.path.dirname(__file__) -output_dir = os.path.join(curdir, 'test_output') +import unittest +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare -class TestcQasmReader(unittest.TestCase): +class TestCqasmReader(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) # ql.set_option("write_qasm_files", "yes") @@ -55,7 +52,8 @@ def test_single_bit_kernel_operations(self): "measure_z q[4]\n" qasm_rdr.string2circuit(qasm_str) program.compile() - self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), os.path.join(curdir, 'golden', name + '.qasm'))) + self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), + os.path.join(qasm_golden_dir, name + '.qasm'))) def test_cqasm_real_numbers(self): platform = ql.Platform('seven_qubits_chip', 'none') @@ -69,7 +67,8 @@ def test_cqasm_real_numbers(self): "rx q[0], 1.0\n" qasm_rdr.string2circuit(qasm_str) program.compile() - self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), os.path.join(curdir, 'golden', name + '.qasm'))) + self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), + os.path.join(qasm_golden_dir, name + '.qasm'))) def test_sub_circuit_programs(self): platform = ql.Platform('seven_qubits_chip', 'cc_light') @@ -89,7 +88,8 @@ def test_sub_circuit_programs(self): " measure_all\n" qasm_rdr.string2circuit(qasm_str) program.compile() - self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), os.path.join(curdir, 'golden', name + '.qasm'))) + self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), + os.path.join(qasm_golden_dir, name + '.qasm'))) def test_parallel_programs(self): platform = ql.Platform('seven_qubits_chip', 'cc_light') @@ -107,7 +107,8 @@ def test_parallel_programs(self): " { measure_z q[0] | measure_z q[1] }\n" qasm_rdr.string2circuit(qasm_str) program.compile() - self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), os.path.join(curdir, 'golden', name + '.qasm'))) + self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), + os.path.join(qasm_golden_dir, name + '.qasm'))) def test_multiple_programs(self): platform = ql.Platform('seven_qubits_chip', 'cc_light') @@ -131,10 +132,11 @@ def test_multiple_programs(self): "measure_all\n" qasm_rdr.string2circuit(qasm_str) program.compile() - self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), os.path.join(curdir, 'golden', name + '.qasm'))) + self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), + os.path.join(qasm_golden_dir, name + '.qasm'))) def test_conditions(self): - cqasm_config_fn = os.path.join(curdir, 'cqasm_config_cc_light.json') + cqasm_config_fn = os.path.join(json_dir, 'config_cc_light.json') platform = ql.Platform('seven_qubits_chip', 'cc_light') number_qubits = platform.get_qubit_number() name = 'test_cqasm_conditions' @@ -186,7 +188,8 @@ def test_conditions(self): "cond(!(false ^^ cb)) z qa\n" qasm_rdr.string2circuit(qasm_str) program.compile() - self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), os.path.join(curdir, 'golden', name + '.qasm'))) + self.assertTrue(file_compare(os.path.join(output_dir, name + '.qasm'), + os.path.join(qasm_golden_dir, name + '.qasm'))) if __name__ == '__main__': diff --git a/tests/test_custom_gate.py b/test/v1x/python/test_custom_gate.py similarity index 57% rename from tests/test_custom_gate.py rename to test/v1x/python/test_custom_gate.py index a228a7a62..bb839ea24 100644 --- a/tests/test_custom_gate.py +++ b/test/v1x/python/test_custom_gate.py @@ -1,26 +1,25 @@ +import openql as ql import os import unittest -from openql import openql as ql -curdir = os.path.dirname(os.path.realpath(__file__)) -platf = ql.Platform("starmon", "cc_light") +from config import output_dir -output_dir = os.path.join(curdir, 'test_output') + +platform = ql.Platform("starmon", "cc_light") ql.set_option('output_dir', output_dir) # ql.set_option('write_qasm_files', 'yes') -class Test_kernel(unittest.TestCase): - +class TestKernel(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() def custom_gate_test(self): - nqubits = 1 + num_qubits = 1 # create a kernel - k = ql.Kernel("aKernel", platf, nqubits) + k = ql.Kernel("aKernel", platform, num_qubits) # load custom instruction definition k.load_custom_instructions("instructions.json") @@ -37,7 +36,7 @@ def custom_gate_test(self): k.gate("rx180", 0) # create a program - p = ql.Program("custom_gate_test", platf, nqubits) + p = ql.Program("custom_gate_test", platform, num_qubits) # add kernel to program p.add_kernel(k) @@ -46,18 +45,16 @@ def custom_gate_test(self): p.compile(optimize=False, scheduler='ASAP', log_level='LOG_WARNING') # load qasm - qasm_files = [] - qasm_files.append(os.path.join(output_dir, 'custom_gate_test.qasm')) - qasm_files.append(os.path.join(output_dir, 'custom_gate_test_scheduled.qasm')) + qasm_files = [os.path.join(output_dir, 'custom_gate_test.qasm'), + os.path.join(output_dir, 'custom_gate_scheduled_test.qasm')] for qasm_file in qasm_files: - qasm_reader = ql.QASM_Loader(qasm_file) - errors = qasm_reader.load() - self.assertTrue(errors == 0) - - + qasm_reader = ql.QASM_Loader(qasm_file) + errors = qasm_reader.load() + self.assertTrue(errors == 0) # all the outputs are generated in 'output' dir + if __name__ == '__main__': unittest.main() diff --git a/test/v1x/python/test_dependence.py b/test/v1x/python/test_dependence.py new file mode 100644 index 000000000..132e68025 --- /dev/null +++ b/test/v1x/python/test_dependence.py @@ -0,0 +1,196 @@ +import openql as ql +import os +import unittest + +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare + +config_fn = os.path.join(json_dir, 'test_config_default.json') +platform = ql.Platform("starmon", config_fn) + + +class TestDependence(unittest.TestCase): + def setUp(self): + ql.initialize() + ql.set_option('output_dir', output_dir) + ql.set_option('optimize', 'no') + ql.set_option('scheduler', 'ASAP') + ql.set_option('scheduler_commute', 'no') + ql.set_option('log_level', 'LOG_WARNING') + # ql.set_option('write_qasm_files', 'yes') + + # @unittest.expectedFailure + # @unittest.skip + def test_independent(self): + num_qubits = 4 + # populate kernel + kernel = ql.Kernel("aKernel", platform, num_qubits) + + for i in range(4): + kernel.prepz(i) + + # no dependence + kernel.cz(0, 1) + kernel.cz(2, 3) + + kernel.measure(0) + kernel.measure(1) + + program = ql.Program("independent", platform, num_qubits) + program.add_kernel(kernel) + program.compile() + + gold_fn = os.path.join(qasm_golden_dir, 'test_independence.qasm') + qasm_fn = os.path.join(output_dir, program.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + # @unittest.skip + def test_waw(self): + num_qubits = 4 + # populate kernel + kernel = ql.Kernel("aKernel", platform, num_qubits) + + for i in range(4): + kernel.prepz(i) + + # q1 dependence + kernel.cz(0, 1) + kernel.cz(2, 1) + + kernel.measure(0) + kernel.measure(1) + + program = ql.Program("WAW", platform, num_qubits) + program.add_kernel(kernel) + program.compile() + + gold_fn = os.path.join(qasm_golden_dir, 'test_WAW_ASAP.qasm') + qasm_fn = os.path.join(output_dir, program.name + '_scheduled.qasm') + + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + # @unittest.skip + def test_rar_control(self): + num_qubits = 4 + + # populate kernel + kernel = ql.Kernel("aKernel", platform, num_qubits) + + for i in range(4): + kernel.prepz(i) + + # q0 dependence + kernel.cz(0, 1) + kernel.cz(0, 2) + + kernel.measure(0) + kernel.measure(1) + + program = ql.Program("RAR", platform, num_qubits) + program.add_kernel(kernel) + program.compile() + + gold_fn = os.path.join(qasm_golden_dir, 'test_RAR_Control_ASAP.qasm') + qasm_fn = os.path.join(output_dir, program.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + # @unittest.skip + def test_raw(self): + + num_qubits = 4 + + # populate kernel + kernel = ql.Kernel("aKernel", platform, num_qubits) + + for i in range(4): + kernel.prepz(i) + + # q1 dependence + kernel.cz(0, 1) + kernel.cz(1, 2) + + kernel.measure(0) + kernel.measure(1) + + program = ql.Program("RAW", platform, num_qubits) + program.add_kernel(kernel) + program.compile() + + gold_fn = os.path.join(qasm_golden_dir, 'test_RAW_ASAP.qasm') + qasm_fn = os.path.join(output_dir, program.name + '_scheduled.qasm') + + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + # @unittest.skip + def test_war(self): + + num_qubits = 4 + + # populate kernel + kernel = ql.Kernel("aKernel", platform, num_qubits) + + for i in range(4): + kernel.prepz(i) + + # q0 dependence + kernel.cz(0, 1) + kernel.cz(2, 0) + + kernel.measure(0) + kernel.measure(1) + + program = ql.Program("WAR", platform, num_qubits) + program.add_kernel(kernel) + program.compile() + + gold_fn = os.path.join(qasm_golden_dir, 'test_WAR_ASAP.qasm') + qasm_fn = os.path.join(output_dir, program.name + '_scheduled.qasm') + + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + # @unittest.skip + def test_swap_single(self): + + num_qubits = 4 + + # populate kernel + kernel = ql.Kernel("aKernel", platform, num_qubits) + + kernel.gate("x", [0]) + kernel.gate("swap", [0, 1]) + kernel.gate("x", [0]) + + program = ql.Program("swap_single", platform, num_qubits) + program.add_kernel(kernel) + program.compile() + + gold_fn = os.path.join(qasm_golden_dir, 'test_swap_single_ASAP.qasm') + qasm_fn = os.path.join(output_dir, program.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + # @unittest.skip + def test_swap_multi(self): + + num_qubits = 5 + + # populate kernel + kernel = ql.Kernel("aKernel", platform, num_qubits) + + # swap test with 2 qubit gates + kernel.gate("x", [0]) + kernel.gate("x", [1]) + kernel.gate("swap", [0, 1]) + kernel.gate("cz", [0, 2]) + kernel.gate("cz", [1, 4]) + + program = ql.Program("swap_multi", platform, num_qubits) + program.add_kernel(kernel) + program.compile() + + gold_fn = os.path.join(qasm_golden_dir, 'test_swap_multi_ASAP.qasm') + qasm_fn = os.path.join(output_dir, program.name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_diamond.py b/test/v1x/python/test_diamond.py similarity index 67% rename from tests/test_diamond.py rename to test/v1x/python/test_diamond.py index c05bd35df..19c9164a2 100644 --- a/tests/test_diamond.py +++ b/test/v1x/python/test_diamond.py @@ -1,13 +1,12 @@ +import openql as ql import os -from utils import file_compare import unittest -from openql import openql as ql -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import cq_dir, output_dir, qasm_golden_dir +from utils import file_compare -class Test_diamond(unittest.TestCase): +class TestDiamond(unittest.TestCase): def test_diamond_api(self): ql.initialize() ql.set_option('output_dir', output_dir) @@ -15,9 +14,9 @@ def test_diamond_api(self): platform = ql.Platform('diamond_test', 'diamond') - nqubits = 3 - p = ql.Program('diamond_api', platform, nqubits) - k = ql.Kernel('kernel', platform, nqubits) + num_qubits = 3 + p = ql.Program('diamond_api', platform, num_qubits) + k = ql.Kernel('kernel', platform, num_qubits) # Initialization k.gate('prep_z', [0]) @@ -39,7 +38,7 @@ def test_diamond_api(self): k.t(0) # two qubit gates - k.gate('cnot', [0, 1]) # only between color center - nuclear spin qubit + k.gate('cnot', [0, 1]) # only between color center - nuclear spin qubit k.gate('cz', [0, 1]) # three qubit gate @@ -58,17 +57,17 @@ def test_diamond_api(self): k.gate('cr', [0, 1], 0, 3.14) # diamond protocols/sequences - k.diamond_crc(0,30,5) - k.diamond_rabi_check(0, 100, 2, 3) # qubit, duration, measurement, t_max - k.diamond_excite_mw(1, 100, 200, 0, 60, 0) # envelope, duration, frequency, phase, amplitude, qubit - k.diamond_qentangle(0,15) # qubit, nuclear qubit + k.diamond_crc(0, 30, 5) + k.diamond_rabi_check(0, 100, 2, 3) # qubit, duration, measurement, t_max + k.diamond_excite_mw(1, 100, 200, 0, 60, 0) # envelope, duration, frequency, phase, amplitude, qubit + k.diamond_qentangle(0, 15) # qubit, nuclear qubit k.gate('nventangle', [0, 1]) - k.diamond_memswap(0,1) # qubit, nuclear qubit - k.diamond_sweep_bias(0, 10, 0, 0, 10, 100, 0) #qubit, value, dacreg, start, step, max, memaddress + k.diamond_memswap(0, 1) # qubit, nuclear qubit + k.diamond_sweep_bias(0, 10, 0, 0, 10, 100, 0) # qubit, value, dacreg, start, step, max, memaddress # timing k.gate('wait', [], 200) - k.gate('qnop', [0]) # qubit, mandatory from openQL + k.gate('qnop', [0]) # qubit, mandatory from openQL # calculate bias k.gate('calculate_current', [0]) @@ -83,11 +82,11 @@ def test_diamond_api(self): p.add_kernel(k) p.compile() - gold_fn = curdir + '/golden/' + p.name + '_scheduled.qasm' + gold_fn = os.path.join(qasm_golden_dir, p.name + '_scheduled.qasm') qasm_fn = os.path.join(output_dir, p.name + '_scheduled.qasm') self.assertTrue(file_compare(qasm_fn, gold_fn)) - gold_fn = curdir + '/golden/' + p.name + '_diamond_codegen.dqasm' + gold_fn = os.path.join(qasm_golden_dir, p.name + '_diamond_codegen.dqasm') qasm_fn = os.path.join(output_dir, p.name + '_diamond_codegen.dqasm') self.assertTrue(file_compare(qasm_fn, gold_fn)) @@ -102,17 +101,17 @@ def test_diamond_cqasm(self): 'io.cqasm.Read', '', { - 'cqasm_file': curdir + '/diamond_cqasm_test.cq', + 'cqasm_file': os.path.join(cq_dir, 'test_diamond.cq'), 'measure_all_target': 'measure_z' } ) compiler.compile_with_frontend(platform) - gold_fn = curdir + '/golden/diamond_cqasm_scheduled.qasm' + gold_fn = os.path.join(qasm_golden_dir, 'diamond_cqasm_scheduled.qasm') qasm_fn = os.path.join(output_dir, 'diamond_cqasm_scheduled.qasm') self.assertTrue(file_compare(qasm_fn, gold_fn)) - gold_fn = curdir + '/golden/diamond_cqasm_diamond_codegen.dqasm' + gold_fn = os.path.join(qasm_golden_dir, 'diamond_cqasm_diamond_codegen.dqasm') qasm_fn = os.path.join(output_dir, 'diamond_cqasm_diamond_codegen.dqasm') self.assertTrue(file_compare(qasm_fn, gold_fn)) diff --git a/tests/test_exceptions.py b/test/v1x/python/test_exceptions.py similarity index 53% rename from tests/test_exceptions.py rename to test/v1x/python/test_exceptions.py index 65f6f6d47..8e331ae39 100644 --- a/tests/test_exceptions.py +++ b/test/v1x/python/test_exceptions.py @@ -1,24 +1,25 @@ -from openql import openql as ql -import unittest +import openql as ql import os +import unittest -curdir = os.path.dirname(os.path.realpath(__file__)) +from config import json_dir -class Test_basic(unittest.TestCase): +class TestBasic(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() # this test should raise exception as specified configuration # file does not exist def test_missing_config(self): - config_fn = os.path.join(curdir, 'test_cfg_cbox_not_available.json') + config_fn = os.path.join(json_dir, 'test_cfg_cbox_not_available.json') try: - platf = ql.Platform("starmon", config_fn) + ql.Platform("starmon", config_fn) raise except: pass + if __name__ == '__main__': unittest.main() diff --git a/tests/test_flux.py b/test/v1x/python/test_flux.py similarity index 61% rename from tests/test_flux.py rename to test/v1x/python/test_flux.py index 5e8244992..719e328f7 100644 --- a/tests/test_flux.py +++ b/test/v1x/python/test_flux.py @@ -2,23 +2,23 @@ # # assumes config files: test_mapper_s7.json # -from openql import openql as ql + +import openql as ql import os import unittest -from utils import file_compare - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import output_dir, qasm_golden_dir +from utils import file_compare -class Test_mapper(unittest.TestCase): +class TestMapper(unittest.TestCase): def setUp(self): ql.initialize() # uses defaults of options in mapper branch except for output_dir and for maptiebreak - ql.set_option('output_dir', output_dir) # this uses output_dir set above - ql.set_option('maptiebreak', 'first') # this makes behavior deterministic to cmp with golden - # and deviates from default + # this uses output_dir set above + ql.set_option('output_dir', output_dir) + # this makes behavior deterministic to cmp with golden and deviates from default + ql.set_option('maptiebreak', 'first') ql.set_option('log_level', 'LOG_NOTHING') ql.set_option('optimize', 'no') @@ -52,33 +52,33 @@ def test_flux_all(self): for j in range(7): k.gate("x", [j]) - k.gate("cz", [0,2]) - k.gate("cz", [0,3]) - k.gate("cz", [1,3]) - k.gate("cz", [1,4]) - k.gate("cz", [2,0]) - k.gate("cz", [2,5]) - k.gate("cz", [3,0]) - k.gate("cz", [3,1]) - k.gate("cz", [3,5]) - k.gate("cz", [3,6]) - k.gate("cz", [4,1]) - k.gate("cz", [4,6]) - k.gate("cz", [5,2]) - k.gate("cz", [5,3]) - k.gate("cz", [6,3]) - k.gate("cz", [6,4]) + k.gate("cz", [0, 2]) + k.gate("cz", [0, 3]) + k.gate("cz", [1, 3]) + k.gate("cz", [1, 4]) + k.gate("cz", [2, 0]) + k.gate("cz", [2, 5]) + k.gate("cz", [3, 0]) + k.gate("cz", [3, 1]) + k.gate("cz", [3, 5]) + k.gate("cz", [3, 6]) + k.gate("cz", [4, 1]) + k.gate("cz", [4, 6]) + k.gate("cz", [5, 2]) + k.gate("cz", [5, 3]) + k.gate("cz", [6, 3]) + k.gate("cz", [6, 4]) for j in range(7): k.gate("x", [j]) prog.add_kernel(k) prog.compile() - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') self.assertTrue(file_compare(qasm_fn, gold_fn)) + if __name__ == '__main__': # ql.set_option('log_level', 'LOG_DEBUG') unittest.main() - diff --git a/test/v1x/python/test_gate_decomposition.py b/test/v1x/python/test_gate_decomposition.py new file mode 100644 index 000000000..3f513d881 --- /dev/null +++ b/test/v1x/python/test_gate_decomposition.py @@ -0,0 +1,51 @@ +import openql as ql +import os +import unittest + +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare + + +class Tester(unittest.TestCase): + @classmethod + def setUp(cls): + ql.initialize() + ql.set_option('output_dir', output_dir) + ql.set_option('optimize', 'no') + ql.set_option('scheduler', 'ALAP') + ql.set_option('log_level', 'LOG_NOTHING') + + def test_decomposition(self): + config_fn = os.path.join(json_dir, 'test_cfg_none.json') + platform = ql.Platform('platform_none', config_fn) + num_qubits = 17 + p = ql.Program('test_decomposition', platform, num_qubits) + + k = ql.Kernel('aKernel', platform, num_qubits) + + k.x(0) # x will be decomposed + k.gate("x", [0]) # x will be decomposed + k.gate("y", [0]) # decomposition not available, will use custom gate + k.gate("s", [1]) # decomposition as well as custom gate not available, will use default gate + k.gate("roty90", [0]) # any name can be used for composite gate + + # decomposition overrules custom(=primitive) gate + # decomposition uses specialized cz q0,q1 + k.gate("cnot", [0, 1]) + # cnot will be decomposed; decomposition falls back to default gate for cz q2,q3 + k.gate("cnot", [2, 3]) + + # add the kernel to the program + p.add_kernel(k) + + # compile the program + p.compile() + + prog_name = "test_decomposition" + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_scheduled.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_instruction_decomposition.py b/test/v1x/python/test_instruction_decomposition.py similarity index 83% rename from tests/test_instruction_decomposition.py rename to test/v1x/python/test_instruction_decomposition.py index cb469c7a9..3484e4c10 100644 --- a/tests/test_instruction_decomposition.py +++ b/test/v1x/python/test_instruction_decomposition.py @@ -1,21 +1,21 @@ +import openql as ql import os import unittest -from openql import openql as ql -from utils import file_compare -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import cq_golden_dir, output_dir +from utils import file_compare -class Test_instruction_decomposition(unittest.TestCase): +class TestInstructionDecomposition(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('log_level', 'LOG_WARNING') - def get_test_program(self, name): - platf = ql.Platform.from_json('test_platform', { + @staticmethod + def get_test_program(name): + platform = ql.Platform.from_json('test_platform', { "hardware_settings": { "qubit_number": 3 }, @@ -42,8 +42,8 @@ def get_test_program(self, name): } } }) - p = ql.Program(name, platf) - k = ql.Kernel('test', platf) + p = ql.Program(name, platform) + k = ql.Kernel('test', platform) k.cnot(0, 1) k.cnot(1, 2) p.add_kernel(k) @@ -63,7 +63,7 @@ def test_decompose_before_schedule(self): for suffix in ['in', 'dec', 'sch']: self.assertTrue(file_compare( os.path.join(output_dir, name + '_' + suffix + '.cq'), - os.path.join(curdir, 'golden', name + '_' + suffix + '.cq') + os.path.join(cq_golden_dir, name + '_' + suffix + '.cq') )) def test_decompose_after_schedule(self): @@ -80,8 +80,9 @@ def test_decompose_after_schedule(self): for suffix in ['in', 'sch', 'dec']: self.assertTrue(file_compare( os.path.join(output_dir, name + '_' + suffix + '.cq'), - os.path.join(curdir, 'golden', name + '_' + suffix + '.cq') + os.path.join(cq_golden_dir, name + '_' + suffix + '.cq') )) + if __name__ == '__main__': unittest.main() diff --git a/test/v1x/python/test_mapper.py b/test/v1x/python/test_mapper.py new file mode 100644 index 000000000..3e2d659e8 --- /dev/null +++ b/test/v1x/python/test_mapper.py @@ -0,0 +1,674 @@ +# tests for mapper +# +# +# tests combination of prescheduler, clifford, mapper, clifford and postscheduler in cc_light context +# by generating .qisa and comparing the generated one with a golden one after assembly +# +# assumes config files: test_mapper_rig.json, test_mapper_s7.json and test_mapper_s17.json +# +# written to avoid initial placement since that is not portable +# (although turning it on with options and enabling it by uncommenting first line of src/mapper.h would test it) +# for option assumptions, see setUp below +# see for more details, comment lines with each individual test below + +import openql as ql +import os +import unittest + +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare + + +class TestMapper(unittest.TestCase): + def setUp(self): + ql.initialize() + # uses defaults of options in mapper branch except for output_dir and for maptiebreak + # this uses output_dir set above + ql.set_option('output_dir', output_dir) + # this makes behavior deterministic to cmp with golden and deviates from default + ql.set_option('maptiebreak', 'first') + + ql.set_option('log_level', 'LOG_NOTHING') + ql.set_option('optimize', 'no') + ql.set_option('use_default_gates', 'no') + ql.set_option('decompose_toffoli', 'no') + ql.set_option('scheduler', 'ALAP') + ql.set_option('scheduler_uniform', 'no') + ql.set_option('scheduler_commute', 'yes') + ql.set_option('prescheduler', 'yes') + ql.set_option('cz_mode', 'manual') + ql.set_option('print_dot_graphs', 'no') + + ql.set_option('clifford_premapper', 'yes') + ql.set_option('clifford_postmapper', 'yes') + ql.set_option('mapper', 'minextend') + ql.set_option('mapusemoves', 'yes') + ql.set_option('mapreverseswap', 'yes') + ql.set_option('mappathselect', 'all') + ql.set_option('maplookahead', 'noroutingfirst') + ql.set_option('maprecNN2q', 'no') + ql.set_option('mapselectmaxlevel', '0') + ql.set_option('mapselectmaxwidth', 'min') + + ql.set_option('write_qasm_files', 'no') + ql.set_option('write_report_files', 'no') + + def test_mapper_max_cut(self): + # rigetti test copied from Venturelli's paper + v = 'max_cut' + config_fn = os.path.join(json_dir, "test_mapper_rig.json") + num_qubits = 8 + + # create and set platform + prog_name = "test_mapper_" + v + kernel_name = "kernel_" + v + starmon = ql.Platform("starmon", config_fn) + prog = ql.Program(prog_name, starmon, num_qubits, 0) + k = ql.Kernel(kernel_name, starmon, num_qubits, 0) + + k.gate("x", [0]) + k.gate("x", [1]) + k.gate("x", [2]) + k.gate("x", [3]) + k.gate("x", [4]) + k.gate("x", [5]) + k.gate("x", [6]) + k.gate("x", [7]) + + k.gate("cz", [1, 4]) + k.gate("cz", [1, 3]) + k.gate("cz", [3, 4]) + k.gate("cz", [3, 7]) + k.gate("cz", [4, 7]) + k.gate("cz", [6, 7]) + k.gate("cz", [5, 6]) + k.gate("cz", [1, 5]) + + k.gate("x", [0]) + k.gate("x", [1]) + k.gate("x", [2]) + k.gate("x", [3]) + k.gate("x", [4]) + k.gate("x", [5]) + k.gate("x", [6]) + k.gate("x", [7]) + + prog.add_kernel(k) + prog.compile() + + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_mapper_one_nn(self): + # just check whether mapper works for trivial case + # parameters + v = 'one_NN' + config_fn = "cc_light.s7" + num_qubits = 7 + + # create and set platform + prog_name = "test_mapper_" + v + kernel_name = "kernel_" + v + starmon = ql.Platform("starmon", config_fn) + prog = ql.Program(prog_name, starmon, num_qubits, 0) + k = ql.Kernel(kernel_name, starmon, num_qubits, 0) + + k.gate("x", [0]) + k.gate("y", [1]) + k.gate("cnot", [2, 5]) + + prog.add_kernel(k) + prog.compile() + + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_mapper_all_nn(self): + # a list of all cnots that are NN in trivial/natural mapping (as in test_mapper_s7.json) + # (s7 is 3 rows: 2 data qubits (0 and 1), 3 ancillas (2 to 4), and 2 data qubits (5 and 6)) + # so no swaps are inserted and map is not changed + # also tests commutation of cnots in mapper and postscheduler + # parameters + v = 'all_NN' + config_fn = "cc_light.s7" + num_qubits = 7 + + # create and set platform + prog_name = "test_mapper_" + v + kernel_name = "kernel_" + v + starmon = ql.Platform("starmon", config_fn) + prog = ql.Program(prog_name, starmon, num_qubits, 0) + k = ql.Kernel(kernel_name, starmon, num_qubits, 0) + + for j in range(7): + k.gate("x", [j]) + k.gate("cnot", [0, 2]) + k.gate("cnot", [0, 3]) + k.gate("cnot", [1, 3]) + k.gate("cnot", [1, 4]) + k.gate("cnot", [2, 0]) + k.gate("cnot", [2, 5]) + k.gate("cnot", [3, 0]) + k.gate("cnot", [3, 1]) + k.gate("cnot", [3, 5]) + k.gate("cnot", [3, 6]) + k.gate("cnot", [4, 1]) + k.gate("cnot", [4, 6]) + k.gate("cnot", [5, 2]) + k.gate("cnot", [5, 3]) + k.gate("cnot", [6, 3]) + k.gate("cnot", [6, 4]) + for j in range(7): + k.gate("x", [j]) + + prog.add_kernel(k) + prog.compile() + + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_mapper_one_d_2(self): + # one cnot with operands that are at distance 2 in s7 + # initial placement should find this + # otherwise ... + # there are 2 alternative paths + # in each path there are 2 alternative places to put the cnot + # this introduces 1 swap/move and so uses an ancilla + # parameters + v = 'one_D2' + config_fn = "cc_light.s7" + num_qubits = 7 + + # create and set platform + prog_name = "test_mapper_" + v + kernel_name = "kernel_" + v + starmon = ql.Platform("starmon", config_fn) + prog = ql.Program(prog_name, starmon, num_qubits, 0) + k = ql.Kernel(kernel_name, starmon, num_qubits, 0) + + k.gate("x", [2]) + k.gate("y", [3]) + k.gate("cnot", [2, 3]) + k.gate("x", [2]) + k.gate("y", [3]) + + prog.add_kernel(k) + prog.compile() + + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_mapper_one_d_4(self): + # one cnot with operands that are at distance 4 in s7 + # initial placement should find this + # otherwise ... + # there are 4 alternative paths + # in each path there are 4 alternative places to put the cnot + # this introduces 3 swaps/moves + # parameters + v = 'one_D4' + config_fn = "cc_light.s7" + num_qubits = 7 + + # create and set platform + prog_name = "test_mapper_" + v + kernel_name = "kernel_" + v + starmon = ql.Platform("starmon", config_fn) + prog = ql.Program(prog_name, starmon, num_qubits, 0) + k = ql.Kernel(kernel_name, starmon, num_qubits, 0) + + k.gate("x", [2]) + k.gate("y", [4]) + k.gate("cnot", [2, 4]) + k.gate("x", [2]) + k.gate("y", [4]) + + prog.add_kernel(k) + prog.compile() + + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_mapper_all_d(self): + # all possible cnots in s7, in lexicographic order + # there is no initial mapping that maps this right so initial placement cannot find it + # so the heuristics must act and insert swaps/moves + # parameters + v = 'all_D' + config_fn = "cc_light.s7" + num_qubits = 7 + + # create and set platform + prog_name = "test_mapper_" + v + kernel_name = "kernel_" + v + starmon = ql.Platform("starmon", config_fn) + prog = ql.Program(prog_name, starmon, num_qubits, 0) + k = ql.Kernel(kernel_name, starmon, num_qubits, 0) + + for j in range(7): + k.gate("x", [j]) + + for i in range(7): + for j in range(7): + if i != j: + k.gate("cnot", [i, j]) + + for j in range(7): + k.gate("x", [j]) + + prog.add_kernel(k) + prog.compile() + + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_mapper_all_d_opt(self): + # all possible cnots in s7, avoiding collisions: + # - the pair of possible CNOTs in both directions hopefully in parallel + # - these pairs ordered from low distance to high distance to avoid disturbance by swaps + # - and then as much as possible in opposite sides of the circuit to improve ILP + # idea is to get the shortest latency circuit with all possible cnots + # there is no initial mapping that maps this right so initial placement cannot find it + # so the heuristics must act and insert swaps/moves + # parameters + v = 'all_D_opt' + config_fn = "cc_light.s7" + num_qubits = 7 + + # create and set platform + prog_name = "test_mapper_" + v + kernel_name = "kernel_" + v + starmon = ql.Platform("starmon", config_fn) + prog = ql.Program(prog_name, starmon, num_qubits, 0) + k = ql.Kernel(kernel_name, starmon, num_qubits, 0) + + for j in range(7): + k.gate("x", [j]) + k.gate("cnot", [0, 3]) + k.gate("cnot", [3, 0]) + k.gate("cnot", [6, 4]) + k.gate("cnot", [4, 6]) + k.gate("cnot", [3, 1]) + k.gate("cnot", [1, 3]) + k.gate("cnot", [5, 2]) + k.gate("cnot", [2, 5]) + k.gate("cnot", [1, 4]) + k.gate("cnot", [4, 1]) + k.gate("cnot", [3, 5]) + k.gate("cnot", [5, 3]) + k.gate("cnot", [6, 3]) + k.gate("cnot", [3, 6]) + k.gate("cnot", [2, 0]) + k.gate("cnot", [0, 2]) + k.gate("cnot", [0, 1]) + k.gate("cnot", [1, 0]) + k.gate("cnot", [3, 4]) + k.gate("cnot", [4, 3]) + k.gate("cnot", [1, 6]) + k.gate("cnot", [6, 1]) + k.gate("cnot", [6, 5]) + k.gate("cnot", [5, 6]) + k.gate("cnot", [3, 2]) + k.gate("cnot", [2, 3]) + k.gate("cnot", [5, 0]) + k.gate("cnot", [0, 5]) + k.gate("cnot", [0, 6]) + k.gate("cnot", [6, 0]) + k.gate("cnot", [1, 5]) + k.gate("cnot", [5, 1]) + k.gate("cnot", [0, 4]) + k.gate("cnot", [4, 0]) + k.gate("cnot", [6, 2]) + k.gate("cnot", [2, 6]) + k.gate("cnot", [2, 1]) + k.gate("cnot", [1, 2]) + k.gate("cnot", [5, 4]) + k.gate("cnot", [4, 5]) + k.gate("cnot", [2, 4]) + k.gate("cnot", [4, 2]) + for j in range(7): + k.gate("x", [j]) + + prog.add_kernel(k) + prog.compile() + + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_mapper_all_ip(self): + # longest string of cnots with operands that could be at distance 1 in s7 + # matches intel NISQ application + # initial placement should find this + # and then no swaps are inserted + # otherwise ... + # the heuristics must act and insert swaps/moves + # parameters + v = 'all_IP' + config_fn = "cc_light.s7" + num_qubits = 7 + + # create and set platform + prog_name = "test_mapper_" + v + kernel_name = "kernel_" + v + starmon = ql.Platform("starmon", config_fn) + prog = ql.Program(prog_name, starmon, num_qubits, 0) + k = ql.Kernel(kernel_name, starmon, num_qubits, 0) + + for j in range(7): + k.gate("x", [j]) + k.gate("cnot", [0, 1]) + k.gate("cnot", [1, 2]) + k.gate("cnot", [2, 3]) + k.gate("cnot", [3, 4]) + k.gate("cnot", [4, 5]) + k.gate("cnot", [5, 6]) + for j in range(7): + k.gate("x", [j]) + + prog.add_kernel(k) + prog.compile() + + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_mapper_ling_ling_5(self): + # parameters + # 'realistic' circuit + v = 'ling_ling_5' + config_fn = "cc_light.s17" + num_qubits = 17 + + # create and set platform + prog_name = "test_mapper_" + v + kernel_name = "kernel_" + v + starmon = ql.Platform("starmon", config_fn) + prog = ql.Program(prog_name, starmon, num_qubits, 0) + k = ql.Kernel(kernel_name, starmon, num_qubits, 0) + + k.gate("prepz", [5]) + k.gate("prepz", [6]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("x", [6]) + k.gate("ym90", [6]) + k.gate("ym90", [0]) + k.gate("cz", [5, 0]) + k.gate("ry90", [0]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [6, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [1, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [2, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [6, 5]) + k.gate("ry90", [5]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("ym90", [3]) + k.gate("cz", [5, 3]) + k.gate("ry90", [3]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("measure", [5]) + k.gate("measure", [6]) + + k.gate("prepz", [5]) + k.gate("prepz", [6]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("x", [6]) + k.gate("ym90", [6]) + k.gate("ym90", [1]) + k.gate("cz", [5, 1]) + k.gate("ry90", [1]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [6, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [2, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [3, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [6, 5]) + k.gate("ry90", [5]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("ym90", [4]) + k.gate("cz", [5, 4]) + k.gate("ry90", [4]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("measure", [5]) + k.gate("measure", [6]) + + k.gate("prepz", [5]) + k.gate("prepz", [6]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("x", [6]) + k.gate("ym90", [6]) + k.gate("ym90", [2]) + k.gate("cz", [5, 2]) + k.gate("ry90", [2]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [6, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [3, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [4, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [6, 5]) + k.gate("ry90", [5]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("ym90", [0]) + k.gate("cz", [5, 0]) + k.gate("ry90", [0]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("measure", [5]) + k.gate("measure", [6]) + + k.gate("prepz", [5]) + k.gate("prepz", [6]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("x", [6]) + k.gate("ym90", [6]) + k.gate("ym90", [3]) + k.gate("cz", [5, 3]) + k.gate("ry90", [3]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [6, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [4, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [0, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [5]) + k.gate("cz", [6, 5]) + k.gate("ry90", [5]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("ym90", [1]) + k.gate("cz", [5, 1]) + k.gate("ry90", [1]) + k.gate("x", [5]) + k.gate("ym90", [5]) + k.gate("measure", [5]) + k.gate("measure", [6]) + + prog.add_kernel(k) + prog.compile() + + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_mapper_ling_ling_7(self): + # parameters + v = 'ling_ling_7' + config_fn = "cc_light.s17" + num_qubits = 17 + + # create and set platform + prog_name = "test_mapper_" + v + kernel_name = "kernel_" + v + starmon = ql.Platform("starmon", config_fn) + prog = ql.Program(prog_name, starmon, num_qubits, 0) + k = ql.Kernel(kernel_name, starmon, num_qubits, 0) + + k.gate("prepz", [7]) + k.gate("prepz", [8]) + k.gate("x", [7]) + k.gate("ym90", [7]) + k.gate("ym90", [4]) + k.gate("cz", [7, 4]) + k.gate("ry90", [4]) + k.gate("ym90", [8]) + k.gate("cz", [0, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [8]) + k.gate("cz", [7, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [6]) + k.gate("cz", [7, 6]) + k.gate("ry90", [6]) + k.gate("ym90", [8]) + k.gate("cz", [2, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [3]) + k.gate("cz", [7, 3]) + k.gate("ry90", [3]) + k.gate("ym90", [8]) + k.gate("cz", [4, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [8]) + k.gate("cz", [7, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [5]) + k.gate("cz", [7, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [8]) + k.gate("cz", [6, 8]) + k.gate("ry90", [8]) + k.gate("x", [7]) + k.gate("ym90", [7]) + k.gate("measure", [7]) + k.gate("measure", [8]) + k.gate("prepz", [7]) + k.gate("prepz", [8]) + k.gate("x", [7]) + k.gate("ym90", [7]) + k.gate("ym90", [5]) + k.gate("cz", [7, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [8]) + k.gate("cz", [1, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [8]) + k.gate("cz", [7, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [6]) + k.gate("cz", [7, 6]) + k.gate("ry90", [6]) + k.gate("ym90", [8]) + k.gate("cz", [2, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [3]) + k.gate("cz", [7, 3]) + k.gate("ry90", [3]) + k.gate("ym90", [8]) + k.gate("cz", [5, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [8]) + k.gate("cz", [7, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [4]) + k.gate("cz", [7, 4]) + k.gate("ry90", [4]) + k.gate("ym90", [8]) + k.gate("cz", [6, 8]) + k.gate("ry90", [8]) + k.gate("x", [7]) + k.gate("ym90", [7]) + k.gate("measure", [7]) + k.gate("measure", [8]) + + k.gate("prepz", [7]) + k.gate("prepz", [8]) + k.gate("x", [7]) + k.gate("ym90", [7]) + k.gate("ym90", [1]) + k.gate("cz", [7, 1]) + k.gate("ry90", [1]) + k.gate("ym90", [8]) + k.gate("cz", [2, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [8]) + k.gate("cz", [7, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [5]) + k.gate("cz", [7, 5]) + k.gate("ry90", [5]) + k.gate("ym90", [8]) + k.gate("cz", [6, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [2]) + k.gate("cz", [7, 2]) + k.gate("ry90", [2]) + k.gate("ym90", [8]) + k.gate("cz", [0, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [8]) + k.gate("cz", [7, 8]) + k.gate("ry90", [8]) + k.gate("ym90", [6]) + k.gate("cz", [7, 6]) + k.gate("ry90", [6]) + k.gate("ym90", [8]) + k.gate("cz", [4, 8]) + k.gate("ry90", [8]) + k.gate("x", [7]) + k.gate("ym90", [7]) + k.gate("measure", [7]) + k.gate("measure", [8]) + + prog.add_kernel(k) + prog.compile() + + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog_name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + +if __name__ == '__main__': + # ql.set_option('log_level', 'LOG_DEBUG') + unittest.main() diff --git a/tests/test_minimal.py b/test/v1x/python/test_minimal.py similarity index 57% rename from tests/test_minimal.py rename to test/v1x/python/test_minimal.py index 517d280cb..0d4da32aa 100644 --- a/tests/test_minimal.py +++ b/test/v1x/python/test_minimal.py @@ -1,25 +1,23 @@ -import os +import openql as ql import unittest -from openql import openql as ql -curdir = os.path.dirname(os.path.realpath(__file__)) -platf = ql.Platform("starmon", "cc_light") +from config import output_dir -output_dir = os.path.join(curdir, 'test_output') +platform = ql.Platform("starmon", "cc_light") -class Test_kernel(unittest.TestCase): +class TestKernel(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) def test_minimal(self): - nqubits = 1 + num_qubits = 1 # create a kernel - k = ql.Kernel("aKernel", platf, nqubits) + k = ql.Kernel("aKernel", platform, num_qubits) # populate a kernel k.prepz(0) @@ -27,7 +25,7 @@ def test_minimal(self): k.measure(0) # create a program - p = ql.Program("minimal", platf, nqubits) + p = ql.Program("minimal", platform, num_qubits) # add kernel to program p.add_kernel(k) @@ -36,5 +34,6 @@ def test_minimal(self): p.compile() # all the outputs are generated in 'output' dir + if __name__ == '__main__': unittest.main() diff --git a/tests/test_multi_core.py b/test/v1x/python/test_multi_core.py similarity index 60% rename from tests/test_multi_core.py rename to test/v1x/python/test_multi_core.py index 1ba23ec43..46acb716b 100644 --- a/tests/test_multi_core.py +++ b/test/v1x/python/test_multi_core.py @@ -3,23 +3,22 @@ # assumes config files: test_multi_core_4x4_full.json # -from openql import openql as ql +import openql as ql import os import unittest -from utils import file_compare - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare -class Test_multi_core(unittest.TestCase): +class TestMultiCore(unittest.TestCase): def setUp(self): ql.initialize() # uses defaults of options in mapper branch except for output_dir and for maptiebreak - ql.set_option('output_dir', output_dir) # this uses output_dir set above - ql.set_option('maptiebreak', 'first') # this makes behavior deterministic to cmp with golden - # and deviates from default + # this uses output_dir set above + ql.set_option('output_dir', output_dir) + # this makes behavior deterministic to cmp with golden and deviates from default + ql.set_option('maptiebreak', 'first') ql.set_option('log_level', 'LOG_NOTHING') ql.set_option('optimize', 'no') @@ -52,13 +51,13 @@ def setUp(self): def test_mc_locals(self): v = 'locals' - config = os.path.join(curdir, "test_multi_core_4x4_full.json") + config_fn = os.path.join(json_dir, "test_multi_core_4x4_full.json") num_qubits = 16 # create and set platform prog_name = "test_mc_" + v kernel_name = "kernel_" + v - starmon = ql.Platform("mc4x4full", config) + starmon = ql.Platform("mc4x4full", config_fn) prog = ql.Program(prog_name, starmon, num_qubits, 0) k = ql.Kernel(kernel_name, starmon, num_qubits, 0) @@ -66,74 +65,74 @@ def test_mc_locals(self): k.gate("x", [4*i]) k.gate("x", [4*i+1]) for i in range(4): - k.gate("cnot", [4*i,4*i+1]) + k.gate("cnot", [4*i, 4*i+1]) prog.add_kernel(k) prog.compile() - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog.name+'_last.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) - def test_mc_noncomms(self): - v = 'noncomms' - config = os.path.join(curdir, "test_multi_core_4x4_full.json") + def test_mc_non_comms(self): + v = 'non_comms' + config_fn = os.path.join(json_dir, "test_multi_core_4x4_full.json") num_qubits = 16 # create and set platform prog_name = "test_mc_" + v kernel_name = "kernel_" + v - starmon = ql.Platform("mc4x4full", config) + starmon = ql.Platform("mc4x4full", config_fn) prog = ql.Program(prog_name, starmon, num_qubits, 0) k = ql.Kernel(kernel_name, starmon, num_qubits, 0) - i=0 - j=1 + i = 0 + j = 1 k.gate("x", [4*i+3]) k.gate("x", [4*j+3]) - k.gate("cnot", [4*i+3,4*j+3]) + k.gate("cnot", [4*i+3, 4*j+3]) prog.add_kernel(k) prog.compile() - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog.name+'_last.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_mc_comms(self): v = 'comms' - config = os.path.join(curdir, "test_multi_core_4x4_full.json") + config_fn = os.path.join(json_dir, "test_multi_core_4x4_full.json") num_qubits = 16 # create and set platform prog_name = "test_mc_" + v kernel_name = "kernel_" + v - starmon = ql.Platform("mc4x4full", config) + starmon = ql.Platform("mc4x4full", config_fn) prog = ql.Program(prog_name, starmon, num_qubits, 0) k = ql.Kernel(kernel_name, starmon, num_qubits, 0) - i=0 - j=1 + i = 0 + j = 1 k.gate("x", [4*i]) k.gate("x", [4*j]) - k.gate("cnot", [4*i,4*j]) + k.gate("cnot", [4*i, 4*j]) prog.add_kernel(k) prog.compile() - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog.name+'_last.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_mc_all(self): v = 'all' - config = os.path.join(curdir, "test_multi_core_4x4_full.json") + config_fn = os.path.join(json_dir, "test_multi_core_4x4_full.json") num_qubits = 16 # create and set platform prog_name = "test_mc_" + v kernel_name = "kernel_" + v - starmon = ql.Platform("mc4x4full", config) + starmon = ql.Platform("mc4x4full", config_fn) prog = ql.Program(prog_name, starmon, num_qubits, 0) k = ql.Kernel(kernel_name, starmon, num_qubits, 0) @@ -141,28 +140,28 @@ def test_mc_all(self): k.gate("x", [4*i]) k.gate("x", [4*i+1]) for i in range(4): - k.gate("cnot", [4*i,4*i+1]) + k.gate("cnot", [4*i, 4*i+1]) for i in range(4): for j in range(4): if i != j: - k.gate("cnot", [4*i,4*j]) + k.gate("cnot", [4*i, 4*j]) prog.add_kernel(k) prog.compile() - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog.name+'_last.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) def test_mc_all_saturate(self): v = 'all_saturate' - config = os.path.join(curdir, "test_multi_core_4x4_full.json") + config_fn = os.path.join(json_dir, "test_multi_core_4x4_full.json") num_qubits = 16 # create and set platform prog_name = "test_mc_" + v kernel_name = "kernel_" + v - starmon = ql.Platform("mc4x4full", config) + starmon = ql.Platform("mc4x4full", config_fn) prog = ql.Program(prog_name, starmon, num_qubits, 0) k = ql.Kernel(kernel_name, starmon, num_qubits, 0) @@ -170,21 +169,22 @@ def test_mc_all_saturate(self): k.gate("x", [4*i]) k.gate("x", [4*i+1]) for i in range(4): - k.gate("cnot", [4*i,4*i+1]) + k.gate("cnot", [4*i, 4*i+1]) for i in range(4): for j in range(4): if i != j: - k.gate("cnot", [4*i,4*j]) - k.gate("cnot", [4*i+1,4*j+1]) - k.gate("cnot", [4*i+2,4*j+2]) - k.gate("cnot", [4*i+3,4*j+3]) + k.gate("cnot", [4*i, 4*j]) + k.gate("cnot", [4*i+1, 4*j+1]) + k.gate("cnot", [4*i+2, 4*j+2]) + k.gate("cnot", [4*i+3, 4*j+3]) prog.add_kernel(k) prog.compile() - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog.name+'_last.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + if __name__ == '__main__': # ql.set_option('log_level', 'LOG_DEBUG') diff --git a/tests/test_options.py b/test/v1x/python/test_options.py similarity index 85% rename from tests/test_options.py rename to test/v1x/python/test_options.py index 8ccec6b97..47c5133a8 100644 --- a/tests/test_options.py +++ b/test/v1x/python/test_options.py @@ -1,14 +1,12 @@ -import os +import openql as ql import unittest -from openql import openql as ql -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import output_dir -class Test_options(unittest.TestCase): +class TestOptions(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() def test_set_all_options(self): @@ -38,7 +36,6 @@ def test_set_all_options(self): ql.set_option('decompose_toffoli', 'NC') ql.set_option('decompose_toffoli', 'AM') - def test_nok(self): # supress error printing first as the following will print errors ql.set_option('log_level', 'LOG_NOTHING') @@ -47,14 +44,15 @@ def test_nok(self): with self.assertRaises(Exception) as cm: ql.set_option('optimize', 'nope') - self.assertEqual(str(cm.exception).split('\n', maxsplit=1)[0], 'Usage error: invalid value for yes/no option optimize: nope') - + self.assertEqual(str(cm.exception).split('\n', maxsplit=1)[0], + 'Usage error: invalid value for yes/no option optimize: nope') with self.assertRaises(Exception) as cm: ql.set_option('scheduler', 'best') - self.assertEqual(str(cm.exception).split('\n', maxsplit=1)[0], 'Usage error: invalid value for option scheduler: possible values are ASAP or ALAP, but best was given') - + self.assertEqual(str(cm.exception).split('\n', maxsplit=1)[0], + 'Usage error: invalid value for option scheduler: ' + 'possible values are ASAP or ALAP, but best was given') def test_get_values(self): # try to set a legal value and then test if it is indeed set @@ -67,26 +65,24 @@ def test_get_values(self): ql.set_option('optimize', 'yes') self.assertEqual(ql.get_option('optimize'), 'yes') - ql.set_option('scheduler', 'ALAP') self.assertEqual(ql.get_option('scheduler'), 'ALAP') ql.set_option('scheduler_uniform', 'yes') self.assertEqual(ql.get_option('scheduler_uniform'), 'yes') - ql.set_option('use_default_gates', 'yes') self.assertEqual(ql.get_option('use_default_gates'), 'yes') ql.set_option('decompose_toffoli', 'NC') self.assertEqual(ql.get_option('decompose_toffoli'), 'NC') - def test_default_scheduler(self): self.tearDown() # tests if 'ALAP' is indeed the default scheduler policy self.assertEqual('ALAP', ql.get_option('scheduler'), - 'ALAP is not the default scheduler!') + 'ALAP is not the default scheduler!') + if __name__ == '__main__': unittest.main() diff --git a/tests/test_parallel_triggers.py b/test/v1x/python/test_parallel_triggers.py similarity index 58% rename from tests/test_parallel_triggers.py rename to test/v1x/python/test_parallel_triggers.py index a33c5d2d9..445ea3f29 100644 --- a/tests/test_parallel_triggers.py +++ b/test/v1x/python/test_parallel_triggers.py @@ -1,44 +1,39 @@ -from openql import openql as ql +import openql as ql import os import unittest +from config import json_dir, output_dir -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') - -class Test_parallel_trigger(unittest.TestCase): +class TestParallelTrigger(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') ql.set_option('log_level', 'LOG_WARNING') # ql.set_option('write_qasm_files', 'yes') - def test_parallel_trigger(self): # You can specify a config location, here we use a default config - config_fn = os.path.join(curdir, 'spin_demo_2811.json') + config_fn = os.path.join(json_dir, 'config_spin_demo_2811.json') platform = ql.Platform("spin_qubit_demo", config_fn) num_qubits = 2 p = ql.Program("program", platform, num_qubits) # populate kernel using default gates k = ql.Kernel("kernel", platform, num_qubits) - #k.prepz(0) - - + # k.prepz(0) k.rx90(0) # 145ns,ch 4,cw 1 k.ry90(0) # 145ns,ch 4,cw 3 - k.mrx90(0) # 145ns,ch 4,cw 2 - k.mry90(0) # 145ns,ch 4,cw 4 - k.identity(0) # 125ns,ch 4,cw 5 + k.mrx90(0) # 145ns,ch 4,cw 2 + k.mry90(0) # 145ns,ch 4,cw 4 + k.identity(0) # 125ns,ch 4,cw 5 - #k.mry90(1) # 145ns,ch 5,cw 4 - k.ry90(1) # 145ns,ch 5,cw 3 + # k.mry90(1) # 145ns,ch 5,cw 4 + k.ry90(1) # 145ns,ch 5,cw 3 # add the kernel to the program p.add_kernel(k) @@ -50,15 +45,13 @@ def test_parallel_trigger(self): if __name__ == '__main__': unittest.main() - - -#wait 1 -#mov r12, 1 -#mov r13, 0 -#start: -#wait 2 -#trigger 1000000, 1 -#wait 2 -#trigger 1000000, 1 -#wait 1 -#beq r13, r13 start + # wait 1 + # mov r12, 1 + # mov r13, 0 + # start: + # wait 2 + # trigger 1000000, 1 + # wait 2 + # trigger 1000000, 1 + # wait 1 + # beq r13, r13 start diff --git a/test/v1x/python/test_qubits.py b/test/v1x/python/test_qubits.py new file mode 100644 index 000000000..6412c3199 --- /dev/null +++ b/test/v1x/python/test_qubits.py @@ -0,0 +1,90 @@ +import openql as ql +import os +import unittest + +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare + + +config_fn = os.path.join(json_dir, 'test_config_default.json') +platform = ql.Platform("starmon", config_fn) + + +class TestQubits(unittest.TestCase): + @classmethod + def setUp(cls): + ql.initialize() + ql.set_option('output_dir', output_dir) + ql.set_option('optimize', 'no') + ql.set_option('scheduler', 'ALAP') + ql.set_option('log_level', 'LOG_WARNING') + # ql.set_option('write_qasm_files', 'yes') + + def test_1_qubit(self): + num_qubits = 1 + + k = ql.Kernel("aKernel", platform, num_qubits) + + # populate kernel + k.prepz(0) + k.x(0) + k.y(0) + k.rx90(0) + k.measure(0) + + p = ql.Program("1_qubit_program", platform, num_qubits) + + p.add_kernel(k) # add kernel to program + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, 'test_1_qubit.qasm') + qasm_fn = os.path.join(output_dir, p.name + '.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_2_qubit(self): + num_qubits = 3 + k = ql.Kernel("aKernel", platform, num_qubits) + + # populate kernel + k.prepz(0) + k.prepz(1) + k.prepz(2) + k.cz(0, 1) + k.clifford(1, 2) + k.measure(2) + + p = ql.Program("2_qubit_program", platform, num_qubits) + + p.add_kernel(k) # add kernel to program + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, 'test_2_qubit.qasm') + qasm_fn = os.path.join(output_dir, p.name + '.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + def test_3_qubit(self): + num_qubits = 3 + + k = ql.Kernel("aKernel", platform, num_qubits) + + # populate kernel + k.prepz(0) + k.prepz(1) + k.prepz(2) + k.toffoli(0, 1, 2) + k.measure(2) + + p = ql.Program("3_qubit_program", platform, num_qubits) + + p.add_kernel(k) # add kernel to program + + ql.set_option('decompose_toffoli', 'no') + p.compile() + + gold_fn = os.path.join(qasm_golden_dir, 'test_3_qubit.qasm') + qasm_fn = os.path.join(output_dir, p.name + '.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_scale.py b/test/v1x/python/test_scale.py similarity index 73% rename from tests/test_scale.py rename to test/v1x/python/test_scale.py index 6546c5b7c..d0eb0c06d 100644 --- a/tests/test_scale.py +++ b/test/v1x/python/test_scale.py @@ -3,23 +3,22 @@ # assumes config files: test_multi_core_8x1092_full.json # -from openql import openql as ql +import openql as ql import os import unittest -from utils import file_compare - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare -class Test_multi_core(unittest.TestCase): +class TestMultiCore(unittest.TestCase): def setUp(self): ql.initialize() # uses defaults of options in mapper branch except for output_dir and for maptiebreak - ql.set_option('output_dir', output_dir) # this uses output_dir set above - ql.set_option('maptiebreak', 'first') # this makes behavior deterministic to cmp with golden - # and deviates from default + # this uses output_dir set above + ql.set_option('output_dir', output_dir) + # this makes behavior deterministic to cmp with golden and deviates from default + ql.set_option('maptiebreak', 'first') ql.set_option('log_level', 'LOG_INFO') ql.set_option('optimize', 'no') @@ -53,13 +52,13 @@ def setUp(self): def test_mc_wide(self): v = 'wide' - config = os.path.join(curdir, "test_multi_core_8x1024_full.json") + config_fn = os.path.join(json_dir, "test_multi_core_8x1024_full.json") num_qubits = 2048 # create and set platform prog_name = "test_mc_" + v kernel_name = "kernel_" + v - starmon = ql.Platform("mc8x1092full", config) + starmon = ql.Platform("mc8x1092full", config_fn) prog = ql.Program(prog_name, starmon, num_qubits, 0) k = ql.Kernel(kernel_name, starmon, num_qubits, 0) @@ -71,9 +70,10 @@ def test_mc_wide(self): prog.add_kernel(k) prog.compile() - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog.name+'_last.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) + gold_fn = os.path.join(qasm_golden_dir, prog_name + '_last.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_last.qasm') + self.assertTrue(file_compare(qasm_fn, gold_fn)) + if __name__ == '__main__': # ql.set_option('log_level', 'LOG_INFO') diff --git a/tests/test_skip.py b/test/v1x/python/test_skip.py similarity index 80% rename from tests/test_skip.py rename to test/v1x/python/test_skip.py index 1cba2e32a..1a8193cb5 100644 --- a/tests/test_skip.py +++ b/test/v1x/python/test_skip.py @@ -3,17 +3,15 @@ # assumes config files: test_mapper_s7.json # -from openql import openql as ql +import openql as ql import os import unittest -from utils import file_compare - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import output_dir, qasm_golden_dir +from utils import file_compare -class Test_skip(unittest.TestCase): +class TestSkip(unittest.TestCase): def setUp(self): ql.initialize() @@ -40,13 +38,13 @@ def test_skip_yes(self): # parameters ql.set_option('issue_skip_319', 'yes') v = 'yes' - config = "cc_light.s7" + config_fn = "cc_light.s7" num_qubits = 7 # create and set platform prog_name = "test_skip_" + v kernel_name = "kernel_" + v - starmon = ql.Platform("starmon", config) + starmon = ql.Platform("starmon", config_fn) prog = ql.Program(prog_name, starmon, num_qubits, 0) qasm_rdr = ql.cQasmReader(starmon, prog) @@ -62,10 +60,10 @@ def test_skip_yes(self): prog.compile() - GOLD_fn = os.path.join(curdir, 'golden', prog.name + '_scheduled.qasm') - QASM_fn = os.path.join(output_dir, prog.name+'_scheduled.qasm') + gold_fn = os.path.join(qasm_golden_dir, prog.name + '_scheduled.qasm') + qasm_fn = os.path.join(output_dir, prog.name + '_scheduled.qasm') - self.assertTrue(file_compare(QASM_fn, GOLD_fn)) + self.assertTrue(file_compare(qasm_fn, gold_fn)) # ql.set_option('write_qasm_files', 'no') # ql.set_option('write_report_files', 'no') @@ -74,6 +72,7 @@ def test_skip_yes(self): ql.set_option('issue_skip_319', 'no') + if __name__ == '__main__': # ql.set_option('log_level', 'LOG_DEBUG') unittest.main() diff --git a/test/v1x/python/test_std_experiments_CCL.py b/test/v1x/python/test_std_experiments_CCL.py new file mode 100644 index 000000000..ced5a7fc3 --- /dev/null +++ b/test/v1x/python/test_std_experiments_CCL.py @@ -0,0 +1,129 @@ +import numpy as np +import openql as ql +import os +import unittest + +from config import output_dir, qasm_golden_dir +from utils import file_compare + + +platform = ql.Platform('seven_qubits_chip', 'cc_light') + +ql.set_option('output_dir', output_dir) +ql.set_option('optimize', 'no') +ql.set_option('scheduler', 'ALAP') +ql.set_option('log_level', 'LOG_WARNING') + + +@unittest.skip +class TestSingleQubitSeqsCcl(unittest.TestCase): + @classmethod + def setUp(cls): + ql.initialize() + + def test_bug(self): + p = ql.Program("bug", platform, 1) + + k = ql.Kernel("bugKernel", platform=platform, qubit_count=1) + k.gate('rx180', [0]) + k.gate('measure', [0]) + + p.add_kernel(k) + p.compile() + + # Test that the generated code is valid + qisa_fn = os.path.join(output_dir, p.name + '.qisa') + assemble(qisa_fn) + + def test_all_xy(self): + p = ql.Program("AllXY", platform, 1) + # uppercase lowercase problems + + all_xy = [ + ['i', 'i'], ['rx180', 'rx180'], ['ry180', 'ry180'], + ['rx180', 'ry180'], ['ry180', 'rx180'], + ['rx90', 'i'], ['ry90', 'i'], ['rx90', 'ry90'], + ['ry90', 'rx90'], ['rx90', 'ry180'], ['ry90', 'rx180'], + ['rx180', 'ry90'], ['ry180', 'rx90'], ['rx90', 'rx180'], + ['rx180', 'rx90'], ['ry90', 'ry180'], ['ry180', 'ry90'], + ['rx180', 'i'], ['ry180', 'i'], ['rx90', 'rx90'], + ['ry90', 'ry90'] + ] + + for i, xy in enumerate(all_xy): + k = ql.Kernel("allXY"+str(i), platform, 1) + k.prepz(0) + k.gate(xy[0], [0]) + k.gate(xy[1], [0]) + k.measure(0) + p.add_kernel(k) + + p.compile() + + # Test that the generated code is valid + gold_fn = os.path.join(qasm_golden_dir, p.name + '.qisa') + qisa_fn = os.path.join(output_dir, p.name + '.qisa') + self.assertTrue(file_compare(qisa_fn, gold_fn)) + + def test_qasm_seq_echo(self): + num_qubits = 1 + p = ql.Program("Echo", platform, num_qubits) + # times = np.linspace(0, 20e3, 61) # in ns + # To prevent superslow workaround + times = np.linspace(0, 60, 61) # in ns + # this should be implicit + for tau in times: + # this is an invalid kernel name (contains '.') + # and will produce and invalid qasm + n = 'echo_tau_{}ns'.format(tau) + n = n.replace(".", "_") + k = ql.Kernel(n, platform, num_qubits) + k.prepz(0) + k.rx90(0) + # This is a dirty hack that repeats the I gate + for j in range(int(tau/2)): + k.gate('i', [0]) + k.rx180(0) + for j in range(int(tau/2)): + k.gate('i', [0]) + k.rx90(0) + k.measure(0) + p.add_kernel(k) + + p.compile() + + # Test that the generated code is valid + gold_fn = os.path.join(qasm_golden_dir, p.name + '.qisa') + qisa_fn = os.path.join(output_dir, p.name + '.qisa') + self.assertTrue(file_compare(qisa_fn, gold_fn)) + + def test_qasm_seq_butterfly(self): + num_qubits = 1 + p = ql.Program("Butterfly", platform, num_qubits) + + k = ql.Kernel('0', platform, num_qubits) + k.prepz(0) + k.measure(0) + k.measure(0) + # what does the measurement tell us it is? + k.measure(0) + # what is the post measuremnet state + p.add_kernel(k) + + k = ql.Kernel('1', platform, num_qubits) + k.prepz(0) + k.measure(0) + k.x(0) + k.measure(0) + k.measure(0) + p.add_kernel(k) + p.compile() + + # Test that the generated code is valid + gold_fn = os.path.join(qasm_golden_dir, p.name + '.qisa') + qisa_fn = os.path.join(output_dir, p.name + '.qisa') + self.assertTrue(file_compare(qisa_fn, gold_fn)) + +if __name__ == '__main__': + unittest.main() + diff --git a/tests/test_structure_decomposition.py b/test/v1x/python/test_structure_decomposition.py similarity index 73% rename from tests/test_structure_decomposition.py rename to test/v1x/python/test_structure_decomposition.py index 862dbbcdf..e925cf64d 100644 --- a/tests/test_structure_decomposition.py +++ b/test/v1x/python/test_structure_decomposition.py @@ -1,21 +1,20 @@ +import openql as ql import os -from utils import file_compare import unittest -from openql import openql as ql -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import cq_dir, cq_golden_dir, json_dir, output_dir +from utils import file_compare -class Test_structure_decomposition(unittest.TestCase): +class TestStructureDecomposition(unittest.TestCase): def run_test_case(self, name): old_wd = os.getcwd() try: - os.chdir(curdir) + os.chdir(json_dir) - in_fn = 'test_' + name + '.cq' - out_fn = 'test_output/' + name + '_out.cq' - gold_fn = 'golden/' + name + '_out.cq' + in_fn = os.path.join(cq_dir, 'test_' + name + '.cq') + out_fn = os.path.join(output_dir, name + '_out.cq') + gold_fn = os.path.join(cq_golden_dir, name + '_out.cq') ql.compile(in_fn) @@ -42,5 +41,6 @@ def test_structure_decomposition_while(self): def test_structure_decomposition_repeat_until(self): self.run_test_case('structure_decomposition_repeat_until') + if __name__ == '__main__': unittest.main() diff --git a/tests/test_uniform_sched.py b/test/v1x/python/test_uniform_sched.py similarity index 51% rename from tests/test_uniform_sched.py rename to test/v1x/python/test_uniform_sched.py index 5721393ee..fa1a82ac8 100644 --- a/tests/test_uniform_sched.py +++ b/test/v1x/python/test_uniform_sched.py @@ -1,17 +1,15 @@ +import openql as ql import os import unittest -from openql import openql as ql -import numpy as np -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import json_dir, output_dir -class Test_uniform_scheduler(unittest.TestCase): +class TestUniformScheduler(unittest.TestCase): @classmethod - def setUp(self): + def setUp(cls): ql.initialize() - + def test_uniform_scheduler_0(self): ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') @@ -19,35 +17,35 @@ def test_uniform_scheduler_0(self): ql.set_option('scheduler_uniform', 'yes') ql.set_option('log_level', 'LOG_WARNING') - config_fn = os.path.join(curdir, 'test_cfg_none_s7.json') - platform = ql.Platform('starmon', config_fn) + config_fn = os.path.join(json_dir, 'test_cfg_none_s7.json') + platform = ql.Platform('starmon', config_fn) num_qubits = 7 p = ql.Program('test_uniform_scheduler_0', platform, num_qubits, 0) k = ql.Kernel('kernel_0', platform, num_qubits, 0) - # a simple first test - # the x gates serve to separate the cnot gates wrt dependences - # this creates big bundles with 7 x gates - # and small bundles with just a cnot - # after uniform scheduling, one or more x gates - # should have been moved next to the cnot - # those will move that do not have operands that overlap those of the cnot + # a simple first test + # the x gates serve to separate the cnot gates wrt dependencies + # this creates big bundles with 7 x gates + # and small bundles with just a cnot + # after uniform scheduling, one or more x gates + # should have been moved next to the cnot + # those will move that do not have operands that overlap those of the cnot for j in range(7): k.gate("x", [j]) - k.gate("cnot", [0,2]) + k.gate("cnot", [0, 2]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [6,3]) + k.gate("cnot", [6, 3]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [1,4]) + k.gate("cnot", [1, 4]) p.add_kernel(k) p.compile() @@ -59,63 +57,63 @@ def test_uniform_scheduler_1(self): ql.set_option('scheduler_uniform', 'yes') ql.set_option('log_level', 'LOG_WARNING') - config_fn = os.path.join(curdir, 'test_cfg_none_s7.json') - platform = ql.Platform('starmon', config_fn) + config_fn = os.path.join(json_dir, 'test_cfg_none_s7.json') + platform = ql.Platform('starmon', config_fn) num_qubits = 7 p = ql.Program('test_uniform_scheduler_1', platform, num_qubits, 0) k = ql.Kernel('kernel_1', platform, num_qubits, 0) - # just as the previous one - # but then more of the same + # just as the previous one + # but then more of the same for j in range(7): k.gate("x", [j]) - k.gate("cnot", [0,2]) + k.gate("cnot", [0, 2]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [6,3]) + k.gate("cnot", [6, 3]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [1,4]) + k.gate("cnot", [1, 4]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [2,5]) + k.gate("cnot", [2, 5]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [3,1]) + k.gate("cnot", [3, 1]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [4,6]) + k.gate("cnot", [4, 6]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [2,0]) + k.gate("cnot", [2, 0]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [3,6]) + k.gate("cnot", [3, 6]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [4,1]) + k.gate("cnot", [4, 1]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [5,2]) + k.gate("cnot", [5, 2]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [1,3]) + k.gate("cnot", [1, 3]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [6,4]) + k.gate("cnot", [6, 4]) for j in range(7): k.gate("x", [j]) @@ -130,46 +128,46 @@ def test_uniform_scheduler_2(self): ql.set_option('scheduler_uniform', 'yes') ql.set_option('log_level', 'LOG_WARNING') - config_fn = os.path.join(curdir, 'test_cfg_none_s7.json') - platform = ql.Platform('starmon', config_fn) + config_fn = os.path.join(json_dir, 'test_cfg_none_s7.json') + platform = ql.Platform('starmon', config_fn) num_qubits = 7 p = ql.Program('test_uniform_scheduler_2', platform, num_qubits, 0) k = ql.Kernel('kernel_2', platform, num_qubits, 0) - # again big bundles with x gates - # alternated with non-trivial cnot bundles; - # these cnots were chosen to be mutually independent - # so will be going all 3 in one bundle - # the single independent x will be moved with it - # but because the cnots take 4 cycles, - # also a lot of empty cycles are created - # which cannot be filled except by that - # stray independent x + # again big bundles with x gates + # alternated with non-trivial cnot bundles; + # these cnots were chosen to be mutually independent + # so will be going all 3 in one bundle + # the single independent x will be moved with it + # but because the cnots take 4 cycles, + # also a lot of empty cycles are created + # which cannot be filled except by that + # stray independent x for j in range(7): k.gate("x", [j]) - k.gate("cnot", [0,2]) - k.gate("cnot", [6,3]) - k.gate("cnot", [1,4]) + k.gate("cnot", [0, 2]) + k.gate("cnot", [6, 3]) + k.gate("cnot", [1, 4]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [2,5]) - k.gate("cnot", [3,1]) - k.gate("cnot", [4,6]) + k.gate("cnot", [2, 5]) + k.gate("cnot", [3, 1]) + k.gate("cnot", [4, 6]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [2,0]) - k.gate("cnot", [3,6]) - k.gate("cnot", [4,1]) + k.gate("cnot", [2, 0]) + k.gate("cnot", [3, 6]) + k.gate("cnot", [4, 1]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [5,2]) - k.gate("cnot", [1,3]) - k.gate("cnot", [6,4]) + k.gate("cnot", [5, 2]) + k.gate("cnot", [1, 3]) + k.gate("cnot", [6, 4]) for j in range(7): k.gate("x", [j]) @@ -184,43 +182,43 @@ def test_uniform_scheduler_3(self): ql.set_option('scheduler_uniform', 'yes') ql.set_option('log_level', 'LOG_WARNING') - config_fn = os.path.join(curdir, 'test_cfg_none_s7.json') - platform = ql.Platform('starmon', config_fn) + config_fn = os.path.join(json_dir, 'test_cfg_none_s7.json') + platform = ql.Platform('starmon', config_fn) num_qubits = 7 p = ql.Program('test_uniform_scheduler_3', platform, num_qubits, 0) k = ql.Kernel('kernel_3', platform, num_qubits, 0) - # as with test 2 but now the cnots are not mutually independent anymore - # this already creates smaller bundles but more of them + # as with test 2 but now the cnots are not mutually independent anymore + # this already creates smaller bundles but more of them for j in range(7): k.gate("x", [j]) - k.gate("cnot", [6,3]) - k.gate("cnot", [0,2]) - k.gate("cnot", [1,3]) - k.gate("cnot", [1,4]) - k.gate("cnot", [0,3]) + k.gate("cnot", [6, 3]) + k.gate("cnot", [0, 2]) + k.gate("cnot", [1, 3]) + k.gate("cnot", [1, 4]) + k.gate("cnot", [0, 3]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [2,5]) - k.gate("cnot", [3,1]) - k.gate("cnot", [2,0]) - k.gate("cnot", [3,6]) + k.gate("cnot", [2, 5]) + k.gate("cnot", [3, 1]) + k.gate("cnot", [2, 0]) + k.gate("cnot", [3, 6]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [4,1]) - k.gate("cnot", [3,0]) - k.gate("cnot", [4,6]) + k.gate("cnot", [4, 1]) + k.gate("cnot", [3, 0]) + k.gate("cnot", [4, 6]) for j in range(7): k.gate("x", [j]) - k.gate("cnot", [3,5]) - k.gate("cnot", [5,2]) - k.gate("cnot", [6,4]) - k.gate("cnot", [5,3]) + k.gate("cnot", [3, 5]) + k.gate("cnot", [5, 2]) + k.gate("cnot", [6, 4]) + k.gate("cnot", [5, 3]) for j in range(7): k.gate("x", [j]) @@ -235,37 +233,38 @@ def test_uniform_scheduler_4(self): ql.set_option('scheduler_uniform', 'yes') ql.set_option('log_level', 'LOG_WARNING') - config_fn = os.path.join(curdir, 'test_cfg_none_s7.json') - platform = ql.Platform('starmon', config_fn) + config_fn = os.path.join(json_dir, 'test_cfg_none_s7.json') + platform = ql.Platform('starmon', config_fn) num_qubits = 7 p = ql.Program('test_uniform_scheduler_4', platform, num_qubits, 0) k = ql.Kernel('kernel_4', platform, num_qubits, 0) - # as with test 3 but now without the big x bundles - # just the cnots in lexicographic order - # the worst you can imagine, - # creating the smallest bundles - - k.gate("cnot", [0,2]) - k.gate("cnot", [0,3]) - k.gate("cnot", [1,3]) - k.gate("cnot", [1,4]) - k.gate("cnot", [2,0]) - k.gate("cnot", [2,5]) - k.gate("cnot", [3,0]) - k.gate("cnot", [3,1]) - k.gate("cnot", [3,5]) - k.gate("cnot", [3,6]) - k.gate("cnot", [4,1]) - k.gate("cnot", [4,6]) - k.gate("cnot", [5,2]) - k.gate("cnot", [5,3]) - k.gate("cnot", [6,3]) - k.gate("cnot", [6,4]) + # as with test 3 but now without the big x bundles + # just the cnots in lexicographic order + # the worst you can imagine, + # creating the smallest bundles + + k.gate("cnot", [0, 2]) + k.gate("cnot", [0, 3]) + k.gate("cnot", [1, 3]) + k.gate("cnot", [1, 4]) + k.gate("cnot", [2, 0]) + k.gate("cnot", [2, 5]) + k.gate("cnot", [3, 0]) + k.gate("cnot", [3, 1]) + k.gate("cnot", [3, 5]) + k.gate("cnot", [3, 6]) + k.gate("cnot", [4, 1]) + k.gate("cnot", [4, 6]) + k.gate("cnot", [5, 2]) + k.gate("cnot", [5, 3]) + k.gate("cnot", [6, 3]) + k.gate("cnot", [6, 4]) p.add_kernel(k) p.compile() + if __name__ == '__main__': unittest.main() diff --git a/test/v1x/python/test_unitary.py b/test/v1x/python/test_unitary.py new file mode 100644 index 000000000..6f165db58 --- /dev/null +++ b/test/v1x/python/test_unitary.py @@ -0,0 +1,1402 @@ +import openql as ql +import os +import unittest + +from config import json_dir, output_dir +from qxelarator import qxelarator + +config_fn = os.path.join(json_dir, 'test_cfg_none_simple.json') +platform = ql.Platform('platform_none', config_fn) +platform_qubits = 17 + + +def to_bit_string(n, size=None): + small_bitstring = bin(n)[2:] + if size is None: + return small_bitstring + + assert(isinstance(size, int)) + assert((1 << size) > n) + assert(len(small_bitstring) <= size) + zeros = ''.join(['0' for _ in range(size - len(small_bitstring))]) + return zeros + small_bitstring + + +def helper_prob(qubit_state): + return qubit_state.real**2 + qubit_state.imag**2 + + +@unittest.skipUnless(ql.Unitary.is_decompose_support_enabled(), + "unitary decomposition support was disabled during OpenQL build") +class TestConjugatedKernel(unittest.TestCase): + @classmethod + def setUp(cls): + ql.initialize() + ql.set_option('output_dir', output_dir) + ql.set_option('optimize', 'no') + ql.set_option('scheduler', 'ASAP') + ql.set_option('log_level', 'LOG_NOTHING') + # ql.set_option('write_qasm_files', 'yes') + + def test_bit_string(self): + self.assertEqual(to_bit_string(5), "101") + self.assertEqual(to_bit_string(5, size=6), "000101") + with self.assertRaises(Exception): + res = to_bit_string(10, size=2) + + def test_unitary_basic(self): + num_qubits = 3 + p = ql.Program('test_unitary_basic', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + u = ql.Unitary('u1', [complex(1.0, 0.0), complex(0.0, 0.0), + complex(0.0, 0.0), complex(0.0, 1.0)]) + u.decompose() + + k.gate("i", [0]) + k.gate("s", [0]) + k.gate(u, [2]) + + p.add_kernel(k) + p.compile() + + def test_unitary_called_hadamard(self): + num_qubits = 3 + p = ql.Program('test_unitary_called_hadamard', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + u = ql.Unitary('hadamard', [complex(1.0, 0.0), complex(0.0, 0.0), + complex(0.0, 0.0), complex(0.0, 1.0)]) + u.decompose() + + k.gate(u, [2]) + + p.add_kernel(k) + p.compile() + + def test_unitary_wrong_number_of_qubits(self): + num_qubits = 3 + # p = ql.Program('test_unitary_wrong_number_of_qubits', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + u = ql.Unitary('u1', [complex(1.0, 0.0), complex(0.0, 0.0), + complex(0.0, 0.0), complex(0.0, 1.0)]) + k.gate("s", [0]) + + # adding un-decomposed u to kernel should raise error + with self.assertRaises(Exception) as cm: + k.gate(u, [1, 2]) + + self.assertEqual(str(cm.exception).split('\n', maxsplit=1)[0], + 'Unknown error: Unitary \'u1\' has been applied to the wrong number of qubits. ' + 'Cannot be added to kernel! 2 and not 1') + + # def test_unitary_wrong_number_of_qubits_too_few(self): + # num_qubits = 3 + # p = ql.Program('test_unitary_wrong_number_of_qubits_too_few', platform, num_qubits) + # k = ql.Kernel('aKernel', platform, num_qubits) + # + # + # u = ql.Unitary('u1', + # [-0.43874989 - 0.10659111j, -0.47325212 + 0.12917344j, + # -0.58227163 + 0.20750072j, -0.29075334 + 0.29807585j, + # 0.30168601 - 0.22307459j, 0.32626000 + 0.45349350j, + # -0.20523265 - 0.42403593j, -0.01012565 + 0.57016830j, + # -0.40954341 - 0.49946371j, 0.28560698 - 0.06740801j, + # 0.52146754 + 0.18335130j, -0.37248653 + 0.22891636j, + # 0.03113162 - 0.48703302j, -0.57180014 + 0.18486244j, + # 0.29436250 - 0.06148912j, 0.55533888 + 0.04322811j]) + # # adding un-decomposed u to kernel should raise error + # with self.assertRaises(Exception) as cm: + # k.gate(u, [0]) + # + # self.assertEqual(str(cm.exception).split('\n', maxsplit=1)[0], + # 'Unknown error: Unitary \'u1\' has been applied to the wrong number of qubits. ' + # 'Cannot be added to kernel! 1 and not 2') + + def test_unitary_decompose_i(self): + num_qubits = 1 + p = ql.Program('test_unitary_decompose_i', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [complex(1.0, 0.0), complex(0.0, 0.0), + complex(0.0, 0.0), complex(1.0, 0.0)] + u = ql.Unitary('u1', matrix) + u.decompose() + k.hadamard(0) + k.gate(u, [0]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + self.assertAlmostEqual(0.5 * (helper_prob(matrix[0])+helper_prob(matrix[1])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.5 * (helper_prob(matrix[2])+helper_prob(matrix[3])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + + def test_unitary_decompose_x(self): + num_qubits = 1 + p = ql.Program('test_unitary_decompose_x', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [complex(0.0, 0.0), complex(1.0, 0.0), + complex(1.0, 0.0), complex(0.0, 0.0)] + u = ql.Unitary('u1', matrix) + u.decompose() + k.gate(u, [0]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[2]), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + + def test_unitary_decompose_y(self): + num_qubits = 1 + p = ql.Program('test_unitary_decompose_y', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [complex(0.0, 0.0), complex(0.0, -1.0), + complex(0.0, 1.0), complex(0.0, 0.0)] + u = ql.Unitary('u1', matrix) + u.decompose() + k.gate(u, [0]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[2]), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + + def test_unitary_decompose_z(self): + num_qubits = 1 + p = ql.Program('test_unitary_decompose_z', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [complex(1.0, 0.0), complex(0.0, 0.0), + complex(0.0, 0.0), complex(-1.0, 0.0)] + u = ql.Unitary('u1', matrix) + u.decompose() + k.gate("hadamard", [0]) + k.gate(u, [0]) + k.gate("hadamard", [0]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + # HZH = X, so the result should be |0> + |1> + self.assertAlmostEqual(0, helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(1, helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + + def test_unitary_decompose_iyz(self): + num_qubits = 1 + p = ql.Program('test_unitary_decompose_iyz', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + u = ql.Unitary('X', [complex(0.0, 0.0), complex(1.0, 0.0), + complex(1.0, 0.0), complex(0.0, 0.0)]) + u.decompose() + k.gate(u, [0]) + u = ql.Unitary('Y', [complex(0.0, 0.0), complex(0.0, -1.0), + complex(0.0, 1.0), complex(0.0, 0.0)]) + u.decompose() + k.gate(u, [0]) + u = ql.Unitary('Z', [complex(1.0, 0.0), complex(0.0, 0.0), + complex(0.0, 0.0), complex(-1.0, 0.0)]) + u.decompose() + k.gate("hadamard", [0]) + k.gate(u, [0]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + # jXYZ = I, so this should change nothing about the state. + self.assertAlmostEqual(0.5, helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.5, helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + + def test_unitary_decompose_iyz_different_order(self): + num_qubits = 1 + p = ql.Program('test_unitary_decompose_iyz_different_order', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + u = ql.Unitary('X', [complex(0.0, 0.0), complex(1.0, 0.0), + complex(1.0, 0.0), complex(0.0, 0.0)]) + + u1 = ql.Unitary('y', [complex(0.0, 0.0), complex(0.0, -1.0), + complex(0.0, 1.0), complex(0.0, 0.0)]) + + u2 = ql.Unitary('Z', [complex(1.0, 0.0), complex(0.0, 0.0), + complex(0.0, 0.0), complex(-1.0, 0.0)]) + u.decompose() + u1.decompose() + u2.decompose() + + k.gate("hadamard", [0]) + k.gate(u, [0]) + k.gate(u1, [0]) + k.gate(u2, [0]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + # jXYZ = I, so this should change nothing about the state. + self.assertAlmostEqual(0.5, helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.5, helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + + def test_unitary_decompose_non_unitary(self): + num_qubits = 1 + p = ql.Program('test_unitary_decompose_non_unitary', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + u = ql.Unitary('WRONG', [complex(0.0, 0.0), complex(0.0, 0.0), + complex(0.0, 0.0), complex(0.0, 0.0)]) + + with self.assertRaises(Exception) as cm: + u.decompose() + k.gate(u, [0]) + + p.add_kernel(k) + p.compile() + + self.assertEqual(str(cm.exception).split('\n\n', maxsplit=1)[0], + "Unknown error: Error: Unitary 'WRONG' is not a unitary matrix. " + "Cannot be decomposed!(0,0) (0,0)\n(0,0) (0,0)") + + # input for the unitary decomposition needs to be an array + def test_unitary_decompose_matrix_instead_of_array(self): + num_qubits = 1 + p = ql.Program('test_unitary_decompose_matrix_instead_of_array', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + with self.assertRaises(TypeError) as cm: + u = ql.Unitary('TypeError', [[1, 0], [0, 1]]) + + def test_unitary_decompose_2_qubit_cnot(self): + num_qubits = 2 + p = ql.Program('test_unitary_decompose_2_qubit_cnot', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), + complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), + complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), + complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0)] + u = ql.Unitary('unitary_decompose_2_qubit_cnot', matrix) + u.decompose() + k.gate(u, [0, 1]) + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + # only two states are nonzero + self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[4]), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + + def test_unitary_decompose_2_qubit_cnot_2(self): + num_qubits = 2 + p = ql.Program('test_unitary_decompose_2_qubit_cnot_2', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 1, + 0, 0, 1, 0] + u = ql.Unitary('unitary_decompose_2_qubit_cnot_2', matrix) + u.decompose() + k.x(1) + k.gate(u, [0, 1]) + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + + qx.set(os.path.join(output_dir, p.name + '.qasm')) + qx.execute() + c0 = qx.get_state() + + # only two states are nonzero + self.assertAlmostEqual(0.0, helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(1.0, helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + + def test_non_90_degree_angle(self): + num_qubits = 2 + p = ql.Program('test_non_90_degree_angle', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + -0.43874989 - 0.10659111j, -0.47325212 + 0.12917344j, -0.58227163 + 0.20750072j, -0.29075334 + 0.29807585j, + 0.30168601 - 0.22307459j, 0.32626000 + 0.45349350j, -0.20523265 - 0.42403593j, -0.01012565 + 0.57016830j, + -0.40954341 - 0.49946371j, 0.28560698 - 0.06740801j, 0.52146754 + 0.18335130j, -0.37248653 + 0.22891636j, + 0.03113162 - 0.48703302j, -0.57180014 + 0.18486244j, 0.29436250 - 0.06148912j, 0.55533888 + 0.04322811j + ] + + u1 = ql.Unitary("non_90_degree_angle", matrix) + u1.decompose() + k.gate(u1, [0, 1]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[4]), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[8]), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[12]), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + + def test_using_qx_00(self): + num_qubits = 2 + p = ql.Program('test_using_qx_00', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + -0.15050486 + 0.32164259j, -0.29086861 + 0.76699622j, 0.17865218 + 0.18573699j, -0.31380116 + 0.19005417j, + -0.65629705 + 0.20915109j, 0.32782708 + 0.16363753j, -0.54511727 - 0.21100055j, 0.06012210 - 0.21446079j, + -0.38935965 - 0.47787084j, 0.30279699 - 0.10056307j, 0.04076564 + 0.54046282j, -0.23847619 + 0.40939808j, + 0.13874319 - 0.01460122j, -0.27256915 + 0.12950497j, -0.49774672 + 0.22449364j, 0.61597430 + 0.46032394j + ] + + u1 = ql.Unitary("using_qx_00", matrix) + u1.decompose() + k.gate(u1, [0, 1]) + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[4]), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[8]), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[12]), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + + def test_using_qx_01(self): + num_qubits = 2 + p = ql.Program('test_using_qx_01', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + -0.15050486 + 0.32164259j, -0.29086861 + 0.76699622j, 0.17865218 + 0.18573699j, -0.31380116 + 0.19005417j, + -0.65629705 + 0.20915109j, 0.32782708 + 0.16363753j, -0.54511727 - 0.21100055j, 0.06012210 - 0.21446079j, + -0.38935965 - 0.47787084j, 0.30279699 - 0.10056307j, 0.04076564 + 0.54046282j, -0.23847619 + 0.40939808j, + 0.13874319 - 0.01460122j, -0.27256915 + 0.12950497j, -0.49774672 + 0.22449364j, 0.61597430 + 0.46032394j + ] + + k.x(0) + + u1 = ql.Unitary("using_qx_01", matrix) + u1.decompose() + k.gate(u1, [0, 1]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(helper_prob(matrix[1]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[5]), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[9]), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[13]), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + + def test_using_qx_10(self): + num_qubits = 2 + p = ql.Program('test_using_qx_10', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + -0.15050486 + 0.32164259j, -0.29086861 + 0.76699622j, 0.17865218 + 0.18573699j, -0.31380116 + 0.19005417j, + -0.65629705 + 0.20915109j, 0.32782708 + 0.16363753j, -0.54511727 - 0.21100055j, 0.06012210 - 0.21446079j, + -0.38935965 - 0.47787084j, 0.30279699 - 0.10056307j, 0.04076564 + 0.54046282j, -0.23847619 + 0.40939808j, + 0.13874319 - 0.01460122j, -0.27256915 + 0.12950497j, -0.49774672 + 0.22449364j, 0.61597430 + 0.46032394j + ] + + u1 = ql.Unitary("using_qx_10", matrix) + u1.decompose() + k.x(1) + k.gate(u1, [0, 1]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(helper_prob(matrix[2]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[6]), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[10]), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[14]), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + + def test_using_qx_11(self): + num_qubits = 2 + p = ql.Program('test_using_qx_11', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + -0.15050486 + 0.32164259j, -0.29086861 + 0.76699622j, 0.17865218 + 0.18573699j, -0.31380116 + 0.19005417j, + -0.65629705 + 0.20915109j, 0.32782708 + 0.16363753j, -0.54511727 - 0.21100055j, 0.06012210 - 0.21446079j, + -0.38935965 - 0.47787084j, 0.30279699 - 0.10056307j, 0.04076564 + 0.54046282j, -0.23847619 + 0.40939808j, + 0.13874319 - 0.01460122j, -0.27256915 + 0.12950497j, -0.49774672 + 0.22449364j, 0.61597430 + 0.46032394j + ] + + u1 = ql.Unitary("using_qx_11", matrix) + u1.decompose() + k.x(0) + k.x(1) + k.gate(u1, [0, 1]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(helper_prob(matrix[3]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[7]), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[11]), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[15]), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + + def test_using_qx_bell_state(self): + num_qubits = 2 + p = ql.Program('test_using_qx_bell_state', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + -0.15050486 + 0.32164259j, -0.29086861 + 0.76699622j, 0.17865218 + 0.18573699j, -0.31380116 + 0.19005417j, + -0.65629705 + 0.20915109j, 0.32782708 + 0.16363753j, -0.54511727 - 0.21100055j, 0.06012210 - 0.21446079j, + -0.38935965 - 0.47787084j, 0.30279699 - 0.10056307j, 0.04076564 + 0.54046282j, -0.23847619 + 0.40939808j, + 0.13874319 - 0.01460122j, -0.27256915 + 0.12950497j, -0.49774672 + 0.22449364j, 0.61597430 + 0.46032394j + ] + + u1 = ql.Unitary("using_qx_bell_state", matrix) + u1.decompose() + k.hadamard(0) + k.cnot(0, 1) + + k.gate(u1, [0, 1]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(0.5 * helper_prob((matrix[0] + matrix[3])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.5 * helper_prob((matrix[4] + matrix[7])), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.5 * helper_prob((matrix[8] + matrix[11])), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.5 * helper_prob((matrix[12] + matrix[15])), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + + def test_using_qx_fully_entangled(self): + num_qubits = 2 + p = ql.Program('test_using_qx_fully_entangled', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + -0.15050486 + 0.32164259j, -0.29086861 + 0.76699622j, + 0.17865218 + 0.18573699j, -0.31380116 + 0.19005417j, + -0.65629705 + 0.20915109j, 0.32782708 + 0.16363753j, + -0.54511727 - 0.21100055j, 0.06012210 - 0.21446079j, + -0.38935965 - 0.47787084j, 0.30279699 - 0.10056307j, + 0.04076564 + 0.54046282j, -0.23847619 + 0.40939808j, + 0.13874319 - 0.01460122j, -0.27256915 + 0.12950497j, + -0.49774672 + 0.22449364j, 0.61597430 + 0.46032394j + ] + + u1 = ql.Unitary("using_qx_fully_entangled", matrix) + u1.decompose() + k.hadamard(0) + k.hadamard(1) + k.cnot(0, 1) + + k.gate(u1, [0, 1]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(0.25 * helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.25 * helper_prob((matrix[4] + matrix[5] + matrix[6] + matrix[7])), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.25 * helper_prob((matrix[8] + matrix[9] + matrix[10] + matrix[11])), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.25 * helper_prob((matrix[12] + matrix[13] + matrix[14] + matrix[15])), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + + def test_using_qx_fully_entangled_3_qubit(self): + num_qubits = 3 + p = ql.Program('test_using_qx_fully_entangled_3_qubit', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + -6.71424156e-01 + 0.20337111j, -1.99816541e-02 + 0.41660484j, -1.54134851e-01 + 0.19449230j, 3.01737845e-01 - 0.27546267j, + 4.44627514e-02 + 0.09208708j, 2.15969389e-01 + 0.05602634j, -4.34685756e-02 - 0.18679037j, -1.06595244e-02 - 0.09070964j, + -2.97602383e-01 + 0.04481956j, -2.02480684e-01 - 0.38012451j, 2.82743377e-02 + 0.15314781j, -2.85687313e-01 - 0.15726268j, + -1.70730583e-04 - 0.15338500j, 2.29149718e-01 + 0.30741448j, 2.10312109e-01 + 0.49212858j, -3.59933779e-01 - 0.08254810j, + -2.53660227e-01 + 0.17691007j, 3.13791732e-01 + 0.27041001j, -2.02215264e-01 - 0.11204691j, -8.86804543e-02 + 0.66976204j, + 7.33676579e-02 - 0.13082467j, -9.97863275e-02 + 0.01447563j, -5.89120641e-02 + 0.42937540j, 3.27562664e-02 + 0.03619316j, + -1.13124674e-01 - 0.00735472j, 9.70967395e-02 - 0.24582965j, -1.01309756e-01 - 0.39478792j, 1.63747452e-01 - 0.02575567j, + -3.55829560e-01 + 0.48277026j, 2.92508802e-01 - 0.34856674j, -2.35490557e-01 + 0.20291125j, -2.05196931e-01 + 0.13496088j, + 1.00349815e-01 - 0.11576965j, 2.96991063e-01 + 0.12974051j, -4.63456662e-01 + 0.26944686j, -3.95037450e-01 - 0.08454082j, + -4.48111249e-01 + 0.29131040j, -5.36978251e-02 + 0.25408623j, 2.01534991e-01 - 0.12684844j, 6.37083728e-03 + 0.10506858j, + -3.22312837e-01 - 0.15860928j, 1.56365350e-01 - 0.10492928j, 3.40842166e-01 + 0.16770422j, 3.86154376e-02 - 0.15216514j, + -2.21887101e-01 - 0.16990398j, -2.64609917e-01 - 0.06773659j, -2.76899134e-02 + 0.12469262j, 2.53068805e-01 + 0.65839736j, + -1.47285402e-01 + 0.02010648j, -1.02440846e-01 - 0.36282662j, -4.07092321e-01 + 0.18619875j, -1.51508597e-01 + 0.08507565j, + -1.60692869e-01 - 0.43953586j, 1.67488911e-01 - 0.42784326j, -1.68066530e-01 - 0.18644660j, 3.03353139e-01 - 0.14152888j, + -3.65022492e-01 + 0.03013316j, 2.23190344e-01 - 0.25817333j, 8.15042751e-02 - 0.23635981j, -1.36339839e-01 + 0.07858377j, + 3.21627053e-02 + 0.00460768j, -4.58271701e-01 - 0.15103882j, 2.70920093e-01 - 0.42767654j, -3.77444900e-01 - 0.17163736j + ] + + u1 = ql.Unitary("using_qx_fully_entangled_3_qubit", matrix) + u1.decompose() + k.hadamard(0) + k.hadamard(1) + k.hadamard(2) + k.cnot(0, 1) + k.cnot(0, 2) + k.cnot(1, 2) + + k.gate(u1, [0, 1, 2]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(0.125 * helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[8] + matrix[9] + matrix[10] + matrix[11] + matrix[12] + matrix[13] + matrix[14] + matrix[15])), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[16] + matrix[17] + matrix[18] + matrix[19] + matrix[20] + matrix[21] + matrix[22] + matrix[23])), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[24] + matrix[25] + matrix[26] + matrix[27] + matrix[28] + matrix[29] + matrix[30] + matrix[31])), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[32] + matrix[33] + matrix[34] + matrix[35] + matrix[36] + matrix[37] + matrix[38] + matrix[39])), helper_prob(state.get(to_bit_string(4, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[40] + matrix[41] + matrix[42] + matrix[43] + matrix[44] + matrix[45] + matrix[46] + matrix[47])), helper_prob(state.get(to_bit_string(5, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[48] + matrix[49] + matrix[50] + matrix[51] + matrix[52] + matrix[53] + matrix[54] + matrix[55])), helper_prob(state.get(to_bit_string(6, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[56] + matrix[57] + matrix[58] + matrix[59] + matrix[60] + matrix[61] + matrix[62] + matrix[63])), helper_prob(state.get(to_bit_string(7, size=platform_qubits), 0.)), 5) + + def test_using_qx_fully_entangled_4_qubit(self): + num_qubits = 4 + p = ql.Program('test_using_qx_fully_entangled_4_qubit', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + -0.11921901-0.30382154j, -0.10645804-0.11760155j, -0.09639953-0.03539260j, -0.32605797+0.19552924j, 0.01682620-0.26748208j, -0.17808469+0.25265196j, -0.24676084-0.23228431j, -0.02960302+0.23697569j, + -0.12435741-0.07223017j, 0.00178745+0.14813263j, -0.11173158+0.26636089j, 0.27656908+0.05229833j, -0.02964214-0.01505502j, -0.26959616+0.23274949j, -0.18183627-0.04041783j, 0.05385991-0.05587908j, + 0.17894461-0.25668366j, -0.01553181-0.07446613j, 0.18764670-0.49135878j, -0.18292006-0.04599956j, -0.01618695+0.21951951j, 0.06003169-0.12728871j, -0.04276406+0.08327372j, 0.30102765+0.18403071j, + -0.08122018-0.08375638j, -0.02971758+0.09096399j, 0.10753511-0.03359547j, -0.15963090+0.20649279j, -0.13684564+0.29450386j, 0.20557421+0.24856224j, 0.06834440+0.01780095j, -0.22317907-0.12123145j, + -0.03235040-0.02668934j, 0.08743777-0.49956832j, -0.30202031-0.22517221j, -0.10642491-0.11883126j, -0.13756817-0.20632933j, 0.02593802+0.00583978j, 0.05130972+0.06678859j, -0.10426135-0.14411822j, + 0.12318252+0.28583957j, 0.04903179-0.31898637j, -0.07650819-0.07261235j, -0.22918932-0.28329527j, -0.26553775+0.04563403j, -0.07728053+0.14952931j, -0.10271285-0.00216319j, -0.09000117+0.09055528j, + -0.15385903+0.01767834j, 0.42229431-0.05610483j, -0.11330491-0.05458018j, 0.01740815-0.01605897j, -0.11908997-0.01830574j, 0.21139794-0.10602858j, -0.23249721-0.25516076j, -0.29066084-0.19129198j, + 0.21273108-0.14369238j, -0.20662513+0.14463032j, 0.25124660-0.20356141j, 0.08694950+0.24425667j, 0.09736427-0.03954332j, 0.14463030+0.14263171j, -0.25679664+0.09389641j, -0.04020309-0.19362247j, + 0.12577257-0.14527364j, 0.00371525+0.14235318j, -0.22416134+0.02069087j, 0.03851418-0.05351593j, -0.00289848-0.33289946j, 0.15454716-0.12663300j, -0.08996296-0.09119411j, -0.00804455-0.19149767j, + -0.13311475-0.47100304j, -0.13920624-0.16994321j, -0.05030304+0.16820614j, 0.05770089-0.15422191j, -0.23739468-0.05651883j, 0.19202883+0.03893001j, 0.48514604+0.01905479j, -0.01593819-0.06475285j, + 0.31543713+0.41579542j, -0.08776349+0.24207219j, -0.07984699-0.12818844j, 0.00359655+0.02677178j, -0.12110453-0.25327887j, -0.21175671-0.16500740j, -0.14570465-0.05140668j, 0.06873883-0.01768705j, + -0.13804809-0.16458822j, 0.15096981-0.02802171j, -0.05750448-0.18911017j, -0.01552104+0.03159908j, -0.04824180+0.09434822j, 0.13364470+0.22030451j, -0.37713640-0.17773263j, 0.16023381+0.26613455j, + 0.12688452-0.07290393j, 0.14834649+0.08064162j, -0.06224533+0.04404318j, 0.03464369+0.19965444j, -0.38140629-0.18927599j, -0.19710535-0.17865700j, -0.05078850+0.19579635j, 0.11741615+0.13922702j, + 0.26733990-0.01439493j, 0.10844591-0.19799688j, 0.01177533+0.03184600j, -0.07643954+0.25870281j, 0.28971442-0.25385986j, -0.23713666+0.01838019j, 0.17318640-0.09372299j, -0.36912353-0.02243029j, + 0.03562803-0.09449815j, 0.13578229-0.19205153j, 0.21279127+0.14541266j, -0.20195524+0.18747700j, -0.06326783+0.01348270j, 0.26953438-0.11153784j, -0.28939961-0.08995754j, 0.20662437-0.15535337j, + -0.03615272+0.00848631j, 0.14124129-0.10250932j, 0.08990493-0.13010897j, -0.04547667+0.17579099j, -0.01292137+0.10354402j, -0.21338733-0.11928412j, 0.19733294+0.12876129j, 0.35162495+0.45226713j, + 0.17112722-0.18496045j, -0.34024071-0.09520237j, 0.18864652-0.07147408j, 0.31340662+0.24027412j, -0.07208740-0.11081564j, 0.08727975+0.02830958j, -0.07584662-0.22555917j, 0.07086867-0.27714915j, + -0.19116148-0.02164144j, -0.24831911+0.10552290j, -0.09939105-0.24800283j, -0.15274706-0.12267535j, 0.05237777-0.09974669j, -0.18435891-0.17370020j, -0.20884292+0.10760810j, -0.31368958-0.02539025j, + 0.03436293-0.19794965j, 0.11892581-0.17440358j, -0.03488877+0.02305411j, 0.29835292-0.08836461j, 0.07893495-0.16881403j, 0.21025843+0.13204032j, 0.17194288-0.06285539j, -0.05004970+0.35833208j, + -0.14979745-0.07567974j, 0.00193804+0.04092128j, -0.07528403-0.18508153j, -0.16873521-0.09470809j, 0.50335605+0.00445803j, 0.11671956+0.30273552j, 0.10253226-0.13365319j, 0.16676135+0.18345473j, + -0.10096334-0.24031019j, -0.18452241+0.05766426j, 0.18102499-0.13532486j, 0.06252468-0.18030042j, -0.00591499+0.07587582j, -0.35209025-0.12186396j, -0.25282963-0.26651504j, -0.13074882+0.14059941j, + 0.18125386-0.03889917j, 0.06983104-0.34250760j, 0.37124455-0.00305632j, 0.04469806-0.31220629j, 0.16501585+0.00125887j, 0.15895714-0.14115809j, -0.01515444+0.06836136j, 0.03934186+0.13425449j, + 0.05134990+0.21915368j, 0.00089628-0.30446110j, 0.05443815-0.05530296j, 0.12091374-0.16717579j, -0.06795704-0.25159470j, -0.43324316+0.13138954j, 0.03753289-0.00666299j, 0.16823686-0.22736152j, + -0.00567807+0.05485941j, -0.11705816+0.39078352j, 0.29136164+0.18699453j, -0.09255109+0.08923507j, 0.11214398+0.00806872j, 0.02971631+0.05584961j, 0.25610000+0.22302638j, 0.12491596+0.01725833j, + 0.23473354-0.19203316j, -0.09144197-0.04827201j, -0.06309750-0.16831612j, 0.01497053+0.11121057j, 0.14268640-0.15815582j, 0.21509872-0.08218510j, 0.00650273+0.42560079j, -0.15721229+0.09919403j, + 0.18076365-0.05697395j, -0.10596487+0.23118383j, 0.30913352+0.24695589j, -0.03403863-0.01778209j, -0.07783213-0.25923847j, 0.06847369-0.24604470j, -0.24223779-0.10590238j, 0.15920784+0.21435437j, + 0.26632193-0.02864663j, 0.06457043+0.05774280j, -0.38792984+0.08474334j, 0.00944311+0.22274564j, 0.11762823+0.36687658j, -0.10584280-0.21036370j, -0.12970051-0.27031414j, 0.12684307+0.08398822j, + 0.06711923+0.23195763j, -0.04537262+0.26478843j, 0.10253668-0.07706414j, -0.13531665-0.27150259j, -0.09124132-0.23306839j, -0.08631867+0.17221145j, 0.17654328-0.10341264j, 0.11171903-0.05824829j, + 0.04708668-0.13436316j, -0.10544253+0.07083904j, 0.04191629+0.28190845j, -0.42129470-0.28704399j, 0.10278485+0.05713015j, 0.02057009-0.19126408j, 0.04856717+0.26648423j, 0.05388858-0.32433511j, + -0.09408669-0.12159016j, -0.01355394+0.04757554j, 0.10925003-0.04539990j, -0.02512057-0.23836324j, 0.31375479-0.09935640j, -0.14702106+0.33395328j, -0.16080290+0.11439592j, -0.11028577-0.00936150j, + -0.08440005-0.12376623j, 0.12932188+0.09711828j, 0.18574716-0.06392924j, -0.13048059+0.02879610j, -0.29552716-0.08768809j, -0.02439943-0.01548155j, 0.07775135+0.00727332j, 0.15615340-0.06489038j, + 0.46665242-0.07708219j, -0.05251139+0.37781248j, -0.35490810-0.10086123j, 0.11180645-0.40408473j, 0.03031085+0.16928711j, 0.11901290-0.10061168j, 0.03180460-0.12504866j, 0.08689947+0.07223655j + ] + + u1 = ql.Unitary("using_qx_fully_entangled_4_qubit", matrix) + u1.decompose() + k.hadamard(0) + k.hadamard(1) + k.hadamard(2) + k.hadamard(3) + k.cnot(0, 1) + k.cnot(0, 2) + k.cnot(0, 3) + k.cnot(1, 2) + k.cnot(1, 3) + k.cnot(2, 3) + + k.gate(u1, [0, 1, 2, 3]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(0.0625 * helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7] + matrix[8] + matrix[9] + matrix[10] + matrix[11] + matrix[12] + matrix[13] + matrix[14] + matrix[15])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[16] + matrix[17] + matrix[18] + matrix[19] + matrix[20] + matrix[21] + matrix[22] + matrix[23] + matrix[24] + matrix[25] + matrix[26] + matrix[27] + matrix[28] + matrix[29] + matrix[30] + matrix[31])), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[32] + matrix[33] + matrix[34] + matrix[35] + matrix[36] + matrix[37] + matrix[38] + matrix[39] + matrix[40] + matrix[41] + matrix[42] + matrix[43] + matrix[44] + matrix[45] + matrix[46] + matrix[47])), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[48] + matrix[49] + matrix[50] + matrix[51] + matrix[52] + matrix[53] + matrix[54] + matrix[55] + matrix[56] + matrix[57] + matrix[58] + matrix[59] + matrix[60] + matrix[61] + matrix[62] + matrix[63])), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[64] + matrix[65] + matrix[66] + matrix[67] + matrix[68] + matrix[69] + matrix[70] + matrix[71] + matrix[72] + matrix[73] + matrix[74] + matrix[75] + matrix[76] + matrix[77] + matrix[78] + matrix[79])), helper_prob(state.get(to_bit_string(4, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[80] + matrix[81] + matrix[82] + matrix[83] + matrix[84] + matrix[85] + matrix[86] + matrix[87] + matrix[88] + matrix[89] + matrix[90] + matrix[91] + matrix[92] + matrix[93] + matrix[94] + matrix[95])), helper_prob(state.get(to_bit_string(5, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[96] + matrix[97] + matrix[98] + matrix[99] + matrix[100] + matrix[101] + matrix[102] + matrix[103] + matrix[104] + matrix[105] + matrix[106] + matrix[107] + matrix[108] + matrix[109] + matrix[110] + matrix[111])), helper_prob(state.get(to_bit_string(6, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[112] + matrix[113] + matrix[114] + matrix[115] + matrix[116] + matrix[117] + matrix[118] + matrix[119] + matrix[120] + matrix[121] + matrix[122] + matrix[123] + matrix[124] + matrix[125] + matrix[126] + matrix[127])), helper_prob(state.get(to_bit_string(7, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[128] + matrix[129] + matrix[130] + matrix[131] + matrix[132] + matrix[133] + matrix[134] + matrix[135] + matrix[136] + matrix[137] + matrix[138] + matrix[139] + matrix[140] + matrix[141] + matrix[142] + matrix[143])), helper_prob(state.get(to_bit_string(8, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[144] + matrix[145] + matrix[146] + matrix[147] + matrix[148] + matrix[149] + matrix[150] + matrix[151] + matrix[152] + matrix[153] + matrix[154] + matrix[155] + matrix[156] + matrix[157] + matrix[158] + matrix[159])), helper_prob(state.get(to_bit_string(9, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[160] + matrix[161] + matrix[162] + matrix[163] + matrix[164] + matrix[165] + matrix[166] + matrix[167] + matrix[168] + matrix[169] + matrix[170] + matrix[171] + matrix[172] + matrix[173] + matrix[174] + matrix[175])), helper_prob(state.get(to_bit_string(10, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[176] + matrix[177] + matrix[178] + matrix[179] + matrix[180] + matrix[181] + matrix[182] + matrix[183] + matrix[184] + matrix[185] + matrix[186] + matrix[187] + matrix[188] + matrix[189] + matrix[190] + matrix[191])), helper_prob(state.get(to_bit_string(11, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[192] + matrix[193] + matrix[194] + matrix[195] + matrix[196] + matrix[197] + matrix[198] + matrix[199] + matrix[200] + matrix[201] + matrix[202] + matrix[203] + matrix[204] + matrix[205] + matrix[206] + matrix[207])), helper_prob(state.get(to_bit_string(12, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[208] + matrix[209] + matrix[210] + matrix[211] + matrix[212] + matrix[213] + matrix[214] + matrix[215] + matrix[216] + matrix[217] + matrix[218] + matrix[219] + matrix[220] + matrix[221] + matrix[222] + matrix[223])), helper_prob(state.get(to_bit_string(13, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[224] + matrix[225] + matrix[226] + matrix[227] + matrix[228] + matrix[229] + matrix[230] + matrix[231] + matrix[232] + matrix[233] + matrix[234] + matrix[235] + matrix[236] + matrix[237] + matrix[238] + matrix[239])), helper_prob(state.get(to_bit_string(14, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[240] + matrix[241] + matrix[242] + matrix[243] + matrix[244] + matrix[245] + matrix[246] + matrix[247] + matrix[248] + matrix[249] + matrix[250] + matrix[251] + matrix[252] + matrix[253] + matrix[254] + matrix[255])), helper_prob(state.get(to_bit_string(15, size=platform_qubits), 0.)), 5) + + def test_using_qx_fully_entangled_5_qubit(self): + num_qubits = 5 + p = ql.Program('test_using_qx_fully_entangled_5_qubit', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + 0.31869031-9.28734622e-02j, 0.38980148+2.14592427e-01j, 0.20279154-1.56580826e-01j, 0.00210273-2.83970875e-01j, -0.04010672-9.26812940e-02j, 0.15747049+6.08283291e-02j, -0.05274772-6.45225841e-02j, 0.05909439-3.23496026e-02j, 0.07868009+6.77298732e-02j, 0.11290142+2.48468763e-02j, 0.10092033-7.03646679e-02j, -0.03557972-3.39117261e-02j, 0.02241562+1.02714684e-02j, -0.04088796-1.12143173e-01j, -0.00144015+1.83925572e-02j, -0.12579480-1.15394681e-01j, 0.13531631-1.84271421e-01j, 0.11293592-1.44170392e-01j, -0.06985893-1.36606289e-01j, -0.08924113-6.35923942e-02j, 0.19393965-6.35656579e-02j, -0.02153233-2.76955143e-01j, -0.12094999+1.05716669e-01j, -0.00624879+1.27471575e-01j, -0.13608981-1.22140261e-01j, -0.08243959-1.72734247e-02j, 0.06562052+1.12197102e-01j, -0.01102025-1.53811069e-01j, 0.13576338-8.95540026e-02j, 0.05730484-5.62973657e-02j, -0.08835493-4.13159024e-02j, -0.04533295+3.70144188e-02j, 0.04116657+1.58298973e-01j, 0.22270976-1.18654603e-01j, + 0.09219815+8.41433858e-02j, -0.02274990+2.33343627e-01j, -0.13334752-6.98059663e-02j, -0.07967301-6.54413909e-02j, -0.09158972-7.03627564e-02j, -0.02332636-1.58060290e-02j, 0.23523954-3.48258461e-02j, 0.21329683+6.37364245e-02j, 0.25821394+1.30648709e-03j, -0.11188090-1.95903237e-01j, -0.07887212-8.81857936e-02j, 0.04763200+9.40535593e-02j, -0.11726632+5.65815234e-02j, 0.08229469-4.38047420e-02j, 0.03117762+1.08469602e-01j, 0.16064616-1.30734886e-01j, 0.22181279-3.31211823e-02j, 0.07309884-2.01468425e-01j, -0.28437382+6.38292807e-02j, -0.23661479+1.17105208e-01j, -0.10436123-5.56443645e-02j, 0.20587544+1.99848797e-02j, 0.20705551+1.75496198e-02j, 0.01791984-8.31956939e-02j, 0.09737992+6.64713628e-03j, 0.06175660-7.11998970e-02j, 0.03073603-7.25651496e-02j, -0.12056479-1.55358931e-01j, -0.09661589+4.90232280e-03j, 0.03110935-1.72748422e-01j, 0.01473304+3.62629583e-01j, 0.11031868-3.67435519e-03j, 0.04301239-1.64601498e-01j, -0.16432353+7.52258615e-02j, + -0.00648176+6.66215752e-02j, 0.12574270-3.71759618e-02j, -0.07793634-7.01586304e-02j, 0.05711560+2.67410653e-01j, -0.00880782+2.09982981e-01j, -0.04961517-6.86953748e-02j, -0.15766986-1.12761472e-01j, -0.07076146-3.12372790e-02j, -0.08715236+9.29279186e-02j, 0.03843817+1.13545744e-01j, -0.10838483-1.19949631e-02j, -0.06342622+1.73231077e-01j, 0.23221532-4.28875040e-02j, 0.16514567-4.90633428e-02j, -0.01096540+6.37891447e-02j, 0.02171279+5.89435085e-02j, 0.01999250-2.96609865e-01j, 0.16702912+8.82996853e-02j, 0.19820571+5.01863737e-02j, -0.01237253-1.21196566e-01j, 0.11042294-2.16811518e-01j, -0.01004066-2.36556101e-01j, -0.12867290-4.01294536e-03j, -0.11254789+5.56025311e-02j, -0.18328088-1.46524167e-02j, -0.13640243-3.71920766e-02j, -0.03793125+9.57786229e-02j, 0.07600542+1.53449546e-01j, -0.12371969+2.19599454e-01j, 0.18106889-3.10905810e-02j, -0.12698597+7.45431556e-02j, 0.02402161-1.66514384e-02j, -0.14313130+4.63501164e-02j, 0.13656065-8.55748891e-02j, + -0.20854810-3.99831111e-02j, -0.05354994+8.14822771e-02j, 0.22188566+8.04753102e-02j, -0.09702996-1.54653045e-01j, -0.10185620-1.01790676e-01j, -0.00335582+2.52475965e-01j, -0.04858119-1.52409323e-01j, 0.09335149-3.90325714e-02j, 0.08277598-4.08970043e-02j, 0.08119049+5.11051755e-02j, -0.01223217+6.17029648e-04j, -0.15137858-9.30742653e-03j, 0.10647060+3.35870801e-02j, -0.04014048+1.33388615e-01j, -0.04315986+1.74367473e-01j, -0.04774817-9.82134162e-02j, -0.08203436+7.74038565e-02j, -0.23391370+1.62306949e-01j, 0.11791971+2.08966161e-01j, -0.07867189-4.18549851e-02j, -0.17291904+9.47505092e-02j, 0.23630015-3.07786925e-01j, -0.09104365-1.33230919e-01j, 0.07679465+1.45726380e-01j, 0.09397243-9.26081447e-02j, -0.16092509+7.38633830e-02j, -0.02289017+1.59777790e-01j, 0.12053722+6.55620680e-02j, 0.12646833+1.04585433e-01j, 0.02644610+1.92009889e-01j, 0.28749442+1.11327480e-01j, 0.15837267+6.12698488e-02j, 0.18181681-5.61278874e-02j, 0.07897084-1.17114924e-01j, + 0.19787494-1.67863968e-01j, 0.03852499-4.21534504e-02j, -0.14091989-1.27321872e-01j, -0.01747868-2.27419946e-01j, -0.02073576-6.24641146e-02j, -0.14241142+2.28697604e-02j, 0.15468346+2.08734157e-02j, 0.04505001-9.46333157e-02j, -0.09148317-2.26152985e-01j, 0.08577989+2.30863031e-01j, -0.08152502-8.74340592e-02j, -0.06465018-7.35108360e-02j, -0.21595512-8.66695180e-03j, 0.03304541-1.91886499e-01j, 0.04448112+3.67289455e-02j, 0.01969849-5.34777195e-02j, -0.03209367+3.02797601e-02j, 0.17389718+1.19098672e-01j, -0.10192559-3.02362398e-01j, -0.10224653-8.09241417e-02j, -0.12601597-6.86631211e-02j, 0.11275009+1.40915100e-01j, 0.03214418+1.48701215e-01j, -0.11571373+3.57083353e-02j, 0.03222285-5.19221441e-02j, -0.00250593+7.32186819e-02j, -0.15549573+1.77404851e-01j, 0.08568275+1.02973155e-01j, 0.11314133-2.13171498e-01j, 0.22748546-5.69951563e-02j, 0.14929197+1.31715414e-01j, -0.16301646+3.65045553e-03j, 0.13494125+2.31602145e-01j, 0.24267648-1.77780817e-01j, + -0.00736974+7.72680290e-02j, -0.04867011+1.22605525e-01j, 0.05051748+8.06196677e-02j, -0.01749415+6.33486594e-02j, 0.06408343-4.51492484e-02j, -0.02543799-1.33253676e-01j, -0.05785745-4.71803669e-02j, -0.24358675-1.18083337e-02j, 0.00061111-5.96573111e-03j, 0.17487681-8.55625475e-02j, 0.13181372-5.47918839e-02j, -0.14072394+1.08475923e-01j, 0.05919593+1.78284217e-01j, -0.00292253-2.17168452e-02j, 0.19948189-1.95177980e-01j, -0.11146926-1.55684600e-01j, 0.02692391-9.18282632e-02j, -0.03804582-7.62499524e-02j, 0.18562866+1.41900953e-01j, 0.15468899+7.03401694e-03j, 0.10617502+2.96183301e-01j, 0.12124371+1.42279327e-02j, -0.12974516+1.87600027e-01j, -0.23270386+1.59618723e-01j, -0.14928652-8.27397154e-02j, 0.06670844+6.35681954e-02j, 0.03466266+1.89244901e-01j, -0.00961646-1.02903972e-01j, 0.19899344-2.38199195e-01j, -0.16594523-4.43067845e-02j, 0.27258801-7.49570862e-02j, 0.08182091+2.03334342e-02j, -0.02454051-4.82668158e-02j, -0.08557127+3.04552132e-02j, + 0.01303575+8.88057122e-02j, 0.13253621+5.05712004e-02j, 0.07763894+1.13841327e-01j, -0.28730914-4.49839630e-02j, 0.07031891-3.38973984e-03j, -0.04794523-1.67972335e-01j, -0.18102171+2.08760542e-01j, -0.08845631-9.70771934e-02j, 0.03546718+4.80846877e-02j, -0.08866794-5.19207245e-02j, -0.15099182-9.77070105e-02j, -0.05473901+2.33013978e-01j, -0.04645356-8.89489153e-02j, 0.07548625+1.80517821e-01j, 0.16840691+2.15268260e-01j, -0.09962074-7.35772706e-03j, -0.10104245+1.74017433e-02j, -0.09302095-1.10945928e-01j, -0.03515700+2.50873519e-02j, 0.10622507+1.29398421e-01j, -0.20965829-4.55862887e-02j, 0.05220909+6.66834897e-02j, -0.09672108+1.09403436e-01j, 0.12697788-6.19212188e-02j, 0.05729917+1.44378294e-01j, -0.15808366-3.82581632e-02j, 0.10716098-4.62942406e-02j, 0.24961573+1.32840816e-01j, 0.06278080+2.39056706e-02j, 0.18311487+7.98582936e-03j, 0.02661541+7.40701198e-02j, 0.04699528+1.88767961e-01j, 0.04750332-2.25995642e-02j, 0.07193907+5.68042859e-02j, + -0.02763382-3.43370436e-02j, 0.11205088-1.98370084e-02j, -0.11424545+1.14269285e-03j, 0.06885854-2.09915302e-01j, -0.05625496-2.88701666e-01j, -0.08183393+2.31774294e-01j, -0.09301037-4.03842722e-02j, -0.06069309+2.57502142e-02j, -0.18634877+9.85377377e-02j, 0.01474395+9.22414287e-02j, 0.04147054-1.74520016e-01j, 0.06794102-1.59508183e-01j, -0.13292245-5.38490513e-02j, -0.18753702+2.82751900e-01j, 0.00899866-2.80951474e-01j, 0.20377748+8.19207845e-02j, -0.14028603-1.39624056e-01j, 0.10741114+2.60308736e-02j, -0.22833573+6.02730469e-02j, 0.16071761-1.25615817e-01j, 0.08060865-5.81044643e-03j, 0.16141495-4.86994019e-02j, 0.11263654-1.87107794e-02j, 0.06859488-1.90280093e-01j, 0.10733862+4.45380867e-02j, -0.11489398-2.10578670e-01j, -0.08648330-1.73958604e-01j, 0.12293904-1.50703768e-01j, -0.00629652+2.98133822e-02j, 0.16452648+7.76415767e-02j, 0.16219009+2.46017766e-01j, -0.04582374-1.16806045e-01j, 0.15109013+9.45671154e-03j, 0.04773975-1.54745106e-01j, + 0.21822796-1.87975523e-03j, 0.16596711-1.31539539e-01j, 0.25621724-4.31460990e-02j, 0.23071937+1.38086347e-01j, 0.10615413-1.24941186e-01j, 0.00343902+5.79927212e-02j, 0.10569282-2.64952183e-01j, -0.13601637+5.39259774e-02j, -0.13182901+9.15307749e-02j, 0.03524551-1.35956850e-01j, 0.09576220-1.71837228e-02j, -0.03707841-5.40514827e-02j, -0.05729147-7.33164458e-02j, -0.18631267+1.00759871e-01j, -0.02434746-2.22824245e-02j, -0.02570765-3.90074186e-02j, 0.17946901+1.86288095e-02j, 0.07742897+3.19064602e-02j, -0.17538437+2.18666227e-01j, 0.10029635-8.92554711e-03j, -0.13379504-1.03683797e-02j, -0.11115363-4.48983441e-02j, 0.00163172-2.05325390e-02j, 0.02753729-1.28591197e-01j, 0.01933548+2.37393316e-01j, 0.07102201-1.19729329e-01j, -0.07517562+7.47947883e-02j, -0.03383077-1.23796732e-01j, -0.05575669-2.97673975e-02j, -0.04860924+1.02986531e-01j, 0.11384071+2.36429953e-01j, -0.26355793+1.30580300e-02j, -0.26655410+6.72995742e-02j, -0.04663019-5.64857364e-03j, + 0.15703188+2.25734925e-02j, -0.02611337-4.94904084e-03j, 0.31897764+7.13870567e-02j, 0.15501272-1.48107261e-01j, 0.18034006-2.37497106e-01j, 0.21350438-8.08313917e-02j, 0.06206880+5.98457145e-02j, -0.04996277+1.09069384e-02j, -0.09282843-5.59942293e-02j, -0.05363359+4.83839918e-02j, -0.20946404-1.85419524e-01j, -0.05481421+8.78420662e-02j, -0.19261214-1.04875021e-01j, -0.00083685-2.70091261e-02j, -0.17618069+8.47803615e-02j, 0.16055652+5.98821538e-03j, -0.06356210+8.16228775e-02j, -0.22507829-4.14268948e-02j, -0.00791737+7.40481825e-02j, 0.19970347-1.15972939e-01j, -0.08619572+1.19678540e-01j, -0.18493100-1.13524848e-01j, 0.04824348-5.85668978e-02j, -0.22446284+1.11472258e-02j, 0.09629746-1.88788542e-01j, -0.18228537-3.89615785e-04j, 0.09084756+4.78058679e-02j, -0.00889583-1.74554680e-01j, -0.07447697-4.48823321e-02j, -0.05076077-6.24206002e-02j, -0.14050658+8.38982646e-02j, 0.07428934-6.30440232e-02j, 0.05701074-1.00819168e-01j, 0.07009481+8.11789378e-02j, + -0.01155395+2.46650660e-01j, 0.25264038-1.98419236e-01j, -0.09155521-2.79616998e-02j, 0.06750545-1.52831769e-01j, 0.10685040-1.78545409e-01j, -0.06203486+2.86380485e-02j, 0.23067545-1.23638547e-01j, -0.02397582+2.15643846e-01j, 0.01810979+1.08067552e-01j, 0.09130261-4.68850866e-02j, 0.13093158-1.51875212e-01j, 0.25207024+5.80216347e-02j, 0.02600999-1.27799785e-01j, 0.03509714-5.46256940e-02j, 0.04362407-3.07563727e-02j, 0.12488249+6.70881126e-02j, 0.05539679+1.15790184e-01j, 0.23107124-9.66168589e-02j, -0.09977799-9.88045601e-02j, -0.05633534+2.79762650e-01j, -0.02304281-2.42282613e-02j, 0.12765180-2.32550502e-02j, 0.25634814-3.02429796e-02j, 0.30827737-2.19288542e-01j, -0.02512791+2.13783374e-01j, 0.15453741-7.04163688e-02j, -0.21441715+2.05959415e-01j, -0.02827968+4.71161636e-02j, -0.03837343+6.70595235e-02j, -0.07854483-3.12796395e-02j, -0.03615927+1.10733671e-01j, 0.21779074-1.39489256e-01j, 0.06619192+5.38352432e-02j, -0.06802160-1.05456770e-01j, + -0.10316128+1.32947183e-01j, -0.06345699-1.85555087e-01j, -0.00893067+1.52852423e-01j, 0.03135864+1.10423220e-01j, -0.18235100+2.77954961e-02j, -0.09252137+1.09061091e-01j, -0.07976950+1.15176285e-02j, 0.05051009+2.57152535e-01j, 0.09344185-1.12906975e-01j, 0.04587659+8.90786692e-02j, -0.02471718+4.53344925e-02j, -0.08880236+3.62673481e-02j, -0.05981018+9.78912466e-02j, -0.00118743-5.07702805e-02j, -0.08119522+5.16043940e-02j, 0.11854883+9.79110177e-02j, 0.28543526-8.57540624e-02j, 0.28069514+2.00242562e-01j, -0.01036913-1.12897546e-01j, -0.08470073+1.91009156e-02j, 0.01428585+7.92620224e-02j, -0.15567322-4.85322282e-02j, 0.14203257-2.97248067e-01j, 0.15075682-1.33294241e-01j, 0.08107944-6.10561974e-02j, 0.07558358-3.29486035e-02j, -0.04042877-2.49142675e-02j, 0.05557881-1.93956804e-01j, -0.00589446+9.44678255e-02j, 0.16536760-4.08479951e-02j, 0.14382039+1.57269491e-02j, -0.22311804-8.79699173e-02j, 0.09825566+1.52084444e-02j, 0.00938452-3.15649024e-01j, + -0.03982978+1.22637508e-01j, -0.15670677-1.93426126e-01j, 0.22741559-4.39643322e-02j, -0.13362661-9.94353174e-02j, -0.09445278+4.93195562e-02j, -0.04684833-8.59308253e-02j, 0.08890091-1.16876390e-01j, -0.18726614+7.50813913e-02j, -0.01806267-2.00321404e-02j, 0.09338316-1.69711164e-01j, -0.03114173+1.43744729e-01j, -0.01515641+7.72217128e-02j, 0.21301431+5.92330407e-02j, 0.12250555+1.16784140e-01j, 0.04925890+1.82225369e-01j, 0.09296806+1.58772507e-02j, -0.06700279+7.86869873e-02j, -0.02389099-5.36170682e-02j, 0.00545649-1.25491880e-03j, 0.09228983+2.64561438e-01j, -0.08125859-3.27415023e-02j, -0.03769576-2.64763488e-01j, 0.09145940+1.90133579e-01j, -0.27352411+6.32203214e-02j, -0.00087467-8.61094525e-02j, 0.13735927+8.73538830e-03j, -0.08484748+1.68213884e-01j, -0.07040327-1.76254392e-01j, -0.08363638-8.30902369e-02j, 0.14643814+6.63711322e-02j, -0.31659998-1.04317904e-01j, 0.07830602+2.93183609e-02j, 0.11041879+1.50347028e-01j, -0.00433818-1.72946523e-01j, + -0.15422074+9.38342826e-02j, -0.14194574+3.64105744e-02j, 0.06297505+7.88548664e-02j, 0.01106598-2.65402837e-01j, 0.07164956-8.12953528e-02j, -0.12514039-1.84403896e-01j, -0.17295559+3.58171829e-02j, -0.03655755-7.10559195e-02j, -0.03821694-1.10973040e-01j, 0.18546141+1.10662839e-01j, -0.10195195+1.32367694e-01j, -0.05016084+2.78628720e-02j, -0.19079393+1.40041256e-02j, 0.07878861-3.38112621e-02j, 0.13730204+1.52897765e-01j, 0.11815899+3.49910958e-02j, -0.02648579-1.03280312e-01j, 0.11970226-2.50844123e-01j, 0.10406627-9.12689026e-02j, 0.07247411-2.51491332e-01j, 0.06550999-2.94078974e-01j, -0.12079469-5.00355065e-02j, 0.06000345-1.02467349e-01j, 0.08823557+3.66136284e-02j, 0.02291526+3.63437115e-02j, -0.07124433+2.31676270e-01j, 0.17493588+5.98421039e-02j, -0.17824122-1.97944096e-02j, -0.00491994-9.10500757e-02j, 0.19633245+6.47815099e-02j, -0.03770238-7.48581318e-02j, -0.18402244+9.04322714e-02j, -0.28428450-1.40285725e-01j, 0.00138785+1.08042021e-01j, + 0.16088797+2.75183648e-01j, -0.08656340-7.36993417e-02j, 0.05178655+5.29576072e-02j, -0.05123872-1.29090313e-02j, -0.03079395-1.69557846e-01j, 0.23219467-7.71729365e-03j, -0.01135984-6.49120093e-02j, 0.08717993-9.71885487e-02j, -0.02043387+1.16518568e-01j, -0.08256357+1.23302259e-02j, 0.13742387-2.00583302e-01j, 0.11087765+2.22213806e-02j, 0.10703254+3.53681589e-02j, -0.04998617+7.13667998e-02j, -0.24635130-2.30198030e-01j, 0.09831487+1.92709068e-01j, 0.10999549+1.28740664e-01j, -0.04056669+9.08016920e-02j, -0.03342728-9.92407179e-02j, 0.09352449-4.93911914e-02j, -0.11841153-8.25481366e-02j, -0.02632050+1.91245810e-01j, -0.15521225-6.80613837e-02j, 0.18223827-2.68908129e-01j, 0.04119450+1.12072453e-01j, -0.02954085+6.34315408e-02j, -0.01019486-1.24389083e-01j, 0.19174201-7.05812742e-02j, 0.19351232+1.42610666e-02j, 0.12937332-1.45006522e-01j, 0.01111355+1.11974478e-01j, 0.25163849+7.58955475e-02j, 0.06967535+1.51710939e-01j, -0.26064587+5.85797495e-02j, + -0.05364486-8.37537594e-02j, 0.02473011+1.57624180e-01j, 0.07885240+4.24067733e-02j, -0.05353458-3.59527188e-02j, 0.24630053-3.09146961e-01j, 0.12673895+2.54501080e-02j, 0.13328446+1.27420821e-01j, -0.03311185+8.64376474e-02j, -0.10126181-3.33404906e-02j, 0.05819512-2.42452607e-01j, 0.12966928+1.92345459e-01j, -0.10237172+7.87217786e-02j, -0.12008000+8.02686485e-02j, 0.11309599+3.47582961e-02j, 0.16921731-6.49645604e-02j, 0.10847358+1.32814258e-01j, 0.09620142+8.29342007e-02j, -0.03836254+1.18815716e-01j, 0.10334279-1.21404737e-02j, -0.19366239-5.73423731e-02j, 0.11445103-7.69154143e-02j, 0.10345336+3.42165082e-02j, 0.08702570+5.06977361e-02j, -0.02628990+4.49013808e-02j, -0.03673880+1.36360059e-02j, 0.00976608-1.86860241e-01j, 0.15386709+1.46930831e-01j, 0.11249562+2.57278918e-02j, 0.08496388-1.11776874e-01j, -0.07162906-1.41500632e-02j, 0.07664900-2.72671417e-01j, 0.12029408-2.43316647e-01j, 0.29672048-6.39702972e-02j, 0.19399620-1.55753156e-02j, + 0.08677801+1.96162231e-01j, 0.12372030-9.61956522e-02j, -0.16119964+3.89474786e-02j, 0.09207276-2.54823411e-01j, 0.03475803-5.50657361e-02j, -0.21263069-7.05923500e-02j, -0.06092331+4.49331302e-02j, -0.02461632+3.39504695e-02j, 0.03457710+2.39801010e-01j, 0.00891307+1.12739196e-01j, 0.13060822-1.11694609e-01j, 0.09803224+1.73134288e-01j, -0.07234639+1.28840723e-02j, 0.11471256+3.77081748e-02j, 0.26422031-1.58104940e-01j, 0.02654836-1.38859272e-01j, -0.04278432-1.46473478e-02j, 0.28242235-5.27977137e-02j, -0.13193171+1.21081065e-01j, 0.06133633-4.22267064e-02j, -0.08280452+2.04720842e-02j, 0.02083153+5.42313877e-02j, 0.12016721+1.60501416e-01j, -0.12225807-2.76668735e-01j, 0.02102305+9.09998231e-02j, 0.11747776+3.62319311e-01j, 0.09912628+1.50849159e-02j, -0.15640258+2.48010133e-02j, 0.05465140+2.59861755e-02j, -0.01002552+6.65787181e-02j, -0.02898995+9.89915581e-02j, -0.00717829-1.37245312e-01j, 0.00055712+1.86303843e-01j, 0.04400996+1.19535156e-01j, + 0.05636026-2.16779961e-01j, -0.05913502-2.77370485e-01j, 0.20737913+2.02848948e-01j, -0.07528717+7.93840780e-02j, 0.05451348+1.33425914e-01j, -0.12290648+7.58881312e-02j, 0.10321466+1.24983234e-01j, 0.13371569-1.00033395e-01j, -0.05791197+2.68575587e-02j, 0.04652659+4.60658211e-02j, 0.00131806+5.92140285e-02j, -0.13481008+2.31672893e-02j, -0.13689412+1.17954022e-01j, 0.04998811-2.02833835e-02j, -0.14165519+3.56756720e-01j, -0.07856852+6.35118506e-02j, 0.05564543-9.74922249e-02j, -0.21743105-5.41409515e-02j, -0.16217875+7.97524864e-02j, -0.19486651-9.99801439e-02j, 0.19124263-4.71432152e-02j, 0.01035372+4.63843919e-02j, -0.07218978+1.32977797e-01j, -0.21002818-1.31679835e-01j, 0.05305256-1.54340691e-02j, -0.19401635+6.69582303e-02j, 0.05139607+1.93092981e-01j, -0.09946416+4.37566125e-02j, 0.10192397-4.16617603e-02j, -0.12405403-9.78811063e-02j, 0.05812519-3.95372746e-05j, 0.00099002-1.14739425e-02j, 0.05247123-8.40118490e-02j, 0.04501583+1.44968196e-01j, + 0.03301905-4.80048648e-02j, 0.02823323-1.78191318e-02j, 0.08196271-6.89791351e-03j, 0.02038618+7.47434818e-02j, -0.03722850+4.85572384e-02j, 0.03293172+1.46606707e-02j, -0.18339563+6.37443359e-02j, -0.11214925-1.13505125e-01j, -0.06063048+1.45448526e-01j, 0.34233663-3.24467430e-01j, 0.07664073-1.44247607e-01j, -0.28993637+1.68069982e-01j, -0.18237161+2.05640159e-01j, 0.05552109+1.44200044e-01j, -0.08757971-2.66443942e-01j, 0.15589710+2.49096061e-02j, -0.16421838+3.76276364e-02j, 0.08841799+3.97688126e-02j, 0.06127403+8.79601343e-02j, -0.11912802+9.38176361e-02j, -0.01512363+1.98779455e-01j, -0.10425168-2.89846412e-02j, 0.16046822-1.77676457e-02j, 0.04871864-4.15742404e-02j, 0.19325653-1.69328440e-01j, -0.05961700+1.87459639e-02j, -0.23497369+7.78523444e-02j, 0.03611522+4.96031106e-02j, 0.02849174+1.81422119e-01j, -0.13379238-1.46097376e-01j, 0.13609017-3.86016200e-02j, -0.13135849-9.04921922e-02j, 0.13333140+1.02431026e-01j, 0.23331259-1.23168916e-02j, + 0.05106233+7.45228667e-02j, 0.12189655+6.42850380e-02j, 0.04943332+2.95462475e-02j, -0.00657986+8.06994964e-02j, 0.32676870+8.99736406e-02j, -0.14260504+1.75648292e-01j, 0.23063331+1.78219849e-01j, 0.10883261+1.28389828e-01j, -0.10597288-1.40386755e-01j, 0.01512138+5.26532655e-02j, -0.24270928-2.39424278e-01j, 0.08582485+1.81061208e-01j, 0.15870471+3.82006536e-03j, -0.14205944-7.88677962e-02j, 0.26780226+1.17371947e-01j, -0.05734894+1.19255894e-01j, -0.00708958-3.87661515e-02j, -0.01239640+1.17519163e-01j, -0.05307584+9.65095189e-02j, -0.04746522+6.19590573e-02j, -0.03677784-2.76400184e-02j, 0.14375332+9.66259420e-02j, -0.09175759-1.16174795e-01j, -0.03764456-1.92660525e-02j, -0.14188024+1.51742465e-01j, -0.00855281-6.80432250e-02j, -0.13963677+6.77341017e-02j, 0.27226725-5.95170973e-03j, 0.07653268+6.86308978e-02j, -0.18769106+2.15711501e-01j, 0.16136537-4.42590061e-02j, -0.26360596+1.04686372e-01j, -0.09155045-8.77382640e-02j, -0.09151231+4.28425508e-02j, + -0.06373803+3.71389234e-03j, 0.12982765+1.93272289e-01j, -0.00676779+9.13731987e-02j, -0.15669531-1.03446811e-01j, 0.13876435+1.73790050e-01j, 0.03724986-6.80542715e-02j, 0.13536485+2.06818477e-02j, 0.21346220+7.76124343e-02j, -0.21930729-1.35324670e-02j, -0.15870289-1.47418944e-01j, -0.10525782-3.21051509e-02j, 0.02651126-7.35636015e-02j, 0.21299852-4.88944015e-02j, 0.15200810+1.18419448e-01j, 0.02837817-1.66734491e-02j, -0.05583337+7.15315919e-02j, 0.00827433-9.71346050e-02j, -0.10828369+1.50029916e-01j, -0.05569338+1.56736408e-01j, -0.10498402-3.01603733e-02j, 0.01972677-3.28801228e-02j, -0.02545466-4.69757450e-02j, 0.23575113-6.13720081e-02j, -0.29064723+8.84431226e-02j, -0.07433566+3.29740230e-02j, 0.07812021-1.02151861e-01j, -0.04250740+1.72860999e-01j, 0.18038703-4.84824047e-02j, 0.06760615-1.08861841e-01j, 0.25746276+7.60469955e-02j, -0.01916844-4.17126464e-02j, 0.05801000+5.47708435e-02j, -0.01089018+7.64307991e-02j, -0.01047013+4.46021957e-01j, + 0.13353520-7.65699052e-02j, 0.04482942-4.66701163e-02j, 0.07857500-6.73430309e-02j, -0.16287533+3.68253915e-02j, -0.00326996+8.45469473e-03j, -0.30822025+1.56452958e-01j, 0.05607748+2.71034262e-02j, -0.15156807-3.99754306e-02j, -0.11732098-2.62196417e-01j, -0.12910811+1.37840055e-01j, -0.11324172+4.51349322e-02j, -0.07238787+1.95625832e-01j, 0.20782018-1.53159222e-01j, -0.00293010-2.05737302e-02j, -0.06307179-7.76953233e-02j, 0.09180174-3.94918551e-02j, 0.09905065+1.64050652e-01j, 0.02119278-1.28555941e-01j, -0.13011198+7.50039022e-02j, 0.00364899+1.56741679e-01j, 0.12967172-4.59481445e-02j, 0.04371742-9.22641848e-02j, 0.01217403+1.42468441e-01j, -0.03321802-6.06556050e-02j, -0.33791815+2.19614336e-02j, -0.02079545-1.62357371e-01j, -0.06115126-1.31463603e-01j, -0.04088450-1.17685338e-01j, -0.00096192-1.80065774e-04j, 0.11813011+6.17214729e-03j, 0.00417459-8.29797298e-02j, 0.08729658+2.67707592e-01j, -0.01118896-8.32911057e-02j, 0.03707148-5.83134279e-02j, + -0.12156735+2.64457587e-01j, -0.02989997-5.84706432e-02j, 0.03302162-6.01695667e-02j, 0.05437034-9.13677674e-02j, 0.10179674+1.40846743e-01j, -0.16635965+1.27949594e-01j, 0.14542720-1.12363084e-01j, -0.11077774-1.22746452e-01j, -0.00185723-4.56720198e-02j, 0.02600582-8.89150489e-02j, -0.22749400-6.67592408e-02j, 0.08533135-1.88751082e-01j, -0.22714608+1.14661652e-01j, -0.02690036-1.30865882e-01j, -0.10121037-6.45046877e-02j, 0.01443838-2.37190078e-02j, -0.02303954-1.61468225e-01j, 0.06055609-2.63250332e-01j, 0.13332186+2.20700929e-01j, -0.02063736+2.65142722e-01j, 0.08332522+5.90342871e-03j, 0.17210380-2.09054691e-01j, -0.15490146-9.27267743e-02j, 0.00453307-3.86153521e-02j, -0.02048122+3.02503499e-01j, 0.01458757-4.21067447e-02j, 0.32754022-3.88409256e-03j, 0.13811814-1.38612894e-01j, -0.12084009+3.73954159e-02j, 0.07102218-2.06344326e-02j, 0.11515796+1.13122542e-01j, -0.08863491-1.39456440e-01j, -0.17917237-4.99661020e-02j, 0.04442141+1.63664359e-01j, + 0.13732508-1.50992137e-01j, -0.05139775+8.97494329e-02j, 0.08732507+1.98929252e-01j, 0.05072904-2.99507910e-02j, 0.07108474+1.65205788e-02j, 0.01946830-8.78868281e-02j, 0.09380987-4.44516495e-02j, 0.17168417+3.91109903e-02j, -0.04639245+2.60582960e-01j, 0.05875205+2.56753485e-01j, -0.07728994-3.17930589e-02j, 0.04520490-1.76709840e-02j, 0.00134074-7.72090938e-02j, 0.20413611-1.94606554e-02j, -0.01910068+1.39711619e-01j, 0.03564990+1.37434345e-01j, 0.30794216-1.09704366e-01j, 0.05284195-5.64409889e-02j, -0.08984104+6.94748250e-02j, 0.02163001+1.03288462e-01j, 0.03915384-9.81971938e-02j, -0.06670679+5.81276525e-02j, -0.11508668+9.47872135e-02j, -0.03545030-3.13816097e-01j, -0.10991197+8.71705953e-02j, 0.06963248-5.65881100e-03j, 0.06577731-1.54696868e-01j, 0.15321403-6.74125684e-03j, 0.08071347+4.48458418e-01j, 0.03395331+1.27262600e-01j, 0.04183345+4.00904175e-03j, -0.01187089-2.21527903e-02j, -0.01851325-1.47271834e-02j, -0.23601169-8.54312072e-02j, + 0.11541862-1.04823473e-01j, -0.11268181-3.21825004e-02j, -0.09001661-1.37514659e-01j, -0.11748964-2.64871993e-02j, -0.05239410-4.95790343e-02j, 0.14652240-1.03971485e-01j, 0.18034942+7.79615744e-02j, 0.09369470-2.22585205e-01j, 0.16751339+8.86578713e-02j, 0.19444547+1.21567778e-02j, 0.04771682+2.78729300e-02j, 0.19635398+9.50820346e-02j, 0.05185621+1.76230346e-01j, 0.07939533-2.18013091e-02j, -0.03596743-9.94674395e-03j, -0.28690236+7.06630196e-02j, -0.01620677+1.20756724e-01j, -0.11835929+3.00001593e-02j, -0.09989775+8.70560634e-02j, 0.06278320-9.47387901e-02j, -0.09171898+2.82637561e-02j, 0.23849114+8.96858167e-02j, -0.24665889+2.03994686e-02j, 0.22245419-4.30604068e-04j, -0.08208490-2.36258787e-01j, -0.11703521-6.52100265e-02j, 0.05282283-4.48185202e-02j, 0.02544553-7.56696642e-02j, 0.03208350+2.09744844e-01j, 0.02707166+2.74207623e-01j, 0.14071592+1.51271647e-02j, 0.05998730-2.12130726e-02j, -0.13238650+1.32285712e-01j, -0.06341490-1.88468438e-01j, + -0.25236535-9.40009628e-02j, 0.05804886-1.24296266e-02j, 0.01463484-1.92411356e-01j, 0.02901968-1.95938408e-01j, 0.05900759-5.70542063e-02j, 0.00392890+1.79168231e-01j, 0.21463779+6.06068544e-02j, 0.02601461+3.44313390e-02j, -0.06804777-1.37777019e-01j, -0.04134655-7.71930937e-02j, 0.26993183+7.04042029e-03j, -0.22478871-1.11219112e-01j, 0.02216198+8.72296592e-03j, 0.00900783-1.81402113e-01j, -0.12568783+5.40727822e-02j, 0.20728804+1.49611785e-01j, -0.15403110-1.04748775e-01j, 0.11524429+1.78469618e-01j, -0.01784981-2.05987600e-01j, -0.04310959+6.72693611e-02j, 0.09204926+1.24870358e-01j, 0.23044143-1.67687891e-01j, -0.04829998+6.96651901e-03j, -0.09200799-1.69548082e-01j, -0.08599541-5.05360845e-02j, 0.05605567-1.23777989e-02j, 0.09183321+2.03716921e-01j, 0.06046671+1.88609777e-01j, -0.35443088-2.50139768e-01j, -0.10418443+1.53252364e-01j, 0.02878444+4.48922173e-02j, -0.07655359-8.92321321e-03j, 0.06322981-5.98952645e-03j, -0.05895737-7.06273994e-02j, + 0.04582500+3.45008534e-02j, -0.03569720+7.58719989e-03j, -0.18135564+2.31658738e-02j, -0.11367649-1.11799943e-01j, -0.02278714-7.26386363e-03j, 0.00527786+1.70825935e-01j, 0.08659992-2.45702546e-02j, -0.16132867-1.40266073e-01j, -0.16275372+1.57528240e-01j, 0.10098732-4.90008453e-02j, -0.14020292-1.26389028e-01j, -0.13387933-1.77044519e-01j, 0.15233209+1.56396670e-01j, -0.01186549+1.66770551e-01j, -0.05911019-9.37506242e-02j, -0.11032036+2.22422316e-01j, -0.32768772+1.23945218e-01j, 0.11693884+1.01153011e-01j, 0.06380873+2.73797332e-02j, -0.15242003-1.78297868e-01j, 0.08576241-9.81537390e-02j, -0.05483774+2.39049552e-02j, 0.08818984-4.80048981e-02j, 0.13795202+3.39576952e-02j, 0.15420435+1.04809134e-01j, -0.14757170-8.35910546e-02j, 0.25587669-9.78491595e-02j, 0.12582976+1.06377618e-01j, -0.04885733+5.85877129e-02j, 0.02768058-8.97097222e-02j, -0.09572117-3.14848747e-03j, -0.09107239-1.48042190e-01j, 0.02633147+1.28206292e-02j, -0.00231722+2.40935942e-01j, + 0.08505098+4.43364674e-02j, 0.04542370-1.20532432e-01j, -0.17493652+1.27595262e-01j, 0.01816818-1.93108598e-01j, -0.17931339+1.06943524e-01j, -0.10671963+1.39014451e-05j, 0.11498691+1.93066834e-02j, 0.23000235+1.04393237e-01j, -0.18572715-1.37399401e-01j, 0.13220069-3.09402657e-02j, 0.02990116+1.12157118e-02j, -0.02942283-1.36235506e-03j, -0.13275055-2.01044204e-02j, -0.05513657-1.15044942e-01j, -0.07453253+1.24162429e-01j, 0.19348874+1.65304419e-01j, -0.01684765-8.28080868e-02j, -0.06982499+2.38660768e-02j, -0.29603023-1.04892178e-01j, 0.31520605-5.80965984e-02j, -0.16452607-3.29924630e-02j, 0.13918688+1.34255787e-01j, 0.14618480-5.91517992e-02j, 0.05246915+2.47209477e-02j, 0.09600898+4.48951448e-02j, -0.03040775+2.25636252e-01j, -0.03104364-1.03378328e-02j, 0.12457642-1.13129265e-02j, 0.25722645-1.07390381e-01j, 0.12453095-1.46405362e-01j, -0.20675192+5.37923723e-02j, -0.08581718-3.76855478e-02j, 0.12881044-7.30139037e-02j, 0.03309130-1.45171188e-02j, + 0.04964024-2.63320298e-01j, -0.06851158+3.25029578e-01j, -0.06736655+3.31741867e-02j, 0.10672767-1.33657818e-02j, -0.03911025+2.71696686e-03j, 0.18376597-2.21089267e-01j, -0.02949093-2.24178456e-02j, -0.07672718+8.63619859e-02j, 0.09011718+1.34863000e-01j, -0.03532004+2.01221708e-02j, -0.01750050+6.62198244e-02j, 0.17146927+8.06205588e-02j, -0.09194709+3.45310559e-02j, 0.05919149+8.90830332e-03j, -0.03890834+6.41903709e-02j, -0.13501504-3.99845589e-02j, -0.10279042+1.03768681e-01j, -0.05259741-5.87714457e-02j, -0.11719418-2.08936502e-02j, 0.09836174-5.44608131e-02j, -0.22877539+2.08355637e-01j, 0.04941838-9.51260734e-02j, -0.06203396+2.28604981e-02j, 0.12098849-1.44576480e-02j, -0.08451115-1.43356466e-01j, 0.15635672-1.46530151e-02j, -0.20437704-3.79884112e-02j, -0.19636121-1.71501698e-02j, 0.07255917-2.20625252e-01j, -0.28061719+7.71279703e-02j, -0.02084913-1.12045005e-01j, 0.04322484+8.40757110e-03j, 0.06080093-9.41283647e-03j, -0.08052508-4.49212849e-03j, + 0.35296504-9.29569583e-02j, 0.30139399+2.02446885e-01j, -0.10435560-1.29299775e-01j, 0.19156652+1.16499747e-02j, 0.20865974-1.46798336e-01j, -0.13729311-1.50569340e-02j, 0.02152623+1.61941611e-01j, 0.05963193-1.30770158e-01j, 0.06462617-1.66387108e-01j, -0.11403091-8.19783097e-02j, -0.17890047-3.87091987e-02j, 0.05041442+2.34797464e-02j, 0.33716094-2.18366246e-01j, 0.04749898+7.95121529e-02j, -0.14276611+5.91160893e-03j, 0.07271710-6.38166930e-02j, -0.03268621+7.25536789e-02j, -0.00994355-5.45862875e-02j, -0.10977213+1.11554079e-01j, 0.01783962-2.78702484e-01j, -0.00306595+2.65697928e-02j, 0.13926720-1.06298955e-01j, -0.10153158-8.24641251e-02j, -0.26939850+6.47512729e-02j, 0.03236581+4.07523974e-02j, -0.14424473+2.51731413e-01j, -0.01873542-2.47536237e-02j, -0.01356796-8.16033886e-02j, -0.07272296-1.47884513e-01j, 0.01967111-1.46373935e-01j, 0.23073323-8.09684340e-02j, 0.14428689+1.18128043e-01j, -0.06420706+1.47110727e-01j, -0.01428800-1.01535529e-01j, + 0.05505723+1.85830802e-02j, 0.00835002+2.95374366e-02j, 0.00710951+4.40654128e-02j, 0.17926977-3.38549657e-01j + ] + + u1 = ql.Unitary("using_qx_fully_entangled_5_qubit", matrix) + u1.decompose() + k.gate(u1, [0, 1, 2, 3, 4]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[32]), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[64]), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[96]), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[128]), helper_prob(state.get(to_bit_string(4, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[160]), helper_prob(state.get(to_bit_string(5, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[192]), helper_prob(state.get(to_bit_string(6, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[224]), helper_prob(state.get(to_bit_string(7, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[256]), helper_prob(state.get(to_bit_string(8, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[288]), helper_prob(state.get(to_bit_string(9, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[320]), helper_prob(state.get(to_bit_string(10, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[352]), helper_prob(state.get(to_bit_string(11, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[384]), helper_prob(state.get(to_bit_string(12, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[416]), helper_prob(state.get(to_bit_string(13, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[448]), helper_prob(state.get(to_bit_string(14, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[480]), helper_prob(state.get(to_bit_string(15, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[512]), helper_prob(state.get(to_bit_string(16, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[544]), helper_prob(state.get(to_bit_string(17, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[576]), helper_prob(state.get(to_bit_string(18, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[608]), helper_prob(state.get(to_bit_string(19, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[640]), helper_prob(state.get(to_bit_string(20, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[672]), helper_prob(state.get(to_bit_string(21, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[704]), helper_prob(state.get(to_bit_string(22, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[736]), helper_prob(state.get(to_bit_string(23, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[768]), helper_prob(state.get(to_bit_string(24, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[800]), helper_prob(state.get(to_bit_string(25, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[832]), helper_prob(state.get(to_bit_string(26, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[864]), helper_prob(state.get(to_bit_string(27, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[896]), helper_prob(state.get(to_bit_string(28, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[928]), helper_prob(state.get(to_bit_string(29, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[960]), helper_prob(state.get(to_bit_string(30, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[992]), helper_prob(state.get(to_bit_string(31, size=platform_qubits), 0.)), 5) + + def test_using_qx_fully_entangled_5_qubit_10011(self): + num_qubits = 5 + p = ql.Program('test_using_qx_fully_entangled_5_qubit_10011', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + 0.31869031-9.28734622e-02j, 0.38980148+2.14592427e-01j, 0.20279154-1.56580826e-01j, 0.00210273-2.83970875e-01j, -0.04010672-9.26812940e-02j, 0.15747049+6.08283291e-02j, -0.05274772-6.45225841e-02j, 0.05909439-3.23496026e-02j, 0.07868009+6.77298732e-02j, 0.11290142+2.48468763e-02j, 0.10092033-7.03646679e-02j, -0.03557972-3.39117261e-02j, 0.02241562+1.02714684e-02j, -0.04088796-1.12143173e-01j, -0.00144015+1.83925572e-02j, -0.12579480-1.15394681e-01j, 0.13531631-1.84271421e-01j, 0.11293592-1.44170392e-01j, -0.06985893-1.36606289e-01j, -0.08924113-6.35923942e-02j, 0.19393965-6.35656579e-02j, -0.02153233-2.76955143e-01j, -0.12094999+1.05716669e-01j, -0.00624879+1.27471575e-01j, -0.13608981-1.22140261e-01j, -0.08243959-1.72734247e-02j, 0.06562052+1.12197102e-01j, -0.01102025-1.53811069e-01j, 0.13576338-8.95540026e-02j, 0.05730484-5.62973657e-02j, -0.08835493-4.13159024e-02j, -0.04533295+3.70144188e-02j, 0.04116657+1.58298973e-01j, 0.22270976-1.18654603e-01j, + 0.09219815+8.41433858e-02j, -0.02274990+2.33343627e-01j, -0.13334752-6.98059663e-02j, -0.07967301-6.54413909e-02j, -0.09158972-7.03627564e-02j, -0.02332636-1.58060290e-02j, 0.23523954-3.48258461e-02j, 0.21329683+6.37364245e-02j, 0.25821394+1.30648709e-03j, -0.11188090-1.95903237e-01j, -0.07887212-8.81857936e-02j, 0.04763200+9.40535593e-02j, -0.11726632+5.65815234e-02j, 0.08229469-4.38047420e-02j, 0.03117762+1.08469602e-01j, 0.16064616-1.30734886e-01j, 0.22181279-3.31211823e-02j, 0.07309884-2.01468425e-01j, -0.28437382+6.38292807e-02j, -0.23661479+1.17105208e-01j, -0.10436123-5.56443645e-02j, 0.20587544+1.99848797e-02j, 0.20705551+1.75496198e-02j, 0.01791984-8.31956939e-02j, 0.09737992+6.64713628e-03j, 0.06175660-7.11998970e-02j, 0.03073603-7.25651496e-02j, -0.12056479-1.55358931e-01j, -0.09661589+4.90232280e-03j, 0.03110935-1.72748422e-01j, 0.01473304+3.62629583e-01j, 0.11031868-3.67435519e-03j, 0.04301239-1.64601498e-01j, -0.16432353+7.52258615e-02j, + -0.00648176+6.66215752e-02j, 0.12574270-3.71759618e-02j, -0.07793634-7.01586304e-02j, 0.05711560+2.67410653e-01j, -0.00880782+2.09982981e-01j, -0.04961517-6.86953748e-02j, -0.15766986-1.12761472e-01j, -0.07076146-3.12372790e-02j, -0.08715236+9.29279186e-02j, 0.03843817+1.13545744e-01j, -0.10838483-1.19949631e-02j, -0.06342622+1.73231077e-01j, 0.23221532-4.28875040e-02j, 0.16514567-4.90633428e-02j, -0.01096540+6.37891447e-02j, 0.02171279+5.89435085e-02j, 0.01999250-2.96609865e-01j, 0.16702912+8.82996853e-02j, 0.19820571+5.01863737e-02j, -0.01237253-1.21196566e-01j, 0.11042294-2.16811518e-01j, -0.01004066-2.36556101e-01j, -0.12867290-4.01294536e-03j, -0.11254789+5.56025311e-02j, -0.18328088-1.46524167e-02j, -0.13640243-3.71920766e-02j, -0.03793125+9.57786229e-02j, 0.07600542+1.53449546e-01j, -0.12371969+2.19599454e-01j, 0.18106889-3.10905810e-02j, -0.12698597+7.45431556e-02j, 0.02402161-1.66514384e-02j, -0.14313130+4.63501164e-02j, 0.13656065-8.55748891e-02j, + -0.20854810-3.99831111e-02j, -0.05354994+8.14822771e-02j, 0.22188566+8.04753102e-02j, -0.09702996-1.54653045e-01j, -0.10185620-1.01790676e-01j, -0.00335582+2.52475965e-01j, -0.04858119-1.52409323e-01j, 0.09335149-3.90325714e-02j, 0.08277598-4.08970043e-02j, 0.08119049+5.11051755e-02j, -0.01223217+6.17029648e-04j, -0.15137858-9.30742653e-03j, 0.10647060+3.35870801e-02j, -0.04014048+1.33388615e-01j, -0.04315986+1.74367473e-01j, -0.04774817-9.82134162e-02j, -0.08203436+7.74038565e-02j, -0.23391370+1.62306949e-01j, 0.11791971+2.08966161e-01j, -0.07867189-4.18549851e-02j, -0.17291904+9.47505092e-02j, 0.23630015-3.07786925e-01j, -0.09104365-1.33230919e-01j, 0.07679465+1.45726380e-01j, 0.09397243-9.26081447e-02j, -0.16092509+7.38633830e-02j, -0.02289017+1.59777790e-01j, 0.12053722+6.55620680e-02j, 0.12646833+1.04585433e-01j, 0.02644610+1.92009889e-01j, 0.28749442+1.11327480e-01j, 0.15837267+6.12698488e-02j, 0.18181681-5.61278874e-02j, 0.07897084-1.17114924e-01j, + 0.19787494-1.67863968e-01j, 0.03852499-4.21534504e-02j, -0.14091989-1.27321872e-01j, -0.01747868-2.27419946e-01j, -0.02073576-6.24641146e-02j, -0.14241142+2.28697604e-02j, 0.15468346+2.08734157e-02j, 0.04505001-9.46333157e-02j, -0.09148317-2.26152985e-01j, 0.08577989+2.30863031e-01j, -0.08152502-8.74340592e-02j, -0.06465018-7.35108360e-02j, -0.21595512-8.66695180e-03j, 0.03304541-1.91886499e-01j, 0.04448112+3.67289455e-02j, 0.01969849-5.34777195e-02j, -0.03209367+3.02797601e-02j, 0.17389718+1.19098672e-01j, -0.10192559-3.02362398e-01j, -0.10224653-8.09241417e-02j, -0.12601597-6.86631211e-02j, 0.11275009+1.40915100e-01j, 0.03214418+1.48701215e-01j, -0.11571373+3.57083353e-02j, 0.03222285-5.19221441e-02j, -0.00250593+7.32186819e-02j, -0.15549573+1.77404851e-01j, 0.08568275+1.02973155e-01j, 0.11314133-2.13171498e-01j, 0.22748546-5.69951563e-02j, 0.14929197+1.31715414e-01j, -0.16301646+3.65045553e-03j, 0.13494125+2.31602145e-01j, 0.24267648-1.77780817e-01j, + -0.00736974+7.72680290e-02j, -0.04867011+1.22605525e-01j, 0.05051748+8.06196677e-02j, -0.01749415+6.33486594e-02j, 0.06408343-4.51492484e-02j, -0.02543799-1.33253676e-01j, -0.05785745-4.71803669e-02j, -0.24358675-1.18083337e-02j, 0.00061111-5.96573111e-03j, 0.17487681-8.55625475e-02j, 0.13181372-5.47918839e-02j, -0.14072394+1.08475923e-01j, 0.05919593+1.78284217e-01j, -0.00292253-2.17168452e-02j, 0.19948189-1.95177980e-01j, -0.11146926-1.55684600e-01j, 0.02692391-9.18282632e-02j, -0.03804582-7.62499524e-02j, 0.18562866+1.41900953e-01j, 0.15468899+7.03401694e-03j, 0.10617502+2.96183301e-01j, 0.12124371+1.42279327e-02j, -0.12974516+1.87600027e-01j, -0.23270386+1.59618723e-01j, -0.14928652-8.27397154e-02j, 0.06670844+6.35681954e-02j, 0.03466266+1.89244901e-01j, -0.00961646-1.02903972e-01j, 0.19899344-2.38199195e-01j, -0.16594523-4.43067845e-02j, 0.27258801-7.49570862e-02j, 0.08182091+2.03334342e-02j, -0.02454051-4.82668158e-02j, -0.08557127+3.04552132e-02j, + 0.01303575+8.88057122e-02j, 0.13253621+5.05712004e-02j, 0.07763894+1.13841327e-01j, -0.28730914-4.49839630e-02j, 0.07031891-3.38973984e-03j, -0.04794523-1.67972335e-01j, -0.18102171+2.08760542e-01j, -0.08845631-9.70771934e-02j, 0.03546718+4.80846877e-02j, -0.08866794-5.19207245e-02j, -0.15099182-9.77070105e-02j, -0.05473901+2.33013978e-01j, -0.04645356-8.89489153e-02j, 0.07548625+1.80517821e-01j, 0.16840691+2.15268260e-01j, -0.09962074-7.35772706e-03j, -0.10104245+1.74017433e-02j, -0.09302095-1.10945928e-01j, -0.03515700+2.50873519e-02j, 0.10622507+1.29398421e-01j, -0.20965829-4.55862887e-02j, 0.05220909+6.66834897e-02j, -0.09672108+1.09403436e-01j, 0.12697788-6.19212188e-02j, 0.05729917+1.44378294e-01j, -0.15808366-3.82581632e-02j, 0.10716098-4.62942406e-02j, 0.24961573+1.32840816e-01j, 0.06278080+2.39056706e-02j, 0.18311487+7.98582936e-03j, 0.02661541+7.40701198e-02j, 0.04699528+1.88767961e-01j, 0.04750332-2.25995642e-02j, 0.07193907+5.68042859e-02j, + -0.02763382-3.43370436e-02j, 0.11205088-1.98370084e-02j, -0.11424545+1.14269285e-03j, 0.06885854-2.09915302e-01j, -0.05625496-2.88701666e-01j, -0.08183393+2.31774294e-01j, -0.09301037-4.03842722e-02j, -0.06069309+2.57502142e-02j, -0.18634877+9.85377377e-02j, 0.01474395+9.22414287e-02j, 0.04147054-1.74520016e-01j, 0.06794102-1.59508183e-01j, -0.13292245-5.38490513e-02j, -0.18753702+2.82751900e-01j, 0.00899866-2.80951474e-01j, 0.20377748+8.19207845e-02j, -0.14028603-1.39624056e-01j, 0.10741114+2.60308736e-02j, -0.22833573+6.02730469e-02j, 0.16071761-1.25615817e-01j, 0.08060865-5.81044643e-03j, 0.16141495-4.86994019e-02j, 0.11263654-1.87107794e-02j, 0.06859488-1.90280093e-01j, 0.10733862+4.45380867e-02j, -0.11489398-2.10578670e-01j, -0.08648330-1.73958604e-01j, 0.12293904-1.50703768e-01j, -0.00629652+2.98133822e-02j, 0.16452648+7.76415767e-02j, 0.16219009+2.46017766e-01j, -0.04582374-1.16806045e-01j, 0.15109013+9.45671154e-03j, 0.04773975-1.54745106e-01j, + 0.21822796-1.87975523e-03j, 0.16596711-1.31539539e-01j, 0.25621724-4.31460990e-02j, 0.23071937+1.38086347e-01j, 0.10615413-1.24941186e-01j, 0.00343902+5.79927212e-02j, 0.10569282-2.64952183e-01j, -0.13601637+5.39259774e-02j, -0.13182901+9.15307749e-02j, 0.03524551-1.35956850e-01j, 0.09576220-1.71837228e-02j, -0.03707841-5.40514827e-02j, -0.05729147-7.33164458e-02j, -0.18631267+1.00759871e-01j, -0.02434746-2.22824245e-02j, -0.02570765-3.90074186e-02j, 0.17946901+1.86288095e-02j, 0.07742897+3.19064602e-02j, -0.17538437+2.18666227e-01j, 0.10029635-8.92554711e-03j, -0.13379504-1.03683797e-02j, -0.11115363-4.48983441e-02j, 0.00163172-2.05325390e-02j, 0.02753729-1.28591197e-01j, 0.01933548+2.37393316e-01j, 0.07102201-1.19729329e-01j, -0.07517562+7.47947883e-02j, -0.03383077-1.23796732e-01j, -0.05575669-2.97673975e-02j, -0.04860924+1.02986531e-01j, 0.11384071+2.36429953e-01j, -0.26355793+1.30580300e-02j, -0.26655410+6.72995742e-02j, -0.04663019-5.64857364e-03j, + 0.15703188+2.25734925e-02j, -0.02611337-4.94904084e-03j, 0.31897764+7.13870567e-02j, 0.15501272-1.48107261e-01j, 0.18034006-2.37497106e-01j, 0.21350438-8.08313917e-02j, 0.06206880+5.98457145e-02j, -0.04996277+1.09069384e-02j, -0.09282843-5.59942293e-02j, -0.05363359+4.83839918e-02j, -0.20946404-1.85419524e-01j, -0.05481421+8.78420662e-02j, -0.19261214-1.04875021e-01j, -0.00083685-2.70091261e-02j, -0.17618069+8.47803615e-02j, 0.16055652+5.98821538e-03j, -0.06356210+8.16228775e-02j, -0.22507829-4.14268948e-02j, -0.00791737+7.40481825e-02j, 0.19970347-1.15972939e-01j, -0.08619572+1.19678540e-01j, -0.18493100-1.13524848e-01j, 0.04824348-5.85668978e-02j, -0.22446284+1.11472258e-02j, 0.09629746-1.88788542e-01j, -0.18228537-3.89615785e-04j, 0.09084756+4.78058679e-02j, -0.00889583-1.74554680e-01j, -0.07447697-4.48823321e-02j, -0.05076077-6.24206002e-02j, -0.14050658+8.38982646e-02j, 0.07428934-6.30440232e-02j, 0.05701074-1.00819168e-01j, 0.07009481+8.11789378e-02j, + -0.01155395+2.46650660e-01j, 0.25264038-1.98419236e-01j, -0.09155521-2.79616998e-02j, 0.06750545-1.52831769e-01j, 0.10685040-1.78545409e-01j, -0.06203486+2.86380485e-02j, 0.23067545-1.23638547e-01j, -0.02397582+2.15643846e-01j, 0.01810979+1.08067552e-01j, 0.09130261-4.68850866e-02j, 0.13093158-1.51875212e-01j, 0.25207024+5.80216347e-02j, 0.02600999-1.27799785e-01j, 0.03509714-5.46256940e-02j, 0.04362407-3.07563727e-02j, 0.12488249+6.70881126e-02j, 0.05539679+1.15790184e-01j, 0.23107124-9.66168589e-02j, -0.09977799-9.88045601e-02j, -0.05633534+2.79762650e-01j, -0.02304281-2.42282613e-02j, 0.12765180-2.32550502e-02j, 0.25634814-3.02429796e-02j, 0.30827737-2.19288542e-01j, -0.02512791+2.13783374e-01j, 0.15453741-7.04163688e-02j, -0.21441715+2.05959415e-01j, -0.02827968+4.71161636e-02j, -0.03837343+6.70595235e-02j, -0.07854483-3.12796395e-02j, -0.03615927+1.10733671e-01j, 0.21779074-1.39489256e-01j, 0.06619192+5.38352432e-02j, -0.06802160-1.05456770e-01j, + -0.10316128+1.32947183e-01j, -0.06345699-1.85555087e-01j, -0.00893067+1.52852423e-01j, 0.03135864+1.10423220e-01j, -0.18235100+2.77954961e-02j, -0.09252137+1.09061091e-01j, -0.07976950+1.15176285e-02j, 0.05051009+2.57152535e-01j, 0.09344185-1.12906975e-01j, 0.04587659+8.90786692e-02j, -0.02471718+4.53344925e-02j, -0.08880236+3.62673481e-02j, -0.05981018+9.78912466e-02j, -0.00118743-5.07702805e-02j, -0.08119522+5.16043940e-02j, 0.11854883+9.79110177e-02j, 0.28543526-8.57540624e-02j, 0.28069514+2.00242562e-01j, -0.01036913-1.12897546e-01j, -0.08470073+1.91009156e-02j, 0.01428585+7.92620224e-02j, -0.15567322-4.85322282e-02j, 0.14203257-2.97248067e-01j, 0.15075682-1.33294241e-01j, 0.08107944-6.10561974e-02j, 0.07558358-3.29486035e-02j, -0.04042877-2.49142675e-02j, 0.05557881-1.93956804e-01j, -0.00589446+9.44678255e-02j, 0.16536760-4.08479951e-02j, 0.14382039+1.57269491e-02j, -0.22311804-8.79699173e-02j, 0.09825566+1.52084444e-02j, 0.00938452-3.15649024e-01j, + -0.03982978+1.22637508e-01j, -0.15670677-1.93426126e-01j, 0.22741559-4.39643322e-02j, -0.13362661-9.94353174e-02j, -0.09445278+4.93195562e-02j, -0.04684833-8.59308253e-02j, 0.08890091-1.16876390e-01j, -0.18726614+7.50813913e-02j, -0.01806267-2.00321404e-02j, 0.09338316-1.69711164e-01j, -0.03114173+1.43744729e-01j, -0.01515641+7.72217128e-02j, 0.21301431+5.92330407e-02j, 0.12250555+1.16784140e-01j, 0.04925890+1.82225369e-01j, 0.09296806+1.58772507e-02j, -0.06700279+7.86869873e-02j, -0.02389099-5.36170682e-02j, 0.00545649-1.25491880e-03j, 0.09228983+2.64561438e-01j, -0.08125859-3.27415023e-02j, -0.03769576-2.64763488e-01j, 0.09145940+1.90133579e-01j, -0.27352411+6.32203214e-02j, -0.00087467-8.61094525e-02j, 0.13735927+8.73538830e-03j, -0.08484748+1.68213884e-01j, -0.07040327-1.76254392e-01j, -0.08363638-8.30902369e-02j, 0.14643814+6.63711322e-02j, -0.31659998-1.04317904e-01j, 0.07830602+2.93183609e-02j, 0.11041879+1.50347028e-01j, -0.00433818-1.72946523e-01j, + -0.15422074+9.38342826e-02j, -0.14194574+3.64105744e-02j, 0.06297505+7.88548664e-02j, 0.01106598-2.65402837e-01j, 0.07164956-8.12953528e-02j, -0.12514039-1.84403896e-01j, -0.17295559+3.58171829e-02j, -0.03655755-7.10559195e-02j, -0.03821694-1.10973040e-01j, 0.18546141+1.10662839e-01j, -0.10195195+1.32367694e-01j, -0.05016084+2.78628720e-02j, -0.19079393+1.40041256e-02j, 0.07878861-3.38112621e-02j, 0.13730204+1.52897765e-01j, 0.11815899+3.49910958e-02j, -0.02648579-1.03280312e-01j, 0.11970226-2.50844123e-01j, 0.10406627-9.12689026e-02j, 0.07247411-2.51491332e-01j, 0.06550999-2.94078974e-01j, -0.12079469-5.00355065e-02j, 0.06000345-1.02467349e-01j, 0.08823557+3.66136284e-02j, 0.02291526+3.63437115e-02j, -0.07124433+2.31676270e-01j, 0.17493588+5.98421039e-02j, -0.17824122-1.97944096e-02j, -0.00491994-9.10500757e-02j, 0.19633245+6.47815099e-02j, -0.03770238-7.48581318e-02j, -0.18402244+9.04322714e-02j, -0.28428450-1.40285725e-01j, 0.00138785+1.08042021e-01j, + 0.16088797+2.75183648e-01j, -0.08656340-7.36993417e-02j, 0.05178655+5.29576072e-02j, -0.05123872-1.29090313e-02j, -0.03079395-1.69557846e-01j, 0.23219467-7.71729365e-03j, -0.01135984-6.49120093e-02j, 0.08717993-9.71885487e-02j, -0.02043387+1.16518568e-01j, -0.08256357+1.23302259e-02j, 0.13742387-2.00583302e-01j, 0.11087765+2.22213806e-02j, 0.10703254+3.53681589e-02j, -0.04998617+7.13667998e-02j, -0.24635130-2.30198030e-01j, 0.09831487+1.92709068e-01j, 0.10999549+1.28740664e-01j, -0.04056669+9.08016920e-02j, -0.03342728-9.92407179e-02j, 0.09352449-4.93911914e-02j, -0.11841153-8.25481366e-02j, -0.02632050+1.91245810e-01j, -0.15521225-6.80613837e-02j, 0.18223827-2.68908129e-01j, 0.04119450+1.12072453e-01j, -0.02954085+6.34315408e-02j, -0.01019486-1.24389083e-01j, 0.19174201-7.05812742e-02j, 0.19351232+1.42610666e-02j, 0.12937332-1.45006522e-01j, 0.01111355+1.11974478e-01j, 0.25163849+7.58955475e-02j, 0.06967535+1.51710939e-01j, -0.26064587+5.85797495e-02j, + -0.05364486-8.37537594e-02j, 0.02473011+1.57624180e-01j, 0.07885240+4.24067733e-02j, -0.05353458-3.59527188e-02j, 0.24630053-3.09146961e-01j, 0.12673895+2.54501080e-02j, 0.13328446+1.27420821e-01j, -0.03311185+8.64376474e-02j, -0.10126181-3.33404906e-02j, 0.05819512-2.42452607e-01j, 0.12966928+1.92345459e-01j, -0.10237172+7.87217786e-02j, -0.12008000+8.02686485e-02j, 0.11309599+3.47582961e-02j, 0.16921731-6.49645604e-02j, 0.10847358+1.32814258e-01j, 0.09620142+8.29342007e-02j, -0.03836254+1.18815716e-01j, 0.10334279-1.21404737e-02j, -0.19366239-5.73423731e-02j, 0.11445103-7.69154143e-02j, 0.10345336+3.42165082e-02j, 0.08702570+5.06977361e-02j, -0.02628990+4.49013808e-02j, -0.03673880+1.36360059e-02j, 0.00976608-1.86860241e-01j, 0.15386709+1.46930831e-01j, 0.11249562+2.57278918e-02j, 0.08496388-1.11776874e-01j, -0.07162906-1.41500632e-02j, 0.07664900-2.72671417e-01j, 0.12029408-2.43316647e-01j, 0.29672048-6.39702972e-02j, 0.19399620-1.55753156e-02j, + 0.08677801+1.96162231e-01j, 0.12372030-9.61956522e-02j, -0.16119964+3.89474786e-02j, 0.09207276-2.54823411e-01j, 0.03475803-5.50657361e-02j, -0.21263069-7.05923500e-02j, -0.06092331+4.49331302e-02j, -0.02461632+3.39504695e-02j, 0.03457710+2.39801010e-01j, 0.00891307+1.12739196e-01j, 0.13060822-1.11694609e-01j, 0.09803224+1.73134288e-01j, -0.07234639+1.28840723e-02j, 0.11471256+3.77081748e-02j, 0.26422031-1.58104940e-01j, 0.02654836-1.38859272e-01j, -0.04278432-1.46473478e-02j, 0.28242235-5.27977137e-02j, -0.13193171+1.21081065e-01j, 0.06133633-4.22267064e-02j, -0.08280452+2.04720842e-02j, 0.02083153+5.42313877e-02j, 0.12016721+1.60501416e-01j, -0.12225807-2.76668735e-01j, 0.02102305+9.09998231e-02j, 0.11747776+3.62319311e-01j, 0.09912628+1.50849159e-02j, -0.15640258+2.48010133e-02j, 0.05465140+2.59861755e-02j, -0.01002552+6.65787181e-02j, -0.02898995+9.89915581e-02j, -0.00717829-1.37245312e-01j, 0.00055712+1.86303843e-01j, 0.04400996+1.19535156e-01j, + 0.05636026-2.16779961e-01j, -0.05913502-2.77370485e-01j, 0.20737913+2.02848948e-01j, -0.07528717+7.93840780e-02j, 0.05451348+1.33425914e-01j, -0.12290648+7.58881312e-02j, 0.10321466+1.24983234e-01j, 0.13371569-1.00033395e-01j, -0.05791197+2.68575587e-02j, 0.04652659+4.60658211e-02j, 0.00131806+5.92140285e-02j, -0.13481008+2.31672893e-02j, -0.13689412+1.17954022e-01j, 0.04998811-2.02833835e-02j, -0.14165519+3.56756720e-01j, -0.07856852+6.35118506e-02j, 0.05564543-9.74922249e-02j, -0.21743105-5.41409515e-02j, -0.16217875+7.97524864e-02j, -0.19486651-9.99801439e-02j, 0.19124263-4.71432152e-02j, 0.01035372+4.63843919e-02j, -0.07218978+1.32977797e-01j, -0.21002818-1.31679835e-01j, 0.05305256-1.54340691e-02j, -0.19401635+6.69582303e-02j, 0.05139607+1.93092981e-01j, -0.09946416+4.37566125e-02j, 0.10192397-4.16617603e-02j, -0.12405403-9.78811063e-02j, 0.05812519-3.95372746e-05j, 0.00099002-1.14739425e-02j, 0.05247123-8.40118490e-02j, 0.04501583+1.44968196e-01j, + 0.03301905-4.80048648e-02j, 0.02823323-1.78191318e-02j, 0.08196271-6.89791351e-03j, 0.02038618+7.47434818e-02j, -0.03722850+4.85572384e-02j, 0.03293172+1.46606707e-02j, -0.18339563+6.37443359e-02j, -0.11214925-1.13505125e-01j, -0.06063048+1.45448526e-01j, 0.34233663-3.24467430e-01j, 0.07664073-1.44247607e-01j, -0.28993637+1.68069982e-01j, -0.18237161+2.05640159e-01j, 0.05552109+1.44200044e-01j, -0.08757971-2.66443942e-01j, 0.15589710+2.49096061e-02j, -0.16421838+3.76276364e-02j, 0.08841799+3.97688126e-02j, 0.06127403+8.79601343e-02j, -0.11912802+9.38176361e-02j, -0.01512363+1.98779455e-01j, -0.10425168-2.89846412e-02j, 0.16046822-1.77676457e-02j, 0.04871864-4.15742404e-02j, 0.19325653-1.69328440e-01j, -0.05961700+1.87459639e-02j, -0.23497369+7.78523444e-02j, 0.03611522+4.96031106e-02j, 0.02849174+1.81422119e-01j, -0.13379238-1.46097376e-01j, 0.13609017-3.86016200e-02j, -0.13135849-9.04921922e-02j, 0.13333140+1.02431026e-01j, 0.23331259-1.23168916e-02j, + 0.05106233+7.45228667e-02j, 0.12189655+6.42850380e-02j, 0.04943332+2.95462475e-02j, -0.00657986+8.06994964e-02j, 0.32676870+8.99736406e-02j, -0.14260504+1.75648292e-01j, 0.23063331+1.78219849e-01j, 0.10883261+1.28389828e-01j, -0.10597288-1.40386755e-01j, 0.01512138+5.26532655e-02j, -0.24270928-2.39424278e-01j, 0.08582485+1.81061208e-01j, 0.15870471+3.82006536e-03j, -0.14205944-7.88677962e-02j, 0.26780226+1.17371947e-01j, -0.05734894+1.19255894e-01j, -0.00708958-3.87661515e-02j, -0.01239640+1.17519163e-01j, -0.05307584+9.65095189e-02j, -0.04746522+6.19590573e-02j, -0.03677784-2.76400184e-02j, 0.14375332+9.66259420e-02j, -0.09175759-1.16174795e-01j, -0.03764456-1.92660525e-02j, -0.14188024+1.51742465e-01j, -0.00855281-6.80432250e-02j, -0.13963677+6.77341017e-02j, 0.27226725-5.95170973e-03j, 0.07653268+6.86308978e-02j, -0.18769106+2.15711501e-01j, 0.16136537-4.42590061e-02j, -0.26360596+1.04686372e-01j, -0.09155045-8.77382640e-02j, -0.09151231+4.28425508e-02j, + -0.06373803+3.71389234e-03j, 0.12982765+1.93272289e-01j, -0.00676779+9.13731987e-02j, -0.15669531-1.03446811e-01j, 0.13876435+1.73790050e-01j, 0.03724986-6.80542715e-02j, 0.13536485+2.06818477e-02j, 0.21346220+7.76124343e-02j, -0.21930729-1.35324670e-02j, -0.15870289-1.47418944e-01j, -0.10525782-3.21051509e-02j, 0.02651126-7.35636015e-02j, 0.21299852-4.88944015e-02j, 0.15200810+1.18419448e-01j, 0.02837817-1.66734491e-02j, -0.05583337+7.15315919e-02j, 0.00827433-9.71346050e-02j, -0.10828369+1.50029916e-01j, -0.05569338+1.56736408e-01j, -0.10498402-3.01603733e-02j, 0.01972677-3.28801228e-02j, -0.02545466-4.69757450e-02j, 0.23575113-6.13720081e-02j, -0.29064723+8.84431226e-02j, -0.07433566+3.29740230e-02j, 0.07812021-1.02151861e-01j, -0.04250740+1.72860999e-01j, 0.18038703-4.84824047e-02j, 0.06760615-1.08861841e-01j, 0.25746276+7.60469955e-02j, -0.01916844-4.17126464e-02j, 0.05801000+5.47708435e-02j, -0.01089018+7.64307991e-02j, -0.01047013+4.46021957e-01j, + 0.13353520-7.65699052e-02j, 0.04482942-4.66701163e-02j, 0.07857500-6.73430309e-02j, -0.16287533+3.68253915e-02j, -0.00326996+8.45469473e-03j, -0.30822025+1.56452958e-01j, 0.05607748+2.71034262e-02j, -0.15156807-3.99754306e-02j, -0.11732098-2.62196417e-01j, -0.12910811+1.37840055e-01j, -0.11324172+4.51349322e-02j, -0.07238787+1.95625832e-01j, 0.20782018-1.53159222e-01j, -0.00293010-2.05737302e-02j, -0.06307179-7.76953233e-02j, 0.09180174-3.94918551e-02j, 0.09905065+1.64050652e-01j, 0.02119278-1.28555941e-01j, -0.13011198+7.50039022e-02j, 0.00364899+1.56741679e-01j, 0.12967172-4.59481445e-02j, 0.04371742-9.22641848e-02j, 0.01217403+1.42468441e-01j, -0.03321802-6.06556050e-02j, -0.33791815+2.19614336e-02j, -0.02079545-1.62357371e-01j, -0.06115126-1.31463603e-01j, -0.04088450-1.17685338e-01j, -0.00096192-1.80065774e-04j, 0.11813011+6.17214729e-03j, 0.00417459-8.29797298e-02j, 0.08729658+2.67707592e-01j, -0.01118896-8.32911057e-02j, 0.03707148-5.83134279e-02j, + -0.12156735+2.64457587e-01j, -0.02989997-5.84706432e-02j, 0.03302162-6.01695667e-02j, 0.05437034-9.13677674e-02j, 0.10179674+1.40846743e-01j, -0.16635965+1.27949594e-01j, 0.14542720-1.12363084e-01j, -0.11077774-1.22746452e-01j, -0.00185723-4.56720198e-02j, 0.02600582-8.89150489e-02j, -0.22749400-6.67592408e-02j, 0.08533135-1.88751082e-01j, -0.22714608+1.14661652e-01j, -0.02690036-1.30865882e-01j, -0.10121037-6.45046877e-02j, 0.01443838-2.37190078e-02j, -0.02303954-1.61468225e-01j, 0.06055609-2.63250332e-01j, 0.13332186+2.20700929e-01j, -0.02063736+2.65142722e-01j, 0.08332522+5.90342871e-03j, 0.17210380-2.09054691e-01j, -0.15490146-9.27267743e-02j, 0.00453307-3.86153521e-02j, -0.02048122+3.02503499e-01j, 0.01458757-4.21067447e-02j, 0.32754022-3.88409256e-03j, 0.13811814-1.38612894e-01j, -0.12084009+3.73954159e-02j, 0.07102218-2.06344326e-02j, 0.11515796+1.13122542e-01j, -0.08863491-1.39456440e-01j, -0.17917237-4.99661020e-02j, 0.04442141+1.63664359e-01j, + 0.13732508-1.50992137e-01j, -0.05139775+8.97494329e-02j, 0.08732507+1.98929252e-01j, 0.05072904-2.99507910e-02j, 0.07108474+1.65205788e-02j, 0.01946830-8.78868281e-02j, 0.09380987-4.44516495e-02j, 0.17168417+3.91109903e-02j, -0.04639245+2.60582960e-01j, 0.05875205+2.56753485e-01j, -0.07728994-3.17930589e-02j, 0.04520490-1.76709840e-02j, 0.00134074-7.72090938e-02j, 0.20413611-1.94606554e-02j, -0.01910068+1.39711619e-01j, 0.03564990+1.37434345e-01j, 0.30794216-1.09704366e-01j, 0.05284195-5.64409889e-02j, -0.08984104+6.94748250e-02j, 0.02163001+1.03288462e-01j, 0.03915384-9.81971938e-02j, -0.06670679+5.81276525e-02j, -0.11508668+9.47872135e-02j, -0.03545030-3.13816097e-01j, -0.10991197+8.71705953e-02j, 0.06963248-5.65881100e-03j, 0.06577731-1.54696868e-01j, 0.15321403-6.74125684e-03j, 0.08071347+4.48458418e-01j, 0.03395331+1.27262600e-01j, 0.04183345+4.00904175e-03j, -0.01187089-2.21527903e-02j, -0.01851325-1.47271834e-02j, -0.23601169-8.54312072e-02j, + 0.11541862-1.04823473e-01j, -0.11268181-3.21825004e-02j, -0.09001661-1.37514659e-01j, -0.11748964-2.64871993e-02j, -0.05239410-4.95790343e-02j, 0.14652240-1.03971485e-01j, 0.18034942+7.79615744e-02j, 0.09369470-2.22585205e-01j, 0.16751339+8.86578713e-02j, 0.19444547+1.21567778e-02j, 0.04771682+2.78729300e-02j, 0.19635398+9.50820346e-02j, 0.05185621+1.76230346e-01j, 0.07939533-2.18013091e-02j, -0.03596743-9.94674395e-03j, -0.28690236+7.06630196e-02j, -0.01620677+1.20756724e-01j, -0.11835929+3.00001593e-02j, -0.09989775+8.70560634e-02j, 0.06278320-9.47387901e-02j, -0.09171898+2.82637561e-02j, 0.23849114+8.96858167e-02j, -0.24665889+2.03994686e-02j, 0.22245419-4.30604068e-04j, -0.08208490-2.36258787e-01j, -0.11703521-6.52100265e-02j, 0.05282283-4.48185202e-02j, 0.02544553-7.56696642e-02j, 0.03208350+2.09744844e-01j, 0.02707166+2.74207623e-01j, 0.14071592+1.51271647e-02j, 0.05998730-2.12130726e-02j, -0.13238650+1.32285712e-01j, -0.06341490-1.88468438e-01j, + -0.25236535-9.40009628e-02j, 0.05804886-1.24296266e-02j, 0.01463484-1.92411356e-01j, 0.02901968-1.95938408e-01j, 0.05900759-5.70542063e-02j, 0.00392890+1.79168231e-01j, 0.21463779+6.06068544e-02j, 0.02601461+3.44313390e-02j, -0.06804777-1.37777019e-01j, -0.04134655-7.71930937e-02j, 0.26993183+7.04042029e-03j, -0.22478871-1.11219112e-01j, 0.02216198+8.72296592e-03j, 0.00900783-1.81402113e-01j, -0.12568783+5.40727822e-02j, 0.20728804+1.49611785e-01j, -0.15403110-1.04748775e-01j, 0.11524429+1.78469618e-01j, -0.01784981-2.05987600e-01j, -0.04310959+6.72693611e-02j, 0.09204926+1.24870358e-01j, 0.23044143-1.67687891e-01j, -0.04829998+6.96651901e-03j, -0.09200799-1.69548082e-01j, -0.08599541-5.05360845e-02j, 0.05605567-1.23777989e-02j, 0.09183321+2.03716921e-01j, 0.06046671+1.88609777e-01j, -0.35443088-2.50139768e-01j, -0.10418443+1.53252364e-01j, 0.02878444+4.48922173e-02j, -0.07655359-8.92321321e-03j, 0.06322981-5.98952645e-03j, -0.05895737-7.06273994e-02j, + 0.04582500+3.45008534e-02j, -0.03569720+7.58719989e-03j, -0.18135564+2.31658738e-02j, -0.11367649-1.11799943e-01j, -0.02278714-7.26386363e-03j, 0.00527786+1.70825935e-01j, 0.08659992-2.45702546e-02j, -0.16132867-1.40266073e-01j, -0.16275372+1.57528240e-01j, 0.10098732-4.90008453e-02j, -0.14020292-1.26389028e-01j, -0.13387933-1.77044519e-01j, 0.15233209+1.56396670e-01j, -0.01186549+1.66770551e-01j, -0.05911019-9.37506242e-02j, -0.11032036+2.22422316e-01j, -0.32768772+1.23945218e-01j, 0.11693884+1.01153011e-01j, 0.06380873+2.73797332e-02j, -0.15242003-1.78297868e-01j, 0.08576241-9.81537390e-02j, -0.05483774+2.39049552e-02j, 0.08818984-4.80048981e-02j, 0.13795202+3.39576952e-02j, 0.15420435+1.04809134e-01j, -0.14757170-8.35910546e-02j, 0.25587669-9.78491595e-02j, 0.12582976+1.06377618e-01j, -0.04885733+5.85877129e-02j, 0.02768058-8.97097222e-02j, -0.09572117-3.14848747e-03j, -0.09107239-1.48042190e-01j, 0.02633147+1.28206292e-02j, -0.00231722+2.40935942e-01j, + 0.08505098+4.43364674e-02j, 0.04542370-1.20532432e-01j, -0.17493652+1.27595262e-01j, 0.01816818-1.93108598e-01j, -0.17931339+1.06943524e-01j, -0.10671963+1.39014451e-05j, 0.11498691+1.93066834e-02j, 0.23000235+1.04393237e-01j, -0.18572715-1.37399401e-01j, 0.13220069-3.09402657e-02j, 0.02990116+1.12157118e-02j, -0.02942283-1.36235506e-03j, -0.13275055-2.01044204e-02j, -0.05513657-1.15044942e-01j, -0.07453253+1.24162429e-01j, 0.19348874+1.65304419e-01j, -0.01684765-8.28080868e-02j, -0.06982499+2.38660768e-02j, -0.29603023-1.04892178e-01j, 0.31520605-5.80965984e-02j, -0.16452607-3.29924630e-02j, 0.13918688+1.34255787e-01j, 0.14618480-5.91517992e-02j, 0.05246915+2.47209477e-02j, 0.09600898+4.48951448e-02j, -0.03040775+2.25636252e-01j, -0.03104364-1.03378328e-02j, 0.12457642-1.13129265e-02j, 0.25722645-1.07390381e-01j, 0.12453095-1.46405362e-01j, -0.20675192+5.37923723e-02j, -0.08581718-3.76855478e-02j, 0.12881044-7.30139037e-02j, 0.03309130-1.45171188e-02j, + 0.04964024-2.63320298e-01j, -0.06851158+3.25029578e-01j, -0.06736655+3.31741867e-02j, 0.10672767-1.33657818e-02j, -0.03911025+2.71696686e-03j, 0.18376597-2.21089267e-01j, -0.02949093-2.24178456e-02j, -0.07672718+8.63619859e-02j, 0.09011718+1.34863000e-01j, -0.03532004+2.01221708e-02j, -0.01750050+6.62198244e-02j, 0.17146927+8.06205588e-02j, -0.09194709+3.45310559e-02j, 0.05919149+8.90830332e-03j, -0.03890834+6.41903709e-02j, -0.13501504-3.99845589e-02j, -0.10279042+1.03768681e-01j, -0.05259741-5.87714457e-02j, -0.11719418-2.08936502e-02j, 0.09836174-5.44608131e-02j, -0.22877539+2.08355637e-01j, 0.04941838-9.51260734e-02j, -0.06203396+2.28604981e-02j, 0.12098849-1.44576480e-02j, -0.08451115-1.43356466e-01j, 0.15635672-1.46530151e-02j, -0.20437704-3.79884112e-02j, -0.19636121-1.71501698e-02j, 0.07255917-2.20625252e-01j, -0.28061719+7.71279703e-02j, -0.02084913-1.12045005e-01j, 0.04322484+8.40757110e-03j, 0.06080093-9.41283647e-03j, -0.08052508-4.49212849e-03j, + 0.35296504-9.29569583e-02j, 0.30139399+2.02446885e-01j, -0.10435560-1.29299775e-01j, 0.19156652+1.16499747e-02j, 0.20865974-1.46798336e-01j, -0.13729311-1.50569340e-02j, 0.02152623+1.61941611e-01j, 0.05963193-1.30770158e-01j, 0.06462617-1.66387108e-01j, -0.11403091-8.19783097e-02j, -0.17890047-3.87091987e-02j, 0.05041442+2.34797464e-02j, 0.33716094-2.18366246e-01j, 0.04749898+7.95121529e-02j, -0.14276611+5.91160893e-03j, 0.07271710-6.38166930e-02j, -0.03268621+7.25536789e-02j, -0.00994355-5.45862875e-02j, -0.10977213+1.11554079e-01j, 0.01783962-2.78702484e-01j, -0.00306595+2.65697928e-02j, 0.13926720-1.06298955e-01j, -0.10153158-8.24641251e-02j, -0.26939850+6.47512729e-02j, 0.03236581+4.07523974e-02j, -0.14424473+2.51731413e-01j, -0.01873542-2.47536237e-02j, -0.01356796-8.16033886e-02j, -0.07272296-1.47884513e-01j, 0.01967111-1.46373935e-01j, 0.23073323-8.09684340e-02j, 0.14428689+1.18128043e-01j, -0.06420706+1.47110727e-01j, -0.01428800-1.01535529e-01j, + 0.05505723+1.85830802e-02j, 0.00835002+2.95374366e-02j, 0.00710951+4.40654128e-02j, 0.17926977-3.38549657e-01j + ] + + u1 = ql.Unitary("using_qx_fully_entangled_5_qubit_10011", matrix) + u1.decompose() + k.x(4) + k.x(1) + k.x(0) + k.gate(u1, [0, 1, 2, 3, 4]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(helper_prob(matrix[19 + 0]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 32]), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 64]), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 96]), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 128]), helper_prob(state.get(to_bit_string(4, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 160]), helper_prob(state.get(to_bit_string(5, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 192]), helper_prob(state.get(to_bit_string(6, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 224]), helper_prob(state.get(to_bit_string(7, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 256]), helper_prob(state.get(to_bit_string(8, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 288]), helper_prob(state.get(to_bit_string(9, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 320]), helper_prob(state.get(to_bit_string(10, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 352]), helper_prob(state.get(to_bit_string(11, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 384]), helper_prob(state.get(to_bit_string(12, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 416]), helper_prob(state.get(to_bit_string(13, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 448]), helper_prob(state.get(to_bit_string(14, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 480]), helper_prob(state.get(to_bit_string(15, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 512]), helper_prob(state.get(to_bit_string(16, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 544]), helper_prob(state.get(to_bit_string(17, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 576]), helper_prob(state.get(to_bit_string(18, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 608]), helper_prob(state.get(to_bit_string(19, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 640]), helper_prob(state.get(to_bit_string(20, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 672]), helper_prob(state.get(to_bit_string(21, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 704]), helper_prob(state.get(to_bit_string(22, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 736]), helper_prob(state.get(to_bit_string(23, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 768]), helper_prob(state.get(to_bit_string(24, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 800]), helper_prob(state.get(to_bit_string(25, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 832]), helper_prob(state.get(to_bit_string(26, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 864]), helper_prob(state.get(to_bit_string(27, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 896]), helper_prob(state.get(to_bit_string(28, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 928]), helper_prob(state.get(to_bit_string(29, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 960]), helper_prob(state.get(to_bit_string(30, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[19 + 992]), helper_prob(state.get(to_bit_string(31, size=platform_qubits), 0.)), 5) + + def test_adding_2_to_the_power_6_unitary(self): + num_qubits = 6 + p = ql.Program('test_adding_2_to_the_power_6_unitary', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + 3.66034993e-01+2.16918726e-01j, 4.63119758e-02-1.25284236e-01j, 3.23689480e-01-1.67028180e-02j, -4.01291192e-02-1.53117445e-01j, 1.84825403e-01-3.19144463e-02j, 5.62152150e-03-1.90239447e-02j, -1.37878659e-01-9.85388790e-02j, -4.12560667e-02+2.40591696e-02j, 1.70864304e-02-9.30023497e-02j, 3.56649947e-02-4.69203339e-02j, -3.83183754e-02+5.12024751e-02j, -1.96496357e-02+2.63675889e-02j, -1.43417236e-01+2.87083079e-02j, -7.64191581e-02+8.10632958e-03j, -5.44376216e-02+3.71068995e-02j, 7.89219612e-02+6.00438590e-02j, 2.32485473e-01-2.61279978e-03j, 3.13800342e-02+1.24253833e-02j, -3.80054586e-03-1.73877756e-02j, -7.12322896e-03+9.73966530e-02j, -1.22838320e-02-6.80562063e-02j, 1.04704708e-01+4.17530991e-02j, -1.45411627e-02-4.56578204e-03j, -3.91129910e-02+8.17248378e-02j, 6.36557074e-02+2.21470313e-02j, 1.10349909e-01-1.21376682e-02j, -4.78526826e-02+5.49355237e-02j, -1.20516087e-01+4.01182200e-03j, 9.38275660e-02+2.24713754e-02j, 8.93979520e-02+5.13816205e-03j, + -4.59396339e-02+1.59721722e-02j, -4.28884340e-03-4.63622637e-02j, 6.12649865e-02-1.22841538e-01j, -5.65913752e-02-6.08971314e-02j, -2.32312060e-02-1.65654059e-02j, 1.41147598e-02+4.73394414e-02j, -4.33854823e-02-1.51947091e-01j, -8.13427974e-02+2.99813808e-02j, -1.17417843e-01+1.90630710e-01j, -1.90231845e-02-8.35713650e-02j, -1.22044267e-01-7.47225397e-02j, -3.60683906e-02+6.78243340e-02j, -7.19769659e-02-2.89274301e-03j, 3.35704664e-02-6.57183304e-02j, -1.77382032e-01-2.84971997e-02j, 1.33681237e-01+1.01754278e-01j, 6.82852215e-02+9.51310080e-03j, 7.78691038e-02+2.00563796e-02j, 1.72520999e-02-4.06637398e-02j, -1.01923775e-02+5.59753174e-03j, 3.10544397e-02+1.61785537e-02j, 8.93474575e-03+6.24199961e-03j, 2.81125596e-02-3.97444226e-02j, 1.51177344e-01+2.05815209e-01j, -5.34831140e-02+1.77651158e-01j, -4.40789322e-02-2.71929907e-02j, -9.66417470e-02-6.07156542e-02j, 1.08161080e-01+1.20076484e-01j, 8.21245796e-02-2.30271819e-02j, -8.84132928e-03-5.48481546e-02j, + -5.14895797e-02-1.37500021e-02j, -1.51874055e-02+6.32818901e-02j, 4.75397973e-02-7.13568201e-03j, 3.13807800e-02-1.14525719e-02j, 1.01592567e-01+1.60695903e-01j, 1.27305395e-01+1.95561563e-01j, 1.12090718e-01-6.51290458e-02j, -1.01825786e-04-1.81692203e-02j, 1.54924689e-01+2.64139117e-02j, 9.26041281e-02-1.10472514e-01j, 1.14444819e-01-2.07202663e-02j, 6.75494235e-03-7.42645200e-02j, 7.77019424e-02+7.23999587e-03j, -1.97577945e-02-1.21556587e-01j, -1.53460462e-01-6.09952436e-02j, 4.01985175e-02+6.32614480e-02j, -6.20026282e-02-1.35839473e-01j, 1.29200169e-01+3.78332216e-03j, -2.59883114e-02-9.05275193e-03j, 8.17860302e-02-3.48868665e-02j, -1.60053834e-01-2.02916150e-01j, 4.82858885e-02+1.09125088e-02j, -1.24753204e-02-1.22518525e-01j, -5.80857579e-02-4.19993263e-02j, 2.28396669e-02-8.40966881e-02j, 6.32309194e-02-1.34709187e-01j, -9.62511113e-02-7.66908701e-02j, -9.03694102e-02+1.30290490e-01j, -1.46952433e-01+1.04814111e-01j, -2.72713771e-02+9.46774405e-02j, + 6.43591466e-02+4.89870962e-03j, 4.75376946e-04+3.50098669e-02j, -1.49839101e-01+4.44685559e-02j, 3.36051502e-02-1.73310171e-02j, 6.33484348e-02+4.71325034e-02j, -2.17711578e-02+1.31801429e-02j, 1.74906999e-01+1.53006903e-01j, 8.86273947e-02+1.97117753e-01j, 2.80636110e-02-1.05335854e-01j, -2.55400957e-02+3.13987536e-03j, 1.90502728e-01-5.65463143e-02j, -4.83648932e-02+9.12606941e-02j, 5.98563090e-02-7.02341588e-02j, -8.94163863e-03+3.75629282e-02j, 7.28101901e-02+7.14544903e-02j, -6.45875285e-03-3.09883105e-02j, 8.81396901e-03+1.99334329e-01j, 7.90997911e-03-6.52739372e-02j, -6.22843622e-02+1.28419510e-02j, -9.96405825e-02+3.88022827e-02j, 2.56561292e-02-2.23919910e-02j, 6.96886035e-02+3.51775332e-02j, -3.51521748e-02+3.76936524e-02j, 9.75324023e-03+6.65739416e-02j, -6.83377964e-02-6.68801536e-02j, 5.26199194e-03-6.98174024e-02j, -3.18191450e-02-8.73246712e-02j, 7.65668019e-02-2.22700208e-01j, 1.39633338e-01+1.29785687e-01j, 7.76075375e-03+1.07250473e-01j, + 5.43176815e-03+1.07893416e-01j, 8.87283358e-02-2.63757540e-02j, 5.90762011e-03+1.21098716e-01j, -5.31234979e-02-7.38219329e-02j, -6.99676596e-02+1.83616052e-02j, -1.13045510e-01-1.38358191e-01j, -6.40257276e-02-1.33332243e-02j, -5.05842389e-02+1.17327054e-01j, 2.19460719e-01+1.53618876e-01j, -1.98098237e-01-1.83046859e-01j, 2.55895738e-01-1.22287636e-01j, 2.24304159e-02+3.12955813e-02j, 8.10330744e-02+9.09937415e-02j, -8.69829415e-02-1.31156605e-01j, 7.13752017e-02+3.22771841e-02j, -1.09383893e-01+2.78555202e-02j, 6.08603366e-03+1.30630331e-01j, -1.38543382e-01-1.32609733e-01j, 8.11354396e-02-1.56139915e-02j, -2.46721034e-02-6.17177733e-02j, 1.17317415e-01+1.46270026e-01j, 1.57044029e-02+2.81859378e-04j, 7.34343516e-02+1.32166441e-02j, -1.94047136e-02+3.71747664e-03j, 1.67740714e-02+1.55308704e-01j, -2.30281717e-01-1.13574589e-02j, 6.66702774e-02-3.44728569e-02j, 6.64536670e-02-4.11020927e-02j, -5.89556075e-02+1.21648953e-01j, -1.33381018e-01+1.11575280e-01j, + -2.04297207e-02-1.44361996e-01j, -1.36404986e-01+1.75670409e-02j, 9.04729266e-02-2.05525311e-02j, -8.54217517e-02+8.81964403e-02j, 4.08009950e-02-4.65066696e-02j, 1.28598663e-01-1.26135509e-03j, -5.88955587e-02-2.16365675e-01j, -5.91081138e-02+3.93697458e-02j, 1.25841320e-01-6.59751293e-02j, 6.64938943e-02+5.27045503e-02j, 1.82761546e-01+9.47007410e-02j, -9.47093986e-02-4.42715353e-03j, 2.14782709e-02+1.08386929e-02j, -1.64295853e-03-6.85829980e-02j, 3.15183688e-02-2.83403844e-02j, 1.32010033e-02-1.35335939e-02j, 1.17740974e-01-4.02249320e-02j, -7.12640244e-03+4.92657515e-02j, 6.62000134e-02-6.58330394e-02j, -8.27247973e-02+5.46860857e-03j, -6.85927353e-02+1.60810901e-02j, 5.28608831e-02-4.24129436e-02j, 7.90603356e-02+5.78672352e-02j, 3.73193949e-02-4.61190576e-02j, 4.91693254e-02-1.00191521e-01j, -8.30279823e-02-4.53136772e-02j, 8.52488016e-02-9.43347617e-03j, -3.36847083e-02+4.29105012e-02j, 1.17835217e-01-1.03615646e-02j, 9.03099416e-03+1.23603737e-01j, + -8.85120477e-02+5.98128080e-02j, -1.07646777e-01-1.06745536e-01j, 2.85703816e-02-1.32915304e-02j, 6.54799867e-02-1.05639352e-01j, 1.56220180e-01-1.94186883e-02j, -8.98506499e-02+1.20794812e-02j, -3.34699800e-02+3.97067051e-02j, -1.13133666e-01+1.39529758e-02j, 3.82233228e-02-6.51392562e-03j, 1.16912282e-01-7.57853365e-02j, -3.02029062e-02+2.03203809e-03j, -7.05833281e-02-3.72791361e-02j, 1.18487986e-01+3.41305694e-02j, 1.90369334e-01-4.23433077e-02j, 1.78329157e-01-2.46079024e-03j, 1.42514615e-02-5.00931284e-02j, 6.22258069e-03+2.71254537e-01j, -1.05493042e-01+4.81011019e-02j, 1.63685462e-01+3.54417709e-02j, -7.92557707e-02+3.37712908e-02j, -6.89388107e-02+9.52917547e-05j, -5.98463661e-02+9.39029791e-02j, 7.83393843e-02+4.48842194e-02j, -4.03889441e-02+1.58463043e-02j, 4.69349327e-02+7.36054463e-02j, -1.23002359e-01+3.56702348e-02j, -8.08745549e-02-9.36340081e-02j, -1.53111649e-01-1.30519031e-01j, -4.55188428e-02-2.63939035e-02j, -5.13289900e-02+3.12841022e-02j, + -7.22190692e-03+9.84746771e-02j, -4.23305508e-02-4.16100064e-02j, 9.70155024e-02-5.10653722e-02j, -1.52262614e-02+9.70290076e-02j, -4.95065203e-02-4.71260667e-02j, 2.63361010e-01+5.88816734e-02j, -3.58878585e-02-2.50486879e-03j, -2.14856796e-01-7.75726911e-02j, -9.45755082e-02-1.02420516e-01j, -1.45089067e-01-1.73675325e-02j, -1.28612734e-01+2.62396621e-02j, -1.27273026e-01-2.41474716e-02j, -1.08532484e-01-7.70550142e-02j, -6.11361542e-02+5.21576989e-02j, -1.49885849e-01+6.33951444e-02j, 1.39221310e-01+4.74904068e-02j, 7.98734756e-03+1.21834984e-01j, -6.70609516e-02+1.03519222e-01j, 9.84581689e-02-1.90608636e-02j, -4.20985103e-04-5.34460521e-02j, 4.61698910e-02-5.36918570e-02j, -1.80638508e-02-5.52001591e-02j, 3.26902700e-02+1.03032250e-01j, 2.19231364e-01+5.34459046e-03j, 2.02344664e-01+8.05112282e-02j, 1.12050260e-01-9.47627052e-02j, 5.01092383e-02+2.80856107e-02j, 1.54394724e-01-2.02727577e-02j, -1.28311863e-02-1.32251018e-02j, 1.24297206e-01+5.16860223e-02j, + -2.40603762e-02+2.74847000e-03j, -7.65154347e-02-6.29854246e-02j, 1.90751859e-01-5.75903679e-02j, 1.31040663e-02-6.01812829e-02j, 3.98490344e-02-8.53582487e-03j, -9.87057147e-03+8.47414791e-02j, 4.96880859e-02+1.52103456e-02j, -2.34893852e-02+2.41581495e-02j, -6.29676487e-02+8.60622743e-02j, 3.33756353e-03+2.80774648e-02j, -6.00395642e-02-1.05197812e-01j, 8.12528420e-02+7.93631414e-02j, -2.07420548e-02+1.38374365e-01j, 5.36463694e-02-3.94927621e-03j, -1.96804868e-02+7.52059881e-02j, -3.71609399e-02+2.89964329e-02j, 1.54225234e-01+1.66400526e-01j, -4.28794858e-02+3.77165370e-02j, -4.72161861e-02+1.05193382e-01j, 1.88483774e-02+7.86924100e-02j, -3.05826462e-02+1.63053493e-01j, 6.64422544e-02+1.30615029e-01j, 1.19393774e-01+1.07635386e-01j, 1.15236137e-01+4.54248967e-02j, 8.36065560e-02-1.16369074e-01j, -7.31696969e-02+3.27398301e-02j, 1.04035711e-02+6.94251001e-02j, -1.12999867e-02-3.91635996e-02j, -6.25688782e-02+1.10951995e-01j, 6.06383062e-02+1.30678577e-01j, + 3.87713914e-02-2.56890752e-02j, -2.12352952e-02+7.46470611e-02j, 3.81665661e-02-4.66485675e-03j, 9.83793872e-02-5.47848105e-02j, -7.89298421e-02+9.89548326e-03j, 8.09874389e-02+2.88991618e-02j, -2.84479799e-02-3.95612619e-02j, 5.96981585e-02-1.18286529e-01j, 6.23627334e-02+1.26721441e-01j, -3.10124832e-02-1.84640556e-02j, 1.03597375e-01-1.34393931e-01j, -1.17812622e-02-6.89229414e-02j, -1.44678634e-01+2.03634696e-02j, -1.92499694e-02+3.83736754e-02j, -1.54185344e-02+1.54256354e-02j, -6.22128278e-02-6.06971077e-02j, -1.54442796e-01-4.55965667e-02j, -1.17280933e-02-2.96076710e-02j, 3.61636242e-01-3.68311909e-02j, 1.62232374e-03-2.46211943e-01j, -4.92385971e-02-8.23015443e-03j, -1.45369403e-01-1.29391236e-02j, -5.95406360e-02-2.40696609e-02j, 1.05369118e-01+3.57907856e-02j, 1.54655257e-01-4.92247169e-02j, -1.92329144e-01+2.80700834e-02j, 7.34014412e-02-6.83985774e-02j, 1.59129968e-01+2.24675645e-02j, 4.50009905e-02+8.28684110e-02j, -1.55862846e-01+1.38581516e-01j, + -5.75055241e-02+2.76394588e-03j, -2.51204024e-01-1.28699277e-01j, -4.06946336e-02+7.17282849e-03j, -5.60177740e-02-2.97766068e-02j, 5.20270958e-02-1.24980073e-01j, -2.70809079e-02-7.62240935e-02j, -9.13895753e-02+3.09052839e-02j, -2.58735369e-02+5.60249825e-02j, -1.47477861e-02+6.08183848e-02j, 4.89102367e-02-2.32083741e-04j, 4.26959278e-02+7.86994426e-02j, -5.37737809e-02+4.29931841e-02j, -7.51527527e-02+1.05047426e-02j, -7.92092909e-02-6.76905017e-02j, -1.53434244e-02+5.39639561e-02j, 1.02041990e-01+1.20369368e-01j, 3.16941445e-03+9.84779820e-02j, 4.50698004e-02+8.95480278e-03j, -3.06674727e-02-3.23950934e-02j, -7.67166598e-02+5.80876145e-03j, 4.03226297e-02+5.02470157e-02j, 9.20435646e-02+6.16208640e-02j, 4.53349090e-02-6.97415185e-02j, -1.43676770e-01+3.16896179e-02j, -5.70956416e-03+1.14461269e-01j, 3.36727523e-02+3.46621803e-02j, -1.28349306e-01+6.15831113e-02j, 2.92131791e-02-1.11494758e-01j, 6.78039246e-02+5.74136771e-02j, -7.37065550e-02-1.55476166e-02j, + 2.56255331e-02-4.43527889e-02j, 3.60829775e-02+1.48859744e-02j, -3.26999034e-02+1.41339655e-01j, 7.33897143e-02-5.13214915e-02j, -3.90630444e-02+7.98559328e-02j, 2.68903082e-02+5.83120382e-02j, 1.14205526e-01-3.53133007e-02j, 1.67581969e-01-2.17414475e-02j, -8.47370959e-02-1.03605182e-01j, -1.02980585e-01+1.87241569e-01j, 4.88560456e-02-1.87154362e-02j, 9.14764037e-04+6.72307848e-02j, 1.54753913e-02+6.22097288e-02j, -2.66815276e-02+7.33037713e-02j, 7.26024183e-03-1.57891621e-01j, 1.61465938e-02-6.23853508e-02j, -1.58906775e-02+9.22861340e-02j, 1.09187430e-01+1.22305747e-03j, 2.04879819e-02+6.30194559e-02j, -4.91774816e-02+1.98730477e-01j, 7.71514495e-02-8.70875038e-03j, 1.57479965e-01+1.04217181e-01j, 4.23884657e-02+9.41224038e-02j, 1.23866904e-01+2.54965114e-01j, -4.96733375e-03-4.34545446e-02j, 1.66863425e-01+1.03216014e-01j, 1.22161732e-02+1.74410123e-01j, 7.56016604e-02+1.14041093e-02j, 1.29416658e-01-1.07683681e-01j, 8.49692580e-03-9.98225347e-02j, + -2.53682806e-03-1.99317517e-01j, 1.32776926e-01+6.57308336e-02j, 2.48792835e-02-2.64841453e-01j, 1.03428049e-01+9.65965570e-02j, -1.51241974e-01-5.72183934e-03j, 1.88201884e-02+9.78051235e-02j, -3.52125401e-03-9.10550190e-02j, -1.21382845e-02-5.61863132e-02j, -2.72633341e-03+3.66383373e-02j, 1.31161516e-01-1.26913372e-02j, 3.46525801e-02-8.46938669e-02j, 1.17489600e-01-1.27053502e-01j, -7.75126317e-02+3.30270148e-02j, -7.85367649e-03-1.59325461e-02j, -2.04527534e-02-1.50973103e-01j, 1.19070061e-01+2.74181755e-02j, -1.24892455e-01-2.71536222e-02j, -8.38973196e-02-2.83671293e-03j, -9.23824862e-02-1.17795710e-01j, -2.12548944e-02+5.61017801e-02j, 1.45278490e-01-9.56859548e-03j, -1.82863761e-03+4.39439680e-02j, -5.97226268e-02-3.11260187e-02j, -4.76076983e-02-2.13141614e-02j, -4.54603071e-02-1.87085243e-02j, 1.40969780e-01-1.09754704e-01j, -1.01455639e-01+7.71777346e-02j, 1.48752797e-02-1.32375476e-01j, -9.40626155e-02+7.11577906e-02j, -2.12131838e-02-7.11116567e-02j, + 1.11184697e-01+1.35340762e-01j, -1.67713585e-01-2.00603909e-02j, 6.69071941e-02+4.20345476e-02j, -6.05717732e-03-9.68103657e-02j, -4.66999484e-02-8.16202516e-02j, -8.45240798e-02+5.60371406e-02j, 1.26572662e-01+4.52015693e-02j, 1.15084298e-01+1.80329121e-02j, -8.19534585e-02+9.92455558e-02j, 5.82837845e-02-9.60191435e-02j, 1.40466777e-01-9.50202996e-02j, 5.11287771e-02-2.53675878e-02j, 2.47544744e-02+2.06020479e-02j, -3.65720656e-03-4.94804816e-02j, -1.41559984e-02+1.67809139e-01j, 3.40859417e-02+1.36896363e-02j, -4.29813547e-02+1.10736905e-01j, 1.27523603e-01+2.07169069e-02j, 1.47572639e-01-4.16243755e-02j, 5.26379357e-02+6.25793319e-02j, 1.49109608e-01+1.47242665e-01j, -6.65329123e-02+3.26931942e-02j, 1.91342477e-01+6.13849533e-02j, -3.48863201e-02+1.16221687e-01j, -1.84725165e-02+8.88063853e-02j, -1.46651117e-01-8.03755334e-02j, 3.18322341e-01+1.28855771e-01j, -7.34176530e-02+6.28676759e-02j, 6.59855007e-02-4.02354168e-03j, -1.14723570e-02-1.41192022e-03j, + 1.31986821e-02+8.66384236e-02j, -2.06143698e-02-1.06385925e-01j, -1.29887505e-01-5.82215934e-02j, 3.55333019e-02+1.72976962e-01j, -4.43318809e-02+7.50029900e-02j, 2.42008445e-02+3.81880311e-02j, 9.24309092e-02+2.08369499e-02j, -1.73024821e-01+5.21566745e-03j, 2.19700726e-01+1.17537260e-01j, 1.63993038e-01+7.53919556e-02j, 7.07529823e-02+3.32108419e-02j, 8.06363236e-02+5.69884702e-02j, 6.53884989e-02-6.06009350e-02j, 1.02796574e-01+7.41913070e-02j, 3.21527509e-02-3.68525050e-02j, 5.23724001e-02+6.69483928e-02j, 1.40581761e-02+7.70120060e-02j, 7.42821790e-02+7.73759929e-02j, 1.03095422e-01-7.83293200e-02j, -5.98649602e-02-9.76718764e-02j, -8.58898366e-02-1.20654270e-01j, 9.76478031e-02-2.49354014e-02j, -3.33481195e-02+1.59120400e-02j, -1.04779024e-02-9.02867422e-02j, -3.68342490e-02+6.83856814e-03j, -5.03744003e-02+2.55842171e-02j, -1.72672267e-02+2.47688542e-02j, -1.81408876e-02-7.60577495e-03j, 6.15478341e-02+9.21537711e-03j, -9.54714639e-02+4.91095211e-02j, + -3.28772457e-02-1.07419632e-02j, 7.91895326e-02-1.16514331e-01j, -3.28981168e-02+6.24741888e-03j, -8.74370047e-02-1.34809532e-02j, -3.78068572e-02-2.85542044e-01j, 2.27133052e-02+8.76888751e-02j, 9.11283724e-03+1.95425832e-02j, 6.35536375e-02-6.45304136e-02j, -6.05664346e-02-8.13326951e-02j, 9.51930052e-02-6.52573951e-02j, -5.72679924e-02+8.44254015e-02j, -3.90623628e-02-3.15090263e-02j, 1.02656566e-01-1.53783548e-02j, -2.90858731e-02+3.83758991e-02j, 4.00015008e-02+9.29419353e-03j, 2.16293344e-02-6.15080785e-02j, -3.94283903e-02-2.86725847e-02j, -9.82554318e-02-3.05356109e-02j, 1.43678779e-01+1.66757227e-01j, 4.33669816e-02+2.09725691e-02j, 6.09968565e-02+1.35896205e-01j, 1.86428835e-02-1.07078161e-02j, 3.59210771e-02-4.96728908e-02j, -3.09977809e-02+4.20063574e-02j, -3.36483096e-02+4.06648103e-03j, -6.78492085e-02+3.60589692e-02j, -4.57256782e-02+2.29382640e-02j, 8.41604265e-02-1.21627615e-01j, 1.23159551e-02-4.33185856e-02j, 2.92901980e-02+7.68246203e-02j, + 3.57537713e-02+1.13757740e-01j, 6.61076239e-03+2.35766830e-03j, -2.50170508e-02+2.02216570e-01j, 1.90226197e-02-9.30319796e-02j, 3.52294231e-02+1.98930350e-01j, 6.47480042e-02-7.71035915e-02j, 1.06576071e-01+1.60636469e-01j, -1.84106675e-01+1.48367027e-02j, -2.26634183e-02-6.05001248e-02j, -4.09795810e-02+4.28997415e-02j, 1.18647136e-01+2.84135141e-02j, 1.05658964e-01+1.11901959e-01j, 1.55385384e-01+1.23916786e-01j, 2.50437539e-02+2.39415647e-01j, -3.10447452e-02+7.27368239e-02j, 2.03285504e-02-9.59860836e-02j, -3.39711391e-03-8.06167738e-02j, -1.36708865e-01+1.58365544e-01j, -7.63968104e-02-4.54852761e-02j, -1.34493163e-01-1.62060048e-01j, 1.37630857e-01-5.97073184e-02j, 1.26456118e-01-8.53282313e-02j, -1.44090748e-01-6.48238553e-02j, 1.14527429e-02-8.90366168e-02j, 1.26772282e-01+1.50468306e-01j, 1.09521345e-01+5.79354942e-03j, -6.36493029e-03+1.04114079e-01j, -3.46448312e-02+1.55499200e-01j, -1.91801782e-02-5.55803895e-02j, -1.09747875e-01+1.16908867e-01j, + -5.98737364e-02+6.92798355e-02j, -7.70045009e-02+8.69529376e-02j, 1.41838471e-01+1.57609972e-01j, 1.05064988e-01+1.27448858e-01j, -5.58481223e-02+1.18970561e-01j, 3.11104760e-02+7.09377243e-03j, 1.17401170e-01-1.29171507e-01j, -9.23143689e-02-6.32936915e-02j, -1.57360238e-02-3.48087654e-03j, -3.68085794e-02-6.90240362e-02j, 3.72129634e-01+1.05885225e-01j, 1.47539078e-01-1.02019375e-01j, 9.10168034e-02-9.45885626e-02j, -6.41230394e-02+5.23466780e-02j, 2.09042766e-01-5.04017256e-02j, -8.18752152e-02-1.67729197e-01j, 2.43479176e-02-3.15791155e-02j, -3.54894844e-02-2.06208641e-01j, 9.79597853e-02+1.27225349e-01j, -3.87549084e-02-2.32046371e-02j, -6.29155767e-02+1.93572123e-02j, 2.80668515e-02+5.94461601e-02j, -6.79156216e-03+3.34189314e-02j, -8.17558519e-02-9.72531723e-02j, -6.93388764e-02+9.75765597e-02j, 1.13872557e-01+5.43605204e-02j, 4.98782889e-03-1.43108491e-01j, 2.50693943e-02-1.18651968e-01j, -8.42094212e-02+3.40094201e-02j, -1.93122748e-03+1.26278033e-01j, + 7.21626311e-02+4.14478810e-02j, 1.30623663e-01+2.44967192e-04j, 9.43901041e-03-9.97110706e-02j, -2.92711792e-03+1.03468344e-01j, -2.26707613e-01+3.41895256e-04j, -1.29510144e-01+1.87631777e-02j, -1.89888081e-04-2.55952955e-02j, -8.26946001e-02+6.13660772e-02j, -1.11228037e-02-1.58220779e-01j, 7.61250434e-02+2.67080152e-02j, 9.25782693e-02+6.13248807e-03j, 2.59736432e-02-2.37141043e-02j, -2.91932014e-02-2.25217711e-02j, -5.16699426e-03-1.36738487e-01j, -2.79601717e-02-4.16723747e-02j, -7.06047980e-02+1.66551658e-02j, 3.72096502e-02+3.30948726e-02j, -1.61133828e-02-1.31037806e-01j, 2.48425980e-02+1.25040461e-01j, 1.24479311e-02+4.85744755e-03j, -6.81173401e-02+7.38703130e-02j, -4.93754225e-02+1.06791006e-01j, -7.68461360e-02-4.01290044e-02j, 1.51095443e-02+6.82241087e-02j, -1.36934200e-01+1.03824672e-01j, 2.64272936e-02-2.80269677e-02j, -8.63367945e-02-3.13888054e-02j, -2.25404421e-04+7.88537649e-02j, 6.92346834e-03+3.17886627e-02j, 5.86120252e-02-2.00444048e-01j, + -6.88131527e-02+3.50491144e-02j, 2.62520589e-02+1.58407829e-02j, 1.66265278e-03-1.03532297e-02j, 7.69386002e-02-2.67185303e-02j, 1.01084098e-02+3.79223130e-03j, -7.29521430e-02+9.08482588e-02j, -4.61024420e-02+1.94411467e-01j, 1.53468094e-03+1.86350862e-02j, 7.27775150e-02-2.59153001e-02j, -2.05928168e-02-4.88869881e-02j, 1.26185139e-01+3.10908628e-02j, 5.16540196e-02-4.63561741e-02j, -4.00987002e-02-4.88168980e-02j, 2.74709517e-02+1.12099875e-01j, 7.06457783e-02+5.46480806e-02j, 3.46431872e-02+7.06736324e-03j, 5.62921199e-03+1.52252805e-01j, -1.05318693e-01-6.42034872e-02j, 2.61399114e-01+3.12581452e-02j, 1.42549889e-01-7.20539802e-03j, -4.01513611e-02-1.09584788e-01j, 2.32103459e-02-3.08901316e-02j, -8.87718807e-02-4.81598900e-02j, 3.88078001e-02-1.48971115e-03j, 8.20382929e-03-1.60908451e-01j, 1.53171161e-01+9.34285397e-02j, -9.84955476e-02-3.77925732e-04j, 1.15359466e-01+1.53988904e-01j, -3.53067842e-02+2.22448115e-02j, -2.76010476e-02-1.02685489e-01j, + 6.47338872e-02+3.21032179e-02j, -6.25630438e-02-9.57348589e-02j, -1.06676085e-01-6.02328785e-02j, 6.32336003e-02+9.18568053e-02j, 4.22806111e-02+3.67386778e-02j, 3.34450227e-02-9.49873539e-02j, -9.25500440e-02+7.10428902e-02j, 5.83735994e-02-1.98170082e-01j, -9.31369416e-02-6.00026885e-02j, -4.19679158e-02+6.04049319e-02j, 2.94658418e-02-2.07003282e-02j, 8.51945088e-02+8.19217414e-02j, -1.40734017e-01+7.52647297e-02j, 2.42289626e-01-1.27759422e-02j, -9.38154491e-02-1.26465660e-01j, -8.95541629e-03-1.42613529e-02j, 8.03314780e-03+1.60930516e-01j, -4.88653862e-02+1.17749379e-01j, -7.39379399e-02+8.62428712e-02j, -2.59414228e-03-7.84326485e-03j, 2.00269020e-01+9.58856720e-03j, -1.19645441e-02+4.34306329e-02j, 6.09717160e-03-1.54242927e-01j, 1.08644840e-01-7.83434868e-02j, -1.45600371e-01-5.53383550e-02j, 6.95876462e-02-3.75146138e-02j, -1.01317383e-01-3.44359913e-03j, -4.61204619e-02-9.77882682e-02j, 7.60823182e-02-1.37389279e-01j, 4.87149823e-02+9.94095931e-03j, + -4.76778208e-02+3.06934398e-02j, 1.34616868e-01-3.35001866e-02j, 9.42819618e-03-7.70997443e-02j, -1.58872569e-01-8.51718385e-02j, -1.08323340e-02-3.58830573e-02j, -9.44807628e-02+1.04462576e-01j, -5.12024697e-02+8.95696029e-02j, -1.23263290e-01-2.11365137e-02j, -6.23407814e-02+5.27129163e-02j, 1.84350076e-01-6.48454604e-02j, 4.47048643e-02+9.55835619e-02j, 3.04136984e-02-1.61047348e-01j, 5.35742906e-02-8.89771961e-02j, 5.21798913e-03-1.01652683e-01j, 9.81082670e-02+6.78883376e-02j, 4.51160517e-02+4.08974261e-02j, 7.24547188e-02+1.43396898e-02j, 1.34520732e-01+7.64023876e-02j, -2.44439308e-02+1.93019446e-01j, 4.70632798e-02+5.40126182e-02j, 1.44082445e-01-6.94027082e-02j, 1.10724758e-01-4.81811556e-02j, 1.75840970e-01+1.16857338e-01j, -1.38125661e-01-1.28426487e-01j, 1.67653981e-01+6.10401648e-02j, -9.27944162e-02-4.45898489e-02j, -6.36024967e-02-1.32504351e-01j, -3.83547731e-02-4.80351172e-02j, 2.87039348e-03+1.86993497e-01j, -8.06227067e-02-8.55853307e-02j, + 1.98050483e-01-5.65883695e-02j, -6.61066167e-02-1.71061740e-01j, -3.88695750e-02+1.09338522e-01j, -7.49700094e-02+9.33229878e-02j, -1.57544410e-02+5.63796550e-02j, 9.53506257e-02-6.37602365e-02j, 2.75211340e-03+7.79446442e-02j, 1.39113602e-01-1.36189229e-01j, 1.17220189e-01+9.46405945e-02j, -1.81301425e-02-2.48995711e-02j, -9.81095323e-02+1.42902852e-01j, 1.41212310e-01-1.26684189e-01j, -5.05751207e-02+9.51904702e-02j, 1.04859322e-01-2.04087816e-02j, -1.21826474e-01-1.07626674e-02j, -9.57058985e-03+1.37576990e-03j, -4.74540116e-02+1.96568999e-01j, -1.38789725e-01+5.29123729e-02j, -1.06381314e-02+7.45998022e-02j, 7.06297513e-02-7.13617157e-03j, -1.75797263e-03+1.12692942e-02j, -1.08418056e-01+7.80141453e-02j, 7.95831370e-02+5.43897927e-02j, -4.77081927e-02-1.65112693e-02j, -3.03381357e-02+8.08941075e-03j, -8.23004681e-02+1.05759705e-02j, -6.56969750e-02-1.79256431e-01j, -3.76059369e-02+1.78724732e-01j, -3.13850703e-02+9.23421858e-03j, -3.23711459e-02+8.23655512e-02j, + -5.52695718e-02-2.86257551e-02j, -8.21930608e-02+2.84104439e-02j, 6.88034715e-02+7.91090633e-02j, -9.58878856e-02+1.62110597e-02j, 1.85489072e-02+7.72518030e-02j, -8.47308705e-02+1.15419402e-01j, -1.27165710e-02-1.47844195e-01j, -3.31225492e-02-1.12256225e-01j, 4.38928408e-02+3.01083140e-02j, 1.49664011e-02-3.23579402e-02j, 6.18136699e-02-3.20311892e-02j, -2.00715491e-02+3.36952165e-02j, 3.84726438e-02-1.47570105e-01j, 5.66270826e-02+1.60052582e-03j, -4.30699454e-03+7.36300298e-02j, 1.17987394e-01+4.71108745e-02j, -6.17743138e-02-7.33753780e-02j, -2.90245523e-02-2.72610689e-02j, 1.91805045e-02+7.28153549e-02j, -2.42663866e-02+1.76970283e-01j, 1.34153427e-01-6.33407243e-02j, 2.80424444e-02+7.13200467e-02j, -1.89628021e-01+3.08308998e-02j, 8.30657938e-02-1.92419259e-01j, 7.56007039e-02+1.32593910e-01j, 4.03658952e-02+9.28689978e-02j, 2.32661487e-01+5.37620195e-02j, 9.71324362e-03+1.55793479e-01j, -7.90003403e-02-9.01055799e-02j, -7.19042248e-03+4.98522998e-02j, + -7.89912325e-03-9.22331480e-02j, -1.52218111e-01-2.70308556e-02j, 1.52204585e-01-1.04355797e-01j, -9.58268719e-02-2.66039347e-02j, -5.85839839e-02-8.45115184e-02j, -7.67554648e-02+4.09816179e-02j, -1.23737409e-02+6.27494390e-02j, 1.76544689e-02+2.91020457e-02j, 7.88970104e-02-3.84634885e-02j, 1.46944340e-01+4.22569979e-02j, 9.45664458e-02+1.75073953e-01j, -7.43530291e-02+5.39858529e-02j, 5.30273947e-02-2.04301186e-02j, 9.01691091e-02-1.37635743e-01j, 5.17323825e-02-4.42395728e-02j, 4.51065835e-02+1.55587162e-01j, -4.32070922e-02-8.47367622e-03j, 8.89766181e-02+7.27808224e-03j, -3.05321402e-02+4.01867117e-02j, 9.02139365e-02-1.02921926e-01j, -9.68996356e-02-5.57902239e-02j, 1.86882008e-01-3.65138998e-03j, -3.56735640e-02-5.38393441e-03j, 1.03631981e-02+6.62353454e-02j, 1.39301908e-02-3.82579866e-02j, 1.29806843e-02+1.15547571e-01j, -7.78767617e-02+1.17577632e-01j, -6.55156854e-02-3.75568378e-02j, -1.16185770e-01-9.97472455e-02j, 1.13027024e-01-1.71188329e-02j, + -6.23765584e-02+9.71995127e-02j, 1.98853369e-02+4.41168144e-02j, 5.16372259e-02+1.04020291e-01j, 2.45487579e-02-7.07505804e-02j, -5.66916759e-03+1.79107188e-01j, 1.34919009e-01-3.38433266e-02j, -9.26335780e-02-2.41450966e-02j, -5.93110207e-02-1.13009956e-01j, -1.12473035e-01-1.02705305e-01j, -4.54029970e-02-8.46187294e-02j, -6.23708588e-02+4.57479972e-02j, 1.03992622e-02+1.00980439e-01j, 1.23694781e-01+1.22523548e-01j, 1.75959124e-01+6.68614671e-02j, 1.27580207e-01-7.10524199e-02j, -2.21112630e-02-3.48999085e-02j, -2.89686819e-02-1.38112449e-01j, -4.03154317e-02+1.30278763e-01j, -9.87558643e-03+2.11808797e-01j, 5.51166437e-02+7.28637045e-02j, -1.08116027e-01-1.25165016e-01j, -3.86238981e-02+8.93334399e-02j, 1.05216928e-01+6.44215494e-02j, 8.30120047e-02+1.60173664e-01j, -1.61665814e-01+1.33604609e-01j, -1.07929918e-01-2.27824193e-02j, 7.55794397e-02+5.35699856e-02j, 6.46640729e-02+6.77207472e-02j, -7.58619365e-02-1.36147809e-02j, 1.13368566e-01+1.41535454e-02j, + 1.16562600e-02+1.40637360e-01j, -3.48865452e-02-3.87334493e-02j, 2.84836458e-02+4.90837454e-02j, -3.44567796e-02+7.63272004e-02j, 1.61636226e-01-1.05180549e-01j, -4.75623594e-02+6.52991698e-02j, 4.99185253e-02+1.14465223e-01j, -5.40773631e-02-8.42919215e-02j, -1.14147601e-01+7.66188244e-02j, -1.40176445e-02+1.81528191e-01j, 4.35191919e-03+4.15940186e-02j, 1.27180295e-01+1.33144935e-01j, 9.06497753e-02-8.52809907e-03j, -1.26885003e-01-1.51045190e-01j, 1.02171723e-01-2.10818775e-02j, -2.98553434e-02+5.76845178e-03j, -1.60706438e-01-2.00370478e-01j, 1.51384923e-02-1.26679865e-01j, 7.55024672e-02+1.00895062e-01j, -7.45007080e-03-7.05098188e-02j, -2.88191949e-04-3.68919966e-02j, 5.62265696e-02+3.61613198e-02j, 4.24155733e-02-1.35428909e-01j, -7.53735593e-02-1.13686296e-02j, -1.16745754e-01+7.74921732e-03j, -6.94457624e-02-7.72663319e-02j, 3.74783331e-02+4.85062269e-02j, 6.52243264e-02-1.18436957e-01j, 1.17192626e-01+2.15233561e-02j, 1.02189810e-02-2.93259136e-01j, + 1.20140155e-02-6.63128933e-02j, -7.59536948e-02+6.71887612e-02j, 1.03744562e-02-1.21868885e-01j, 2.44016980e-02+6.89084519e-02j, -4.65470072e-02+1.22685320e-01j, -4.86962360e-02-4.88161112e-02j, -2.34017454e-02-5.77271045e-02j, 1.13502743e-02+4.16363888e-02j, -1.23278700e-01+1.12353134e-01j, -1.00881756e-01+1.17893431e-02j, 1.43470161e-01-3.29644042e-02j, -6.02563150e-02-4.45108227e-02j, 2.08219274e-01-1.67238564e-02j, 1.17121095e-02-6.33598388e-02j, 1.02538269e-01+3.22547888e-02j, 2.06012703e-03+1.07778634e-01j, 2.65464923e-02-3.46848652e-03j, 1.26264949e-02-7.16205403e-02j, 1.88694092e-02+9.58433324e-03j, -1.35215533e-01+2.75775658e-02j, 8.38743345e-02-3.94921696e-03j, 7.32804883e-02+4.21473224e-02j, 9.07604721e-02+1.45926883e-02j, -6.18641521e-02+7.52679281e-02j, 3.77612246e-02+2.95629420e-02j, -1.09369090e-01+3.64775541e-02j, -8.08080517e-02-8.08179068e-02j, 1.25920478e-01+1.02020075e-01j, 1.48976545e-01-3.02271686e-02j, -6.94345873e-02-9.09390945e-03j, + 1.31215815e-01-4.81602495e-03j, -2.05577715e-01+1.85648890e-01j, -4.20038791e-02-6.79461932e-03j, -4.21802223e-02+3.20414345e-02j, -3.87813853e-02+8.90865396e-02j, -4.21262137e-03-2.67890619e-02j, 6.79636786e-02-1.01093511e-01j, 1.40097339e-01+1.13907091e-02j, -1.88534819e-02+1.86465325e-01j, 2.71881881e-02-3.96160387e-02j, -6.42435188e-02-5.92185512e-03j, -4.89365496e-02-5.43585428e-02j, -4.57530970e-02-4.59613671e-02j, -3.61926650e-02+6.52346667e-02j, -9.61553968e-02-1.04451040e-02j, 9.04112402e-02-1.17533502e-01j, 1.74545444e-02-4.57240195e-02j, -4.89015824e-02+7.55148764e-02j, -1.42395993e-01-2.07951667e-02j, -1.04312418e-01+1.84020305e-02j, 1.04123907e-01-2.12641676e-02j, 1.81621294e-02-1.38150470e-01j, 6.90749445e-02-5.41908577e-02j, 1.25242285e-01+6.69590747e-02j, -1.12044943e-01+7.01709827e-02j, 1.18559009e-01+6.36320518e-03j, -4.09721959e-02-7.48052629e-02j, 2.11912964e-01+6.98119674e-03j, -5.53338736e-02+3.84548615e-02j, -1.73475512e-02+4.66847305e-03j, + -1.39453707e-01+3.59052683e-02j, 5.65519475e-02+1.33581775e-01j, 9.24610673e-02+9.71550192e-04j, 1.01271681e-01+2.91580010e-02j, 5.65757574e-02-5.63073301e-02j, -6.89138190e-02+8.79709939e-02j, 1.32780848e-01+1.15842424e-01j, 5.74757429e-02+4.60581605e-02j, 1.30747705e-01-1.09382867e-01j, -6.81587412e-02+7.23700700e-02j, -4.77640537e-02-8.69425608e-02j, 5.41468987e-02+4.70866972e-02j, -5.45249768e-02+1.28327565e-01j, 3.88602977e-03+1.11946956e-01j, 2.58870901e-02-1.91503109e-01j, -3.66945777e-02-1.10208009e-01j, -2.56790612e-02+1.58065038e-01j, -1.90786566e-01+1.14107636e-01j, -5.60322067e-02-1.21127263e-02j, 1.08860290e-02+1.24596622e-01j, -1.48768362e-01+2.37695281e-04j, -1.47649036e-02-1.64313895e-01j, -4.79489441e-02-2.08483452e-01j, -8.71341644e-03-2.32533010e-02j, 7.23197740e-04-1.45104996e-01j, -1.03649950e-01+5.46849449e-02j, -1.40039869e-02+1.54117586e-02j, 1.34270729e-01+7.10254799e-02j, -1.62944885e-02-6.79478047e-02j, 3.02355044e-02+9.34069481e-02j, + -4.19572996e-02-2.36984771e-03j, 5.19461879e-02+1.37769363e-02j, -1.56996645e-01-1.34660692e-01j, -4.48308181e-02-3.38817723e-02j, 5.73788104e-02+1.42412043e-01j, -1.15377475e-01-3.01131028e-02j, -7.77514856e-03+8.05802903e-02j, -1.80121894e-02-4.97689832e-02j, 2.74606415e-02+1.48966719e-01j, -1.17119892e-01+8.81288551e-02j, 7.95268357e-02-3.87759152e-02j, -1.66297510e-02-7.62547866e-02j, 4.37512230e-02-4.07918510e-03j, -7.00709466e-02-1.80395743e-02j, 1.17198057e-01-7.79683242e-03j, 1.75402728e-01-1.75827182e-02j, 5.42956130e-02-3.91441862e-04j, 1.01465093e-01+9.25475158e-02j, 5.36093332e-02+8.63715906e-02j, 3.05460006e-03+4.52463764e-02j, -1.46059785e-01-1.29686001e-02j, 1.80571255e-02+1.12753039e-01j, -8.21657514e-02-4.73360574e-02j, -1.10948811e-02-8.29924942e-02j, 8.52411894e-02+5.18029751e-02j, -8.02700769e-02+1.90210044e-01j, -2.34714253e-02-2.31241051e-02j, -3.19869719e-01+4.57770182e-02j, -4.75928400e-02+1.12895685e-02j, -3.75738567e-02+6.21213961e-02j, + -1.14920013e-01-2.12107989e-03j, 4.77491260e-02-5.19463759e-02j, 1.03806006e-01+7.16366977e-03j, -8.27636909e-02-5.08812397e-02j, 2.22322180e-02+1.43361348e-02j, 3.14670279e-02+1.39911830e-02j, 8.48418379e-02+1.81601566e-01j, -7.46942903e-02+7.89752532e-02j, 7.08970727e-02-6.91124197e-02j, -1.13741776e-02+1.23825472e-01j, -6.59798634e-02+1.24967591e-01j, -6.33113532e-02-1.64307450e-01j, 1.14099231e-01+3.41222046e-03j, -4.61570543e-03-2.19001396e-01j, 2.84759810e-02-7.17797193e-02j, -5.39314225e-02-1.64591007e-01j, -1.16438285e-01+6.52426253e-02j, 5.86854248e-02-4.05905194e-02j, 1.47438624e-02+5.30606235e-02j, -1.90230877e-02+4.63842878e-02j, 8.00044760e-03+1.58689396e-01j, 4.42361550e-02+5.13313063e-02j, 2.55319954e-02-9.75583568e-02j, 3.01793771e-02+1.11081312e-01j, 1.27308954e-01+1.69452356e-01j, -4.94643829e-02-3.50989191e-02j, 2.42630119e-01-3.22834423e-02j, -9.43879468e-03+1.54569386e-02j, -1.26451530e-01+1.07634561e-02j, 6.53072639e-02+1.64004515e-01j, + 4.73037239e-02+6.72621484e-02j, 7.86355859e-02+1.37091046e-01j, 3.48468450e-02+5.01002189e-03j, -4.96409372e-02-1.79874187e-02j, -8.08977821e-03-1.60325464e-02j, -6.18986724e-02-9.03950614e-02j, -8.57358123e-03-1.05211425e-01j, -1.19635684e-01-9.84001742e-04j, -9.29477188e-02-8.10903125e-02j, -6.60847827e-02+1.07380011e-01j, 6.65522847e-02+2.25450350e-01j, -8.20410767e-04-1.28445752e-01j, 6.14568901e-02-4.79238345e-02j, -1.06893529e-01+1.36044214e-01j, 1.15138674e-02-4.90252547e-02j, -2.76216857e-02+6.76507128e-03j, -1.09382658e-01-5.30334315e-02j, 7.08950419e-02+3.44793514e-02j, -7.60439516e-03-1.03572965e-01j, -5.88875512e-02-1.16117780e-02j, -1.76441304e-02+1.51394952e-01j, 1.31994928e-01+4.65974993e-02j, -5.68107027e-02-3.38323177e-02j, -1.00658392e-01+9.28555205e-04j, -7.05082372e-02-1.20465449e-01j, 6.60549798e-02-1.08205211e-01j, 1.56747849e-01+1.21419663e-01j, -1.92613366e-01-1.52102819e-01j, 1.13592085e-02+2.83411765e-02j, 5.99946763e-02+1.22827499e-02j, + 6.29184081e-02+1.00151916e-01j, 2.10898432e-03-1.59215144e-02j, 1.66631398e-02+1.18954419e-01j, 8.45398912e-02-1.10186016e-01j, -1.19940961e-01+9.68249560e-02j, 4.70304208e-02+7.70342680e-02j, -1.22124543e-01+4.39697557e-02j, -9.96175775e-02+1.38251492e-01j, 6.97555402e-02+1.33210859e-02j, 2.56989939e-01+1.26134536e-01j, -3.26770849e-02-1.47901277e-02j, 2.42109734e-02-1.35712836e-01j, -1.47972097e-01+4.14172508e-02j, -5.11927028e-02+1.22448971e-01j, 6.62366501e-02+5.95513442e-02j, -5.32415834e-02+3.72035869e-02j, -1.52278830e-03+1.27320604e-01j, 6.50991303e-02-1.55212986e-01j, 4.34075807e-02+1.02149453e-02j, 4.30717490e-02+9.20139462e-02j, 1.16886206e-02-1.87138194e-01j, -6.64847366e-02+1.09856866e-01j, -3.67840574e-02+6.02029631e-02j, -9.81671194e-02-7.20999183e-02j, -6.04451121e-02+7.52633656e-02j, 2.81976119e-03+1.06633536e-01j, 5.26129880e-02-3.98349053e-02j, -2.87998493e-02-7.12947090e-03j, -3.94344408e-02-1.20091657e-01j, 8.38152379e-02+5.55474575e-02j, + 9.41964471e-02+2.98721048e-02j, 8.16069823e-02-2.59474209e-02j, 1.55022162e-01+1.57407270e-01j, -5.67424378e-02-1.25923094e-01j, -2.06889103e-02+1.23693612e-01j, 8.49745423e-02+6.37954576e-02j, 7.18887232e-02+1.75903579e-01j, -6.08588164e-03+2.03191283e-01j, 6.86348025e-02-2.78848587e-01j, -4.14352560e-02-7.92352365e-02j, 1.99800580e-02-1.07011810e-01j, -4.77750533e-02-4.29164779e-02j, -9.80129418e-02+2.26179330e-01j, 2.44211579e-03+8.87315263e-02j, -2.48518186e-04-2.58477922e-02j, 1.46163656e-02+2.66665629e-02j, -1.08518799e-01-1.22626080e-01j, -4.62433206e-02+6.55029395e-02j, -9.33013316e-02-1.22087077e-01j, -1.31539219e-01-2.41402172e-02j, 2.25238757e-01-4.21429135e-02j, 6.27985064e-03-1.07195959e-01j, 4.34640320e-02+5.35187773e-03j, 7.32060940e-02-8.45846618e-02j, 1.83126542e-01-1.06954649e-01j, 2.22212559e-03-1.29315970e-01j, 6.01963053e-03-3.51904776e-02j, 1.02955536e-01-3.85218206e-02j, 9.46926580e-02-7.37961277e-02j, -8.61772814e-02+1.07443737e-01j, + 2.04379335e-03+5.94079303e-02j, 8.23537953e-02-1.41231083e-02j, -8.33955001e-02-7.33002238e-02j, -4.63586972e-02-7.49582675e-02j, 1.44258446e-01+5.05833339e-02j, -7.26785087e-02+7.99070748e-03j, 9.65967758e-02+2.55373847e-03j, 4.56168318e-02-6.98355136e-02j, 1.34466635e-01+9.33168643e-03j, 1.35620410e-01-3.63893984e-02j, -2.18310783e-01-9.07642078e-03j, 2.41046715e-02+8.68133750e-02j, 8.46941220e-02-9.87087721e-02j, 2.32699075e-02+7.70324105e-02j, -6.83066191e-02+6.26029815e-02j, 3.96917401e-03+3.19047344e-02j, -1.93167112e-02-5.87602583e-02j, 6.40947853e-02+3.49325001e-02j, -8.48481277e-02+1.00080104e-01j, 1.43703227e-01-2.70626163e-02j, -1.56896525e-01-4.98153190e-02j, -1.06529060e-01+1.09204216e-01j, 1.34564483e-02-2.22232431e-01j, -5.20802942e-02-5.67593041e-02j, 6.29414647e-02-1.10240712e-01j, -1.54707424e-02-6.35737164e-02j, 8.94634583e-03-1.06767329e-02j, -4.21134431e-02-3.53658066e-02j, 2.41746297e-02-3.68212148e-02j, -9.21559781e-02-2.99118897e-02j, + -5.89654642e-02-2.28852318e-02j, -5.20985361e-02-1.16771130e-01j, 5.35843151e-02-1.32214156e-02j, 4.58936445e-03+3.34103858e-02j, -1.46128686e-03-7.50434059e-03j, -1.37118260e-01-2.96979592e-02j, -4.28133426e-02+3.29193671e-02j, 1.22565726e-01-6.37325294e-02j, -5.96435200e-02+6.19807323e-02j, 8.28472218e-02+1.93521885e-02j, -8.88354299e-03-1.16922356e-01j, 1.17046722e-01+7.55087525e-02j, 1.11458497e-01-4.97578367e-03j, 3.03775840e-02-6.26278785e-02j, 9.34835767e-02-8.35671209e-02j, 1.92817644e-01+6.09168886e-02j, 1.55965719e-02-3.49551218e-02j, -9.23258088e-02+2.02094665e-01j, 7.07259110e-02+6.29610500e-02j, 2.65355792e-02-1.45360966e-01j, -8.38484133e-02-2.25673551e-02j, -5.99920073e-02+1.19442828e-01j, 3.08096147e-02+2.05383373e-01j, 1.46680157e-01-1.34303106e-01j, 1.78416469e-01-2.56761475e-02j, -7.04073547e-03-4.26410412e-02j, 5.92741489e-03+2.73194162e-02j, 3.28330300e-02+1.38975663e-01j, 1.36088703e-01-7.00656141e-02j, -7.16088585e-02-5.01751384e-02j, + 1.07261982e-01-6.08676344e-02j, 3.29984881e-02-4.11527154e-02j, -1.22180830e-01-1.79219988e-01j, 1.52540838e-01-3.98900946e-02j, -6.59340891e-02-1.13945351e-01j, 3.26860116e-02+7.75988849e-02j, 1.84680188e-03-7.15874930e-02j, 5.75188825e-02-1.59627565e-01j, -1.45799524e-02+1.40916322e-02j, -1.89600216e-02+2.20952202e-01j, 3.67478575e-02+1.30282642e-01j, -9.75462649e-02+1.15756251e-01j, 1.16468796e-02+1.17487817e-01j, -2.76444195e-03+7.54195399e-02j, 1.01904254e-01+1.43117381e-02j, 6.03665982e-02-8.65537954e-03j, -1.32384893e-01-5.91759860e-02j, -1.26867457e-01-1.99641121e-02j, -7.35718904e-02+7.37721086e-02j, -4.37046524e-02-5.73821921e-02j, -4.88920306e-02+4.85533481e-02j, -2.58084890e-01-4.52105731e-02j, 8.83268017e-02-3.24794517e-02j, 3.97109460e-02+2.31464221e-02j, -8.74443503e-02+5.05459657e-02j, 3.49357665e-02+5.74013249e-02j, 7.76023292e-02+1.24157281e-01j, 4.67657992e-02+8.54501007e-02j, -2.73903139e-02+3.20710850e-02j, -7.22744938e-02+2.98218349e-02j, + -1.66836536e-02-5.55139728e-02j, -1.00817364e-01+1.98738235e-02j, 1.06000799e-01-4.17864489e-02j, 2.47089963e-02-6.89030059e-02j, 1.02071912e-02+1.40803829e-03j, -4.29064727e-02+1.48247071e-01j, 8.86549012e-02-1.49688762e-01j, -1.37487726e-01-6.88685909e-02j, 9.74446290e-02+3.34782789e-02j, 3.09376006e-02-8.18948969e-03j, -6.07821142e-02+2.05709303e-02j, 6.20301019e-03-1.07661389e-01j, 2.66360798e-02-1.95200123e-02j, -8.70121352e-03+6.27192787e-03j, 5.67467889e-03-4.71688645e-03j, -3.96568337e-02+2.60335168e-03j, 1.26272851e-01-7.88612171e-02j, 2.39896969e-02-1.94449288e-01j, 1.01939995e-01+5.40381344e-02j, 3.38010121e-02-1.07535239e-01j, 1.01694129e-01+1.58769881e-01j, -1.60525228e-01+1.61402777e-02j, 2.46147533e-02+1.84478112e-01j, -2.24323874e-02+1.44766330e-01j, -7.44818491e-02+1.10475796e-01j, -7.03647417e-03-7.89877995e-03j, -7.12605582e-02-6.00421868e-02j, 8.19735532e-02+3.10232290e-02j, 1.29199728e-01+8.64579318e-03j, 1.04093008e-01-2.16880641e-02j, + 2.62815057e-02-3.82377454e-02j, -1.62557224e-01-1.01320720e-01j, -5.68005830e-02-6.94736514e-03j, -1.49055391e-01+5.18207090e-02j, 6.27178782e-02+1.01489809e-02j, 1.25981379e-01-8.58405608e-02j, -8.20377419e-02+8.24372614e-02j, 6.37946588e-02+8.57050701e-03j, 6.54024538e-02+4.63840214e-02j, 6.18224834e-02-2.22489702e-02j, 1.17291795e-01-7.38374742e-03j, 1.48954910e-02-3.86650743e-02j, -3.77589928e-02-1.39936721e-01j, 4.52316221e-02-1.57936117e-01j, -6.23943129e-02+4.81748404e-02j, -1.92620084e-02-2.15996053e-02j, 1.71279612e-01+7.73412683e-02j, 2.23232062e-02-5.61065685e-02j, 1.57779087e-01+7.85148897e-02j, 1.40230327e-03+6.35368648e-02j, 8.38305347e-02+1.63118880e-02j, -9.03278369e-02+1.01139458e-02j, 3.54020248e-02+1.78314505e-02j, -1.70735336e-01-1.07777517e-01j, -3.34738370e-02+7.44591431e-02j, -2.16874208e-02-2.16863527e-02j, 1.15546757e-01-1.47632133e-01j, -1.64688932e-01+4.66255948e-02j, 5.97823744e-04-2.02720511e-02j, 2.98168578e-02-9.41198035e-02j, + 6.21270773e-02+6.40834784e-02j, 2.58933539e-02-2.42667870e-01j, 5.70136258e-02-3.77350337e-02j, 1.98579632e-01-9.20701075e-02j, 9.55640150e-02+3.54843433e-02j, 7.45928560e-02+4.26588872e-02j, 6.09447733e-02+3.16539556e-02j, -1.80171093e-01+5.60133264e-02j, 9.40854193e-02+4.31389113e-02j, 3.03850816e-04-2.85530728e-02j, 5.41410801e-02-6.13161714e-02j, 9.12148494e-02+1.80281943e-01j, 5.09948266e-02-3.86997536e-02j, -1.91113131e-02+1.94498984e-01j, 2.08692927e-01+6.43547140e-03j, 5.20633056e-03-1.90022093e-03j, 3.62398834e-02+1.08762806e-01j, 1.33590408e-01-1.61775350e-02j, -9.28966408e-02-5.91354052e-02j, 3.90924936e-02+3.49619784e-02j, -1.10597598e-02+1.62593761e-01j, -1.19019882e-01+1.11694210e-01j, 7.64944486e-02+8.29783985e-02j, 3.19470164e-02-2.07941529e-01j, -6.16504642e-02-5.17749153e-02j, -9.19641302e-02+1.26001118e-01j, 7.48796227e-02-5.35446337e-02j, 8.61395046e-02+7.66827772e-02j, 5.67446200e-02-1.44510489e-01j, -3.64513131e-02-9.95038225e-02j, + -5.23694938e-02+1.68673670e-01j, -9.98489889e-02+4.49214566e-02j, -2.62137478e-03+5.31844467e-02j, -1.97293197e-02-1.01779130e-02j, 6.56118297e-02-1.39819961e-01j, 1.07078888e-01-9.60455951e-02j, 4.04114157e-02-2.75185153e-02j, -1.06731160e-01+2.45576423e-02j, 3.97224538e-02+4.80422979e-02j, -1.41155662e-01+5.37056668e-02j, 3.94804097e-02-5.91553615e-02j, 1.02421169e-01+1.97936296e-01j, -1.01728301e-01-1.38399695e-02j, 8.76776513e-02+1.40003856e-02j, -1.53801875e-02+2.04027278e-02j, -8.81370764e-02+7.21575549e-02j, 2.88433274e-02-1.42749089e-01j, -6.16490703e-02-2.20430462e-01j, -1.98880578e-02-7.67322432e-02j, 5.79127107e-02-1.00419699e-02j, -1.09662385e-02+1.26745293e-01j, 7.36261795e-03-1.62045074e-02j, -1.45951390e-01-8.98045669e-02j, 1.04518882e-01+7.87311257e-02j, 1.84677017e-01+2.57397149e-02j, 9.20387231e-02+4.51211489e-02j, -8.11699179e-02+6.13269405e-02j, -7.54782810e-02-1.53812051e-02j, -2.27439779e-02+5.40599197e-02j, 5.27509423e-02+4.94672673e-02j, + 6.01908515e-02+7.08980366e-02j, 7.29386254e-03-4.35495079e-02j, 2.59865264e-02+5.23991312e-03j, -2.80790961e-02-3.17079888e-02j, 3.06137050e-02+7.10525322e-02j, 1.98725682e-01+1.63806997e-01j, -3.85808044e-02+3.17497500e-02j, -8.38991266e-02-8.29634220e-02j, 1.14568111e-01-2.51524437e-01j, 1.89161580e-01+1.22405055e-01j, 2.67369898e-02-6.29372223e-02j, -5.55112811e-03+8.24912321e-02j, 3.06911272e-02+1.24362478e-01j, 6.90052196e-02+4.78403406e-02j, 3.32511878e-02-5.54954803e-02j, -6.83065225e-02-9.83139293e-02j, -2.24205878e-03-1.08330998e-01j, 1.32158911e-01+6.21895108e-02j, 6.04041228e-02+2.26998786e-02j, 1.19910251e-03+2.40133006e-02j, 1.95384495e-02+7.25223079e-02j, -7.51114128e-02+7.50023940e-03j, -6.91753048e-02-1.84426984e-01j, 8.93361350e-02+6.14020197e-02j, -1.11027212e-02-2.73006053e-02j, -1.58027594e-01+1.12196684e-01j, 6.13191254e-02+2.98921562e-02j, 9.36940475e-02+1.74832860e-01j, 3.54488913e-02-1.86012865e-02j, 1.18886717e-01-5.60421606e-03j, + -5.08023225e-02+1.58187433e-01j, 2.05543121e-02+2.36229478e-02j, 7.56607990e-02-9.20635412e-03j, 3.04571802e-02-5.32735635e-02j, 1.05681520e-02+7.99310770e-02j, 1.00900200e-01+3.39036295e-02j, 6.00254366e-02+1.29251252e-01j, 1.73747341e-01-3.50700834e-02j, 8.68889594e-02+4.32124921e-02j, 1.20809063e-01-9.57225859e-02j, -5.08827469e-02-1.56682461e-01j, -5.51578706e-02-1.60825072e-01j, 7.75492052e-03+3.62310778e-02j, 2.70830573e-02+3.42352710e-03j, -3.35299324e-02-3.07678678e-03j, -2.09542652e-02-8.28876236e-02j, 1.67136215e-03+9.77623412e-02j, -8.33024445e-02+9.68319454e-03j, -1.27694754e-01-3.43756377e-02j, -1.05215118e-03+1.09484097e-01j, 5.77644996e-02+2.26376332e-02j, -2.27042043e-02+4.64923429e-02j, -7.52065556e-03+8.32320454e-02j, -3.45650834e-02-9.36227416e-02j, 1.58893895e-02-5.88622612e-02j, 6.75234381e-02+1.17750436e-01j, 9.91136713e-02-4.90548054e-02j, 1.14744296e-03-2.03805309e-01j, 1.26681748e-01+7.20946491e-02j, 1.72091738e-01+9.45687729e-02j, + -2.23781476e-02-3.05658385e-02j, -4.79846553e-02-9.53644599e-02j, 8.98978713e-02+3.73340639e-02j, 9.71904756e-02-5.07401492e-03j, 4.70042328e-03+2.98136201e-02j, 3.20602243e-02+8.90046751e-03j, 2.91870381e-01+1.56310942e-02j, 1.47571000e-02+1.74082211e-01j, 1.98727480e-01+1.81545936e-02j, 5.76140047e-02-1.37512019e-01j, 2.84157891e-02-8.90169341e-02j, 2.58144712e-02-8.66533513e-02j, 1.26007423e-01-1.42353852e-04j, 1.22011887e-02-1.50599335e-01j, -1.03678605e-01+1.77343389e-02j, 1.01880582e-01+1.02053135e-01j, -6.89911020e-04-1.34757213e-01j, -4.67669409e-02+5.62588217e-02j, 5.42306518e-02-4.70868860e-02j, 1.87819392e-02+5.88306140e-02j, -1.39180077e-01-5.74473723e-02j, -7.71319085e-02+1.05052464e-01j, -1.76084377e-01+4.53754001e-02j, 5.78987630e-02-1.39030598e-01j, -1.36379204e-03+1.03197101e-01j, -1.29842079e-01+6.46203124e-02j, 3.63331025e-03-1.52651696e-03j, -9.63370297e-02-5.23631453e-02j, 7.11523907e-02-7.71438142e-02j, -3.33129359e-02+4.04006262e-02j, + 2.49142373e-02+1.48066271e-01j, -2.26183059e-02+7.66734818e-02j, -5.45495074e-03-1.19942778e-01j, 9.13909578e-02+4.79952618e-02j, -5.35918216e-02-1.60654037e-02j, 5.98871312e-02-1.87532022e-02j, -1.12910440e-01-2.78610231e-02j, 1.46838755e-01+9.92565647e-02j, -4.13814974e-02+7.56087587e-02j, -4.88973691e-02+3.13114227e-02j, 7.56532879e-03+9.34644447e-02j, -2.67290794e-02-3.42410745e-02j, 8.46376955e-02-1.22432585e-01j, -3.13201588e-02-3.59657622e-02j, 1.52126152e-01+9.91205244e-02j, -9.45677226e-02-8.05276033e-03j, 5.46044728e-02-2.63756752e-01j, 1.95345701e-01+1.33669072e-02j, -3.25932513e-03-5.43829049e-02j, 1.53950498e-01-1.42848111e-01j, 1.48524300e-01+8.79890137e-03j, 1.17396603e-01+2.64318281e-02j, -2.62384138e-02+1.38751108e-01j, -9.52598923e-02+7.62648401e-02j, -1.80631676e-01-1.35669199e-01j, 8.51086298e-03-1.10183317e-01j, -8.83923576e-02+1.37131346e-01j, -3.89492392e-02-8.90366047e-02j, 1.90119483e-02+4.19438222e-02j, 1.12797080e-01+7.86580908e-02j, + 7.80716814e-02-9.09945481e-02j, 8.64121030e-02-7.22343210e-02j, -6.86716918e-02+1.03223441e-01j, 9.38556460e-02+7.85191865e-02j, 3.12389310e-02-8.62865526e-02j, 1.19593208e-02+6.74798173e-02j, -9.97752646e-02+4.73740307e-02j, 8.50920494e-02+1.21420677e-01j, -3.36867683e-02+7.31079808e-02j, 7.80684211e-02-1.11358256e-01j, -1.03606051e-01-1.00017901e-01j, 7.46662567e-02-4.58176146e-02j, -1.77215554e-01+5.14045000e-03j, -7.35851406e-02-5.88169005e-02j, -2.34091949e-02+5.56784850e-02j, -1.92734776e-01+5.23357550e-02j, 1.20534005e-01+6.92412538e-02j, -3.03040274e-02-2.43467856e-02j, 1.60451360e-01-1.02238503e-02j, 6.15204165e-02-1.94133488e-03j, -2.33847089e-02-8.66114982e-02j, 4.19745705e-02-4.99401327e-02j, -1.03928808e-02+8.20517312e-02j, -1.72244615e-03-4.42743317e-02j, 1.67168913e-01-3.07829598e-02j, -9.92849889e-02+4.65088178e-02j, -5.21084550e-02+2.70599004e-02j, -1.44242685e-01+1.42099698e-01j, 1.31564015e-01+6.03947617e-02j, 7.79295470e-02+1.16599297e-01j, + -1.44508140e-01+3.90326398e-02j, -1.63189060e-01-4.80102773e-02j, -4.23892524e-02+7.24586719e-02j, -1.08354291e-01+2.46926730e-02j, -3.31000925e-02-2.02469979e-02j, -1.06440911e-01+5.74076867e-02j, 2.98674990e-02-2.56460099e-02j, 3.27784317e-02-1.09277698e-01j, -1.11743589e-01-5.16542702e-02j, -4.38449856e-03+1.25111334e-02j, 4.20069024e-02+6.10391773e-02j, -8.31398473e-02-3.81548729e-02j, 1.09141869e-01+1.50926344e-01j, -4.57654467e-02-6.46747717e-02j, -8.54458173e-02+1.86067568e-01j, 6.94294608e-02-8.10150126e-02j, -5.70344424e-02+7.83521518e-04j, 3.21090931e-02+9.47319893e-03j, -6.02959548e-02-1.01689715e-01j, 1.25328049e-01+1.14694700e-02j, -3.84840481e-02-8.31927703e-02j, -6.76446553e-02-1.86440782e-01j, -9.65863639e-02+4.30146576e-02j, 1.86429327e-01+1.77285461e-02j, -2.79125197e-02+1.55599615e-02j, 9.66942708e-02+5.05933675e-02j, -1.96844343e-01-9.05549515e-02j, -1.06330695e-01-1.29754415e-01j, 9.69592860e-02+7.87237719e-02j, -3.20763173e-03-6.01830255e-03j, + -5.75846436e-02-3.07527027e-02j, -2.15090340e-02-1.13335909e-01j, 2.05999323e-02-1.64092718e-02j, 6.20217109e-02-7.21962400e-02j, 2.52569512e-02+8.67133723e-02j, 6.73469570e-02+5.06801423e-02j, -4.47799880e-02-1.27433227e-01j, -2.43147056e-02-4.19481682e-02j, -3.99145646e-02+1.36650217e-01j, -1.17600891e-02-3.67255385e-02j, -2.41082251e-02-1.48703792e-01j, 1.45917987e-01-2.09551629e-02j, 1.12455567e-01+4.32809709e-02j, -1.41748964e-01+8.50598353e-02j, -3.11770116e-02-5.18172723e-02j, 1.83579810e-01-7.06905345e-03j, 9.71116808e-02-7.25783826e-03j, -6.06413346e-02+1.83309774e-02j, 1.32067152e-01-8.04329623e-02j, -3.70830182e-02+3.25924415e-02j, 5.99945661e-02+1.39581640e-01j, 4.95057896e-02+1.41585780e-03j, 1.27163533e-01-2.79494886e-02j, -1.12806297e-01-1.38597417e-01j, -1.70331848e-01-6.41623156e-02j, 1.13320890e-01+4.80817353e-02j, 2.35832464e-01-5.92082391e-02j, 8.74837897e-02-2.86661849e-02j, 6.11698809e-02+6.06877492e-02j, 4.24028809e-02-6.62392146e-02j, + 4.30315505e-02-2.17789106e-01j, -2.72931426e-02+1.52670758e-02j, -3.82654806e-02+9.56802873e-02j, 2.43401149e-02-1.78124583e-02j, 9.02901686e-03-1.65710546e-01j, 8.04870293e-02+5.50553769e-02j, -4.69870057e-02+3.41343271e-02j, -3.50577896e-02+7.23143438e-02j, 1.10225646e-01-2.15752004e-03j, -9.61299965e-02-4.18347593e-02j, 8.68479349e-02+4.70126112e-02j, -1.07545082e-01+2.49148829e-02j, -4.53040726e-02-1.06734716e-01j, -1.59436033e-02+8.10286351e-02j, 2.02915812e-02-6.81132744e-02j, -6.08982393e-02+8.40773887e-02j, 1.50191978e-01-6.42097008e-02j, 1.35274591e-01+1.57431907e-01j, 3.53273620e-02+7.14369281e-02j, 1.81320909e-02+7.20914621e-02j, 6.03721972e-02+1.96226127e-01j, -3.18042660e-02-3.39904414e-02j, -1.19303840e-01+6.14160382e-02j, -1.76524156e-02-8.04986522e-02j, 1.76157967e-02-1.36875912e-02j, -4.49031451e-02-1.89495355e-01j, 1.26341022e-02-4.84818365e-02j, 7.93666935e-02-1.20859425e-01j, -9.00060617e-02+7.53951193e-02j, 6.15384669e-02+1.81702718e-01j, + -1.96562939e-02+6.02270326e-02j, -1.53637264e-01-3.42216746e-02j, 5.82845366e-02+1.35589726e-01j, -9.69854953e-02+7.81307161e-02j, 9.47424015e-03-7.67839223e-02j, -5.21777176e-02+1.18463908e-01j, 1.08597440e-02+7.34720754e-02j, 1.25753709e-02-4.59227875e-02j, 4.66065304e-03+3.16832178e-02j, -1.70642799e-01+1.09175443e-01j, -1.07616067e-01-6.77062304e-02j, -4.94690131e-02-1.33454471e-02j, -1.13671465e-01-1.13124774e-02j, 1.79311462e-01+1.36206373e-02j, -5.44546549e-02+2.39954931e-01j, 1.53720058e-01+8.17470362e-02j, -1.65785647e-01+4.99276923e-02j, 1.24051085e-01+2.08575029e-02j, -1.27344695e-02-1.00323698e-01j, 1.26323841e-01-1.75232843e-01j, 1.42829963e-02+9.51676108e-02j, -1.36837621e-02-5.10102254e-02j, -1.09035252e-01+3.04699753e-02j, -5.73977327e-02-9.67364763e-02j, -4.18955867e-02-7.26363284e-03j, -1.11110425e-01+9.11072318e-02j, -3.33402440e-03-9.81640668e-02j, 5.00153545e-02+2.96772715e-02j, 8.34464143e-02-1.07141828e-01j, 1.66627515e-02-1.76768451e-01j, + 3.01046178e-03+4.29920679e-02j, 3.90382225e-02+6.48627085e-02j, -1.29633542e-01-1.21639020e-01j, -1.81455901e-02+1.81332342e-02j, 1.70046497e-01+9.18523538e-02j, -7.49819636e-04+2.57010470e-02j, 6.14006255e-03-7.49534371e-02j, 5.73079131e-02+6.45021320e-02j, -1.25906199e-01+3.61504866e-02j, -4.14229989e-02-2.91283203e-02j, 3.22455405e-02+8.63451878e-02j, 1.23237528e-01-1.89968509e-01j, -3.05088062e-02+1.73009137e-02j, 2.14194747e-03+5.29985319e-02j, 6.96329432e-02+2.60627319e-02j, 1.57695179e-01+8.59454119e-03j, 7.26680354e-02+7.21484481e-02j, 7.00651142e-03-2.90372350e-03j, 2.90015482e-02-5.68542701e-02j, -1.27693027e-01-1.14964625e-01j, 1.50753348e-02-1.36610446e-01j, -1.47676083e-01+8.13290718e-02j, 9.24954421e-02+3.54388660e-02j, 1.81954041e-01+1.07582710e-01j, 1.15127848e-01+5.98445734e-02j, -6.47767365e-02+1.22084642e-01j, 5.54779597e-02-2.11336155e-01j, 2.33200724e-02+3.44422083e-02j, -3.99506520e-02-1.46402335e-01j, -3.39094996e-02-2.32080319e-02j, + 6.38032383e-02+4.58309555e-02j, 9.80627186e-02+6.74309177e-02j, 2.09243817e-01-9.21844569e-02j, 1.16068394e-01+3.58375950e-02j, 2.34470731e-02+1.34662899e-02j, -4.87953052e-02-3.39548474e-02j, 1.77551778e-02-7.33967642e-02j, -4.28970865e-02+2.14591815e-02j, 1.36029417e-01-9.66574708e-02j, -3.16822200e-02+1.06454016e-01j, -1.93320117e-01+1.76505036e-02j, 1.09916758e-01+1.27398554e-01j, -1.65850940e-01+7.04898942e-03j, -6.53608621e-02-1.87281647e-01j, -1.57179762e-02+3.65905427e-02j, -4.77377390e-02+5.01770606e-02j, 7.38286054e-02+5.86402502e-02j, 2.00220886e-01+2.14556567e-02j, -7.99321902e-02+1.20661845e-01j, 2.25130739e-02-7.92813095e-02j, 9.39404226e-02+4.23514982e-02j, 5.59759953e-02+5.29013915e-03j, 1.42272381e-01-2.03889918e-02j, -7.70692925e-02+2.18788591e-02j, 9.46416245e-02-5.40567083e-02j, -1.16864668e-01-1.17453747e-02j, -6.80245475e-02-8.85472661e-03j, -5.07648557e-02-1.41856238e-02j, -6.57054741e-02+4.87753999e-02j, 6.79140250e-02+7.57999993e-02j, + 8.31558858e-02+4.88031390e-02j, 7.04245127e-02+5.11799739e-02j, 1.92019820e-01+1.63346011e-01j, -1.08430098e-01+2.88148366e-02j, 2.15534804e-02-2.40090002e-02j, -2.83413932e-02+7.28009270e-02j, 2.77128550e-02-7.17129530e-02j, 4.43451848e-02+4.62015889e-02j, 2.29868386e-02-1.58564488e-01j, -1.80745027e-01-3.09626852e-02j, -5.25473622e-02-5.09485093e-02j, 4.13635441e-02+2.95240616e-03j, 3.46266625e-02+3.40501706e-02j, -1.36957085e-01+5.93795536e-02j, 1.71716569e-01+6.62369454e-02j, 2.00789628e-02+1.02579168e-01j, -2.49268976e-04+4.05793649e-03j, -8.70948659e-02+2.67855934e-02j, 9.58058704e-02-3.92343326e-02j, 6.37344353e-02+2.91954856e-02j, -1.62573041e-02+1.44050769e-01j, -2.12950381e-01+1.05380057e-01j, 1.54420103e-02-1.58531345e-02j, 4.62275644e-02-1.44131724e-02j, 9.63943826e-03+1.43294871e-01j, -6.82715621e-02+7.72801050e-02j, 1.19392259e-01-4.32006940e-02j, -9.25898691e-02+1.73642675e-01j, 7.87258333e-02-5.00345685e-02j, 6.74252100e-02-3.22021492e-03j, + -1.05938764e-02-4.80682200e-02j, -3.79109088e-02-7.18862647e-02j, -7.85329094e-03+5.08832953e-02j, -1.22207965e-01-2.08985568e-01j, 3.86004176e-02+9.75474606e-02j, 5.47838699e-02-2.51857867e-03j, 7.32135146e-02-2.02847686e-02j, -9.54663596e-02-1.51302713e-01j, 1.17232603e-01-8.67695572e-04j, 1.13627781e-02-2.45710953e-01j, 1.21005570e-01-1.25331270e-01j, -4.93568188e-02-6.26654349e-02j, -1.10411812e-01+1.72674386e-02j, 7.51406502e-02+1.35621387e-01j, -9.34619657e-03+4.06835362e-02j, -1.69436966e-01+2.11265428e-02j, 9.44593750e-02+9.45454295e-02j, 6.29973849e-02+7.81106789e-03j, -2.31884880e-02-6.08022409e-02j, -1.28506085e-02+4.57155954e-02j, -1.78724877e-01-8.40636436e-02j, -2.74516446e-03+6.87567686e-02j, 1.66154851e-01+2.97763171e-03j, 8.62945953e-02+1.33624387e-01j, -1.23971712e-01+1.06764084e-01j, -8.40377309e-02-4.45037883e-02j, -3.26308419e-02-1.03329380e-01j, -1.06682028e-01+9.15113745e-02j, 1.13743906e-01-7.02685477e-02j, -1.06680734e-01-1.29465759e-02j, + -6.97277691e-02-1.31064309e-01j, -1.10091153e-02+2.23611713e-01j, -4.61136052e-02-8.17268905e-03j, -1.69987303e-02-9.10722748e-02j, 2.79034389e-02-4.16172595e-02j, 1.24405356e-01-5.92755001e-02j, 3.02072420e-02+3.43359378e-02j, 1.10650997e-01+6.44841711e-02j, -9.59093007e-02-1.11423798e-02j, -5.96787368e-02-7.04578949e-02j, 3.28918399e-03+1.32284061e-01j, -3.72764227e-02+1.55273833e-01j, 2.06921775e-02+1.00442523e-01j, 7.21325549e-03+5.71288626e-02j, -2.14453527e-02-4.68398310e-02j, -6.82026389e-02-1.12497749e-02j, 4.92381808e-02+6.02284521e-03j, 7.83207240e-02+2.07448764e-02j, -5.05939363e-02-3.85781833e-02j, -3.35242535e-03-2.19084108e-02j, -3.49651101e-02+1.07847538e-01j, -2.45290850e-03-6.24826573e-02j, -1.51023459e-02+5.37010336e-02j, 6.37016602e-02-1.23760494e-01j, 2.91215038e-02-2.81493758e-02j, -3.39612485e-02+8.42272097e-02j, 7.35061854e-03+4.18985182e-02j, 1.12694901e-01+3.44174546e-02j, 2.75030448e-02-1.15362720e-02j, -6.56825803e-02+7.69914664e-02j, + 2.45522893e-01+1.94445453e-01j, 1.95565169e-02-6.02333458e-02j, -4.23341023e-02-4.08553715e-02j, -1.65720107e-02+1.11636285e-01j, 6.43254764e-02+5.20975294e-02j, 1.16324230e-01+4.30064237e-02j, -2.35493523e-04+7.94067955e-02j, -3.13234546e-02+3.31928019e-03j, -1.21907959e-01+8.94697709e-03j, -5.86229364e-02+5.00083180e-02j, 1.68440179e-01+1.58008999e-01j, -1.09277389e-02-5.63942582e-02j, -4.33874746e-02-9.18770776e-02j, -3.70318230e-02+2.10558944e-02j, 7.28110664e-02-4.99081181e-02j, 1.31921880e-01-4.54760418e-03j, 3.94635300e-02-8.20549821e-02j, 1.48897886e-01-1.45917759e-01j, -1.18265542e-01+3.70289451e-03j, 3.85086358e-03+1.91440435e-01j, 7.03135105e-02+2.60050811e-02j, -4.21039425e-02+3.01867113e-02j, -1.39706071e-01-2.85504702e-02j, 1.81921714e-03-1.40860236e-01j, 4.20339153e-02+1.95430738e-01j, -2.30135850e-02+3.09767448e-02j, 1.29258195e-01+9.14976478e-02j, -1.58756793e-01+1.28822164e-01j, -3.50036492e-02+8.00893734e-02j, 3.02776094e-02+1.42172163e-03j, + 2.57023140e-03-1.85433098e-02j, 3.72525284e-02+1.05139165e-01j, -9.12678942e-02+2.18607649e-01j, -1.46180909e-01-5.56793105e-02j, -6.56707703e-02-3.19916670e-02j, -7.38160928e-02-1.34669909e-02j, 3.23396348e-02-2.36520392e-01j, 3.30483293e-02-1.02266954e-01j, -4.19639544e-03-6.59678771e-02j, -8.19179151e-02+4.51704171e-02j, 3.09570371e-02-5.32005536e-02j, -5.22790586e-02-3.26500699e-02j, 1.56455025e-01-1.25231125e-01j, -5.05761174e-02+8.32852024e-02j, -2.59554971e-02+4.37847037e-02j, 2.16226296e-01-1.45471321e-01j, 2.65695033e-02+1.26666001e-01j, 4.68381033e-02+1.99629530e-01j, -1.50825778e-02+3.50747365e-02j, 1.26681152e-01-9.75019945e-02j, -1.71499088e-02-2.09581248e-02j, 1.61066501e-01+9.30902661e-02j, 2.60354119e-02+4.88141211e-02j, -6.21761636e-03-4.91509192e-03j, 1.70671987e-03-1.58639200e-02j, 9.95150572e-02-1.68503093e-02j, -3.98240701e-02-2.10542532e-02j, -7.76479029e-02+7.39797509e-03j, -5.77613183e-02+1.49932253e-01j, -1.67637878e-01+2.32658756e-01j, + 4.10173784e-02-4.51688638e-02j, 8.65002182e-02-1.06406855e-01j, 8.46830254e-02-1.72799554e-01j, 1.45422299e-02+2.59367720e-02j, 4.41673701e-02+1.11838918e-01j, 3.26970392e-02+4.00980128e-02j, -5.24772172e-02-7.49030751e-03j, -8.86683859e-02+1.79684474e-02j, -7.43158293e-02+1.44772160e-01j, -1.15935800e-01+6.86790801e-02j, 1.00946401e-02-5.68803310e-02j, 1.40177229e-01-1.19713358e-01j, -1.95130289e-01+5.29709085e-02j, 1.35467559e-01-2.15847353e-02j, 7.09552640e-02-7.66496576e-02j, -8.57302586e-02-1.37409094e-01j, -5.84144286e-02+4.22725006e-02j, -1.13523127e-01-2.08960999e-02j, -1.27785798e-01+2.27385357e-01j, 1.56444767e-03+1.48328917e-02j, 1.82904744e-02+9.01221738e-03j, -4.38128497e-03+4.96827820e-03j, -6.21944033e-02-7.90469632e-02j, 3.44125896e-04-4.79139098e-02j, 8.43927403e-03+4.11354177e-02j, 5.77038887e-02+8.29289688e-02j, 1.22039812e-01+1.12839590e-01j, -1.05530964e-02-1.15582561e-01j, -8.10699111e-02-1.07817350e-01j, -1.20022792e-01+6.78991377e-02j, + 6.48498574e-02-1.02145011e-01j, 2.90657255e-02+3.23596981e-02j, -1.43699949e-02+3.12920727e-02j, 1.71904194e-01-1.42590729e-01j, -5.09140335e-02+3.29766258e-02j, -3.01653038e-02+6.95227171e-02j, -3.76048324e-02-7.94865380e-02j, 6.51687233e-02+1.42580112e-01j, -1.39256310e-01-1.85980964e-02j, -1.10957689e-01-8.32129945e-02j, -1.22937408e-01+1.05433745e-01j, 2.32827863e-01-7.84040766e-02j, 9.68891514e-02+5.50536106e-02j, -7.66146565e-02-1.07485097e-01j, 3.75854655e-02+1.78256175e-02j, -1.05510057e-01+5.39334433e-02j, 2.59293770e-02+5.25056351e-02j, 4.17658585e-02+2.16550525e-02j, 1.79434516e-02-3.79639158e-02j, 4.54758271e-02-1.62169263e-01j, -9.15537346e-02-4.55546358e-02j, -2.87057950e-02-1.51850321e-01j, -4.73431627e-02-4.27936002e-02j, -7.34456848e-02+1.14503191e-01j, 3.21215086e-02-1.16222983e-01j, -1.86452641e-03-1.97148035e-02j, 9.35736392e-02+6.43359360e-03j, 9.90720039e-02+6.49407638e-02j, -1.30861723e-01-1.10397435e-01j, -6.06187143e-02+4.34780133e-03j, + -2.59141536e-02-8.36660746e-03j, 7.99764395e-02+2.05827485e-03j, -6.79710115e-02+2.19632538e-01j, -8.17267130e-03+1.30090034e-01j, 2.42203491e-02-1.18482312e-01j, -9.65525880e-03-7.27160937e-02j, 1.71710961e-02+3.97131195e-02j, 2.44032297e-02+1.55142147e-01j, -6.95618609e-02+1.14777484e-01j, -3.04082242e-02-2.56808488e-01j, -3.31333938e-02-4.42257523e-02j, 9.09829518e-02-6.41355665e-02j, 1.86082355e-01+8.21534305e-02j, 4.98683358e-02+2.30843433e-02j, 8.69232620e-02-5.72734258e-02j, 9.65089746e-02+4.63738692e-02j, 1.29934009e-01+6.98672714e-03j, -9.55106837e-02-2.11435206e-02j, -1.07437846e-01-4.34196605e-02j, 5.95822062e-02-1.60023155e-01j, 1.45094000e-01+3.62098607e-02j, -4.08020893e-02-3.54469118e-02j, -6.41922431e-02-1.50165876e-01j, 1.37778604e-01+1.57148644e-01j, 1.29772868e-01+3.87413012e-03j, -3.85445235e-04+9.15633467e-02j, 1.46217004e-02-7.02722233e-02j, -9.12225513e-02-1.34467186e-01j, -3.51468484e-02+4.68272859e-02j, -5.28148474e-02-7.05527841e-03j, + 9.85502435e-02-1.44725584e-01j, 4.52535985e-04-4.44306972e-02j, 1.03723988e-01+1.65607843e-01j, -4.21749097e-02-5.54886967e-02j, -9.10799975e-02+7.58681664e-02j, -2.17843207e-02+9.52639644e-02j, -3.30284395e-02+5.94376825e-02j, 9.26534994e-02+2.66802719e-02j, 1.03979128e-02-1.37706931e-02j, 2.33812820e-01+8.59946927e-02j, 6.98746888e-02+9.14639956e-02j, -1.08516120e-01+8.58234842e-02j, 4.21850071e-03+8.71853039e-02j, 6.36273247e-02+7.74673226e-02j, -3.91881255e-02+1.50528746e-01j, 1.09723495e-01+1.04344141e-01j, 7.43803264e-02-1.19685892e-01j, 2.19504862e-02+1.67527045e-01j, -1.60452930e-02-2.00978073e-02j, 6.55173044e-02+2.93255757e-02j, -8.85404950e-02-1.20757531e-02j, 1.14761440e-01-4.57840469e-02j, -5.41528486e-02-5.53916169e-02j, 4.21003566e-02-1.93226229e-02j, 3.45660820e-02-3.52093150e-02j, 1.17626157e-01-1.16988622e-01j, 8.56072498e-02-3.37517615e-02j, -5.90244905e-02-5.24335807e-02j, -5.65206254e-02-2.43446279e-02j, 1.20279495e-01+3.42123716e-03j, + -3.05654890e-02+1.98042481e-01j, 1.08387964e-02+2.84799289e-03j, -9.91462670e-02-3.82499265e-02j, 5.61732300e-02-2.25129588e-02j, 8.25340529e-02-1.45756514e-02j, -4.43017854e-02-1.98422787e-02j, -2.75902371e-02+2.17979919e-02j, -1.90295706e-02+4.21368188e-02j, -8.80691660e-02+1.15852296e-01j, -3.90388495e-02-2.17922247e-02j, 8.14551313e-02-6.28102543e-03j, 2.79352673e-02+6.35843316e-02j, -3.36457227e-02+1.90578786e-02j, -1.45100657e-02+3.63295744e-02j, -7.00631811e-03-7.40466939e-02j, -2.90520577e-02+7.81154295e-02j, -7.99312633e-02-5.37780863e-02j, 2.30177660e-01-1.83888371e-01j, -2.98717843e-02-1.13899232e-01j, -2.05273534e-02-1.81141663e-02j, 2.96813771e-02+5.94044596e-02j, -3.18971173e-02+7.22385762e-02j, 9.83167960e-02-8.92023743e-02j, 4.25608743e-03+9.09134290e-02j, 1.56893561e-01-4.23935738e-02j, 9.05556547e-02+3.59624971e-02j, 3.15980257e-02-5.46643490e-02j, -1.15196957e-01-8.82593135e-02j, -1.61272928e-01+1.78448561e-01j, 4.00567109e-03+1.76993307e-02j, + 1.17540437e-01-1.36239393e-01j, -6.69383706e-04+5.79926839e-02j, -1.12770659e-01-5.62223146e-02j, -6.21953015e-03-5.98234743e-02j, -4.10342219e-02-5.59744623e-02j, -5.66841235e-02+4.25833208e-03j, -8.23118814e-02+5.33394692e-02j, -1.34412900e-01-1.45272792e-01j, 1.15702329e-01+1.02297961e-01j, -3.19323625e-02+1.39788468e-01j, -2.24923180e-02-6.37168336e-02j, 1.39975574e-01+2.96315967e-02j, -2.05526833e-01-8.05348577e-02j, 1.20419312e-02+1.04877206e-01j, -5.36581838e-03-2.21242391e-01j, 1.43312392e-01+9.03085637e-02j, 1.50230560e-01+9.50231348e-02j, -4.59445185e-03+1.12399647e-02j, 5.16547174e-02+8.01461708e-02j, -9.43895891e-02-3.75397968e-03j, -4.73242216e-02-1.01945370e-01j, 3.44673025e-02+1.96628490e-01j, -9.88840012e-02+8.85464110e-02j, -7.92955362e-02-2.28998407e-02j, 1.69410571e-01+7.44974887e-02j, 6.20173928e-02+1.38106734e-01j, 8.52039046e-02-1.21666670e-01j, 6.84100368e-02-1.00904176e-01j, -1.42596295e-03+1.64268960e-01j, -1.24100632e-01-1.61368165e-02j, + 1.35519012e-02-2.59310892e-02j, 9.05490250e-02+4.84747479e-02j, -4.58662366e-02+1.34930496e-01j, -1.40646551e-01-1.69831134e-01j, -3.16239770e-02-1.48493455e-01j, 1.29115221e-02-4.76191420e-02j, 1.02846452e-01-1.15790746e-01j, 1.59952958e-01+3.50029230e-02j, 5.52164979e-02+5.58300761e-02j, -2.34098143e-02+1.20508448e-01j, -4.62940339e-02-1.16252123e-01j, 7.14945735e-02+8.50853849e-02j, 1.90523893e-02+1.82220632e-01j, 8.47593047e-02-3.87876272e-02j, -1.55367396e-01+9.11388648e-02j, -8.67503920e-02+3.87326858e-02j, -7.47073348e-02+1.13616928e-01j, -8.05356534e-02+7.50838943e-02j, -4.42508043e-02+1.04776551e-04j, 1.91365405e-02+4.59602654e-03j, -5.53849081e-02+9.81402899e-02j, 5.65523118e-02-1.28923219e-01j, 1.09708674e-02-7.17405169e-02j, 5.10870804e-02-4.18029754e-02j, -2.35923190e-02-3.54344675e-02j, 1.05632412e-01-1.52723227e-01j, 2.29356400e-02+1.72003014e-01j, -7.77818089e-02-8.58774571e-02j, -4.12300311e-02-1.40778154e-02j, 3.85331791e-02+1.34956847e-01j, + 9.08599023e-02-2.22765047e-02j, -6.47141773e-02+5.39631501e-02j, 3.78096842e-02+1.20010133e-02j, 6.56218844e-02-6.51650219e-02j, 9.31690801e-04-8.33640650e-02j, -1.79665558e-01+5.36828027e-02j, -7.18696825e-02+5.98082781e-02j, -7.60979310e-02+2.96533884e-02j, 8.38090767e-02+4.64776836e-02j, -1.90640176e-01-2.67445829e-03j, -3.33244747e-02+1.46650575e-01j, -2.87164842e-02-2.38484574e-02j, -1.31368281e-01+8.97392419e-02j, 1.70551482e-01-3.06077010e-02j, -1.23763743e-02-7.87055709e-02j, 1.03033690e-01-1.32308263e-01j, 4.89975988e-02-1.35921611e-01j, 9.42844960e-02+4.92092484e-02j, 1.25975887e-01-6.46248221e-02j, 2.04355365e-02+1.39811567e-01j, -8.13697343e-02+1.30030354e-01j, 1.44452639e-01-4.59256835e-02j, 8.30262490e-02-1.07582941e-01j, -1.01352710e-01+2.50968168e-02j, 3.80275778e-02+7.06296634e-02j, 1.01240183e-01-1.09841276e-01j, 7.93654229e-02+4.00721967e-02j, -1.27232823e-01+1.45125955e-01j, -1.63935684e-01-5.06866305e-02j, -3.33110180e-02+6.38573847e-02j, + 8.29906205e-02+2.45941583e-02j, 7.72777568e-02-2.18729918e-02j, -2.52670750e-02-1.33657547e-02j, 1.23713405e-01+6.60009234e-02j, 1.76105250e-03-5.13327294e-02j, 4.14606615e-02-1.08656071e-01j, -6.28912224e-02-1.07107702e-01j, 1.78069853e-01-3.95319222e-03j, -1.45753269e-03+7.84868919e-02j, 2.06813821e-02-4.02431446e-02j, 9.90237621e-02+1.96007825e-02j, 5.95901068e-02-2.92985389e-02j, 8.53920666e-02+9.47685100e-02j, -9.07144863e-02-2.48034646e-02j, -7.01707091e-02+1.05577150e-01j, -1.42941920e-01+1.06365145e-02j, -1.07249613e-01+2.31065721e-02j, -2.88007686e-05+1.70984097e-01j, -1.33993560e-01+4.60814975e-02j, 6.46602337e-02-1.73007798e-01j, 1.06092053e-02+1.77117336e-01j, -7.41235355e-02+6.72405741e-02j, -4.45379901e-02-2.75973792e-02j, 4.40770486e-02-4.07231141e-02j, 7.43855652e-02+3.34408901e-02j, 2.40780172e-02+7.63837816e-02j, -1.23431650e-02-2.96942615e-02j, -5.36958281e-02-9.09460148e-03j, 4.83507887e-02-3.64673587e-02j, -3.15949181e-03-6.78532281e-02j, + 1.49790019e-01+7.14330627e-02j, -2.59849469e-03+1.08797910e-02j, 2.39996357e-02-2.49046686e-02j, -1.70855065e-02-1.66572246e-01j, 2.50384745e-02-1.73555395e-03j, -8.79488783e-02-4.43380740e-02j, 4.04368200e-02-1.43535828e-01j, 6.99699704e-02+5.53061802e-02j, 1.06809669e-01+3.35034661e-03j, 2.35091058e-01+1.76495810e-01j, -1.04838058e-01+1.73042549e-02j, -1.79707883e-01-4.28597418e-02j, 1.06487618e-01+6.53314431e-02j, -7.12396824e-02-1.91412368e-03j, 1.75034759e-01+7.74238869e-02j, -2.80836905e-02+6.22152256e-02j, -9.72723299e-02-6.42131837e-02j, 1.28855782e-01-8.94346738e-02j, -6.34807923e-02-8.95849148e-02j, -1.76639575e-01+4.70857161e-02j, -8.66457034e-02+8.75818452e-02j, -9.89288233e-05+9.88579156e-02j, -8.42255352e-02+2.32390595e-02j, 5.68654338e-02+9.42482354e-02j, -7.55075952e-02-3.11797796e-02j, -1.77843576e-01+3.45449165e-03j, 5.22159678e-02+1.35185694e-01j, -4.83698045e-02+3.87913053e-03j, -1.51332382e-01-5.08730574e-02j, 9.19052718e-02+8.92932328e-02j, + -1.04864609e-01+1.59277075e-02j, 1.96860199e-01-1.54596648e-02j, -1.57519029e-01+8.28875556e-02j, 5.32027166e-02+1.80537329e-02j, -5.28489142e-02+4.64273257e-02j, 9.67687293e-02+5.45402170e-02j, -1.09668159e-01-1.19911498e-01j, 1.22173698e-01+7.19935237e-02j, -7.36173466e-02+1.19121401e-01j, 2.12661940e-01+8.30574676e-02j, 1.23393312e-01-1.96849020e-01j, 1.12986422e-01-1.66096746e-01j, -1.11544289e-01-9.50296086e-03j, 1.18875205e-01-9.74865066e-03j, -2.66898723e-02-6.04765594e-02j, 4.87295234e-02-3.00176126e-02j, -1.83928516e-02-1.56550584e-01j, -8.42099875e-02-1.94351327e-02j, 1.64034367e-01-1.73681939e-01j, 1.10112511e-01-7.38060195e-02j, 5.57965855e-02+1.27055482e-02j, 2.16746832e-02+3.08951640e-02j, -1.42130558e-02-2.70500110e-02j, -6.24735154e-02+1.00099685e-01j, -1.50431500e-03+1.77847451e-01j, 1.79109657e-01+4.53034157e-02j, 2.48493244e-01-1.15072362e-01j, 7.02539989e-02-8.21793869e-02j, 5.26929496e-02-4.78438510e-03j, 1.32560795e-02-2.04357332e-02j, + -1.65817978e-02-3.27041521e-02j, 1.45683239e-02+5.08346595e-02j, -2.16494395e-02-4.55596860e-02j, -1.19823818e-01-7.82211212e-02j, 5.69451958e-02-1.04748797e-01j, -7.35412255e-02-1.04581354e-01j, -1.12094932e-02+9.56866013e-03j, 1.07333598e-01-5.03504846e-02j, 3.98839186e-02+4.91837612e-02j, 1.24111729e-03+5.80244038e-02j, -8.12136032e-02-1.25906033e-01j, -1.47795068e-02-1.41661383e-01j, 7.28039351e-02-1.53666294e-01j, -1.44006427e-02-1.07568591e-01j, 2.89558773e-02+5.20172567e-02j, -3.64643948e-02-1.80813430e-01j, -6.77284194e-02-2.19340382e-02j, -1.51800732e-01+1.26354418e-01j, -2.73948963e-02-8.30809951e-02j, -1.23354114e-01+7.76964520e-02j, -2.26546949e-02-1.00472928e-01j, -4.60740997e-02+2.85918430e-02j, 4.98523677e-02+2.73595143e-02j, 6.84538848e-02-4.23015752e-02j, -1.23786500e-01-1.03759657e-01j, -4.63580185e-02-4.20827278e-02j, 5.00822284e-02+2.97891211e-02j, 1.20486086e-01-1.05685993e-01j, -4.83546445e-02-1.50608054e-01j, 4.41121465e-02+6.52452726e-02j, + -8.48704931e-02+1.00099989e-01j, 3.64618144e-02-5.84049288e-02j, 1.22257358e-01-2.46209538e-02j, -3.55664948e-02+3.00069552e-02j, -3.74424330e-02+1.03840630e-01j, 6.62161956e-02-1.24088728e-01j, -1.74591936e-02-6.08432847e-02j, -4.30903776e-02+2.28280325e-02j, -1.32783585e-01+2.54915665e-02j, 7.19465639e-02+7.60218114e-02j, 6.47195234e-02-6.25988897e-02j, 4.43633032e-02+1.13628071e-01j, -9.61062592e-02-1.10626660e-01j, 5.02086545e-03+1.71097394e-01j, 2.79457756e-01+3.62937257e-02j, 7.00690199e-02-7.77637776e-02j, 1.79011229e-01-8.68805824e-03j, 1.11655273e-01+1.15277003e-01j, 6.95789332e-02+7.61278729e-02j, 5.46339890e-02+4.89518665e-02j, 4.17643112e-02-9.89158287e-03j, 4.33563805e-02+8.13926965e-02j, -1.21887314e-01-2.12994079e-01j, 6.62822033e-02-9.28126086e-02j, 1.19584184e-01+5.96549891e-02j, -8.66323535e-02-6.73417091e-02j, -1.10895596e-01+1.63722633e-02j, 1.07332452e-01-2.05194027e-02j, 2.33547227e-02+2.92104674e-02j, 1.63241181e-01-3.72177572e-02j, + -8.50373601e-02-4.58981785e-02j, 1.30399262e-01+6.79769702e-02j, -3.88839698e-02-2.80027695e-02j, -1.42123694e-02-1.13992336e-02j, -3.91191271e-03-8.38363973e-02j, -3.00525620e-02-4.84482749e-02j, -7.07061618e-02+3.40883522e-02j, -2.65451649e-02+7.82186705e-02j, 7.06263189e-02+1.90006089e-01j, -1.06830313e-01+3.57336561e-02j, -1.83318787e-02-2.98391334e-02j, -1.26094265e-01-2.95955671e-02j, 6.69916734e-03-3.29056342e-02j, -4.56437407e-02-3.00362417e-02j, -1.97638423e-02-4.53695081e-02j, 5.62720421e-03+6.57464963e-02j, 1.62152741e-02+5.08849146e-02j, 7.15579817e-03-1.46367176e-01j, -3.66457634e-02-7.32904103e-02j, 1.47588967e-02+1.42117835e-01j, -4.15077413e-02+5.32471543e-02j, 1.81074012e-01-2.15788297e-01j, 1.37761481e-01+1.98205227e-02j, -5.49664338e-02+1.98201091e-01j, 1.06526105e-01+4.25454460e-02j, -1.11587932e-01-1.46278311e-02j, -5.20473894e-03+3.93591568e-02j, -3.98053192e-03-2.77757585e-02j, 8.01758751e-02+5.52518513e-02j, -1.89902375e-02-7.50263130e-02j, + 1.02340693e-01-1.07484115e-01j, 5.97194024e-02+2.99637326e-02j, 4.97079433e-02+9.42118947e-02j, -1.21749063e-01+5.12413635e-02j, 8.86514824e-02+2.02168637e-01j, -6.29512938e-02-5.10894134e-02j, 1.72194219e-02-1.39583523e-01j, -5.59939033e-02-7.47071549e-02j, 5.46002846e-02+1.44836673e-01j, -2.74093589e-02-4.62528590e-02j, -2.06132176e-02+2.54445042e-02j, 5.49369216e-02+1.13085624e-01j, 5.31450092e-02-5.77602131e-02j, 9.76193562e-02+1.59068016e-01j, -2.98195751e-02+4.85882645e-02j, 1.73318274e-02-9.95944267e-02j, 4.46831226e-02-8.05748385e-02j, 1.55069124e-01+1.85506946e-03j, 1.74618570e-01+7.88387737e-02j, 4.88827187e-02-6.57641635e-02j, -4.83705302e-04-3.66495970e-02j, -6.84625471e-03+9.00931899e-03j, 5.99085139e-02+9.55878693e-02j, 4.53412056e-03+4.82660251e-02j, 3.32400505e-02-7.24208945e-02j, 6.90343685e-02+5.16744895e-02j, 2.55541118e-02+2.68896192e-02j, -7.11313208e-03+5.40454970e-02j, -7.37568243e-02+3.56452181e-02j, -1.51159026e-01-3.32725818e-02j, + 2.76447397e-01-9.71246013e-02j, 1.40445833e-01-1.63819214e-01j, -7.47529467e-02+3.29702300e-02j, -5.24187826e-02+1.18661825e-01j, 8.31870820e-02-1.44188935e-01j, -9.53324502e-02+1.03506147e-01j, 3.50388013e-02-2.05399091e-02j, 5.87599572e-02-1.22481738e-01j, 1.06554427e-01+1.09594224e-02j, -2.37403722e-02-4.05386383e-02j, 1.30906014e-01+2.30293496e-02j, 3.42586203e-03+7.21644220e-02j, 4.28718087e-02-1.63183726e-03j, -9.74581387e-02-2.17171279e-02j, 4.79794062e-03+9.69996568e-02j, -2.81152594e-02+3.64640848e-02j, 1.41057044e-01-8.55610176e-02j, 1.13579799e-01-6.86894625e-02j, 3.26039112e-02-3.18036182e-02j, -1.03442985e-01+7.34067502e-03j, 2.45074328e-01-8.02551876e-02j, -9.95980284e-03-1.25597027e-01j, -1.13072351e-01+5.84716931e-02j, -2.91466791e-02-1.12346923e-01j, 1.39940920e-01+4.33022175e-02j, 9.62152966e-02+6.44762437e-02j, -1.78502974e-02+3.61510360e-02j, 1.58364304e-01-4.44919730e-02j, 5.56087485e-02-7.78226361e-02j, -1.28642124e-01+9.25199650e-02j, + -1.37827615e-02+8.63485029e-03j, -5.90489222e-02-6.21678061e-02j, -8.97089270e-02-5.55332554e-02j, 4.60473118e-04-7.44873712e-03j, -3.01789780e-02+2.62505348e-01j, -5.24922624e-02-1.16998291e-01j, -4.48619660e-02+7.75534691e-03j, -2.16942247e-02-1.32529990e-01j, 2.06845106e-01-3.99952263e-02j, 4.21013041e-03+3.75442281e-02j, 2.08877999e-02+4.65784759e-03j, 1.10316161e-01-1.85375840e-01j, 1.10518071e-01-5.97296649e-02j, 6.06210473e-02+4.13367885e-02j, -3.90943334e-02-8.60356454e-04j, 3.38772694e-02+2.12803762e-03j, 5.50896120e-02-2.37097732e-02j, -9.23532584e-03-2.15778018e-01j, -5.35860008e-02-4.10930146e-02j, 5.10150050e-02-9.19891264e-02j, -3.12179156e-02+5.16581942e-02j, -4.79608112e-02-9.76871529e-02j, -2.24134346e-02+1.11195765e-01j, 1.61216262e-01-9.33898111e-02j, 7.84476912e-03-1.25747019e-01j, -1.28241441e-02+1.46830948e-01j, 1.66002493e-01+6.78124856e-02j, 2.38609868e-01-1.74669970e-01j, 1.00056091e-01-1.91285012e-02j, 4.36951377e-02+3.92636206e-02j, + -6.33700025e-02+1.00688791e-01j, -9.01457033e-02-5.55666105e-02j, -2.74920713e-02-5.60945304e-02j, -1.12460738e-01+2.08926976e-01j, 1.47746830e-01+3.73544016e-02j, -1.18480516e-01+7.28623868e-02j, 4.33540648e-02+6.69355465e-02j, 4.12853021e-02-5.74198610e-02j, -5.08905281e-02-2.89177495e-02j, 4.39371436e-02+3.64541436e-02j, -1.86339121e-02+2.31353377e-02j, 9.01016810e-02+5.74020539e-02j, -1.46629405e-01-8.14734300e-02j, 8.38912755e-03+8.15995264e-02j, 4.11653085e-02-2.59878024e-02j, -5.12357023e-02+2.53150165e-04j, 1.36426369e-02+2.64118687e-03j, -1.95895595e-02+5.62617047e-02j, 2.47361159e-02-1.29518847e-01j, 3.88829366e-02+2.03908544e-02j, 3.41960599e-03-5.46266792e-02j, 7.46357033e-02-7.37336342e-02j, 2.42879656e-02-8.25850576e-02j, -1.30434368e-02+5.12158348e-02j, -5.86799503e-02-1.20936502e-01j, -3.64627451e-02-1.14700770e-01j, 8.79969190e-02+1.08108855e-01j, 2.86271051e-03+1.42659207e-02j, -4.16354582e-02+8.06660296e-02j, 4.15301680e-02+1.79575574e-02j, + -1.86461656e-01-2.42490106e-02j, 8.35776870e-02+5.65352490e-02j, 5.17627809e-02-2.14815383e-03j, 6.94949108e-02-1.12716819e-01j, 1.24952171e-01+5.87906220e-02j, 7.17725463e-02-1.19516974e-02j, 1.38777023e-01+1.91666559e-02j, -7.70714927e-02-8.45921195e-02j, -5.50990910e-02+1.88816346e-02j, -4.52069047e-02+9.92559466e-02j, 1.52931927e-01+2.18224356e-03j, 6.36110833e-02-1.49446746e-01j, -1.04306099e-01+2.55936479e-02j, -2.43190570e-02-1.24642498e-01j, 1.07908919e-01-5.24542844e-02j, 1.18023420e-01+1.82251949e-01j, -9.87945471e-04+2.24670038e-02j, 6.88747033e-02+3.88424142e-02j, 4.65620995e-02+6.84585535e-02j, 4.55186370e-02-1.10679652e-02j, 2.45232445e-01+1.21957784e-01j, -1.46216991e-01-6.73000332e-03j, 1.88431703e-01-7.71881296e-02j, 1.64320240e-01+5.78847160e-04j, 9.79316716e-02+4.54526962e-02j, 3.20288139e-03+1.55014950e-01j, 5.47467470e-02+4.35107341e-03j, -2.08130010e-01-5.64307911e-03j, -1.10232566e-01+7.32351151e-02j, 1.35941251e-01+1.38078108e-02j, + -7.56788025e-02+3.73517234e-02j, 2.04679302e-01+3.90147242e-02j, 1.08785662e-01-6.94594148e-02j, 7.20045941e-02+2.78459276e-02j, 1.92400736e-01-1.50979597e-01j, -1.58869068e-01-8.22425262e-02j, -2.98171534e-02+1.71665472e-03j, -3.06886027e-02-8.02964429e-03j, -4.25762489e-02+3.23637065e-02j, -2.79618445e-02-2.07485498e-02j, 1.18857251e-02-1.75486789e-02j, -4.36645926e-02+6.80482134e-02j, 7.37583273e-03+1.26666694e-01j, 3.95626865e-02-9.77189985e-02j, -1.48716204e-01+2.68786987e-01j, -3.72800597e-02+5.71237210e-02j, 7.41890650e-02-7.52430682e-02j, 3.90385347e-02-2.07079317e-02j, 3.84685342e-02+5.01376534e-02j, -5.27350224e-03+1.47858994e-01j, 3.90452488e-02-8.37384564e-02j, -7.98233712e-02-1.79529336e-02j, 1.33565706e-01+4.92479091e-02j, 3.72930254e-02+1.73346346e-02j, -8.85513745e-02-3.44914310e-02j, -2.55952093e-03+1.10740235e-01j, 1.22295953e-01-6.26298383e-02j, 1.07479323e-01+4.08024277e-02j, 1.94989868e-02+4.87243296e-02j, 1.43449277e-01-1.01261533e-01j, + -2.16939069e-02-4.18289269e-02j, 6.07804273e-02+9.37183963e-02j, -4.85826992e-02+4.34844713e-02j, -2.86068223e-02+1.03414084e-02j, -6.82958979e-02+7.45791847e-02j, 9.92759338e-03-1.01013890e-01j, 4.46668242e-02+5.34278176e-02j, 2.05957081e-01-8.43994442e-02j, -3.17105069e-02-2.64039322e-02j, -1.23137159e-02-1.67162172e-02j, -7.10187538e-02+1.11568931e-01j, 4.83956551e-02+1.38122479e-01j, 1.06745393e-01+3.55201390e-02j, 5.36566000e-02-1.64529636e-01j, -3.22813703e-02-4.03551165e-02j, -8.16829634e-02-1.59310035e-02j, 9.19194280e-02-1.87254021e-03j, 5.39877612e-02-1.41864131e-01j, -9.76301436e-02-1.21547018e-01j, -9.20678092e-02+1.74387849e-01j, 1.40685348e-01-1.27548000e-01j, 2.96123871e-02-1.02922618e-01j, 1.11352902e-01-8.62467830e-02j, -1.09712727e-01-3.89440732e-02j, 1.18222416e-01+5.77362689e-02j, -6.58226250e-02-1.00553320e-01j, -7.08216359e-02-3.82394234e-02j, 5.22392245e-02-9.90544241e-02j, 1.04343923e-01-2.21400076e-02j, -1.50119333e-01-2.08365776e-03j, + -2.00031377e-03+5.81542663e-02j, 3.83065634e-02+1.08315594e-01j, -1.52024028e-01+1.13697356e-01j, 5.98038406e-02-4.82362581e-02j, 8.65636860e-02-6.35096970e-02j, 7.72958756e-02-2.56093728e-02j, 2.29512769e-02+9.62400436e-03j, 4.45398156e-02+8.80887704e-02j, 9.49028759e-03-2.35771406e-02j, -2.36791919e-03-7.62382381e-02j, 1.19090719e-01-8.93309279e-02j, 5.19314568e-02+3.85447831e-02j, -3.87628280e-02+7.77506760e-02j, -3.26884566e-02+1.91066264e-02j, 1.43129957e-01+5.06655538e-02j, -8.14216372e-02-1.24857868e-01j, 4.08149916e-03+3.39964438e-02j, -3.18000514e-02+4.94502870e-02j, -8.59753841e-02-6.05242613e-02j, -7.02375587e-03-7.23709227e-02j, -5.90808602e-02-5.10396991e-03j, -3.99358436e-02+1.54029042e-01j, -1.48939165e-01-2.30986046e-02j, -1.36109697e-02+6.09298717e-02j, 3.36241127e-02-2.08250661e-01j, -6.48593373e-02-2.60921265e-02j, 4.78423392e-02+1.56280882e-01j, -3.67274730e-02-8.41030956e-02j, -1.44975443e-02+7.80523865e-02j, -1.13469394e-01-6.74622693e-02j, + 4.70147160e-02+3.56008433e-02j, 1.80886023e-01+6.94462782e-02j, 2.01441028e-01-2.41069795e-02j, -1.77832245e-01+1.67730057e-01j, -1.72926391e-01+8.72396028e-02j, 1.05716876e-01+7.93440128e-02j, -7.17398366e-02+2.39715722e-02j, 9.40991385e-02+9.48572465e-02j, 7.56374392e-02+1.26422068e-02j, -3.42567574e-02+6.57554524e-03j, -9.80583679e-02-2.48742400e-01j, 1.94821099e-03-4.61412351e-02j, -1.15171892e-01+4.23163024e-02j, 9.55046504e-02-2.85351271e-02j, 6.87501834e-02-9.09245253e-02j, 8.69873372e-02-1.36599865e-01j, 8.72279542e-03+1.71002218e-01j, -1.47382708e-01+1.48146962e-02j, -4.20312282e-03+1.48338430e-01j, 9.18441565e-02-1.67967981e-03j, 1.16613728e-01+1.50842236e-01j, 3.91945313e-02-1.54576297e-01j, -1.04976187e-02+6.29468802e-02j, 1.25177984e-02-8.77763898e-02j, 4.89867798e-02-5.41877145e-03j, 1.09219986e-01+4.12706256e-03j, 4.09641507e-02-2.21297934e-02j, -2.48745776e-02+1.70792444e-01j, -1.24622984e-01-5.47605581e-02j, -6.76718048e-02+5.83777721e-02j, + 1.08185457e-01-1.27066585e-02j, -4.14109909e-02-3.11627607e-03j, 9.79107799e-03+1.12951585e-01j, -4.09954965e-02+4.97455619e-02j, -1.01938277e-01-1.20867638e-01j, 5.94627844e-02+5.46678428e-02j, -2.22617431e-02-1.00320800e-01j, -5.28175862e-02-8.33668982e-02j, 5.18586133e-02+1.16558179e-02j, -6.29728280e-02+1.05923649e-01j, -5.99212755e-02+1.94190572e-02j, 6.94771130e-02-1.55683386e-01j, 5.19897813e-02+6.27034419e-02j, 7.90956993e-02-9.01446300e-02j, 1.88130641e-02-1.49956110e-02j, -4.23517166e-02-8.81984045e-02j, -8.63174858e-03-1.60373942e-01j, -8.74400710e-02+1.35436105e-01j, 1.05708057e-01-4.90293166e-02j, -8.38220286e-02+6.93173211e-02j, -9.44596245e-02+1.41396701e-02j, 1.44384840e-01-5.37706430e-03j, -1.41297717e-02+2.07240685e-01j, -8.91091924e-03+2.76415024e-02j, -5.69003223e-02-1.87856438e-02j, -3.10382650e-02-9.69041662e-02j, -8.46753743e-02-4.51121121e-02j, 2.13287292e-01+2.96795365e-02j, -6.78000993e-02-7.27014711e-02j, -5.24643121e-02+1.97358995e-02j, + 8.62181411e-03+1.79870726e-01j, 1.52898138e-01-9.88048051e-02j, 4.74521169e-02-3.56121574e-02j, 9.22896695e-02+1.40223845e-02j, 4.68319387e-02-7.26391162e-03j, 5.92394125e-03-4.79254400e-02j, 2.16269967e-01+5.54358310e-03j, -4.27515151e-02-1.23614667e-02j, 9.83446073e-02+8.83227942e-02j, -1.09197854e-01+4.99396436e-02j, -8.15404308e-02+2.55541009e-02j, 7.39865612e-02+6.55508075e-02j, 6.63286555e-04+1.54249963e-01j, 9.27110573e-02+3.41628715e-02j, 1.45527728e-01-1.41080682e-01j, -1.41359130e-02-6.02124272e-02j, -1.70089668e-01-9.50888884e-03j, -5.90907847e-02+9.90858589e-02j, 1.20282993e-01+1.63169966e-02j, -6.01831403e-02+4.99282270e-02j, 1.48186487e-02-1.19425802e-02j, 1.58460014e-01-4.80879586e-02j, 1.74692437e-01+1.32829541e-01j, -7.74148211e-02-3.37385643e-02j, 9.17695643e-02-3.98154413e-02j, 2.37156746e-02+9.59269352e-02j, 2.12142259e-01+2.79772767e-02j, 1.07204688e-01+7.30996249e-02j, -1.02045757e-01+1.90798954e-01j, -1.41858107e-01-1.07587269e-01j, + -1.43454403e-01+3.73650281e-02j, 2.32833516e-02-1.36078422e-02j, 8.83472839e-02+2.71852498e-02j, 1.19513218e-01+5.01626287e-03j, -5.92568345e-02+4.09442957e-04j, -8.14238995e-03+1.83183640e-02j, -6.61149944e-03+7.80984936e-02j, -1.12162965e-01-1.19962828e-01j, 5.48458766e-03+1.00469491e-01j, 2.73708801e-02-5.82827636e-03j, -1.19046015e-02-3.82564125e-02j, 7.29885631e-02-9.01451280e-03j, -4.94120509e-02+8.26467259e-02j, -5.51635770e-02+5.15768294e-02j, 3.20117208e-02+5.85584915e-03j, 1.06872987e-01-4.31353939e-02j, 4.40304662e-02+2.91857939e-02j, 1.68500095e-01-2.82738129e-02j, -2.03371967e-02-1.26195722e-01j, 2.83846022e-02+8.17355207e-02j, -1.51547265e-02+1.12602067e-01j, 7.81649864e-02-2.38189548e-01j, -1.35224365e-02+3.19631898e-02j, 1.17490585e-01+4.01554664e-02j, -4.72704834e-03-3.99565213e-02j, -8.84904826e-02-4.28727274e-02j, -1.22198482e-01-2.42786041e-02j, -1.12897707e-03-6.94497623e-03j, -2.19884514e-02+8.55486354e-02j, 8.70638696e-02-1.07127798e-01j, + -2.29371995e-02+4.63320598e-02j, 1.93873091e-02+1.86337449e-01j, -1.25468921e-02-5.18952165e-02j, -7.45890764e-03-8.03295372e-02j, -3.56745327e-02-6.25638362e-02j, -4.75510121e-02-7.83464611e-02j, -1.39534894e-01+8.16425405e-02j, 7.70005031e-02+8.69423266e-02j, 1.43911987e-02-1.33546977e-01j, -1.47102056e-01+1.15681347e-01j, -1.33126375e-01+1.02235868e-02j, -1.45122855e-01-2.89314423e-02j, 1.11563142e-02+3.69740758e-02j, 1.00779242e-01-3.90064124e-02j, 1.26325368e-01+6.71845381e-02j, 3.24794315e-02+1.38737288e-02j, 6.81836122e-02+1.40750598e-01j, 3.44546719e-02-5.21553657e-02j, -4.57601524e-02-3.27555405e-02j, 8.24373398e-02-8.90390790e-02j, -1.16860314e-01+1.25653018e-01j, 1.46493260e-01+1.41194112e-01j, -1.45396010e-01-1.32885959e-01j, -7.73293855e-02-6.72724685e-02j, 1.49309687e-01+6.97139456e-02j, 1.91464376e-01+3.82211888e-03j, -3.63957571e-02-1.31754413e-01j, -2.46974881e-02+1.39206134e-01j, 5.83769856e-02-3.77826253e-02j, -6.72768215e-02+2.28114923e-02j, + 2.55957644e-02+4.21858672e-02j, -5.88391848e-02+1.42670909e-01j, -7.05483919e-02-3.98423804e-02j, -7.02652206e-02+1.00856608e-01j, -1.41224511e-01+4.66217961e-02j, 1.07977589e-01+2.05966808e-01j, 1.27139331e-01-9.33860861e-02j, -5.36280638e-04-3.59555623e-02j, 2.38548900e-03+1.08390515e-01j, 5.57620979e-02+2.13967089e-01j, 2.14044445e-02-6.81976237e-02j, 1.33050862e-01+9.78079190e-02j, 9.59093734e-02-1.86488160e-02j, 6.43843748e-02-1.00325395e-01j, -3.78896000e-02-5.56830122e-02j, -9.49734363e-02+1.78783106e-01j, 8.92016398e-02-5.73330404e-02j, -1.49081326e-01-8.02418770e-02j, 1.29000520e-02+2.00740628e-01j, 9.56015376e-02-7.84317559e-02j, 7.74367443e-02+1.73620000e-02j, 6.30112118e-02-2.32571601e-01j, 3.00303803e-02-9.83705381e-02j, 1.61844259e-01+1.05485097e-01j, 2.40291349e-01-4.01070715e-02j, 1.18754377e-01+4.31127547e-02j, -2.18267030e-03+2.88200832e-02j, 1.17227459e-01+1.26467873e-01j, -8.49409061e-02+4.97160270e-02j, -1.63005455e-03-4.99396218e-03j, + 8.44483610e-02+7.05728728e-02j, 1.24861205e-02-2.58181667e-02j, -5.50187440e-02-4.48743334e-02j, 2.80015656e-03-4.82029670e-02j, 4.06373407e-02+1.17659005e-01j, 6.92546145e-02+5.26651932e-02j, 4.41971443e-02-7.53547930e-03j, 1.58836470e-01+1.43051517e-01j, 1.75841588e-01-9.63643389e-02j, -8.17547660e-02-3.31679339e-02j, -3.90876419e-02-9.54602863e-02j, -5.27660299e-02-4.52618847e-02j, -3.29940397e-02-7.32188040e-04j, 1.33182711e-01-3.30125326e-03j, -1.73800247e-01+7.37850658e-02j, -9.03044053e-03-5.62976198e-02j, -7.23873677e-03-5.29735141e-02j, 2.81516307e-03+5.96141674e-03j, 3.40919441e-02-4.95963107e-02j, -5.85547763e-02+1.19710083e-01j, 3.71410507e-02-1.14337865e-01j, -3.28786435e-02-1.31582104e-01j, -3.11008227e-02-1.06387141e-01j, 5.70725503e-02-5.01012877e-02j, -5.67037266e-02-1.45846038e-01j, 5.12987918e-02-5.27321657e-02j, -2.91698456e-02+7.36045193e-02j, -1.78732183e-03+3.56761928e-02j, -4.22088087e-02-2.10621398e-02j, -4.93624568e-02+1.57929069e-02j, + -7.57986052e-02+1.05462121e-01j, 9.12211212e-02-2.55913922e-02j, 1.65492733e-01+1.11378639e-01j, 1.23643907e-01-6.70361505e-02j, 8.91758326e-02+8.21455575e-02j, -5.05051969e-02+5.59456241e-03j, -1.26290743e-01-5.67854069e-03j, -1.18931736e-01+1.53843733e-01j, -7.50296683e-02-1.07846045e-01j, -1.21333537e-01+4.07381039e-02j, -8.52090624e-02+1.29604666e-01j, 8.09572029e-02+5.23771628e-04j, -5.44002980e-02+1.27113581e-01j, 5.79705919e-02-4.22805852e-02j, 1.26732210e-01+1.50354241e-03j, -4.77950234e-02+1.99087102e-02j, 1.03424607e-01+3.40027024e-02j, -5.83845975e-02+1.59746122e-01j, -2.17388369e-01+6.74992723e-03j, 1.42500131e-01+5.05071268e-02j, 5.45543560e-02+3.92456147e-02j, 2.18488301e-02-6.14267392e-03j, -5.57776866e-02+8.26003743e-02j, 3.49894774e-02+1.41336726e-01j, 6.69241650e-03-1.04471824e-01j, 1.21772946e-01+1.91210500e-01j, 1.19217589e-01-5.38115139e-02j, 1.88246371e-02-1.83004726e-02j, 2.08866104e-03-7.33113093e-02j, -8.12529253e-02+4.61430645e-02j, + -4.46184815e-02-3.01757956e-02j, -1.35634714e-02+3.38777008e-02j, 4.94210365e-02-2.07529226e-01j, 8.74104130e-02-5.08970513e-02j, 1.53550582e-02-9.11243595e-02j, 8.84523103e-02-4.03101881e-02j, -2.23589887e-01-7.04136609e-02j, 1.23249442e-01+7.55507497e-03j, -1.36224452e-02+1.24659565e-01j, 2.28284552e-01-1.13277060e-01j, -5.96268468e-02-5.73745561e-03j, 1.29530326e-01-8.61904688e-02j, 8.54578487e-02-1.00686862e-01j, 2.70928472e-02-4.63967514e-03j, 1.48161107e-02-5.46569087e-02j, 2.85271880e-02+3.26964639e-02j, 7.96782967e-02+1.10891607e-02j, -1.34176030e-01+6.96277781e-02j, -3.29195127e-02+9.64297617e-02j, 3.03391090e-02+9.71757423e-02j, 5.29277338e-02+3.47785677e-03j, -6.26896146e-02+4.62296383e-02j, -7.85231220e-03+3.56225075e-02j, -1.59413042e-01-7.66033618e-02j, -8.52104081e-03-3.79146418e-02j, -8.48098551e-02-1.08488438e-01j, 6.84002684e-02-9.27612240e-02j, -6.64407275e-02+4.15485835e-02j, 6.08387005e-02+8.19913120e-02j, 1.00446088e-01+1.55852725e-01j, + 3.97609833e-02+1.00146008e-01j, -5.22778987e-02-8.21009007e-02j, -3.77077303e-02+5.13288886e-02j, 9.21346640e-02-1.02972511e-01j, -5.81472043e-02+9.22815026e-03j, -6.72925561e-02-4.11932180e-02j, 6.44503140e-02+1.29261896e-02j, -1.32762347e-01+9.23711163e-03j, -1.03599757e-01-4.56192544e-03j, 3.24505339e-02-2.45398116e-03j, 6.58694205e-02-3.21227618e-02j, 1.24036462e-01+1.47475323e-02j, 1.30152316e-02+1.35707105e-01j, 1.56039110e-01-5.18164633e-02j, -7.03152690e-02+3.12506934e-01j, 8.76117464e-02+1.17448220e-02j, -4.68448704e-02+4.10314253e-02j, -3.22028182e-03-1.22678955e-01j, -1.14178360e-01-6.71304826e-02j, 4.55256387e-02+3.82766596e-02j, 1.48401693e-01-5.47951986e-02j, -7.56378950e-02+1.20320511e-01j, 6.30532615e-02+1.01337916e-01j, -4.99127404e-02+1.37739974e-02j, 2.35931263e-02-3.96687088e-02j, 2.67108253e-02+6.13453731e-02j, 1.62891049e-01+7.84529123e-02j, 7.49086743e-02+1.10381126e-01j, 7.63873637e-02-1.19047306e-02j, 6.77266410e-02-3.28310781e-02j, + -8.53110808e-02-2.50184384e-02j, 3.83933170e-02+1.43491474e-01j, -8.86989164e-02+7.99727750e-02j, -7.37362920e-02-1.49473969e-01j, 6.43959171e-02+1.99276397e-02j, 6.27697475e-02-2.27116899e-02j, 8.40868521e-02-5.22837391e-02j, -1.12648545e-02-1.12680946e-01j, -1.32392949e-01+4.13293428e-02j, 1.14842189e-01+3.80617047e-02j, 4.67782370e-02+1.54746874e-01j, 8.23224982e-02+4.56644140e-02j, -2.82310492e-02+1.47896780e-01j, 6.71171984e-02+3.63367239e-03j, -1.30820895e-02-1.66233584e-02j, 1.56041973e-01-5.91053002e-02j, 9.72049576e-03+1.57604493e-01j, 3.99164787e-02-1.39203421e-01j, 1.33473022e-02-2.20465140e-02j, 8.28185122e-02-6.79543638e-02j, 3.82282405e-02-5.77487822e-02j, -1.55532854e-02-1.04539428e-01j, -5.91946563e-02-1.84369274e-02j, -3.82486186e-02+4.42172266e-02j, 1.18801889e-01-8.57833822e-02j, -2.51752531e-01-1.52096140e-01j, 1.55380879e-01+7.23105262e-03j, -1.01032533e-02+1.06962879e-02j, -1.31703458e-01+3.76881824e-02j, 1.60460085e-02+6.30850547e-02j, + 4.19255549e-02+3.92629725e-02j, 4.93357915e-02+4.62217751e-02j, -2.46551328e-02+9.18461625e-02j, 7.84824861e-03+3.42026930e-02j, 2.27842145e-02+1.02988705e-01j, 8.89143553e-02-1.32777071e-01j, -1.53255753e-01-5.64168441e-02j, 2.60864735e-02+6.83070308e-02j, 1.24089898e-01+1.46531300e-01j, 8.03861657e-02+8.44347212e-02j, -3.99675456e-02-4.13219148e-02j, 1.99496563e-02-1.68741956e-01j, -9.61656011e-02-9.85036805e-02j, 3.81645661e-02-1.58403405e-01j, -1.22222597e-01+2.27927369e-02j, -1.95541768e-01-3.26566021e-02j, 3.06440615e-02+3.05364521e-02j, -8.76411203e-02-1.79424422e-02j, -2.13722727e-02-1.46393081e-01j, 1.81898579e-02-1.17003644e-01j, 1.36627407e-01-1.57758323e-01j, -5.03748616e-02-1.47579680e-01j, -3.40991053e-02+2.60350260e-02j, 6.61586084e-02+1.13051859e-01j, 9.27199042e-03+6.76019455e-03j, 1.97908095e-01-7.26532762e-02j, 8.82218775e-03+6.06572679e-03j, -7.52454053e-02-6.42541289e-02j, -8.99883870e-02+4.02263836e-02j, -1.59753697e-02+1.71002481e-01j, + -2.61136199e-02-1.03271017e-01j, 1.56419876e-02+3.02378993e-02j, -1.06994379e-02-4.42494478e-02j, 7.02703110e-02+5.64923383e-02j, 5.07122277e-02+4.74081563e-02j, 7.67303013e-02-1.56906009e-02j, 9.16318724e-02-3.07214532e-02j, -5.18225692e-02+1.08506378e-02j, -7.67455403e-02+5.55639645e-02j, 6.64535546e-02-9.01565151e-03j, -9.14990010e-02+3.73538098e-02j, -7.28625453e-02-1.19186740e-01j, -2.77589055e-02-8.22322098e-02j, -3.22296245e-02+1.31757376e-01j, -3.50339775e-02+1.37913873e-01j, 3.84813010e-02+1.67884657e-01j, -7.00195023e-02-6.19230041e-03j, 8.02979751e-03+1.25547652e-01j, 3.81418938e-02-8.66550141e-02j, 6.66673422e-02-2.80517890e-02j, 1.47446194e-01-1.21608923e-01j, -1.06983782e-01+1.61685673e-02j, 1.45128417e-01-9.97579672e-02j, 4.78343409e-02-3.43103884e-02j, 5.46402843e-02+3.32975311e-02j, -1.17712449e-01+3.53043129e-02j, 6.17783098e-02+7.68043303e-02j, -4.12278356e-02+2.20803550e-01j, -1.27049166e-01+5.43901474e-02j, -3.76806434e-02+1.87060854e-01j, + -8.90334008e-02+4.81197426e-02j, -1.61805869e-01-5.83124248e-03j, -2.35021073e-01-1.36839690e-02j, 5.95583000e-02-8.53455811e-03j, -1.36475568e-02+1.02072032e-02j, 6.57874310e-04-5.54357406e-02j, -1.16075063e-02-1.88043201e-01j, -4.10593532e-02-1.25295385e-01j, -1.01181308e-02-1.83976177e-02j, 1.22655279e-01-1.17069920e-01j, 4.31446899e-02-6.57352962e-02j, -1.00119330e-01-1.39878527e-01j, 9.98658335e-02-4.26160789e-02j, -1.34536488e-01+9.74478087e-02j, -6.92874025e-02-8.13138795e-02j, 2.45163582e-02-1.76548089e-01j, 3.22174804e-02-5.65589817e-03j, 8.07679515e-03+6.33986691e-03j, -6.31184637e-02-4.41509650e-02j, 2.05374550e-02+4.76306825e-03j, -1.36800160e-01+3.66858887e-02j, 1.47490170e-01-1.20606391e-01j, 8.14807620e-02-2.11446690e-01j, -1.45202365e-02+8.19600273e-02j, -1.59974770e-01+4.89558755e-02j, 1.40694468e-01-3.31038214e-02j, 1.41222361e-02+1.88783167e-02j, -1.39964930e-04-7.90888896e-03j, 4.02400089e-02-1.91496498e-02j, -2.10975834e-02+2.55743635e-02j, + -1.24830235e-02-1.04506988e-01j, -7.83991128e-02+7.24495291e-02j, -7.67997026e-02+1.15793120e-01j, 7.71299789e-02+1.54784598e-02j, 1.00227939e-01+1.64355312e-01j, 8.14056190e-02+1.20896109e-01j, -5.07211511e-02-4.31177626e-03j, -5.98801754e-02+1.87757032e-01j, -5.58581009e-02+1.11035307e-01j, 8.64549886e-02+9.22623166e-02j, 1.33102211e-01-8.68358502e-02j, -4.38973116e-02+3.47998547e-02j, -1.51802312e-01-9.79580479e-02j, 2.32964551e-01-2.62447131e-01j, 5.48006171e-02-8.11579033e-02j, -1.74315936e-02+9.52579508e-03j, 1.17761070e-01+1.11200729e-01j, -8.00284541e-02+1.32515499e-01j, -1.49555446e-02+1.88069542e-01j, -7.57884206e-03-4.58967652e-02j, -9.50078367e-02-1.00631395e-01j, 1.72491605e-02+4.47670026e-02j, -2.03781472e-02+3.26250698e-02j, -9.59715607e-02-4.37484169e-03j, -9.58454167e-03+2.95792410e-02j, 1.05438691e-01-1.33092379e-01j, 3.09937517e-02-2.42140206e-04j, -1.44752997e-01-1.10462732e-01j, 3.59606533e-02-3.84511090e-02j, -3.56750817e-02+5.75093775e-02j, + -4.15723422e-02+5.09095742e-02j, -2.50051531e-02+3.74719107e-02j, -3.34371919e-02-2.69992518e-02j, 2.17278805e-02-1.59555220e-01j, -1.18390615e-01+3.06546257e-02j, 5.93851132e-04+6.14587651e-02j, 1.40201832e-01-1.17018742e-01j, 6.30594857e-03+5.45456872e-03j, -3.76289949e-02-1.52282039e-02j, 1.32512888e-01-1.48351173e-01j, -7.54453520e-02-4.61426234e-02j, -3.03461225e-02-5.67156398e-02j, -8.36462232e-02-1.37701819e-01j, 1.70123787e-02-2.07730468e-02j, 2.02734494e-01+6.52242080e-02j, 1.92557330e-02+1.00734613e-01j, 1.75343958e-01+8.81780749e-02j, -1.19044611e-02+5.91177580e-02j, 1.67539379e-02+4.06442164e-02j, -8.00636857e-02+7.89439667e-02j, -4.75474374e-02+2.83892572e-02j, 2.61253074e-02+1.39692416e-02j, 1.27684922e-01+1.17156954e-01j, 2.73419985e-03-8.15456779e-02j, 1.30767101e-01-7.98744725e-02j, -1.17162715e-02-1.65840395e-01j, -5.76548732e-02+5.87985325e-02j, 7.07963445e-02-1.79886324e-01j, -4.20474415e-02+1.08883511e-01j, -5.75618414e-02+5.21190462e-03j, + -7.21987996e-03-3.10182665e-02j, 5.50605465e-02-7.25079912e-02j, -5.35629253e-03-3.15994255e-02j, 1.45261311e-02+1.13362595e-01j, -2.76125254e-02-3.24502000e-02j, 3.91132852e-02+7.99084254e-02j, 1.36671884e-01-4.22167609e-02j, -2.78745524e-02+1.66604820e-01j, -5.79322711e-02+1.89892952e-01j, 5.80213545e-02-5.63300106e-02j, 4.21450402e-02-2.34111878e-01j, -9.04896655e-02+8.57572295e-02j, -1.03359661e-01-7.96324957e-02j, 6.02369786e-02-6.27833326e-02j, 1.19673196e-01+1.10677207e-02j, 8.30081547e-02-3.58778391e-02j, 6.11783668e-02+6.11887674e-02j, -7.68605931e-02-5.39948682e-03j, 1.21343778e-01-2.97186254e-02j, 1.29116081e-01+1.87106712e-01j, 5.15873038e-03+6.61919344e-02j, -1.83282876e-03-3.68731936e-02j, 1.17016771e-01+1.58222912e-01j, -3.87226282e-03-9.70371654e-04j, -1.79300200e-01-2.83260393e-02j, -1.41400483e-03+1.35331847e-02j, 5.72087458e-02-7.75475006e-02j, -1.58108785e-01-7.97071215e-02j, -3.31189056e-03-5.73357007e-02j, 4.13786706e-03+1.22780539e-01j, + -5.36931375e-02-6.72722822e-02j, 1.11920724e-01+1.29862093e-02j, -5.24987149e-02+4.76643575e-02j, 1.05637164e-01+8.27861165e-02j, -1.18864055e-01-1.74568296e-01j, 5.81192411e-03-4.04070185e-02j, -1.03430483e-01-1.69035282e-01j, -1.13502716e-02+8.34191056e-02j, 1.05325163e-01-4.76216714e-03j, -9.25772817e-02+1.50670237e-01j, 4.28140700e-02+3.46151756e-02j, 9.73338934e-02+7.53926315e-02j, -1.25555176e-01+4.50327447e-02j, 2.83269738e-02+2.14864449e-02j, 1.03088528e-01-1.14373265e-01j, -7.31401450e-02+1.77769898e-01j, -1.12535149e-02+4.78161974e-03j, 8.18570896e-02-3.81132366e-02j, -1.33295296e-01-9.10001207e-02j, 8.58276762e-02-1.41863647e-02j, 1.67874702e-01-1.33988434e-02j, -8.67651467e-02+1.32689953e-01j, -3.90355992e-02-3.43351624e-02j, 7.26507704e-02+2.64829915e-02j, 1.11678187e-01+3.90653261e-02j, 1.15906135e-01+1.76724059e-02j, 9.82619413e-02-6.25174727e-02j, -7.37921876e-03+2.82544110e-02j, 1.03018820e-01-6.28247854e-02j, 1.87003733e-01+3.37938203e-02j, + 4.85530302e-03+7.88810000e-02j, -9.36602683e-02+2.03654036e-01j, 6.70298724e-02-1.28682263e-02j, -2.54909646e-02-1.98646445e-02j, -1.98543086e-02+6.61216538e-02j, -8.48576080e-02-2.49620592e-02j, -6.71496603e-02+7.22095879e-02j, 4.76262959e-02+1.21009164e-01j, -4.58951514e-02-5.17531968e-02j, -6.47960010e-02-1.20728072e-01j, 1.60295792e-01-1.40473647e-01j, -1.63756748e-03+1.76260693e-01j, -2.14187214e-02-1.44486405e-01j, 1.38935677e-01+1.82433112e-02j, 2.72551076e-02-8.98792607e-02j, -1.71326545e-01-1.10489461e-01j, 2.59713517e-02+1.80210728e-01j, -1.13356997e-01-5.39655073e-02j, -1.15002327e-01+2.11468680e-02j, 1.22206680e-01+2.00740144e-01j, 5.31251355e-02+3.41911572e-02j, -2.85470406e-02+3.40588721e-02j, 1.62612378e-02-1.25619786e-01j, -5.56722710e-02+8.35975795e-02j, 9.53800031e-02-8.43482473e-02j, -1.09105819e-01+9.48804730e-02j, 4.77081838e-02+9.49219343e-02j, 8.11850606e-02+1.08680074e-01j, 1.22006741e-01+5.82741535e-02j, -2.29701893e-02+6.62232347e-02j, + 3.92315193e-02+6.55030120e-02j, 2.03376796e-01+9.27366361e-02j, 6.35392164e-02+3.23680200e-02j, -5.31622978e-02-2.88908372e-02j, -7.02426374e-03+6.75379556e-02j, -2.12237232e-02-1.83434699e-02j, -6.78967104e-02-5.80275574e-02j, 1.69828044e-01+9.49136570e-02j, -5.08448568e-02-5.19598149e-02j, -1.06691250e-01-9.62889583e-02j, 5.32046688e-02-1.90509591e-02j, -2.50194692e-02-9.29642044e-02j, 1.88093417e-02+7.48436505e-02j, -6.10298150e-02-3.20064291e-02j, 4.40991893e-02+8.70526883e-02j, -3.11373800e-02-7.99283258e-03j, -1.21129358e-03+6.04760979e-02j, 1.23181705e-01+3.86186523e-02j, -3.45111027e-02+4.90467351e-02j, -6.92065655e-02-3.02708167e-02j, 5.84411839e-02-4.52250729e-03j, -2.94612333e-02-1.11594151e-01j, -4.35060760e-02+3.08939714e-04j, 1.65268661e-01+1.78101296e-02j, -9.71783036e-02-9.50097168e-02j, 3.12533928e-02-1.60026912e-02j, -7.79738476e-03+4.88586564e-02j, -8.40499527e-02-6.37198817e-02j, 9.61353831e-02+1.26583069e-01j, -5.53354967e-02-2.40176823e-02j, + -1.15968617e-01+3.30895067e-02j, 1.62856623e-01-3.47484132e-02j, 1.63934966e-02-1.56508626e-01j, 1.64466893e-01-1.15467354e-01j, 3.63366559e-02-1.20918496e-02j, 5.57051607e-02-2.18319816e-01j, 6.95284985e-03+1.83828937e-01j, 4.11729400e-03-1.49751410e-01j, 1.16899770e-01+5.20485323e-02j, -5.34538311e-02-1.12893252e-02j, 2.25104422e-02+1.11501556e-01j, -4.55768609e-02+2.15601916e-02j, -1.94808270e-02-1.27154235e-02j, 2.91608554e-03-5.58722359e-03j, -1.03179399e-01+6.99009222e-02j, 1.13405865e-01-2.56399009e-02j, 3.13735506e-02-5.75109182e-02j, 3.65624418e-03+1.07627557e-01j, -2.24465012e-02+9.87669291e-02j, -9.35607749e-02-5.07987181e-02j, 5.79961983e-02+3.09445598e-02j, 2.97307432e-03+3.93021054e-02j, 2.11226275e-02-9.88357430e-03j, 3.13416632e-02+1.03456485e-01j, -1.01917192e-02+6.18006060e-02j, 2.71549373e-02+1.35561825e-01j, -7.68074153e-02-6.85512247e-02j, -1.17581867e-02-2.53829160e-02j, 9.28375780e-02-6.14954707e-02j, -1.41596614e-01+1.07188921e-02j, + -7.28860525e-03+2.43651634e-01j, -8.80650359e-02+1.43082304e-01j, -1.26341313e-03+8.32647482e-02j, 2.03115842e-01+6.89095479e-02j, 1.67115866e-01-4.60730662e-02j, -1.05755428e-01+1.22039239e-01j, -1.43352206e-01-2.39082798e-02j, -4.18043091e-02+8.97024776e-02j, -7.77240171e-02+2.19308414e-01j, -9.11640110e-03+8.65422721e-02j, -1.05457490e-01-1.84014637e-02j, 6.77892119e-02+2.28872910e-02j, 1.16564450e-02+4.25565495e-02j, 1.26894200e-01-1.70513750e-01j, -1.20932866e-02-1.23697146e-01j, -1.05797816e-01-7.67449744e-02j, 5.47589103e-03-1.90378815e-01j, -1.22361425e-01-3.64873506e-04j, -4.92975620e-02+2.03877639e-01j, -1.01416867e-01-2.20615975e-02j, -4.04668442e-02+1.54538885e-02j, -7.31195916e-02+1.47711186e-01j, 1.28543207e-02+3.67988918e-02j, 6.59874297e-02-2.20951499e-02j, -5.69867977e-02-2.77874616e-02j, -1.39863923e-02-3.92723193e-02j, 3.44966375e-02+9.17851631e-02j, -1.35718074e-01+3.35410957e-02j, 2.56668817e-01+3.62517597e-02j, 1.45008246e-03-1.67266042e-02j, + 7.23949189e-02+3.50058311e-02j, 2.95906913e-02-5.11673530e-03j, -2.89210703e-02-7.83260207e-02j, -3.95276055e-02+2.62070530e-02j, 1.89223565e-02-3.73511633e-03j, -1.49815586e-01-3.23024572e-02j, -2.76757428e-01+1.09794058e-01j, -1.55603333e-02-9.26240637e-02j, -8.34324290e-02+1.10717331e-01j, -8.49852684e-02+1.21096192e-01j, -2.34217533e-03-2.20533245e-02j, -4.05124372e-02+4.91544177e-02j, 2.21939474e-01+1.06585662e-02j, -1.14788852e-01-1.45670084e-02j, -2.31864711e-02+8.16787838e-02j, 1.05772073e-01-3.81363629e-02j, 1.06410310e-02+5.56535302e-02j, 7.49474640e-02-2.44079960e-01j, -1.14493374e-01+2.54362093e-03j, -9.10842184e-02+4.58644113e-03j, -1.50764400e-01+9.60854982e-02j, 1.17718269e-01-1.33115252e-02j, 2.88747212e-02+2.37461286e-02j, -1.41759597e-02+1.51999121e-02j, -2.47353248e-02+7.48763400e-02j, -3.83509977e-02-3.50842772e-04j, 2.44222600e-02+5.36360149e-02j, -4.15187177e-02+1.66291792e-02j, -6.98415077e-02+1.55027916e-01j, 1.75717100e-01+4.63332796e-02j, + 1.62118073e-01+1.44290350e-01j, 2.27418566e-01-1.45684285e-01j, 3.06208328e-02+4.27399784e-03j, 7.46468629e-02-2.60921832e-02j, 1.36523904e-01+4.44488001e-02j, 4.42830359e-02-8.76058694e-02j, -5.01048932e-02+1.06328634e-02j, 1.74182387e-02-7.92930529e-02j, 1.30387046e-01-5.77562670e-03j, 3.38661732e-03-2.66393819e-02j, -5.84555746e-02+7.24533139e-03j, 9.24386154e-03-7.38257239e-02j, -2.01353089e-01-1.54900117e-01j, -7.64397545e-02-2.64763460e-02j, -1.05638845e-02+4.79286399e-02j, 3.31547555e-02+1.82840041e-01j, 1.02455279e-01-3.22470454e-02j, -2.02968636e-02-1.20561400e-01j, -1.53201600e-03-4.86412356e-02j, -3.36622849e-02+1.23466127e-01j, -3.17666031e-02-5.30530230e-03j, 7.87856594e-02-1.10488726e-02j, -6.50752335e-02-1.53696600e-01j, 1.12242184e-01+9.63039070e-02j, 7.29070752e-03-6.12939915e-02j, -1.27887554e-01-5.27193958e-02j, 2.67746028e-02+1.70487967e-02j, -7.75381791e-02-8.27737207e-02j, -2.68419314e-02+3.52729473e-02j, 2.08583372e-02-4.61001172e-02j, + 1.35435125e-02+7.17668513e-03j, 7.51284375e-02+1.57659374e-01j, -1.16573329e-01+3.45952874e-02j, 1.16952561e-01-1.92810160e-01j, 8.91983080e-03-1.72847221e-01j, -1.37395165e-01-1.29769519e-01j, -5.57858716e-02-1.29509855e-01j, -3.78818453e-02+8.97323481e-03j, -9.26055477e-02-3.82225179e-02j, -1.02176844e-01+7.72429422e-02j, -2.77767386e-02-7.89175823e-02j, 1.08550789e-01-1.24801337e-01j, -7.51967666e-02+4.42884220e-02j, -3.84132813e-02-2.23818923e-02j, 2.10290591e-02-1.63910071e-02j, -1.55546281e-02+6.83243462e-02j, 7.04925956e-02+1.13334991e-01j, -7.80853320e-02+6.46462801e-02j, -3.21182665e-02+5.84735194e-03j, -1.01335631e-03+2.56732273e-01j, 4.63262263e-02-8.08179095e-02j, 3.58066672e-02+4.41791548e-02j, 6.73367098e-02-7.01266251e-02j, -8.73687243e-02+8.94059276e-02j, -7.39072106e-02-1.65025667e-01j, -7.66981818e-02-3.34616641e-03j, -4.22405675e-02-1.60785801e-01j, -4.05947796e-02-6.73805916e-02j, 2.08188645e-02+6.87961393e-02j, 1.67132980e-01+2.05388800e-02j, + 2.10096943e-02-7.14703997e-02j, -1.96928545e-02-2.18626018e-01j, 3.85125630e-02+7.57691532e-05j, 8.30529385e-02-2.07160668e-02j, 1.38867666e-02+1.41588611e-01j, -6.60239944e-02-2.31858478e-01j, -5.97977022e-02-1.57154782e-01j, 1.12189711e-01-1.18577658e-02j, -3.53731368e-02-7.82586039e-02j, 1.75438251e-02+8.76571977e-04j, 1.41945832e-01+9.28040164e-02j, 3.52110938e-02-1.77822589e-02j, 4.95572709e-02-2.87314727e-02j, -1.30143044e-01+5.82148327e-02j, 1.45779892e-01+5.21651803e-02j, -1.98968827e-02+4.94037736e-02j, 6.58149682e-02-6.44416128e-02j, 9.20102049e-02+3.04692222e-03j, -3.38008186e-02-5.63391322e-02j, 8.37698748e-03-3.59590496e-02j, -4.35261097e-02-3.87390686e-02j, 5.76792009e-02+3.44475463e-02j, 9.59522963e-02+2.15717502e-01j, 1.88552950e-02-4.53059574e-02j, 1.70086117e-01-2.64053284e-02j, 2.22595913e-02-7.30566035e-03j, -1.12054071e-02+1.22101799e-01j, -6.41573620e-02+1.66227099e-01j, -3.58693002e-02-2.83078773e-02j, -6.60688819e-02-2.56512600e-02j, + -4.86337540e-02-1.57859846e-01j, -1.25599279e-02-4.54959147e-02j, -2.03534357e-02-2.87431987e-02j, -1.27646849e-02-3.90012510e-03j, 3.47598092e-02+7.87069224e-02j, -3.62772635e-03+1.62428369e-01j, 3.62281855e-02+5.50061027e-02j, -5.70765622e-02-1.34000365e-01j, -9.44564719e-02+1.49567942e-01j, 1.21510992e-01+1.17693975e-01j, -6.62911619e-02-6.46359390e-02j, 7.09082700e-02+2.48476467e-02j, 1.57824600e-01+1.17066315e-02j, -8.44151788e-02+5.34910078e-02j, 8.22583660e-02-9.68421318e-02j, 8.59570275e-03-1.91844681e-01j, 3.00350172e-02+6.80688724e-02j, 8.21553079e-03+3.06162281e-02j, 9.23264499e-02+1.94905975e-01j, -4.14970965e-02+1.08064766e-01j, 2.58033773e-02-6.91497742e-02j, 1.55917773e-01-5.09599368e-02j, -3.65483160e-03+1.14380435e-01j, 5.51468816e-02-2.59419769e-02j, 1.70702211e-01-1.99296533e-01j, 1.47724497e-02-1.85515054e-02j, 2.72122021e-02+7.29287795e-02j, 1.49109842e-01+5.93069060e-02j, -1.66613542e-02-8.67137446e-02j, -1.20909604e-01-2.93675341e-02j, + -9.83917085e-02-1.84204761e-02j, 1.62814792e-01-1.35139306e-01j, 4.73460440e-02+1.31337461e-01j, 2.32713411e-01+2.88388028e-02j, -6.68972821e-02+2.22197631e-02j, 3.92719612e-02+1.52580203e-01j, 2.53776470e-02+7.74832234e-02j, -4.36193830e-02+4.24058557e-02j, 8.23322375e-02+1.76410134e-01j, 1.54890627e-01+5.32375276e-02j, 4.37512275e-02+4.15304821e-02j, -3.49403249e-03+1.52670688e-01j, -9.70650860e-02+1.44844260e-01j, -1.95678640e-03+1.99977290e-02j, -4.80695395e-02+1.94770744e-01j, 2.79827269e-02+9.91437026e-02j, -1.29906563e-02-1.00716455e-01j, 5.77525685e-02-1.30956086e-01j, 2.57358361e-02-6.44845883e-02j, 1.72803438e-02-8.23410272e-02j, 6.55852364e-02+2.73660529e-02j, 1.25689774e-03+5.70941527e-02j, -6.05442115e-02+8.50756711e-02j, -1.20872173e-01+1.94266740e-02j, 1.99440268e-02+6.12317022e-03j, -8.27951261e-02+2.42864309e-02j, -3.47486834e-02+9.66718780e-03j, -9.44474618e-03-1.29324625e-03j, 1.08077651e-01-7.63083493e-02j, 1.77039940e-01+1.34457007e-02j, + 1.02205651e-01-1.32673224e-03j, 2.00202803e-01-4.79903919e-02j, -4.07654990e-02+1.99179948e-02j, 6.65024855e-02+9.63731804e-02j, 6.17223649e-02-2.41440229e-02j, 6.21646020e-02-4.29251282e-04j, -1.19217377e-01-5.11233888e-03j, 5.00452355e-02+9.64116293e-02j, 6.72018105e-02+1.58383035e-02j, 1.04920585e-02-3.75171295e-02j, -5.15836453e-02+4.10383258e-02j, -4.50121432e-02-1.56393689e-01j, -3.69949558e-02-3.49941789e-02j, 4.24813266e-02+4.56446662e-02j, -1.40693525e-01+3.62119110e-02j, 3.54644935e-02+6.55820345e-02j, -1.15036248e-01-6.70995814e-02j, 1.74477980e-01-8.46266302e-02j, 5.63822416e-02+7.09389700e-02j, -6.32001141e-02+5.22351752e-02j, 4.98335744e-02+8.47202636e-02j, 4.63525184e-02-2.59316779e-03j, 1.21744758e-01-2.32443032e-02j, -2.57646251e-01-1.06662161e-01j, 2.17462637e-02+8.80639240e-02j, 9.00883144e-03-1.80037699e-02j, -4.06906387e-02-4.18911845e-02j, 9.21795940e-02-4.20689728e-03j, -6.49150463e-02-8.38487063e-04j, 2.29472275e-02-1.09014529e-01j, + -1.18350148e-01+4.08252745e-02j, 4.82206235e-02-1.43520408e-02j, 8.95036890e-02+1.93669906e-02j, -1.15319803e-01+1.36806111e-01j, -1.74398823e-02-2.77018578e-02j, 2.58644789e-02+5.38396709e-02j, 9.21745774e-02-7.13300386e-02j, 8.49353400e-02+1.58488850e-01j, 1.05015608e-01-3.77073810e-03j, 9.35912413e-03+1.63510644e-01j, -4.73810170e-03-5.70824705e-02j, 6.57060173e-03-1.96057621e-03j, -7.21801277e-02+1.52720724e-01j, 9.56171753e-02+1.17779754e-01j, 4.28275190e-02-3.45548941e-02j, -4.86463734e-02-1.09920637e-01j, -6.83698564e-02-3.81786068e-02j, 1.08564055e-01-1.99558529e-01j, 2.14653459e-01-4.88992080e-02j, -8.24321086e-02+6.30930070e-02j, 3.37396930e-02+8.09973287e-03j, 3.12656291e-02+2.90758576e-03j, 4.19413119e-02+1.76739590e-01j, -1.78314610e-02+1.95598017e-01j, -1.03324368e-02-5.77691340e-02j, 4.49029815e-02+6.21737213e-02j, -8.40076602e-02-9.83562420e-02j, 1.13326150e-01+9.91253684e-02j, 2.38893291e-02+1.12755456e-01j, -8.37705940e-02+1.55665879e-02j, + -4.29407233e-02-1.17518245e-02j, 5.13377269e-02-8.93171618e-02j, 1.20001217e-01+2.01425975e-01j, 1.90297138e-01-8.38967425e-02j, -3.87460366e-02+7.49288218e-02j, -1.24320906e-01+6.56743495e-02j, -6.02213153e-02+3.79364325e-02j, -2.18310318e-02+1.88705143e-02j, 4.26490839e-02-7.19299318e-02j, -9.25682258e-02+2.18607895e-01j, -1.01660296e-01+1.12017637e-01j, 1.51315515e-01+1.84926829e-02j, 8.57594723e-02-7.50221664e-02j, -1.98220124e-02-1.20395767e-01j, 1.27485048e-01-6.69181634e-02j, -2.73468470e-02+4.65786430e-02j, -7.72377306e-02-2.68279016e-02j, -4.41939063e-02-1.86501327e-01j, 3.79414469e-02+1.29131092e-01j, 1.93659647e-03-1.92419385e-01j, -4.08341014e-02+6.14073848e-02j, -3.84304585e-02+7.01256300e-02j, 5.60045546e-03+9.27319924e-02j, -2.27222077e-02-8.96927881e-02j, -5.53554102e-02+8.30322612e-02j, 1.00213142e-01-6.38125486e-02j, 5.47423951e-02-9.71559022e-02j, 3.82241837e-03+1.21289781e-01j, -4.04486610e-02+1.79941878e-02j, -1.03559368e-02-4.30334206e-02j, + 5.89578314e-02+4.00524147e-02j, 1.40916511e-01+6.67082696e-02j, 4.40418631e-02+3.70535594e-03j, -2.67797544e-01+8.62091694e-02j, -3.76648865e-02-2.31015760e-02j, -7.67526017e-02-8.08939654e-02j, 9.26572419e-02+2.16789139e-02j, -6.29159288e-02+1.04174588e-01j, -1.11529756e-01+5.62658454e-02j, 1.17951934e-02-1.61302278e-01j, -1.80869076e-03-6.34125495e-02j, 7.62696393e-02-7.90164136e-02j, -7.87952131e-02-1.39323485e-01j, 1.02348156e-02+5.51626383e-02j, -1.67469740e-02+1.83413897e-02j, -2.87239563e-02-5.06066118e-02j, 8.87510480e-02+8.98941416e-02j, -5.76729095e-02-3.50195824e-02j, -8.61756954e-02+3.10618350e-02j, 2.94118856e-01-7.48255388e-02j, 1.58173913e-02-1.09383861e-01j, 3.21889474e-02+1.12228748e-01j, -6.28360404e-02-1.16637975e-01j, 7.93730300e-03-1.09748836e-02j, 1.27800657e-01-9.16258515e-03j, 3.27511712e-02+1.01571073e-01j, 9.85438792e-02-5.31420117e-02j, 1.61275851e-02-2.80605417e-03j, -1.19686377e-01+1.32242066e-01j, 1.87543551e-01+2.38937126e-03j, + 1.16921884e-02+2.62848401e-02j, -9.86694177e-03+7.77981844e-02j, -9.85602566e-02+2.38507308e-02j, 2.35400707e-03-5.43592014e-02j, -7.23858021e-02-5.93465697e-02j, -1.58506446e-02-5.97662787e-02j, -8.75208135e-03+5.09418023e-02j, -3.08916406e-02-3.48724890e-02j, -1.60191352e-02+1.03111217e-01j, -5.68159068e-02+7.46244049e-02j, 9.23995849e-02-1.05567241e-01j, 1.02643630e-01-4.48982087e-02j, -2.37025557e-02+9.91981818e-02j, -1.51080851e-01-6.60829227e-02j, -1.27955345e-01-3.54218582e-02j, 6.68788444e-02+7.48446185e-02j, 1.25809616e-01+8.22238020e-02j, 5.76912904e-02-7.07594599e-02j, -8.78078680e-02+1.75702063e-02j, 2.23150487e-01+1.21618743e-01j, 3.68863819e-02-2.30063462e-01j, -2.78605009e-02+3.00439015e-02j, 4.76710874e-02-4.21785515e-02j, -2.06022674e-02-8.33240131e-02j, 1.53185096e-01+5.43462784e-02j, 1.10483025e-01-9.58798477e-02j, -1.64335314e-02-1.37741584e-02j, 1.26456713e-01-6.49290331e-02j, 7.02876284e-02+8.95977937e-02j, 8.45954555e-03+1.52604418e-01j, + -1.26458774e-01-1.00591188e-01j, -1.51082804e-01-7.07219691e-02j, 1.35312036e-02+2.42766701e-02j, -2.57820349e-03-5.82206445e-02j, 1.25394937e-02+1.54994794e-01j, 4.34303108e-02+1.67758088e-01j, 2.50193827e-02-1.68203339e-02j, -7.42770942e-03+1.19995245e-01j, -2.14668364e-01-1.80954136e-01j, -7.90535193e-02+7.86162084e-02j, 1.63419690e-02-6.09920610e-02j, -1.35407002e-01-1.56744993e-02j, 1.23914645e-01-4.03721439e-02j, 1.77204484e-03+2.66140087e-02j, 1.25716789e-01-3.78667856e-02j, -2.99746760e-02+4.86935208e-03j, 1.38225290e-02+7.04359534e-02j, 1.72072353e-01+1.31015253e-02j, -6.19101329e-02+1.24807440e-02j, 5.20454040e-02-2.47656886e-01j, 1.05189919e-01-2.88161306e-02j, -1.53992477e-02+7.55199009e-03j, 5.82505243e-03+1.20984659e-01j, -1.42134562e-01+1.12480596e-02j, -1.09111335e-01-1.54002884e-01j, 4.21553065e-02+5.76813852e-03j, -7.58350800e-03+2.26849903e-01j, 4.77762685e-02+3.40790650e-02j, 3.85152600e-03+1.26559590e-01j, -4.06218500e-02+1.26222670e-01j, + -1.28628510e-01-1.00489682e-02j, 7.45782354e-02+6.90716494e-02j, -1.39804487e-01-5.89119056e-02j, -3.13298452e-02-1.40520253e-01j, -3.01100745e-02-8.12306975e-02j, 9.58783144e-02+8.71888394e-02j, 8.17466446e-02-5.59117276e-02j, 8.32972084e-03+1.02402858e-01j, -5.98910605e-02+1.77552646e-01j, -1.62084309e-01+4.79064238e-02j, 4.56745968e-02+2.37759503e-03j, -1.73401279e-01+2.45332405e-02j, -1.08518076e-02-5.51290615e-02j, 1.61371652e-01+7.02663314e-02j, 5.77371628e-03+3.08382613e-02j, -5.23348517e-02+6.18789064e-02j, 6.05004292e-02-4.83654472e-02j, 1.26452871e-02-1.00891539e-01j, 3.01323647e-02+1.96240326e-01j, -5.92861632e-02+1.08424895e-01j, 1.07222615e-01+1.41348222e-01j, -3.52439375e-02+9.37165441e-03j, 2.68309794e-02-1.10349093e-01j, 1.94493578e-02+1.47608062e-01j, 6.93871662e-02-9.40535516e-02j, -6.68998398e-02+3.72529839e-02j, 7.31071439e-02+4.62749207e-02j, 8.22767275e-02+4.33738687e-03j, -1.27461890e-01+7.16800653e-02j, -2.59615938e-02-4.42029716e-02j, + 5.93603172e-02+8.00663553e-02j, -1.30433729e-01+1.22098338e-01j, 6.08017369e-02-7.05338115e-03j, -4.97809705e-02+1.42873842e-02j, -4.40948151e-03-3.62800038e-02j, -7.23446309e-03-2.28188194e-02j, 7.55706875e-02-1.69914898e-02j, 1.20151025e-01+9.98944293e-02j, -2.80746263e-02-5.48362337e-02j, -1.32263858e-01+9.17482255e-02j, -1.57415802e-03-1.08396653e-02j, 3.69312813e-02-2.91296460e-02j, -3.41443670e-02-7.03052603e-02j, -1.38221692e-02-3.27697123e-02j, 8.95111448e-02-3.25747369e-02j, 9.12661146e-02+7.88395467e-02j, 1.33323387e-02+8.39085279e-02j, 1.03179796e-01-2.57974091e-04j, -4.01998444e-02+1.51487692e-02j, -3.29247221e-02+2.28990460e-01j, 1.72097871e-02+3.03322059e-02j, 3.56471471e-02+3.53238951e-02j, -7.01989588e-02+1.25589194e-01j, -1.27727238e-01-2.56240149e-02j, 1.11420554e-01+1.79185848e-02j, -6.33720285e-02-5.24980027e-02j, 1.69408311e-02+2.10972901e-02j, 4.61900829e-02+2.30128229e-02j, 1.64914084e-01+9.53427779e-02j, -8.10370774e-02-4.02999617e-02j, + -2.28926173e-02+6.01414298e-03j, 4.15959537e-02-1.62844430e-02j, -1.04015567e-01-2.28197070e-01j, 5.70917647e-02+6.10634039e-02j, 1.86651786e-02-1.32786359e-01j, 3.52815399e-02+2.63096329e-01j, -5.20942911e-03+9.32562283e-02j, 6.02358871e-02-2.03967495e-01j, 3.07765966e-02+4.43833301e-02j, -1.25342748e-01+9.30307464e-02j, -8.02078208e-02-7.48545491e-02j, 4.41479684e-02+4.55319347e-02j, -1.30358039e-02+3.44938629e-02j, 2.59548001e-03+8.55018910e-02j, -7.24207391e-02+7.25371152e-02j, 4.75649287e-02+8.49041681e-03j, 7.98960425e-02-2.09135805e-02j, -8.16200773e-03+8.52944822e-02j, 5.76132389e-02+7.92413488e-02j, -7.86674994e-03-5.18220519e-02j, 1.61866259e-03+4.58226858e-02j, 2.10573498e-02+1.21302913e-02j, 1.50642093e-01+3.18694799e-02j, -5.11976007e-02+3.35902634e-01j, 1.30304319e-02+1.20557949e-02j, 1.93169643e-02-2.04117390e-02j, 4.21485086e-03+4.50653899e-02j, -6.99644728e-02-4.38648373e-02j, -5.57760973e-02+1.03144757e-01j, -2.77981225e-04-6.55103561e-02j, + -2.47429687e-02-5.56510136e-02j, -1.30487865e-01-2.53886778e-01j, -5.31332551e-02+1.83257653e-01j, 4.49553366e-02-1.27860901e-01j, -1.41877991e-01-9.17018436e-02j, 1.41319426e-01+9.76950302e-02j, 1.69036782e-02+4.32713109e-02j, -2.21736722e-02-1.35943321e-02j, 8.45566133e-02+1.56861643e-01j, 6.06872432e-02+1.10300630e-01j, 8.18810463e-03+4.90937472e-02j, 2.59253095e-02+2.16031285e-02j, 2.91014435e-04-1.31594533e-01j, -1.54684856e-02+2.54619375e-02j, -2.12487171e-02+3.36985235e-02j, -2.13034153e-01-3.81858886e-03j, -2.27912308e-02-3.15100249e-02j, 8.56614800e-02-4.73562392e-02j, -3.21653523e-03-1.00666344e-01j, 4.76758478e-02+1.13788672e-01j, 1.04992660e-01-7.19338205e-03j, 2.61845427e-02-1.95367436e-04j, -5.70545419e-02-8.24770580e-02j, 2.59511921e-02-1.47959999e-01j, 9.90365911e-02-1.07073452e-01j, 4.24238401e-02+6.83240999e-04j, -9.29305355e-03+2.57478648e-02j, 5.09306367e-02+5.17850540e-02j, -3.35412235e-02+5.12389402e-02j, 2.46636595e-02+1.52497496e-01j, + -3.69885214e-02-1.43051224e-03j, -6.34083688e-02+7.95585662e-02j, -7.63159733e-02-9.59472692e-02j, 1.37701675e-01+1.72715523e-02j, 4.43926374e-03+1.03978366e-01j, -9.76045082e-04+1.16177364e-01j, 9.75501498e-02+1.10711036e-01j, -8.61395371e-02+4.75590898e-02j, -1.86326972e-02-8.72703099e-02j, -3.98222506e-02-2.01927936e-03j, -4.56659343e-02+6.85048391e-03j, -8.52516866e-02-3.58323276e-03j, 6.43698794e-02+9.95628825e-02j, -4.39734955e-02+2.10779642e-02j, 1.14785069e-01+1.09119788e-01j, -1.80570955e-01-6.60318868e-02j, 1.82596842e-02+1.32847306e-01j, -1.25277200e-01+1.85473095e-02j, 3.61733437e-02+1.42379572e-02j, -8.92845204e-03+6.77236053e-02j, 1.58690519e-01+6.45710673e-03j, -1.24921492e-02-9.99208311e-02j, -1.91513019e-01+3.48823651e-02j, -9.84584655e-02+1.76559101e-02j, -8.56099318e-02+1.49766608e-01j, -6.12707229e-02+1.07577597e-02j, 1.16550002e-01-2.40802989e-01j, -1.23620543e-02+4.45149950e-02j, -1.76292863e-01-1.09460504e-01j, 3.85853397e-02-5.33685000e-02j, + -4.33475627e-02+6.06156460e-02j, -1.87846565e-02+1.14931789e-01j, -1.02013650e-01-2.29362151e-02j, 6.16651648e-02+7.99999963e-03j, -3.24185056e-01-1.48847542e-01j, -1.15048411e-02-5.67954670e-02j, -1.31298592e-01+9.40862751e-02j, -3.38096707e-02-4.96639503e-03j, 1.01303563e-01-1.20893708e-01j, 3.69567985e-02-7.34673617e-02j, 1.17120440e-01+1.46681717e-01j, -1.08104493e-01+4.59797898e-02j, 1.57388412e-02-9.05862553e-02j, 1.28683206e-01+1.36862876e-01j, 1.20579464e-01+4.56797568e-02j, 5.32546371e-03+2.00030811e-03j, -4.47207586e-02+6.84790769e-02j, -4.28425820e-03+7.32050329e-02j, -5.49771829e-02+3.00964687e-02j, -2.52478091e-02+1.04723922e-01j, -3.75356066e-03-1.20885506e-01j, 3.37046879e-02+4.44937988e-02j, -5.52111021e-02+4.18487207e-02j, 6.53305005e-02+2.24424425e-03j, -4.86068425e-02+1.00608085e-03j, 1.60271931e-01+6.63649255e-02j, 4.60478432e-02+3.98226836e-02j, 3.26150010e-02+1.82968788e-01j, -9.10672877e-02-1.11311630e-01j, 1.00893232e-02-1.39737503e-02j, + 2.71754161e-02-2.34544035e-02j, 9.15977387e-02+1.99426961e-02j, -1.97642710e-01+9.12888621e-02j, 4.74121316e-02-5.13504981e-02j, 5.07225943e-02+9.46633787e-02j, -9.53911293e-02-1.80654690e-01j, 1.64115127e-01-6.50378535e-02j, 1.09449061e-01+5.60124725e-02j, 1.53796325e-01+5.18189982e-02j, 5.17206905e-02+1.90530640e-01j, 7.50057667e-02-1.03567448e-01j, -3.82878661e-02-1.80075937e-01j, 4.01978788e-02-1.00698223e-01j, 1.03377853e-03-3.07692277e-02j, 1.20225227e-01+2.07456969e-01j, 1.04309283e-01-9.26611183e-02j, -1.03361361e-01+1.95889640e-02j, 2.58259256e-02+1.58281886e-01j, 7.75239291e-02-1.01311736e-01j, 9.15117078e-02-7.60188931e-03j, 1.14475846e-01-6.79271552e-02j, 5.44144608e-02-1.28520982e-01j, -9.52291620e-02-6.55706207e-02j, 3.43890303e-02-2.76969004e-02j, -1.02611436e-01-1.50417588e-01j, 3.21748176e-02-3.07119412e-02j, -3.86609986e-02+7.35572270e-02j, -5.24141267e-02-2.68636860e-02j, 1.15398753e-02+5.32210898e-02j, -1.73433735e-01-1.20650971e-01j, + 1.59124482e-01-1.31576336e-02j, 1.20225299e-01-1.52593103e-01j, -9.55610838e-02-6.95071254e-02j, 5.40075010e-03+3.80444187e-02j, -1.17110757e-02-3.28355329e-02j, -3.14854352e-02+9.13669332e-02j, -2.11449648e-02-7.11967389e-02j, -1.05950323e-02+1.75284874e-01j, 1.84744416e-02-6.85391690e-02j, 3.46360131e-02+4.62850612e-02j, 8.41213852e-02-1.24326928e-02j, 9.98813964e-02+2.08812494e-02j, 5.76777438e-03-5.35307536e-02j, -9.73557829e-02+2.03322351e-01j, -7.32834396e-03+3.51292305e-02j, 1.97020322e-01-3.69066750e-02j, -4.20662160e-02-1.01225755e-01j, 4.66345435e-02+4.48953960e-02j, -2.96526616e-02+2.70537698e-02j, -1.12505815e-01-4.81118731e-02j, 6.21206830e-02-7.15323882e-02j, -4.47070431e-02+1.45161193e-01j, 5.16437799e-02+1.48994784e-01j, -4.60222096e-02-9.52131423e-02j, 5.53010620e-02-4.16026288e-02j, 3.29589607e-01-8.01715204e-02j, 7.43597136e-02-8.52844592e-02j, -1.50760562e-02-1.18150067e-01j, 2.04861788e-01+5.84783818e-02j, 1.93288780e-02-2.43307354e-02j, + -1.99745724e-01+3.64362975e-02j, -3.43725281e-02-6.21676876e-02j, 3.63703503e-02-6.52874052e-02j, 8.94751529e-02+4.47611628e-02j, -6.65470145e-02-7.98519549e-02j, 1.01433775e-02-7.72488898e-02j, 1.06307469e-01+7.79035119e-02j, -4.78507257e-02-6.23415087e-02j, 3.78893691e-02+2.62410143e-02j, 1.73318720e-01-3.21495796e-02j, -1.65681634e-01+6.67285599e-02j, 1.94291731e-01-2.89109408e-02j, -4.54548567e-02+5.83158238e-02j, 5.61383335e-02+3.83324113e-02j, 1.21596304e-01+1.70747464e-01j, 1.27954274e-01-1.93444819e-03j, -8.37891724e-02-8.64889585e-02j, 3.80499478e-02+2.01027939e-02j, 9.43965724e-02-8.90623338e-02j, -4.79597835e-02+4.75603864e-02j, -8.61574607e-02+8.32130201e-02j, -1.55412399e-02-1.27006036e-02j, -7.42519286e-02-8.61685534e-02j, -8.10108175e-02-6.16012333e-03j, -7.37177736e-02-4.44450757e-02j, 1.43980441e-01+5.66282763e-02j, -7.16666783e-02-1.66644680e-01j, 1.52513989e-01+5.67736253e-02j, -7.22985818e-02+4.50107611e-03j, 8.57243393e-02+1.44598168e-01j, + 2.61325291e-03-1.17556073e-01j, 7.88519979e-02+6.74275525e-02j, 7.41806885e-02-4.95153472e-02j, -1.84676918e-03+3.29891980e-02j, 3.84952719e-02+1.48034075e-01j, 3.04972039e-02-7.37869287e-02j, 7.01507010e-02-2.44450088e-02j, 3.33009500e-03+1.05487204e-04j, -4.25430453e-02+5.86220817e-02j, -1.05973079e-01+7.39664382e-02j, 2.92878309e-02+5.28859984e-02j, 5.61329338e-02+1.69166909e-01j, 5.28499244e-02+3.45360084e-02j, -6.53900660e-02-8.61522262e-02j, 7.96946190e-02-3.41452511e-02j, 5.22770869e-02-7.40489497e-03j, -1.88772294e-01+3.96780063e-03j, -2.32936723e-02-5.37723356e-03j, -1.24854292e-01-1.40224821e-02j, 3.07904415e-02-3.15381949e-02j, -3.25235318e-02+8.42701028e-03j, 1.66862279e-01+1.19354852e-01j, 1.57978914e-01+3.63014900e-02j, 8.67807480e-02+1.40379161e-01j, -5.07193433e-02-1.40569523e-02j, -5.00888412e-02-2.23435528e-02j, -7.17048440e-02-9.81330153e-02j, -2.12409092e-02+5.45752543e-02j, 6.06474942e-02+5.88358912e-02j, 6.80174213e-02+3.30162415e-02j, + -6.07282111e-02+1.02939777e-01j, -1.87732930e-02+1.92200565e-02j, -1.16626047e-01+6.45786333e-02j, 1.37742795e-01+8.42180324e-02j, -1.20841908e-01+7.65002919e-02j, 3.46012372e-02-4.84411652e-02j, -1.01213514e-02+1.20822878e-01j, 1.20196281e-02-3.67275266e-02j, 3.92842430e-02+2.04356272e-02j, -3.50278977e-02+1.22347382e-01j, 1.91917372e-01-6.95304549e-02j, 9.29916189e-02+6.32480707e-02j, -1.40237138e-01+4.73312139e-02j, -5.46257907e-03-3.43833080e-02j, 5.25735063e-02+1.22349339e-02j, 5.55091124e-02+4.13346745e-02j, 3.80292721e-02+8.69044043e-02j, -1.57996649e-01-7.65619514e-02j, 1.75325367e-03-1.92975200e-02j, 4.93539327e-02+1.78264744e-01j, 1.02628124e-01-9.66824408e-02j, -3.21786689e-02+4.29915452e-02j, -8.65810365e-02+1.13052509e-02j, -3.85279691e-02+6.40545958e-02j, 1.08229295e-02-8.43402245e-02j, 1.79862749e-01+7.88074870e-03j, -2.87530932e-02+2.46179737e-01j, -1.27639034e-01+1.94348924e-04j, 8.38416209e-02+1.18533050e-01j, -9.80168967e-02-2.75891572e-02j, + -1.18741656e-01-1.12401688e-01j, 1.73015815e-01+3.17142696e-02j, -1.12689840e-01-6.31993322e-03j, -1.42069958e-01+1.71043064e-01j, -7.41914581e-02-1.51931975e-01j, -3.66012909e-02+2.39026896e-03j, 5.14718439e-02-1.03341673e-01j, -4.72099830e-02+1.26667668e-02j, 1.37512313e-02-2.60230700e-02j, -6.00589937e-02+2.54281176e-03j, -1.55002558e-02+6.29291268e-02j, -1.19615201e-01+6.77959328e-02j, 2.31292548e-02-1.08782093e-01j, -1.09964341e-01+1.25294910e-01j, -7.47861771e-02-5.98894488e-02j, 4.71331416e-02+1.43755876e-01j, -1.38666615e-02+1.01256745e-02j, -1.00179410e-02+1.11863487e-01j, 6.31224250e-02+1.19440718e-01j, -4.16177531e-02-4.36345510e-02j, -3.48014985e-02+8.85623335e-02j, 1.24650686e-01+1.48734266e-01j, -2.24549336e-02-1.00924355e-01j, -1.02751585e-01-2.12847917e-01j, -1.05847008e-01-5.29000688e-02j, -4.67909943e-02-1.36206316e-01j, -4.85632359e-02+1.42473156e-01j, -1.24246749e-01+6.42615904e-02j, 5.81696877e-03-4.96687519e-02j, -2.24424614e-02-3.88848488e-02j, + -7.74915273e-02+1.54367388e-02j, 4.34592454e-02-1.56021904e-01j, -8.56892132e-02+1.24030217e-01j, -4.89507658e-02+5.90317176e-02j, -1.25697664e-01-2.32861745e-02j, -1.61863374e-01+1.19418496e-01j, -2.90213516e-03-2.82791717e-02j, 4.50605390e-02-1.85114054e-01j, 1.02768328e-01-7.98889081e-02j, -8.15041765e-02+7.49613006e-02j, 7.62836130e-02-1.09942641e-01j, -2.43957305e-02+1.60075781e-02j, 1.25368088e-01-4.97508023e-02j, 4.32447252e-02-6.48555547e-02j, -2.64345140e-02-1.18679637e-01j, -5.49407140e-02+2.89175240e-02j, -4.47502071e-02+7.51395018e-02j, -4.99554424e-02-1.05535549e-01j, 7.47066390e-02+1.23133955e-01j, 1.03069754e-01-1.57446612e-01j, -2.38467760e-01+1.51184192e-01j, 3.55395997e-02-1.03355238e-01j, -2.32302845e-02+4.74672683e-02j, 8.73424064e-02+9.29539222e-03j, 1.37790158e-01-1.37543346e-01j, -9.47568754e-02+4.59808420e-02j, 1.41612817e-01-7.50145993e-02j, -1.21252993e-01+2.11071077e-02j, 5.93864166e-03-1.03518747e-01j, 1.00814386e-01-1.08636130e-01j, + 8.47764700e-02-1.36804644e-01j, -4.06295973e-02-3.17316929e-02j, -1.29388374e-01-1.13022235e-01j, 4.05034297e-02-1.51303513e-01j, 5.35895225e-02-9.81906501e-02j, 1.01307296e-02-6.14659966e-02j, 7.19860763e-03-7.87661099e-02j, 6.87236698e-03+7.01353724e-03j, 1.84117743e-01+1.14586080e-01j, 3.91942011e-02-1.67427533e-01j, -4.34340225e-02-2.41238971e-02j, -4.20038485e-02+5.76875010e-02j, 5.23551179e-02-3.79231514e-02j, 1.17465353e-01+1.19464437e-01j, -9.14539775e-02+9.32704953e-02j, -3.28255936e-02+2.00709680e-01j, -3.47973061e-02-6.96489860e-02j, 5.68759165e-02+4.46913265e-02j, -4.55834517e-02-6.49989637e-03j, 6.92236117e-02+6.31449747e-02j, -1.00908352e-01-7.69839513e-03j, 1.81960295e-02-3.79970705e-03j, 1.68374360e-02+1.05842359e-02j, 1.28460284e-01+6.09000930e-02j, -1.02077544e-01+6.69284634e-02j, -1.53969863e-02-1.52720337e-02j, 1.81218895e-01+3.16794729e-02j, -1.24806065e-01+2.26699104e-02j, -3.03130859e-02-2.23873943e-02j, -6.99493462e-02-7.03904849e-03j, + -3.67200875e-02+2.84145877e-02j, 9.43878591e-02+7.21251481e-02j, 6.58129601e-02-3.60549923e-02j, 6.61779478e-02-3.04054186e-02j, -6.13842814e-02-6.07921661e-02j, 8.98783698e-03-7.41166890e-02j, 1.16392800e-02-2.36748091e-02j, -1.10768989e-01+4.56420908e-02j, 3.72471227e-03-1.25668424e-03j, -1.29167025e-01+5.63022023e-02j, 1.05866530e-01+1.86155416e-02j, -6.67515779e-02+6.46395437e-02j, -1.03224770e-02-6.42898639e-02j, 6.21606257e-02-5.26347583e-02j, 2.57841919e-02+3.56828380e-02j, -8.55918562e-02+1.63670027e-01j, -4.31423671e-02+7.94041400e-03j, 8.59410574e-03+5.25343549e-02j, -1.33389296e-02+4.52481973e-03j, 7.58536209e-02+7.06748771e-02j, -4.14761871e-02-1.02294821e-01j, -6.50116056e-02-2.21306166e-02j, 2.33077150e-01+5.67852132e-02j, 4.86390845e-02-2.02001648e-03j, 7.53644961e-02-1.89453116e-02j, 2.08862978e-02-1.49855086e-02j, 1.33052297e-02+1.01522608e-01j, 1.51083846e-01+1.12903477e-01j, -1.62667787e-01+6.56239071e-02j, 1.45208158e-01-5.36623261e-02j, + -6.95826831e-02+1.39196707e-01j, 3.29916774e-02-6.75590243e-02j, 3.95917337e-02+5.93925052e-02j, -2.26219692e-02-2.87050486e-02j, -7.18277375e-02-2.33909540e-01j, 3.23958840e-02+6.33185484e-02j, 6.84165483e-02+1.09982301e-01j, -1.76022868e-02+1.67477409e-01j, 1.23647618e-01+5.72347084e-02j, 1.01034190e-01-2.91422180e-02j, -9.75792719e-02+6.92072056e-02j, 2.24926784e-02+4.92453456e-02j, 9.72881515e-02-1.19536229e-02j, -3.46137229e-02-2.17219106e-01j, 1.18110854e-01-2.25904054e-02j, 7.03378796e-02+3.42026266e-02j, -8.74713404e-02+8.22715157e-03j, -1.03981674e-01-1.24708617e-01j, 3.55529717e-02-3.88864430e-02j, -1.37342148e-01-9.40956813e-02j, 4.45450338e-02+2.39754202e-01j, 2.41743357e-02+2.06386810e-01j, 1.08491505e-01+8.89560185e-02j, 5.47927931e-02+4.36730443e-02j, -1.77677037e-01-1.15306877e-01j, 2.38957141e-02+1.47875042e-01j, 4.55000869e-02-2.62193008e-02j, 2.12153347e-01+1.42025329e-01j, -5.30709017e-02-7.21771704e-02j, -5.46350714e-02+5.94590117e-02j, + 4.20227987e-02+5.33808606e-02j, -5.44950519e-03-1.02152548e-01j, -8.52371557e-02+6.87526175e-02j, -9.88849806e-02+8.63653429e-02j, -3.29535337e-02+1.11468767e-01j, -8.91525767e-02-1.10460050e-01j, 8.65861644e-02+6.93102010e-04j, -9.60730971e-02+1.56945079e-01j, -5.14109278e-03-2.81513903e-02j, -1.40068665e-01+2.86562459e-02j, -9.83017425e-02+5.21354581e-02j, 4.69469551e-02-8.89922402e-02j, 2.21941752e-02-5.57626726e-03j, 1.66024586e-01-7.95503934e-02j, -1.38920743e-01+6.04827362e-02j, 8.25451438e-02-6.28766108e-02j, 4.25038037e-02+1.82529097e-02j, 2.62973135e-02-4.18821635e-02j, -1.45761903e-01-1.47286365e-01j, 9.89672045e-02-1.24387645e-01j, -5.78704218e-02-1.62675064e-02j, -4.71981727e-02+2.44048888e-01j, 3.99979719e-02-5.61776567e-02j, -5.90057528e-03-2.06685934e-02j, 1.00743108e-01+1.26113923e-01j, -8.30394273e-02-8.67700959e-02j, -2.42292161e-02+5.45664588e-02j, 1.03200164e-01+4.38793374e-03j, -1.29760046e-01-1.16149074e-01j, -4.06013934e-02-2.91615196e-02j, + -7.66643814e-02-2.82129167e-02j, 5.18827442e-02-9.09744909e-03j, 1.74289199e-02+1.30371358e-01j, -2.12748239e-01+8.60445151e-02j, -4.50027204e-02-4.68921603e-03j, -1.65936974e-02+9.74970666e-03j, 1.89314727e-02-1.52142208e-02j, 1.40710985e-03-7.24579715e-02j, -2.85195855e-02-4.64302487e-02j, 9.28808388e-02-5.38966974e-02j, -8.37647013e-02+3.87783304e-02j, -7.93612636e-02+5.52106771e-02j, -8.24627154e-02-7.29275080e-02j, -9.95466967e-02-2.55863384e-02j, -1.11330369e-01-1.07026510e-02j, 9.03801665e-02+7.48566039e-02j, -1.57610909e-02-2.11373355e-03j, -1.29136461e-01-1.57473543e-02j, 1.44036925e-01-1.17830341e-01j, -1.67628907e-02+1.06263346e-01j, -1.78654592e-02-1.01880945e-01j, -2.49916456e-02+4.60896420e-02j, 2.10042132e-01-7.70664131e-02j, -7.63588341e-02-3.73507331e-02j, -7.46108448e-02+1.98266460e-02j, 7.96343195e-03+3.98058310e-02j, 7.08286705e-02+5.89683331e-02j, 9.06570839e-03-1.68675820e-01j, -7.58415198e-02-1.61708205e-02j, 1.63594232e-01+1.06080863e-01j, + -5.27043428e-02+1.97776646e-01j, 1.68672907e-01+1.72692116e-01j, 1.20883554e-01-4.19624503e-02j, -4.06781283e-02-3.62701240e-02j, -1.81279165e-02-5.02802312e-02j, 1.06586105e-01-6.34529844e-02j, 2.24092969e-01-1.34142134e-02j, 4.64319738e-02-5.98185270e-03j, -7.72761980e-02+6.83240697e-02j, -2.47197188e-02-6.64142633e-02j, 6.12047543e-02-5.67342772e-02j, 6.89583775e-02-7.32779423e-02j, -9.73665566e-02-1.38092077e-01j, 9.42299578e-02-7.83134489e-02j, 4.66576304e-02+5.01211578e-02j, -5.84347124e-03+2.76985347e-02j, 2.32720197e-02-4.52208360e-03j, 1.03896607e-01-4.81745519e-02j, -2.53632308e-02-9.39062130e-02j, -1.33410903e-01+1.61699487e-01j, 1.41818815e-01+7.56963929e-02j, -1.38784180e-01+1.42229126e-01j, -7.82906496e-02+1.02452713e-01j, 1.62728062e-01+5.26600513e-02j, -4.70320160e-02+4.62832652e-02j, -1.34884657e-03+5.09580708e-02j, -1.21163909e-01+1.96909871e-01j, -2.72261417e-01-6.42506010e-02j, 2.86136429e-02+8.86315131e-02j, 5.31085101e-02-2.71828288e-02j, + -3.21727877e-02-5.77796931e-02j, -9.44638527e-02+1.37507662e-02j, -1.21657787e-01+8.65124885e-02j, -4.96839239e-03-2.97644254e-02j, -1.19540366e-01-1.34414909e-01j, 1.30160754e-01-1.26480898e-02j, -7.18591735e-02-2.46715270e-02j, 1.36140893e-01+4.14359423e-02j, -5.71317147e-03-1.18124735e-01j, 3.73988883e-02-2.36730347e-02j, 5.33823290e-02-8.47267547e-03j, 5.80851057e-02-3.92213264e-02j, 2.96021470e-02+1.06824598e-01j, 9.52300406e-02+8.04315308e-02j, -2.19648403e-02-8.28498260e-02j, -2.89222027e-02-9.84731848e-02j, 1.10461055e-01-1.58070614e-01j, 2.09076408e-01+3.68001449e-02j, -6.73813906e-02+9.16108413e-03j, 3.03631342e-02+2.95543290e-02j, -4.54437979e-03-3.18493443e-03j, -7.63023942e-02+1.55592989e-01j, -3.19220889e-02+4.73941064e-02j, 7.13699814e-02-5.69129591e-02j, -9.54995207e-02-3.92267051e-02j, -3.94296081e-02-1.51384146e-01j, 9.68318889e-02-7.70409747e-02j, 1.25939378e-02+3.18634620e-02j, -6.89127002e-02+7.07882363e-02j, 2.43254950e-02+1.16436448e-01j, + -9.91874227e-03-5.42893449e-02j, 1.23743411e-01+4.78200570e-02j, -5.85714409e-02+3.39221080e-02j, 3.65412457e-03-4.02554546e-03j, -2.05342433e-02+2.06713323e-01j, -3.02186741e-03+1.99788433e-02j, 1.16854339e-01-1.15247241e-01j, 9.62932923e-02+3.42143052e-03j, 4.26837528e-02+1.80563531e-01j, -1.23230416e-01+8.43397964e-02j, -1.66241403e-01-7.38559917e-02j, 8.12086119e-02-6.97547686e-03j, -7.31213186e-02+7.79960115e-02j, 2.85823841e-02-2.07511068e-02j, 8.27080727e-02+4.36355847e-02j, -1.10859884e-01-1.36676547e-02j, 1.28303434e-01-1.06149501e-02j, -1.46242136e-01+7.04963534e-02j, -8.26304595e-02-4.38762538e-02j, 1.71071748e-01+4.02667862e-02j, -1.35488426e-01-6.87212472e-02j, -4.67922162e-02-1.03931421e-02j, -2.44813702e-02-5.53092986e-02j, 4.73878499e-02+2.91459937e-02j, 1.98580413e-02-6.12412029e-03j, 1.10488978e-01-2.45764352e-02j, 8.00241132e-02-8.57174156e-02j, 1.03702916e-02-5.49489277e-02j, 3.93099516e-02+3.06121558e-02j, -3.02550594e-02+1.18718205e-01j, + -1.36619382e-01+2.34100763e-02j, -1.45312692e-01-2.24127604e-01j, -2.38248910e-02-1.11579180e-01j, 2.29159458e-02+6.19272697e-02j, 7.32380697e-02+1.36444819e-01j, -4.61302116e-02-2.18822134e-01j, -4.49007145e-02-2.24886131e-02j, -1.47568288e-01-2.04472654e-02j, 2.73175459e-02-2.19629877e-02j, 1.24524515e-01+9.26245193e-02j, -3.55583512e-02+5.09874867e-02j, 1.81713481e-01+8.06582753e-02j, 3.11561167e-02-1.22752357e-01j, -1.72074875e-01-1.29423169e-01j, 5.08999251e-02-6.26136051e-02j, 1.02390035e-01+8.45685534e-02j, 5.52593493e-02+3.68538488e-02j, -5.70061651e-02-4.25009402e-02j, -1.56072617e-02+8.62563257e-03j, -5.21205630e-02+2.36450605e-02j, -1.08956603e-01+5.57188609e-02j, -6.99571459e-02-3.51674530e-02j, 4.86802380e-02+3.37359307e-03j, -4.13618066e-02-2.12316403e-02j, -1.46621977e-01-4.74596174e-02j, -9.63426212e-02+1.72166337e-02j, 2.51705991e-02+3.21369206e-01j, 4.96769009e-02+3.48387702e-02j, -1.04762586e-02+1.56285574e-01j, -3.67404105e-03+7.68483799e-02j, + -4.46016110e-02+1.95201429e-02j, 4.38113722e-02+8.65962895e-03j, 7.74746787e-02+6.94607249e-02j, 2.47130647e-02-1.12600318e-02j, -7.48410468e-02+7.24300380e-02j, -3.77887553e-02-4.43488254e-02j, 1.32708760e-01+4.87164738e-02j, 1.63778016e-01+1.40758747e-01j, 8.20076371e-02-1.79740773e-01j, 5.49371276e-02+3.22196346e-02j, -2.37249431e-02-1.30833713e-01j, 1.19126218e-01+1.15211057e-01j, -8.03659026e-03+2.24442260e-02j, 9.06621949e-02+1.69073869e-02j, -9.84253648e-02-1.22959233e-01j, -1.13106787e-01-1.00708166e-02j + ] + + u1 = ql.Unitary("adding_2_to_the_power_6_unitary", matrix) + + def test_using_qx_sparse_unitary(self): + num_qubits = 5 + p = ql.Program('test_using_qx_sparse_unitary', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + -0.11921901-0.30382154j, -0.10645804-0.11760155j, -0.09639953-0.03539260j, -0.32605797+0.19552924j, 0.01682620-0.26748208j, -0.17808469+0.25265196j, -0.24676084-0.23228431j, -0.02960302+0.23697569j, + -0.12435741-0.07223017j, 0.00178745+0.14813263j, -0.11173158+0.26636089j, 0.27656908+0.05229833j, -0.02964214-0.01505502j, -0.26959616+0.23274949j, -0.18183627-0.04041783j, 0.05385991-0.05587908j, + 0.17894461-0.25668366j, -0.01553181-0.07446613j, 0.18764670-0.49135878j, -0.18292006-0.04599956j, -0.01618695+0.21951951j, 0.06003169-0.12728871j, -0.04276406+0.08327372j, 0.30102765+0.18403071j, + -0.08122018-0.08375638j, -0.02971758+0.09096399j, 0.10753511-0.03359547j, -0.15963090+0.20649279j, -0.13684564+0.29450386j, 0.20557421+0.24856224j, 0.06834440+0.01780095j, -0.22317907-0.12123145j, + -0.03235040-0.02668934j, 0.08743777-0.49956832j, -0.30202031-0.22517221j, -0.10642491-0.11883126j, -0.13756817-0.20632933j, 0.02593802+0.00583978j, 0.05130972+0.06678859j, -0.10426135-0.14411822j, + 0.12318252+0.28583957j, 0.04903179-0.31898637j, -0.07650819-0.07261235j, -0.22918932-0.28329527j, -0.26553775+0.04563403j, -0.07728053+0.14952931j, -0.10271285-0.00216319j, -0.09000117+0.09055528j, + -0.15385903+0.01767834j, 0.42229431-0.05610483j, -0.11330491-0.05458018j, 0.01740815-0.01605897j, -0.11908997-0.01830574j, 0.21139794-0.10602858j, -0.23249721-0.25516076j, -0.29066084-0.19129198j, + 0.21273108-0.14369238j, -0.20662513+0.14463032j, 0.25124660-0.20356141j, 0.08694950+0.24425667j, 0.09736427-0.03954332j, 0.14463030+0.14263171j, -0.25679664+0.09389641j, -0.04020309-0.19362247j, + 0.12577257-0.14527364j, 0.00371525+0.14235318j, -0.22416134+0.02069087j, 0.03851418-0.05351593j, -0.00289848-0.33289946j, 0.15454716-0.12663300j, -0.08996296-0.09119411j, -0.00804455-0.19149767j, + -0.13311475-0.47100304j, -0.13920624-0.16994321j, -0.05030304+0.16820614j, 0.05770089-0.15422191j, -0.23739468-0.05651883j, 0.19202883+0.03893001j, 0.48514604+0.01905479j, -0.01593819-0.06475285j, + 0.31543713+0.41579542j, -0.08776349+0.24207219j, -0.07984699-0.12818844j, 0.00359655+0.02677178j, -0.12110453-0.25327887j, -0.21175671-0.16500740j, -0.14570465-0.05140668j, 0.06873883-0.01768705j, + -0.13804809-0.16458822j, 0.15096981-0.02802171j, -0.05750448-0.18911017j, -0.01552104+0.03159908j, -0.04824180+0.09434822j, 0.13364470+0.22030451j, -0.37713640-0.17773263j, 0.16023381+0.26613455j, + 0.12688452-0.07290393j, 0.14834649+0.08064162j, -0.06224533+0.04404318j, 0.03464369+0.19965444j, -0.38140629-0.18927599j, -0.19710535-0.17865700j, -0.05078850+0.19579635j, 0.11741615+0.13922702j, + 0.26733990-0.01439493j, 0.10844591-0.19799688j, 0.01177533+0.03184600j, -0.07643954+0.25870281j, 0.28971442-0.25385986j, -0.23713666+0.01838019j, 0.17318640-0.09372299j, -0.36912353-0.02243029j, + 0.03562803-0.09449815j, 0.13578229-0.19205153j, 0.21279127+0.14541266j, -0.20195524+0.18747700j, -0.06326783+0.01348270j, 0.26953438-0.11153784j, -0.28939961-0.08995754j, 0.20662437-0.15535337j, + -0.03615272+0.00848631j, 0.14124129-0.10250932j, 0.08990493-0.13010897j, -0.04547667+0.17579099j, -0.01292137+0.10354402j, -0.21338733-0.11928412j, 0.19733294+0.12876129j, 0.35162495+0.45226713j, + 0.17112722-0.18496045j, -0.34024071-0.09520237j, 0.18864652-0.07147408j, 0.31340662+0.24027412j, -0.07208740-0.11081564j, 0.08727975+0.02830958j, -0.07584662-0.22555917j, 0.07086867-0.27714915j, + -0.19116148-0.02164144j, -0.24831911+0.10552290j, -0.09939105-0.24800283j, -0.15274706-0.12267535j, 0.05237777-0.09974669j, -0.18435891-0.17370020j, -0.20884292+0.10760810j, -0.31368958-0.02539025j, + 0.03436293-0.19794965j, 0.11892581-0.17440358j, -0.03488877+0.02305411j, 0.29835292-0.08836461j, 0.07893495-0.16881403j, 0.21025843+0.13204032j, 0.17194288-0.06285539j, -0.05004970+0.35833208j, + -0.14979745-0.07567974j, 0.00193804+0.04092128j, -0.07528403-0.18508153j, -0.16873521-0.09470809j, 0.50335605+0.00445803j, 0.11671956+0.30273552j, 0.10253226-0.13365319j, 0.16676135+0.18345473j, + -0.10096334-0.24031019j, -0.18452241+0.05766426j, 0.18102499-0.13532486j, 0.06252468-0.18030042j, -0.00591499+0.07587582j, -0.35209025-0.12186396j, -0.25282963-0.26651504j, -0.13074882+0.14059941j, + 0.18125386-0.03889917j, 0.06983104-0.34250760j, 0.37124455-0.00305632j, 0.04469806-0.31220629j, 0.16501585+0.00125887j, 0.15895714-0.14115809j, -0.01515444+0.06836136j, 0.03934186+0.13425449j, + 0.05134990+0.21915368j, 0.00089628-0.30446110j, 0.05443815-0.05530296j, 0.12091374-0.16717579j, -0.06795704-0.25159470j, -0.43324316+0.13138954j, 0.03753289-0.00666299j, 0.16823686-0.22736152j, + -0.00567807+0.05485941j, -0.11705816+0.39078352j, 0.29136164+0.18699453j, -0.09255109+0.08923507j, 0.11214398+0.00806872j, 0.02971631+0.05584961j, 0.25610000+0.22302638j, 0.12491596+0.01725833j, + 0.23473354-0.19203316j, -0.09144197-0.04827201j, -0.06309750-0.16831612j, 0.01497053+0.11121057j, 0.14268640-0.15815582j, 0.21509872-0.08218510j, 0.00650273+0.42560079j, -0.15721229+0.09919403j, + 0.18076365-0.05697395j, -0.10596487+0.23118383j, 0.30913352+0.24695589j, -0.03403863-0.01778209j, -0.07783213-0.25923847j, 0.06847369-0.24604470j, -0.24223779-0.10590238j, 0.15920784+0.21435437j, + 0.26632193-0.02864663j, 0.06457043+0.05774280j, -0.38792984+0.08474334j, 0.00944311+0.22274564j, 0.11762823+0.36687658j, -0.10584280-0.21036370j, -0.12970051-0.27031414j, 0.12684307+0.08398822j, + 0.06711923+0.23195763j, -0.04537262+0.26478843j, 0.10253668-0.07706414j, -0.13531665-0.27150259j, -0.09124132-0.23306839j, -0.08631867+0.17221145j, 0.17654328-0.10341264j, 0.11171903-0.05824829j, + 0.04708668-0.13436316j, -0.10544253+0.07083904j, 0.04191629+0.28190845j, -0.42129470-0.28704399j, 0.10278485+0.05713015j, 0.02057009-0.19126408j, 0.04856717+0.26648423j, 0.05388858-0.32433511j, + -0.09408669-0.12159016j, -0.01355394+0.04757554j, 0.10925003-0.04539990j, -0.02512057-0.23836324j, 0.31375479-0.09935640j, -0.14702106+0.33395328j, -0.16080290+0.11439592j, -0.11028577-0.00936150j, + -0.08440005-0.12376623j, 0.12932188+0.09711828j, 0.18574716-0.06392924j, -0.13048059+0.02879610j, -0.29552716-0.08768809j, -0.02439943-0.01548155j, 0.07775135+0.00727332j, 0.15615340-0.06489038j, + 0.46665242-0.07708219j, -0.05251139+0.37781248j, -0.35490810-0.10086123j, 0.11180645-0.40408473j, 0.03031085+0.16928711j, 0.11901290-0.10061168j, 0.03180460-0.12504866j, 0.08689947+0.07223655j + ] + + u1 = ql.Unitary("using_qx_sparse_unitary", matrix) + u1.decompose() + k.hadamard(0) + k.hadamard(1) + k.hadamard(2) + k.hadamard(3) + k.cnot(0, 1) + k.cnot(0, 2) + k.cnot(0, 3) + k.cnot(1, 2) + k.cnot(1, 3) + k.cnot(2, 3) + + k.gate(u1, [0, 1, 2, 3]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(0.0625 * helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7] + matrix[8] + matrix[9] + matrix[10] + matrix[11] + matrix[12] + matrix[13] + matrix[14] + matrix[15])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[16] + matrix[17] + matrix[18] + matrix[19] + matrix[20] + matrix[21] + matrix[22] + matrix[23] + matrix[24] + matrix[25] + matrix[26] + matrix[27] + matrix[28] + matrix[29] + matrix[30] + matrix[31])), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[32] + matrix[33] + matrix[34] + matrix[35] + matrix[36] + matrix[37] + matrix[38] + matrix[39] + matrix[40] + matrix[41] + matrix[42] + matrix[43] + matrix[44] + matrix[45] + matrix[46] + matrix[47])), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[48] + matrix[49] + matrix[50] + matrix[51] + matrix[52] + matrix[53] + matrix[54] + matrix[55] + matrix[56] + matrix[57] + matrix[58] + matrix[59] + matrix[60] + matrix[61] + matrix[62] + matrix[63])), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[64] + matrix[65] + matrix[66] + matrix[67] + matrix[68] + matrix[69] + matrix[70] + matrix[71] + matrix[72] + matrix[73] + matrix[74] + matrix[75] + matrix[76] + matrix[77] + matrix[78] + matrix[79])), helper_prob(state.get(to_bit_string(4, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[80] + matrix[81] + matrix[82] + matrix[83] + matrix[84] + matrix[85] + matrix[86] + matrix[87] + matrix[88] + matrix[89] + matrix[90] + matrix[91] + matrix[92] + matrix[93] + matrix[94] + matrix[95])), helper_prob(state.get(to_bit_string(5, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[96] + matrix[97] + matrix[98] + matrix[99] + matrix[100] + matrix[101] + matrix[102] + matrix[103] + matrix[104] + matrix[105] + matrix[106] + matrix[107] + matrix[108] + matrix[109] + matrix[110] + matrix[111])), helper_prob(state.get(to_bit_string(6, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[112] + matrix[113] + matrix[114] + matrix[115] + matrix[116] + matrix[117] + matrix[118] + matrix[119] + matrix[120] + matrix[121] + matrix[122] + matrix[123] + matrix[124] + matrix[125] + matrix[126] + matrix[127])), helper_prob(state.get(to_bit_string(7, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[128] + matrix[129] + matrix[130] + matrix[131] + matrix[132] + matrix[133] + matrix[134] + matrix[135] + matrix[136] + matrix[137] + matrix[138] + matrix[139] + matrix[140] + matrix[141] + matrix[142] + matrix[143])), helper_prob(state.get(to_bit_string(8, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[144] + matrix[145] + matrix[146] + matrix[147] + matrix[148] + matrix[149] + matrix[150] + matrix[151] + matrix[152] + matrix[153] + matrix[154] + matrix[155] + matrix[156] + matrix[157] + matrix[158] + matrix[159])), helper_prob(state.get(to_bit_string(9, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[160] + matrix[161] + matrix[162] + matrix[163] + matrix[164] + matrix[165] + matrix[166] + matrix[167] + matrix[168] + matrix[169] + matrix[170] + matrix[171] + matrix[172] + matrix[173] + matrix[174] + matrix[175])), helper_prob(state.get(to_bit_string(10, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[176] + matrix[177] + matrix[178] + matrix[179] + matrix[180] + matrix[181] + matrix[182] + matrix[183] + matrix[184] + matrix[185] + matrix[186] + matrix[187] + matrix[188] + matrix[189] + matrix[190] + matrix[191])), helper_prob(state.get(to_bit_string(11, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[192] + matrix[193] + matrix[194] + matrix[195] + matrix[196] + matrix[197] + matrix[198] + matrix[199] + matrix[200] + matrix[201] + matrix[202] + matrix[203] + matrix[204] + matrix[205] + matrix[206] + matrix[207])), helper_prob(state.get(to_bit_string(12, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[208] + matrix[209] + matrix[210] + matrix[211] + matrix[212] + matrix[213] + matrix[214] + matrix[215] + matrix[216] + matrix[217] + matrix[218] + matrix[219] + matrix[220] + matrix[221] + matrix[222] + matrix[223])), helper_prob(state.get(to_bit_string(13, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[224] + matrix[225] + matrix[226] + matrix[227] + matrix[228] + matrix[229] + matrix[230] + matrix[231] + matrix[232] + matrix[233] + matrix[234] + matrix[235] + matrix[236] + matrix[237] + matrix[238] + matrix[239])), helper_prob(state.get(to_bit_string(14, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[240] + matrix[241] + matrix[242] + matrix[243] + matrix[244] + matrix[245] + matrix[246] + matrix[247] + matrix[248] + matrix[249] + matrix[250] + matrix[251] + matrix[252] + matrix[253] + matrix[254] + matrix[255])), helper_prob(state.get(to_bit_string(15, size=platform_qubits), 0.)), 5) + + def test_extremely_sparse_unitary(self): + num_qubits = 4 + p = ql.Program('test_extremely_sparse_unitary', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + -0.59111943+0.15726005j, -0. +0.j , -0.15509793+0.32339668j, -0. +0.j , -0.33317562+0.00860528j, -0. +0.j , -0.5566068 +0.27625195j, -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j, + -0. +0.j , -0.59111943+0.15726005j, -0. +0.j , -0.15509793+0.32339668j, -0. +0.j , -0.33317562+0.00860528j, -0. +0.j , -0.5566068 +0.27625195j, -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j, + -0.00563624-0.59423429j, 0. -0.j , 0.46013302+0.40732351j, 0. +0.j , -0.30528142-0.21246605j, 0. -0.j , 0.25389832+0.25771317j, 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j, + 0. -0.j , -0.00563624-0.59423429j, 0. +0.j , 0.46013302+0.40732351j, 0. -0.j , -0.30528142-0.21246605j, 0. +0.j , 0.25389832+0.25771317j, 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j, + 0.01676811-0.33500121j, 0. +0.j , -0.46028079-0.49188018j, 0. -0.j , -0.18833511+0.15673318j, -0. +0.j , 0.14043556+0.59492096j, 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j, + 0. +0.j , 0.01676811-0.33500121j, 0. -0.j , -0.46028079-0.49188018j, -0. +0.j , -0.18833511+0.15673318j, 0. +0.j , 0.14043556+0.59492096j, 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j, + 0.3733514 +0.14423137j, 0. +0.j , -0.18039476+0.08589294j, -0. +0.j , -0.80479128+0.20701926j, -0. +0.j , 0.06883732-0.32342174j, 0. +0.j , 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j, + 0. +0.j , 0.3733514 +0.14423137j, -0. +0.j , -0.18039476+0.08589294j, -0. +0.j , -0.80479128+0.20701926j, 0. +0.j , 0.06883732-0.32342174j, 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j, + -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0.59111943+0.15726005j, -0. +0.j , -0.15509793+0.32339668j, -0. +0.j , -0.33317562+0.00860528j, -0. +0.j , -0.5566068 +0.27625195j, -0. +0.j, + -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0.59111943+0.15726005j, -0. +0.j , -0.15509793+0.32339668j, -0. +0.j , -0.33317562+0.00860528j, -0. +0.j , -0.5566068 +0.27625195j, + 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , -0.00563624-0.59423429j, 0. -0.j , 0.46013302+0.40732351j, 0. +0.j , -0.30528142-0.21246605j, 0. -0.j , 0.25389832+0.25771317j, 0. +0.j, + 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. -0.j , -0.00563624-0.59423429j, 0. +0.j , 0.46013302+0.40732351j, 0. -0.j , -0.30528142-0.21246605j, 0. +0.j , 0.25389832+0.25771317j, + 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j , 0.01676811-0.33500121j, 0. +0.j , -0.46028079-0.49188018j, 0. -0.j , -0.18833511+0.15673318j, -0. +0.j , 0.14043556+0.59492096j, 0. +0.j, + 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0.01676811-0.33500121j, 0. -0.j , -0.46028079-0.49188018j, -0. +0.j , -0.18833511+0.15673318j, 0. +0.j , 0.14043556+0.59492096j, + 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j , 0.3733514 +0.14423137j, 0. +0.j , -0.18039476+0.08589294j, -0. +0.j , -0.80479128+0.20701926j, -0. +0.j , 0.06883732-0.32342174j, 0. +0.j, + 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0.3733514 +0.14423137j, -0. +0.j , -0.18039476+0.08589294j, -0. +0.j , -0.80479128+0.20701926j, 0. +0.j , 0.06883732-0.32342174j + ] + + u1 = ql.Unitary("extremely_sparse_unitary", matrix) + u1.decompose() + k.hadamard(0) + k.hadamard(1) + k.hadamard(2) + k.hadamard(3) + k.cnot(0, 1) + k.cnot(0, 2) + k.cnot(0, 3) + k.cnot(1, 2) + k.cnot(1, 3) + k.cnot(2, 3) + + k.gate(u1, [0, 1, 2, 3]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(0.0625 * helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7] + matrix[8] + matrix[9] + matrix[10] + matrix[11] + matrix[12] + matrix[13] + matrix[14] + matrix[15])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[16] + matrix[17] + matrix[18] + matrix[19] + matrix[20] + matrix[21] + matrix[22] + matrix[23] + matrix[24] + matrix[25] + matrix[26] + matrix[27] + matrix[28] + matrix[29] + matrix[30] + matrix[31])), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[32] + matrix[33] + matrix[34] + matrix[35] + matrix[36] + matrix[37] + matrix[38] + matrix[39] + matrix[40] + matrix[41] + matrix[42] + matrix[43] + matrix[44] + matrix[45] + matrix[46] + matrix[47])), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[48] + matrix[49] + matrix[50] + matrix[51] + matrix[52] + matrix[53] + matrix[54] + matrix[55] + matrix[56] + matrix[57] + matrix[58] + matrix[59] + matrix[60] + matrix[61] + matrix[62] + matrix[63])), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[64] + matrix[65] + matrix[66] + matrix[67] + matrix[68] + matrix[69] + matrix[70] + matrix[71] + matrix[72] + matrix[73] + matrix[74] + matrix[75] + matrix[76] + matrix[77] + matrix[78] + matrix[79])), helper_prob(state.get(to_bit_string(4, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[80] + matrix[81] + matrix[82] + matrix[83] + matrix[84] + matrix[85] + matrix[86] + matrix[87] + matrix[88] + matrix[89] + matrix[90] + matrix[91] + matrix[92] + matrix[93] + matrix[94] + matrix[95])), helper_prob(state.get(to_bit_string(5, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[96] + matrix[97] + matrix[98] + matrix[99] + matrix[100] + matrix[101] + matrix[102] + matrix[103] + matrix[104] + matrix[105] + matrix[106] + matrix[107] + matrix[108] + matrix[109] + matrix[110] + matrix[111])), helper_prob(state.get(to_bit_string(6, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[112] + matrix[113] + matrix[114] + matrix[115] + matrix[116] + matrix[117] + matrix[118] + matrix[119] + matrix[120] + matrix[121] + matrix[122] + matrix[123] + matrix[124] + matrix[125] + matrix[126] + matrix[127])), helper_prob(state.get(to_bit_string(7, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[128] + matrix[129] + matrix[130] + matrix[131] + matrix[132] + matrix[133] + matrix[134] + matrix[135] + matrix[136] + matrix[137] + matrix[138] + matrix[139] + matrix[140] + matrix[141] + matrix[142] + matrix[143])), helper_prob(state.get(to_bit_string(8, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[144] + matrix[145] + matrix[146] + matrix[147] + matrix[148] + matrix[149] + matrix[150] + matrix[151] + matrix[152] + matrix[153] + matrix[154] + matrix[155] + matrix[156] + matrix[157] + matrix[158] + matrix[159])), helper_prob(state.get(to_bit_string(9, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[160] + matrix[161] + matrix[162] + matrix[163] + matrix[164] + matrix[165] + matrix[166] + matrix[167] + matrix[168] + matrix[169] + matrix[170] + matrix[171] + matrix[172] + matrix[173] + matrix[174] + matrix[175])), helper_prob(state.get(to_bit_string(10, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[176] + matrix[177] + matrix[178] + matrix[179] + matrix[180] + matrix[181] + matrix[182] + matrix[183] + matrix[184] + matrix[185] + matrix[186] + matrix[187] + matrix[188] + matrix[189] + matrix[190] + matrix[191])), helper_prob(state.get(to_bit_string(11, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[192] + matrix[193] + matrix[194] + matrix[195] + matrix[196] + matrix[197] + matrix[198] + matrix[199] + matrix[200] + matrix[201] + matrix[202] + matrix[203] + matrix[204] + matrix[205] + matrix[206] + matrix[207])), helper_prob(state.get(to_bit_string(12, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[208] + matrix[209] + matrix[210] + matrix[211] + matrix[212] + matrix[213] + matrix[214] + matrix[215] + matrix[216] + matrix[217] + matrix[218] + matrix[219] + matrix[220] + matrix[221] + matrix[222] + matrix[223])), helper_prob(state.get(to_bit_string(13, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[224] + matrix[225] + matrix[226] + matrix[227] + matrix[228] + matrix[229] + matrix[230] + matrix[231] + matrix[232] + matrix[233] + matrix[234] + matrix[235] + matrix[236] + matrix[237] + matrix[238] + matrix[239])), helper_prob(state.get(to_bit_string(14, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[240] + matrix[241] + matrix[242] + matrix[243] + matrix[244] + matrix[245] + matrix[246] + matrix[247] + matrix[248] + matrix[249] + matrix[250] + matrix[251] + matrix[252] + matrix[253] + matrix[254] + matrix[255])), helper_prob(state.get(to_bit_string(15, size=platform_qubits), 0.)), 5) + + def test_sparse_2_qubit_unitary(self): + num_qubits = 2 + p = ql.Program('test_sparse_2_qubit_unitary', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + 0.2309453 -0.79746147j, -0.53683301+0.15009925j, 0. +0.j , -0. +0.j, + 0.39434916-0.39396473j, 0.80810853+0.19037107j, 0. +0.j , 0. +0.j, + 0. +0.j , -0. +0.j , 0.2309453 -0.79746147j, -0.53683301+0.15009925j, + 0. +0.j , 0. +0.j , 0.39434916-0.39396473j, 0.80810853+0.19037107j + ] + + u1 = ql.Unitary("sparse_2_qubit_unitary", matrix) + u1.decompose() + k.gate(u1, [0, 1]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[4]), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[8]), 0, 5) # Zero probabilities do not show up in the output list + self.assertAlmostEqual(helper_prob(matrix[12]), 0, 5) + + def test_sparse_2_qubit_unitary_other_qubit(self): + num_qubits = 2 + p = ql.Program('test_sparse_2_qubit_unitary_other_qubit', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + 0.30279949-0.60010283j, 0. +0.j , -0.58058628-0.45946559j, 0. -0.j, + 0. +0.j , 0.30279949-0.60010283j, 0. -0.j , -0.58058628-0.45946559j, + 0.04481146-0.73904059j, 0. +0.j , 0.64910478+0.17456782j, 0. +0.j, + 0. +0.j , 0.04481146-0.73904059j, 0. +0.j , 0.64910478+0.17456782j + ] + + u1 = ql.Unitary("sparse2_qubit_unitary_other_qubit", matrix) + u1.decompose() + k.gate(u1, [0, 1]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[4]), 0, 5) # Zero probabilities do not show up in the output list + self.assertAlmostEqual(helper_prob(matrix[8]), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(helper_prob(matrix[12]), 0, 5) + + def test_sparse_2_qubit_unitary_other_qubit_check(self): + num_qubits = 1 + p = ql.Program('test_sparse_2_qubit_unitary_other_qubit_check', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [0.30279949 - 0.60010283j, -0.58058628 - 0.45946559j, + 0.04481146 - 0.73904059j, 0.64910478 + 0.17456782j] + u1 = ql.Unitary("sparse_2_qubit_unitary_other_qubit_check", matrix) + u1.decompose() + k.gate(u1, [0]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + # Zero probabilities do not show up in the output list + self.assertAlmostEqual(helper_prob(matrix[1]), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + + def test_sparse_2_qubit_multiplexor(self): + num_qubits = 2 + p = ql.Program('test_sparse_2_qubit_multiplexor', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = [ + 0.30279949-0.60010283j, -0.58058628-0.45946559j, 0 , 0, + 0.04481146-0.73904059j, 0.64910478+0.17456782j, 0 , 0, + 0. +0.j , -0. +0.j , 0.2309453 -0.79746147j, -0.53683301+0.15009925j, + 0. +0.j , 0. +0.j , 0.39434916-0.39396473j, 0.80810853+0.19037107j + ] + u1 = ql.Unitary("sparse_2_qubit_multiplexor", matrix) + u1.decompose() + k.hadamard(0) + k.hadamard(1) + k.gate(u1, [0, 1]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(0.25 * helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.25 * helper_prob((matrix[4] + matrix[5] + matrix[6] + matrix[7])), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.25 * helper_prob((matrix[8] + matrix[9] + matrix[10] + matrix[11])), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.25 * helper_prob((matrix[12] + matrix[13] + matrix[14] + matrix[15])), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + + def test_decomposition_rotated_toffoli(self): + num_qubits = 3 + p = ql.Program('test_decomposition_rotated_toffoli', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = (np.exp(-1j*0.3*3.141562) * np.array([[1, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 1, 0]])).flatten() + + u1 = ql.Unitary("decomposition_rotated_toffoli", matrix) + u1.decompose() + k.hadamard(0) + k.hadamard(1) + k.hadamard(2) + + k.gate(u1, [0, 1, 2]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(0.125 * helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[8] + matrix[9] + matrix[10] + matrix[11] + matrix[12] + matrix[13] + matrix[14] + matrix[15])), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[16] + matrix[17] + matrix[18] + matrix[19] + matrix[20] + matrix[21] + matrix[22] + matrix[23])), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[24] + matrix[25] + matrix[26] + matrix[27] + matrix[28] + matrix[29] + matrix[30] + matrix[31])), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[32] + matrix[33] + matrix[34] + matrix[35] + matrix[36] + matrix[37] + matrix[38] + matrix[39])), helper_prob(state.get(to_bit_string(4, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[40] + matrix[41] + matrix[42] + matrix[43] + matrix[44] + matrix[45] + matrix[46] + matrix[47])), helper_prob(state.get(to_bit_string(5, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[48] + matrix[49] + matrix[50] + matrix[51] + matrix[52] + matrix[53] + matrix[54] + matrix[55])), helper_prob(state.get(to_bit_string(6, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[56] + matrix[57] + matrix[58] + matrix[59] + matrix[60] + matrix[61] + matrix[62] + matrix[63])), helper_prob(state.get(to_bit_string(7, size=platform_qubits), 0.)), 5) + + def test_decomposition_toffoli(self): + num_qubits = 3 + p = ql.Program('test_decomposition_toffoli', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = np.array([[1, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 1], + [0, 0, 0, 0, 0, 0, 1, 0]]).flatten() + + u1 = ql.Unitary("decomposition_toffoli", matrix) + u1.decompose() + k.hadamard(0) + k.hadamard(1) + k.hadamard(2) + k.gate(u1, [0, 1, 2]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + self.assertAlmostEqual(0.125 * helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[8] + matrix[9] + matrix[10] + matrix[11] + matrix[12] + matrix[13] + matrix[14] + matrix[15])), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[16] + matrix[17] + matrix[18] + matrix[19] + matrix[20] + matrix[21] + matrix[22] + matrix[23])), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[24] + matrix[25] + matrix[26] + matrix[27] + matrix[28] + matrix[29] + matrix[30] + matrix[31])), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[32] + matrix[33] + matrix[34] + matrix[35] + matrix[36] + matrix[37] + matrix[38] + matrix[39])), helper_prob(state.get(to_bit_string(4, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[40] + matrix[41] + matrix[42] + matrix[43] + matrix[44] + matrix[45] + matrix[46] + matrix[47])), helper_prob(state.get(to_bit_string(5, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[48] + matrix[49] + matrix[50] + matrix[51] + matrix[52] + matrix[53] + matrix[54] + matrix[55])), helper_prob(state.get(to_bit_string(6, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[56] + matrix[57] + matrix[58] + matrix[59] + matrix[60] + matrix[61] + matrix[62] + matrix[63])), helper_prob(state.get(to_bit_string(7, size=platform_qubits), 0.)), 5) + + def test_decomposition_controlled_u(self): + num_qubits = 3 + p = ql.Program('test_decomposition_controlled_u', platform, num_qubits) + k = ql.Kernel('aKernel', platform, num_qubits) + + matrix = np.array([[1, 0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0, 0], + [0, 0, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 1, 0, 0, 0, 0], + [0, 0, 0, 0, 1, 0, 0, 0], + [0, 0, 0, 0, 0, 1, 0, 0], + [0, 0, 0, 0, 0, 0, 0.30279949 - 0.60010283j, -0.58058628 - 0.45946559j], + [0, 0, 0, 0, 0, 0, 0.04481146 - 0.73904059j, 0.64910478 + 0.17456782j]]).flatten() + + u1 = ql.Unitary("decomposition_controlled_u", matrix) + u1.decompose() + k.hadamard(0) + k.hadamard(1) + k.hadamard(2) + k.gate(u1, [0, 1, 2]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + print(state) + + self.assertAlmostEqual(0.125 * helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[8] + matrix[9] + matrix[10] + matrix[11] + matrix[12] + matrix[13] + matrix[14] + matrix[15])), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[16] + matrix[17] + matrix[18] + matrix[19] + matrix[20] + matrix[21] + matrix[22] + matrix[23])), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[24] + matrix[25] + matrix[26] + matrix[27] + matrix[28] + matrix[29] + matrix[30] + matrix[31])), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[32] + matrix[33] + matrix[34] + matrix[35] + matrix[36] + matrix[37] + matrix[38] + matrix[39])), helper_prob(state.get(to_bit_string(4, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[40] + matrix[41] + matrix[42] + matrix[43] + matrix[44] + matrix[45] + matrix[46] + matrix[47])), helper_prob(state.get(to_bit_string(5, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[48] + matrix[49] + matrix[50] + matrix[51] + matrix[52] + matrix[53] + matrix[54] + matrix[55])), helper_prob(state.get(to_bit_string(6, size=platform_qubits), 0.)), 5) + self.assertAlmostEqual(0.125 * helper_prob((matrix[56] + matrix[57] + matrix[58] + matrix[59] + matrix[60] + matrix[61] + matrix[62] + matrix[63])), helper_prob(state.get(to_bit_string(7, size=platform_qubits), 0.)), 5) + + def test_decomposition_msc_thesis_aritra(self): + num_qubits = 4 + p = ql.Program("test_decomposition_msc_thesis_aritra", platform, num_qubits) + k = ql.Kernel("aKernel", platform, num_qubits) + + matrix = [ + 0.3672, -0.3654, -0.3654, -0.2109, -0.3654, -0.2109, -0.2109, -0.1218, -0.3654, -0.2109, -0.2109, -0.1218, -0.2109, -0.1218, -0.1218, -0.0703, + -0.3654, 0.7891, -0.2109, -0.1218, -0.2109, -0.1218, -0.1218, -0.0703, -0.2109, -0.1218, -0.1218, -0.0703, -0.1218, -0.0703, -0.0703, -0.0406, + -0.3654, -0.2109, 0.7891, -0.1218, -0.2109, -0.1218, -0.1218, -0.0703, -0.2109, -0.1218, -0.1218, -0.0703, -0.1218, -0.0703, -0.0703, -0.0406, + -0.2109, -0.1218, -0.1218, 0.9297, -0.1218, -0.0703, -0.0703, -0.0406, -0.1218, -0.0703, -0.0703, -0.0406, -0.0703, -0.0406, -0.0406, -0.0234, + -0.3654, -0.2109, -0.2109, -0.1218, 0.7891, -0.1218, -0.1218, -0.0703, -0.2109, -0.1218, -0.1218, -0.0703, -0.1218, -0.0703, -0.0703, -0.0406, + -0.2109, -0.1218, -0.1218, -0.0703, -0.1218, 0.9297, -0.0703, -0.0406, -0.1218, -0.0703, -0.0703, -0.0406, -0.0703, -0.0406, -0.0406, -0.0234, + -0.2109, -0.1218, -0.1218, -0.0703, -0.1218, -0.0703, 0.9297, -0.0406, -0.1218, -0.0703, -0.0703, -0.0406, -0.0703, -0.0406, -0.0406, -0.0234, + -0.1218, -0.0703, -0.0703, -0.0406, -0.0703, -0.0406, -0.0406, 0.9766, -0.0703, -0.0406, -0.0406, -0.0234, -0.0406, -0.0234, -0.0234, -0.0135, + -0.3654, -0.2109, -0.2109, -0.1218, -0.2109, -0.1218, -0.1218, -0.0703, 0.7891, -0.1218, -0.1218, -0.0703, -0.1218, -0.0703, -0.0703, -0.0406, + -0.2109, -0.1218, -0.1218, -0.0703, -0.1218, -0.0703, -0.0703, -0.0406, -0.1218, 0.9297, -0.0703, -0.0406, -0.0703, -0.0406, -0.0406, -0.0234, + -0.2109, -0.1218, -0.1218, -0.0703, -0.1218, -0.0703, -0.0703, -0.0406, -0.1218, -0.0703, 0.9297, -0.0406, -0.0703, -0.0406, -0.0406, -0.0234, + -0.1218, -0.0703, -0.0703, -0.0406, -0.0703, -0.0406, -0.0406, -0.0234, -0.0703, -0.0406, -0.0406, 0.9766, -0.0406, -0.0234, -0.0234, -0.0135, + -0.2109, -0.1218, -0.1218, -0.0703, -0.1218, -0.0703, -0.0703, -0.0406, -0.1218, -0.0703, -0.0703, -0.0406, 0.9297, -0.0406, -0.0406, -0.0234, + -0.1218, -0.0703, -0.0703, -0.0406, -0.0703, -0.0406, -0.0406, -0.0234, -0.0703, -0.0406, -0.0406, -0.0234, -0.0406, 0.9766, -0.0234, -0.0135, + -0.1218, -0.0703, -0.0703, -0.0406, -0.0703, -0.0406, -0.0406, -0.0234, -0.0703, -0.0406, -0.0406, -0.0234, -0.0406, -0.0234, 0.9766, -0.0135, + -0.0703, -0.0406, -0.0406, -0.0234, -0.0406, -0.0234, -0.0234, -0.0135, -0.0406, -0.0234, -0.0234, -0.0135, -0.0234, -0.0135, -0.0135, 0.9922 + ] + + u1 = ql.Unitary("decomposition_msc_thesis_aritra", matrix) + u1.decompose() + k.hadamard(0) + k.hadamard(1) + k.hadamard(2) + k.hadamard(3) + k.gate(u1, [0, 1, 2, 3]) + + p.add_kernel(k) + p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') + p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') + p.compile() + state = qxelarator.execute_file(os.path.join(output_dir, p.name + '.qasm')).state + + # less accuracy because of less accurate input + self.assertAlmostEqual(0.0625 * helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7] + matrix[8] + matrix[9] + matrix[10] + matrix[11] + matrix[12] + matrix[13] + matrix[14] + matrix[15])), helper_prob(state.get(to_bit_string(0, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[16] + matrix[17] + matrix[18] + matrix[19] + matrix[20] + matrix[21] + matrix[22] + matrix[23] + matrix[24] + matrix[25] + matrix[26] + matrix[27] + matrix[28] + matrix[29] + matrix[30] + matrix[31])), helper_prob(state.get(to_bit_string(1, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[32] + matrix[33] + matrix[34] + matrix[35] + matrix[36] + matrix[37] + matrix[38] + matrix[39] + matrix[40] + matrix[41] + matrix[42] + matrix[43] + matrix[44] + matrix[45] + matrix[46] + matrix[47])), helper_prob(state.get(to_bit_string(2, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[48] + matrix[49] + matrix[50] + matrix[51] + matrix[52] + matrix[53] + matrix[54] + matrix[55] + matrix[56] + matrix[57] + matrix[58] + matrix[59] + matrix[60] + matrix[61] + matrix[62] + matrix[63])), helper_prob(state.get(to_bit_string(3, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[64] + matrix[65] + matrix[66] + matrix[67] + matrix[68] + matrix[69] + matrix[70] + matrix[71] + matrix[72] + matrix[73] + matrix[74] + matrix[75] + matrix[76] + matrix[77] + matrix[78] + matrix[79])), helper_prob(state.get(to_bit_string(4, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[80] + matrix[81] + matrix[82] + matrix[83] + matrix[84] + matrix[85] + matrix[86] + matrix[87] + matrix[88] + matrix[89] + matrix[90] + matrix[91] + matrix[92] + matrix[93] + matrix[94] + matrix[95])), helper_prob(state.get(to_bit_string(5, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[96] + matrix[97] + matrix[98] + matrix[99] + matrix[100] + matrix[101] + matrix[102] + matrix[103] + matrix[104] + matrix[105] + matrix[106] + matrix[107] + matrix[108] + matrix[109] + matrix[110] + matrix[111])), helper_prob(state.get(to_bit_string(6, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[112] + matrix[113] + matrix[114] + matrix[115] + matrix[116] + matrix[117] + matrix[118] + matrix[119] + matrix[120] + matrix[121] + matrix[122] + matrix[123] + matrix[124] + matrix[125] + matrix[126] + matrix[127])), helper_prob(state.get(to_bit_string(7, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[128] + matrix[129] + matrix[130] + matrix[131] + matrix[132] + matrix[133] + matrix[134] + matrix[135] + matrix[136] + matrix[137] + matrix[138] + matrix[139] + matrix[140] + matrix[141] + matrix[142] + matrix[143])), helper_prob(state.get(to_bit_string(8, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[144] + matrix[145] + matrix[146] + matrix[147] + matrix[148] + matrix[149] + matrix[150] + matrix[151] + matrix[152] + matrix[153] + matrix[154] + matrix[155] + matrix[156] + matrix[157] + matrix[158] + matrix[159])), helper_prob(state.get(to_bit_string(9, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[160] + matrix[161] + matrix[162] + matrix[163] + matrix[164] + matrix[165] + matrix[166] + matrix[167] + matrix[168] + matrix[169] + matrix[170] + matrix[171] + matrix[172] + matrix[173] + matrix[174] + matrix[175])), helper_prob(state.get(to_bit_string(10, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[176] + matrix[177] + matrix[178] + matrix[179] + matrix[180] + matrix[181] + matrix[182] + matrix[183] + matrix[184] + matrix[185] + matrix[186] + matrix[187] + matrix[188] + matrix[189] + matrix[190] + matrix[191])), helper_prob(state.get(to_bit_string(11, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[192] + matrix[193] + matrix[194] + matrix[195] + matrix[196] + matrix[197] + matrix[198] + matrix[199] + matrix[200] + matrix[201] + matrix[202] + matrix[203] + matrix[204] + matrix[205] + matrix[206] + matrix[207])), helper_prob(state.get(to_bit_string(12, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[208] + matrix[209] + matrix[210] + matrix[211] + matrix[212] + matrix[213] + matrix[214] + matrix[215] + matrix[216] + matrix[217] + matrix[218] + matrix[219] + matrix[220] + matrix[221] + matrix[222] + matrix[223])), helper_prob(state.get(to_bit_string(13, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[224] + matrix[225] + matrix[226] + matrix[227] + matrix[228] + matrix[229] + matrix[230] + matrix[231] + matrix[232] + matrix[233] + matrix[234] + matrix[235] + matrix[236] + matrix[237] + matrix[238] + matrix[239])), helper_prob(state.get(to_bit_string(14, size=platform_qubits), 0.)), 2) + self.assertAlmostEqual(0.0625 * helper_prob((matrix[240] + matrix[241] + matrix[242] + matrix[243] + matrix[244] + matrix[245] + matrix[246] + matrix[247] + matrix[248] + matrix[249] + matrix[250] + matrix[251] + matrix[252] + matrix[253] + matrix[254] + matrix[255])), helper_prob(state.get(to_bit_string(15, size=platform_qubits), 0.)), 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_wait.py b/test/v1x/python/test_wait.py similarity index 70% rename from tests/test_wait.py rename to test/v1x/python/test_wait.py index fa7c8adf5..6f88964fc 100644 --- a/tests/test_wait.py +++ b/test/v1x/python/test_wait.py @@ -1,15 +1,14 @@ +import openql as ql import os import unittest -from openql import openql as ql -from utils import file_compare - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') +from config import json_dir, output_dir, qasm_golden_dir +from utils import file_compare -class Test_wait(unittest.TestCase): - def setUp(self): +class TestWait(unittest.TestCase): + @classmethod + def setUp(cls): ql.initialize() ql.set_option('output_dir', output_dir) ql.set_option('use_default_gates', 'no') @@ -18,12 +17,10 @@ def setUp(self): ql.set_option('scheduler', 'ASAP') ql.set_option('scheduler_post179', 'yes') ql.set_option("scheduler_commute", 'no') - @unittest.skip def test_wait_simple(self): - - config_fn = os.path.join(curdir, 'hardware_config_cc_light.json') + config_fn = os.path.join(json_dir, 'config_cc_light.json') platform = ql.Platform('seven_qubits_chip', config_fn) num_qubits = platform.get_qubit_number() p = ql.Program('test_wait_simple', platform, num_qubits) @@ -37,14 +34,13 @@ def test_wait_simple(self): p.add_kernel(k) p.compile() - QISA_fn = os.path.join(output_dir, p.name+'.qisa') - gold_fn = curdir + '/golden/test_wait_simple.qisa' - self.assertTrue(file_compare(QISA_fn, gold_fn)) + qisa_fn = os.path.join(output_dir, p.name + '.qisa') + gold_fn = os.path.join(qasm_golden_dir, 'test_wait_simple.qisa') + self.assertTrue(file_compare(qisa_fn, gold_fn)) @unittest.skip def test_wait_parallel(self): - - config_fn = os.path.join(curdir, 'hardware_config_cc_light.json') + config_fn = os.path.join(json_dir, 'config_cc_light.json') platform = ql.Platform('seven_qubits_chip', config_fn) num_qubits = platform.get_qubit_number() p = ql.Program('test_wait_parallel', platform, num_qubits) @@ -59,14 +55,13 @@ def test_wait_parallel(self): p.add_kernel(k) p.compile() - QISA_fn = os.path.join(output_dir, p.name+'.qisa') - gold_fn = curdir + '/golden/test_wait_parallel.qisa' - self.assertTrue(file_compare(QISA_fn, gold_fn)) + qisa_fn = os.path.join(output_dir, p.name + '.qisa') + gold_fn = os.path.join(qasm_golden_dir, 'test_wait_parallel.qisa') + self.assertTrue(file_compare(qisa_fn, gold_fn)) @unittest.skip def test_wait_sweep(self): - - config_fn = os.path.join(curdir, 'hardware_config_cc_light.json') + config_fn = os.path.join(json_dir, 'config_cc_light.json') platform = ql.Platform('seven_qubits_chip', config_fn) num_qubits = 7 p = ql.Program('test_wait_sweep', platform, num_qubits) @@ -95,13 +90,13 @@ def test_wait_sweep(self): # compile the program p.compile() - QISA_fn = os.path.join(output_dir, p.name+'.qisa') - gold_fn = curdir + '/golden/test_wait_sweep.qisa' - self.assertTrue(file_compare(QISA_fn, gold_fn)) + qisa_fn = os.path.join(output_dir, p.name + '.qisa') + gold_fn = os.path.join(qasm_golden_dir, 'test_wait_sweep.qisa') + self.assertTrue(file_compare(qisa_fn, gold_fn)) @unittest.skip def test_wait_multi(self): - config_fn = os.path.join(curdir, 'hardware_config_cc_light.json') + config_fn = os.path.join(json_dir, 'config_cc_light.json') platform = ql.Platform('seven_qubits_chip', config_fn) num_qubits = platform.get_qubit_number() p = ql.Program('test_wait_multi', platform, num_qubits) @@ -120,10 +115,9 @@ def test_wait_multi(self): p.add_kernel(k) p.compile() - QISA_fn = os.path.join(output_dir, p.name+'.qisa') - gold_fn = curdir + '/golden/test_wait_multi.qisa' - self.assertTrue(file_compare(QISA_fn, gold_fn)) - + qisa_fn = os.path.join(output_dir, p.name + '.qisa') + gold_fn = os.path.join(qasm_golden_dir, 'test_wait_multi.qisa') + self.assertTrue(file_compare(qisa_fn, gold_fn)) if __name__ == '__main__': diff --git a/tests/utils.py b/test/v1x/python/utils.py similarity index 96% rename from tests/utils.py rename to test/v1x/python/utils.py index cc5e3803c..778e158da 100644 --- a/tests/utils.py +++ b/test/v1x/python/utils.py @@ -20,6 +20,5 @@ def file_compare(fn1, fn2): if diffs: # all rows with changes raise AssertionError("Files not equal\n"+"".join(diffs)) - return False else: return True diff --git a/test/v1x/python/visualizer/config.py b/test/v1x/python/visualizer/config.py new file mode 100644 index 000000000..3d6c95f74 --- /dev/null +++ b/test/v1x/python/visualizer/config.py @@ -0,0 +1,16 @@ +import os + +cur_dir = os.path.dirname(os.path.realpath(__file__)) +root_dir = os.path.join(cur_dir, '..', '..', '..', '..') +res_dir = os.path.join(root_dir, 'res', 'v1x') + +cq_dir = os.path.join(res_dir, 'cq') +cq_golden_dir = os.path.join(cq_dir, 'golden') + +json_dir = os.path.join(res_dir, 'json') +json_visualizer_dir = os.path.join(json_dir, 'visualizer') + +qasm_dir = os.path.join(res_dir, 'qasm') +qasm_golden_dir = os.path.join(qasm_dir, 'golden') + +output_dir = "visualizer_output" diff --git a/test/v1x/python/visualizer/deutsch-josza.py b/test/v1x/python/visualizer/deutsch-josza.py new file mode 100644 index 000000000..5e4393328 --- /dev/null +++ b/test/v1x/python/visualizer/deutsch-josza.py @@ -0,0 +1,45 @@ +import openql as ql +import os + +from config import json_visualizer_dir, output_dir + + +# ql.set_option('log_level', 'LOG_DEBUG') +# ql.set_option('log_level', 'LOG_INFO') +ql.set_option('unique_output', 'yes') + +c = ql.Compiler("testCompiler") +# c.append_pass("sch.Schedule", "scheduler", {"scheduler_heuristic": "asap"}) +c.append_pass("ana.visualize.Interaction", "visualizer", + {"config": os.path.join(json_visualizer_dir, "config_example_1.json"), "interactive": "yes"}) +c.set_option("**.output_prefix", output_dir + "/%N") + +platformCustomGates = ql.Platform('starmon', os.path.join(json_visualizer_dir, 'config_cc_light_2.json')) +num_qubits = 2 +p = ql.Program("Deutsch", platformCustomGates, num_qubits, 0) +k = ql.Kernel("kernel", platformCustomGates, num_qubits, 0) +for q in range(num_qubits): + k.gate('prepz', [q]) +k.gate('x', [1]) +for q in range(num_qubits): + k.gate('h', [q]) +# cr = random() +cr = 0.23 +if cr < 0.25: + print("Balanced : IDENTITY") + k.gate('cnot', [0, 1]) +elif cr < 0.50: + print("Balanced : NOT") + k.gate('x', [0]) + k.gate('cnot', [0, 1]) + k.gate('x', [0]) +elif cr < 0.75: + print("Unbalanced : RESET") +else: + print("Unbalanced : SET") + k.gate('x', [1]) +k.gate('h', [0]) +for q in range(num_qubits): + k.gate('measure', [q]) +p.add_kernel(k) +c.compile(p) diff --git a/tests/visualizer/visualizer_example1.py b/test/v1x/python/visualizer/example_1.py similarity index 68% rename from tests/visualizer/visualizer_example1.py rename to test/v1x/python/visualizer/example_1.py index 5c73ee133..5eecb13ec 100644 --- a/tests/visualizer/visualizer_example1.py +++ b/test/v1x/python/visualizer/example_1.py @@ -1,8 +1,8 @@ -from openql import openql as ql +import openql as ql import os -curdir = os.path.dirname(__file__) -output_dir = os.path.join(curdir, 'visualizer_example_output') +from config import json_visualizer_dir, output_dir + ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') @@ -25,24 +25,24 @@ ql.set_option('write_qasm_files', 'no') ql.set_option('write_report_files', 'no') -platformCustomGates = ql.Platform('starmon', os.path.join(curdir, 'test_s7.json')) -nqubits = 7 -p = ql.Program("testProgram1", platformCustomGates, nqubits, 0) -k = ql.Kernel("aKernel1", platformCustomGates, nqubits, 0) +platformCustomGates = ql.Platform('starmon', os.path.join(json_visualizer_dir, 'test_s7.json')) +num_qubits = 7 +p = ql.Program("testProgram1", platformCustomGates, num_qubits, 0) +k = ql.Kernel("aKernel1", platformCustomGates, num_qubits, 0) k.gate("x", [2]) k.gate("y", [3]) -k.gate("cnot", [2,3]) +k.gate("cnot", [2, 3]) k.gate("x", [2]) k.gate("y", [3]) p.add_kernel(k) -k = ql.Kernel("aKernel2", platformCustomGates, nqubits, 0) +k = ql.Kernel("aKernel2", platformCustomGates, num_qubits, 0) k.gate("x", [2]) k.gate("y", [3]) -k.gate("cnot", [2,3]) +k.gate("cnot", [2, 3]) k.gate("x", [2]) k.gate("y", [3]) @@ -52,7 +52,7 @@ 'mapper', 'ana.visualize.Mapping', 'before_mapping', { - 'config': os.path.join(curdir, "visualizer_config_example1.json"), + 'config': os.path.join(json_visualizer_dir, 'config_example_1.json'), 'output_prefix': output_dir + '/%N_before', 'interactive': 'yes' } @@ -62,7 +62,7 @@ 'mapper', 'ana.visualize.Mapping', 'after_mapping', { - 'config': os.path.join(curdir, "visualizer_config_example1.json"), + 'config': os.path.join(json_visualizer_dir, 'config_example_1.json'), 'output_prefix': output_dir + '/%N_after', 'interactive': 'yes' } diff --git a/test/v1x/python/visualizer/example_2.py b/test/v1x/python/visualizer/example_2.py new file mode 100644 index 000000000..c752d7615 --- /dev/null +++ b/test/v1x/python/visualizer/example_2.py @@ -0,0 +1,64 @@ +import openql as ql +import os + +from config import json_visualizer_dir, output_dir + + +ql.initialize() +ql.set_option('output_dir', output_dir) +ql.set_option('optimize', 'no') +ql.set_option('scheduler', 'ASAP') +# ql.set_option('log_level', 'LOG_DEBUG') +ql.set_option('log_level', 'LOG_INFO') +ql.set_option('unique_output', 'yes') +ql.set_option('write_qasm_files', 'no') +ql.set_option('write_report_files', 'no') + +platformCustomGates = ql.Platform('starmon', os.path.join(json_visualizer_dir, 'config_cc_light.json')) +num_qubits = 4 +p = ql.Program("testProgram1", platformCustomGates, num_qubits, 0) +k = ql.Kernel("aKernel1", platformCustomGates, num_qubits, 0) +k.gate('x', [0]) +for i in range(num_qubits): + k.gate('prepz', [i]) +k.gate('wait', [1], 40) +k.gate('wait', [2], 40) +k.gate('wait', [3], 40) +k.gate('x', [0]) +k.gate('x', [0]) +k.gate('x', [0]) +k.gate('wait', [2], 40) +k.gate('h', [2]) +k.gate('cz', [3, 1]) +k.gate('cz', [2, 0]) +k.gate('cz', [2, 0]) +k.gate('wait', [3], 40) +k.gate('measure', [3]) +k.gate('measure', [0]) +k.gate('measure', [1]) +k.gate('measure', [2]) +# k.gate('measure', [3]) +p.add_kernel(k) + +# p.get_compiler().append_pass( +# 'ana.visualize.Interaction', +# 'visualize_interaction', +# { +# 'output_prefix': output_dir + '/%N_interaction', +# 'config': os.path.join(cur_dir, "config_example_2.json"), +# 'interactive': 'yes' +# } +# ) + +p.get_compiler().append_pass( + 'ana.visualize.Circuit', + 'visualize_circuit', + { + 'output_prefix': output_dir + '/%N_circuit', + 'config': os.path.join(json_visualizer_dir, "config_example_2.json"), + 'waveform_mapping': os.path.join(json_visualizer_dir, "waveform_mapping.json"), + 'interactive': 'yes' + } +) + +p.compile() diff --git a/test/v1x/python/visualizer/example_3.py b/test/v1x/python/visualizer/example_3.py new file mode 100644 index 000000000..abd459fdf --- /dev/null +++ b/test/v1x/python/visualizer/example_3.py @@ -0,0 +1,63 @@ +import openql as ql +import os + +from config import json_visualizer_dir, output_dir + + +ql.set_option('output_dir', output_dir) +ql.set_option('optimize', 'no') +ql.set_option('scheduler', 'ASAP') +# ql.set_option('log_level', 'LOG_DEBUG') +ql.set_option('log_level', 'LOG_INFO') +ql.set_option('unique_output', 'yes') +ql.set_option('write_qasm_files', 'no') +ql.set_option('write_report_files', 'no') + +platformCustomGates = ql.Platform('starmon', os.path.join(json_visualizer_dir, 'config_cc_light.json')) +num_qubits = 4 +p = ql.Program("testProgram1", platformCustomGates, num_qubits, 0) +k = ql.Kernel("aKernel1", platformCustomGates, num_qubits, 0) +k.gate('x', [0]) +for i in range(num_qubits): + k.gate('prepz', [i]) +k.gate('wait', [1], 40) +k.gate('wait', [2], 40) +k.gate('wait', [3], 40) +k.gate('x', [0]) +k.gate('x', [0]) +k.gate('x', [0]) +k.gate('wait', [2], 40) +k.gate('h', [2]) +k.gate('cz', [3, 1]) +k.gate('cz', [2, 0]) +k.gate('cz', [2, 0]) +k.gate('wait', [3], 40) +k.gate('measure', [3]) +k.gate('measure', [0]) +k.gate('measure', [1]) +k.gate('measure', [2]) +# k.gate('measure', [3]) +p.add_kernel(k) + +# p.get_compiler().append_pass( +# 'ana.visualize.Interaction', +# 'visualize_interaction', +# { +# 'output_prefix': output_dir + '/%N_interaction', +# 'config': os.path.join(json_visualizer_dir, 'config_example_3.json'), +# 'interactive': 'yes' +# } +# ) + +p.get_compiler().append_pass( + 'ana.visualize.Circuit', + 'visualize_circuit', + { + 'output_prefix': output_dir + '/%N_circuit', + 'config': os.path.join(json_visualizer_dir, 'config_example_3.json'), + 'waveform_mapping': os.path.join(json_visualizer_dir, 'waveform_mapping.json'), + 'interactive': 'yes' + } +) + +p.compile() diff --git a/tests/visualizer/visualizer_example4.py b/test/v1x/python/visualizer/example_4.py similarity index 58% rename from tests/visualizer/visualizer_example4.py rename to test/v1x/python/visualizer/example_4.py index 9e202fa79..16c096d3b 100644 --- a/tests/visualizer/visualizer_example4.py +++ b/test/v1x/python/visualizer/example_4.py @@ -1,8 +1,8 @@ -from openql import openql as ql +import openql as ql import os -curdir = os.path.dirname(__file__) -output_dir = os.path.join(curdir, 'visualizer_example_output') +from config import json_visualizer_dir, output_dir + ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') @@ -12,11 +12,11 @@ ql.set_option('write_qasm_files', 'no') ql.set_option('write_report_files', 'no') -platformCustomGates = ql.Platform('starmon', os.path.join(curdir, 'hardware_config_cc_light_visualizer.json')) -nqubits = 6 -p = ql.Program("testProgram1", platformCustomGates, nqubits, 0) -k = ql.Kernel("aKernel1", platformCustomGates, nqubits, 0) -for i in range(nqubits): +platformCustomGates = ql.Platform('starmon', os.path.join(json_visualizer_dir, 'config_cc_light.json')) +num_qubits = 6 +p = ql.Program("testProgram1", platformCustomGates, num_qubits, 0) +k = ql.Kernel("aKernel1", platformCustomGates, num_qubits, 0) +for i in range(num_qubits): k.gate('prepz', [i]) k.gate('x', [0]) k.gate('cnot', [0, 3]) @@ -38,11 +38,10 @@ 'visualize_circuit', { 'output_prefix': output_dir + '/%N_circuit', - 'config': os.path.join(curdir, "visualizer_config_example4.json"), - 'waveform_mapping': os.path.join(curdir, "waveform_mapping.json"), + 'config': os.path.join(json_visualizer_dir, 'config_example_4.json'), + 'waveform_mapping': os.path.join(json_visualizer_dir, 'waveform_mapping.json'), 'interactive': 'yes' } ) - p.compile() diff --git a/tests/visualizer/visualizer_example5.py b/test/v1x/python/visualizer/example_5.py similarity index 59% rename from tests/visualizer/visualizer_example5.py rename to test/v1x/python/visualizer/example_5.py index 8e9c4e387..61511c5f4 100644 --- a/tests/visualizer/visualizer_example5.py +++ b/test/v1x/python/visualizer/example_5.py @@ -1,24 +1,24 @@ -from openql import openql as ql +import openql as ql import os -curdir = os.path.dirname(__file__) -output_dir = os.path.join(curdir, 'visualizer_example_output') +from config import json_visualizer_dir, output_dir + ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') ql.set_option('scheduler', 'ASAP') -#ql.set_option('log_level', 'LOG_DEBUG') +# ql.set_option('log_level', 'LOG_DEBUG') ql.set_option('log_level', 'LOG_INFO') ql.set_option('unique_output', 'yes') ql.set_option('write_qasm_files', 'no') ql.set_option('write_report_files', 'no') -platformCustomGates = ql.Platform('starmon', os.path.join(curdir, 'hardware_config_cc_light_visualizer.json')) -nqubits = 6 -p = ql.Program("testProgram1", platformCustomGates, nqubits, 0) -k = ql.Kernel("aKernel1", platformCustomGates, nqubits, 0) +platformCustomGates = ql.Platform('starmon', os.path.join(json_visualizer_dir, 'config_cc_light.json')) +num_qubits = 6 +p = ql.Program("testProgram1", platformCustomGates, num_qubits, 0) +k = ql.Kernel("aKernel1", platformCustomGates, num_qubits, 0) k.gate('x', [0]) -for i in range(nqubits): +for i in range(num_qubits): k.gate('prepz', [i]) k.gate('wait', [1], 40) k.gate('wait', [2], 40) @@ -38,7 +38,7 @@ k.gate('measure', [0]) k.gate('measure', [1]) k.gate('measure', [2]) -#k.gate('measure', [3]) +# k.gate('measure', [3]) p.add_kernel(k) p.get_compiler().append_pass( @@ -46,8 +46,8 @@ 'visualize_circuit', { 'output_prefix': output_dir + '/%N_circuit', - 'config': os.path.join(curdir, "visualizer_config_example5.json"), - 'waveform_mapping': os.path.join(curdir, "waveform_mapping.json"), + 'config': os.path.join(json_visualizer_dir, 'config_example_5.json'), + 'waveform_mapping': os.path.join(json_visualizer_dir, 'waveform_mapping.json'), 'interactive': 'yes' } ) diff --git a/tests/visualizer/visualizer_example6.py b/test/v1x/python/visualizer/example_6.py similarity index 69% rename from tests/visualizer/visualizer_example6.py rename to test/v1x/python/visualizer/example_6.py index 989189534..e26cb4473 100644 --- a/tests/visualizer/visualizer_example6.py +++ b/test/v1x/python/visualizer/example_6.py @@ -1,8 +1,8 @@ -from openql import openql as ql +import openql as ql import os -curdir = os.path.dirname(__file__) -output_dir = os.path.join(curdir, 'visualizer_example_output') +from config import json_visualizer_dir, output_dir + ql.set_option('output_dir', output_dir) ql.set_option('optimize', 'no') @@ -25,14 +25,14 @@ ql.set_option('write_qasm_files', 'no') ql.set_option('write_report_files', 'no') -platformCustomGates = ql.Platform('starmon', os.path.join(curdir, 'test_s7.json')) -nqubits = 7 -p = ql.Program("testProgram1", platformCustomGates, nqubits, 0) -k = ql.Kernel("aKernel1", platformCustomGates, nqubits, 0) +platformCustomGates = ql.Platform('starmon', os.path.join(json_visualizer_dir, 'test_s7.json')) +num_qubits = 7 +p = ql.Program("testProgram1", platformCustomGates, num_qubits, 0) +k = ql.Kernel("aKernel1", platformCustomGates, num_qubits, 0) k.gate("x", [2]) k.gate("y", [4]) -k.gate("cnot", [2,4]) +k.gate("cnot", [2, 4]) k.gate("x", [2]) k.gate("y", [4]) @@ -42,7 +42,7 @@ 'mapper', 'ana.visualize.Mapping', 'after_mapping', { - 'config': os.path.join(curdir, "visualizer_config_example1.json"), + 'config': os.path.join(json_visualizer_dir, 'config_example_1.json'), 'output_prefix': output_dir + '/%N_after', 'interactive': 'yes' } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt deleted file mode 100644 index b04d5596b..000000000 --- a/tests/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -cmake_minimum_required(VERSION 3.1 FATAL_ERROR) - -add_openql_test(test_cc cc/test_cc.cc cc) -add_openql_test(test_unitary cc/test_unitary.cc cc) -target_link_libraries(test_unitary doctest) -add_openql_test(test_mapper test_mapper.cc .) -add_openql_test(test_multi_core test_multi_core.cc .) -add_openql_test(program_test program_test.cc .) -add_openql_test(test_179 test_179.cc .) diff --git a/tests/cc/test_unitary.cc b/tests/cc/test_unitary.cc deleted file mode 100644 index f6a87df31..000000000 --- a/tests/cc/test_unitary.cc +++ /dev/null @@ -1,43 +0,0 @@ -#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -#include "doctest/doctest.h" - -#include "openql.h" - -// Fails in CI on some platforms. -TEST_CASE("decomposition_controlled_U" * doctest::skip(!ql::Unitary::is_decompose_support_enabled())) { - auto platform = ql::Platform("platform_none", "test_cfg_none_simple.json"); - auto num_qubits = 3; - auto p = ql::Program("test_usingqx_toffoli", platform, num_qubits); - auto k = ql::Kernel("akernel", platform, num_qubits); - - std::vector> matrix = { 1, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, std::complex(0.30279949, -0.60010283), std::complex(-0.58058628, -0.45946559), - 0, 0, 0, 0, 0 ,0, std::complex(0.04481146, -0.73904059), std::complex(0.64910478, 0.17456782)}; - - auto u1 = ql::Unitary("arbitrarycontrolled",matrix); - u1.decompose(); - k.hadamard(0); - k.hadamard(1); - k.hadamard(2); - k.gate(u1, { 0, 1, 2 }); - - - p.add_kernel(k); - p.get_compiler().set_option("initialqasmwriter.cqasm_version", "1.0"); - p.get_compiler().set_option("initialqasmwriter.with_metadata", "no"); - p.compile(); - - CHECK_EQ(0.125*std::norm((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7])), doctest::Approx(std::norm(std::complex(0.03708885276142243, 0.3516026407762626)))); - CHECK_EQ(0.125*std::norm((matrix[8] + matrix[9] + matrix[10]+ matrix[11]+ matrix[12]+ matrix[13]+ matrix[14]+ matrix[15])), doctest::Approx(std::norm(std::complex(0.03708885276142243, 0.3516026407762626)))); - CHECK_EQ(0.125*std::norm((matrix[16] + matrix[17]+ matrix[18]+ matrix[19]+ matrix[20]+ matrix[21]+ matrix[22]+ matrix[23])), doctest::Approx(std::norm(std::complex(0.03708885276142243, 0.3516026407762626)))); - CHECK_EQ(0.125*std::norm((matrix[24] + matrix[25]+ matrix[26]+ matrix[27]+ matrix[28]+ matrix[29]+ matrix[30]+ matrix[31])), doctest::Approx(std::norm(std::complex(0.03708885276142243, 0.3516026407762626)))); - CHECK_EQ(0.125*std::norm((matrix[32] + matrix[33]+ matrix[34]+ matrix[35]+ matrix[36]+ matrix[37]+ matrix[38]+ matrix[39])), doctest::Approx(std::norm(std::complex(0.03708885276142243, 0.3516026407762626)))); - CHECK_EQ(0.125*std::norm((matrix[40] + matrix[41]+ matrix[42]+ matrix[43]+ matrix[44]+ matrix[45]+ matrix[46]+ matrix[47])), doctest::Approx(std::norm(std::complex(0.03708885276142243, 0.3516026407762626)))); - CHECK_EQ(0.125*std::norm((matrix[48] + matrix[49]+ matrix[50]+ matrix[51]+ matrix[52]+ matrix[53]+ matrix[54]+ matrix[55])), doctest::Approx(std::norm(std::complex(-0.38284984896211677, 0.058372391728338066)))); - CHECK_EQ(0.125*std::norm((matrix[56] + matrix[57]+ matrix[58]+ matrix[59]+ matrix[60]+ matrix[61]+ matrix[62]+ matrix[63])), doctest::Approx(std::norm(std::complex(-0.17273355873910606, -0.2649184303119007)))); -} \ No newline at end of file diff --git a/tests/golden/test_issue179_ALAP_last.qasm b/tests/golden/test_issue179_ALAP_last.qasm deleted file mode 100644 index 957936dd6..000000000 --- a/tests/golden/test_issue179_ALAP_last.qasm +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by OpenQL 0.9.0 for program test_issue179_ALAP -version 1.2 - -pragma @ql.name("test_issue179_ALAP") - - -.kernel_issue179_ALAP - y q[3] - skip 1 - { # start at cycle 2 - x q[2] - x q[4] - } - skip 1 diff --git a/tests/golden/test_mapper_oneNN_last.qasm b/tests/golden/test_mapper_oneNN_last.qasm deleted file mode 100644 index a23033ad7..000000000 --- a/tests/golden/test_mapper_oneNN_last.qasm +++ /dev/null @@ -1,11 +0,0 @@ -# Generated by OpenQL 0.10.5 for program test_mapper_oneNN -version 1.2 - -pragma @ql.name("test_mapper_oneNN") - - -.kernel_oneNN - cnot q[2], q[5] - skip 1 - x q[0] - y q[1] diff --git a/tests/golden/test_mc_noncomms_last.qasm b/tests/golden/test_mc_noncomms_last.qasm deleted file mode 100644 index c0b5c9f00..000000000 --- a/tests/golden/test_mc_noncomms_last.qasm +++ /dev/null @@ -1,13 +0,0 @@ -# Generated by OpenQL 0.11.1 for program test_mc_noncomms -version 1.2 - -pragma @ql.name("test_mc_noncomms") - - -.kernel_noncomms - x q[7] - tmove q[7], q[0] - skip 38 - x q[3] - cnot q[3], q[0] - skip 4 diff --git a/tests/golden/test_measure_available01_last.qasm b/tests/golden/test_measure_available01_last.qasm deleted file mode 100644 index 342851ace..000000000 --- a/tests/golden/test_measure_available01_last.qasm +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by OpenQL 0.9.0 for program test_measure_available01 -version 1.2 - -pragma @ql.name("test_measure_available01") - - -.aKernel - { # start at cycle 0 - measure q[0] - measure q[1] - } - skip 1 diff --git a/tests/golden/test_measure_available02_last.qasm b/tests/golden/test_measure_available02_last.qasm deleted file mode 100644 index f207a8004..000000000 --- a/tests/golden/test_measure_available02_last.qasm +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by OpenQL 0.9.0 for program test_measure_available02 -version 1.2 - -pragma @ql.name("test_measure_available02") - - -.aKernel - { # start at cycle 0 - measure q[0] - measure q[2] - } - skip 1 diff --git a/tests/program_test.cc b/tests/program_test.cc deleted file mode 100644 index 1321e7241..000000000 --- a/tests/program_test.cc +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -int main(int argc, char **argv) { - size_t nqubits = 5; - - // create platform - auto qplatform = ql::Platform("target_platform", "cc_light"); - - // create program - auto prog = ql::Program("prog", qplatform, nqubits); - - // create a kernel - auto kernel = ql::Kernel("my_kernel", qplatform, nqubits); - - // add gates to kernel - kernel.gate("prepz", {0}); - kernel.gate("prepz", {1}); - kernel.gate("x", {0}); - kernel.gate("y", {2}); - kernel.gate("cnot", {0,2}); - kernel.gate("measure", {0}); - kernel.gate("measure", {1}); - kernel.gate("measure", {2}); - - // add kernel to prog - prog.add_kernel(kernel); - - // compile the program - prog.compile(); - - return 0; -} - diff --git a/tests/test_cc_light_long_duration.py b/tests/test_cc_light_long_duration.py deleted file mode 100644 index 693b70a92..000000000 --- a/tests/test_cc_light_long_duration.py +++ /dev/null @@ -1,64 +0,0 @@ -import numpy as np -import os -import unittest -from openql import openql as ql -from utils import file_compare - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') - -class Test_CCL_long_duration(unittest.TestCase): - - @classmethod - def setUp(self): - ql.initialize() - - def test_AllXY(self): - """ - Single qubit AllXY sequence. - Writes output files to the directory specified in openql. - Output directory is set as an attribute to the program for convenience. - - Input pars: - qubit_idx: int specifying the target qubit (starting at 0) - platf_cfg: filename of the platform config file - double_points: if true repeats every element twice - Returns: - p: OpenQL Program object containing - - - """ - ql.set_option('output_dir', output_dir) - config_fn = os.path.join(curdir, 'test_cfg_CCL_long_duration.json') - platf = ql.Platform('seven_qubits_chip', config_fn) - p = ql.Program("AllXYLongDuration", platf, platf.get_qubit_number()) - - allXY = [ ['i', 'i'], ['rx180', 'ry180'], ['ry180', 'rx180'] ] - # , - # ['rx180', 'ry180'], ['ry180', 'rx180'], - # ['rx90', 'i'], ['ry90', 'i'], ['rx90', 'ry90'], - # ['ry90', 'rx90'], ['rx90', 'ry180'], ['ry90', 'rx180'], - # ['rx180', 'ry90'], ['ry180', 'rx90'], ['rx90', 'rx180'], - # ['rx180', 'rx90'], ['ry90', 'ry180'], ['ry180', 'ry90'], - # ['rx180', 'i'], ['ry180', 'i'], ['rx90', 'rx90'], - # ['ry90', 'ry90']] - - qubit_idx=0 - for i, xy in enumerate(allXY): - k = ql.Kernel("AllXY_"+str(i), platf, platf.get_qubit_number()) - k.prepz(qubit_idx) - k.gate(xy[0], [qubit_idx]) - k.gate(xy[1], [qubit_idx]) - k.measure(qubit_idx) - p.add_kernel(k) - - p.compile() - - GOLD_fn = os.path.join(curdir, 'golden', p.name + '_last.qasm') - QISA_fn = os.path.join(output_dir, p.name+'_last.qasm') - - self.assertTrue(file_compare(QISA_fn, GOLD_fn)) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_cfg_none_simple.json b/tests/test_cfg_none_simple.json deleted file mode 100644 index e2f3db3a9..000000000 --- a/tests/test_cfg_none_simple.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "eqasm_compiler" : "none", - - "hardware_settings": { - "qubit_number": 17, - "cycle_time" : 20, - "mw_mw_buffer": 0, - "mw_flux_buffer": 0, - "mw_readout_buffer": 0, - "flux_mw_buffer": 0, - "flux_flux_buffer": 0, - "flux_readout_buffer": 0, - "readout_mw_buffer": 0, - "readout_flux_buffer": 0, - "readout_readout_buffer": 0 - }, - - "instructions": { - }, - - "gate_decomposition": { - }, - - "resources": {}, - "topology": {} -} diff --git a/tests/test_commutation.py b/tests/test_commutation.py deleted file mode 100644 index d5b0abba0..000000000 --- a/tests/test_commutation.py +++ /dev/null @@ -1,718 +0,0 @@ -import os -from utils import file_compare -import unittest -from openql import openql as ql - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') - -# s5 would do as well -# cnot, t, z, etc. must not have been decomposed to exploit their commute properties -config = 'cc_light.s7' - -class Test_commutation(unittest.TestCase): - - def setUp(self): - ql.initialize() - ql.set_option('output_dir', output_dir) - ql.set_option('log_level', 'LOG_WARNING') - - # ASAP is easier to construct and verify the tests - ql.set_option('scheduler', 'ASAP') - - # don't optimize since gates are used by the tests to create 'latency' - # to enforce schedules that make a difference with/without commutation - ql.set_option('clifford_prescheduler', 'no') - ql.set_option('clifford_postscheduler', 'no') - ql.set_option('clifford_premapper', 'no') - ql.set_option('clifford_postmapper', 'no') - - def test_cnot_z_NN_commute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'no'); - ql.set_option("scheduler_commute_rotations", 'no'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on z operand of CNOT/T/Z/... - # gates on q0 commute with gates on q3 and could even be in parallel - # q3 is cnot control and thus z-commuting operand i.e. with t q3 and z q3 - # q0 is cnot target and thus x-commuting operand, of which there are none - # so: cnot commutes with later t q3 and z q3, making t q3 and z q3 available in parallel to q0 gates, - # while cnot has to be after t q0 and z q0, so intended result is that t q3 and z q3 get before cnot - # - # both commutation options are 'no' so input order must be kept - k.gate("t", [0]); - k.gate("z", [0]); - k.gate("cnot", [3,0]); - k.gate("t", [3]); - k.gate("z", [3]); - - - p = ql.Program("test_cnot_z_NN_commute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_z_2N_commute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'no'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on z operand of CNOT/T/Z/... - # gates on q0 commute with gates on q3 and could even be in parallel - # q3 is cnot control and thus z-commuting operand i.e. with t q3 and z q3 - # q0 is cnot target and thus x-commuting operand, of which there are none - # so: cnot commutes with later t q3 and z q3, making t q3 and z q3 available in parallel to q0 gates, - # while cnot has to be after t q0 and z q0, so intended result is that t q3 and z q3 get before cnot - # - # only cnot/cz commutation is enabled so input order must be kept - k.gate("t", [0]); - k.gate("z", [0]); - k.gate("cnot", [3,0]); - k.gate("t", [3]); - k.gate("z", [3]); - - - p = ql.Program("test_cnot_z_2N_commute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_z_2R_commute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'yes'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on z operand of CNOT/T/Z/... - # gates on q0 commute with gates on q3 and could even be in parallel - # q3 is cnot control and thus z-commuting operand i.e. with t q3 and z q3 - # q0 is cnot target and thus x-commuting operand, of which there are none - # so: cnot commutes with later t q3 and z q3, making t q3 and z q3 available in parallel to q0 gates, - # while cnot has to be after t q0 and z q0, so intended result is that t q3 and z q3 get before cnot - # - # also rotation commutation is enabled so intended result as above should be result - k.gate("t", [0]); - k.gate("z", [0]); - k.gate("cnot", [3,0]); - k.gate("t", [3]); - k.gate("z", [3]); - - - p = ql.Program("test_cnot_z_2R_commute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - - def test_cnot_x_NN_commute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'no'); - ql.set_option("scheduler_commute_rotations", 'no'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on x operand of CNOT/X/X45/... - # gates on q0 commute with gates on q3 and could even be in parallel - # q3 is cnot control and thus z-commuting operand, of which there are none - # q0 is cnot target and thus x-commuting operand, i.e. x q0 and x45 q0 - # so: cnot commutes with later x q0 and x45 q0, making x q0 and x45 q0 available in parallel to q3 gates, - # while cnot has to be after x q3 and x45 q3, so intended result is that x q0 and x45 q0 get before cnot - # - # both commutation options are 'no' so input order must be kept - k.gate("x", [3]); - k.gate("x45", [3]); - k.gate("cnot", [3,0]); - k.gate("x", [0]); - k.gate("x45", [0]); - - - p = ql.Program("test_cnot_x_NN_commute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_x_2N_commute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'no'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on x operand of CNOT/X/X45/... - # gates on q0 commute with gates on q3 and could even be in parallel - # q3 is cnot control and thus z-commuting operand, of which there are none - # q0 is cnot target and thus x-commuting operand, i.e. x q0 and x45 q0 - # so: cnot commutes with later x q0 and x45 q0, making x q0 and x45 q0 available in parallel to q3 gates, - # while cnot has to be after x q3 and x45 q3, so intended result is that x q0 and x45 q0 get before cnot - # - # only cnot/cz commutation is enabled so input order must be kept - k.gate("x", [3]); - k.gate("x45", [3]); - k.gate("cnot", [3,0]); - k.gate("x", [0]); - k.gate("x45", [0]); - - - p = ql.Program("test_cnot_x_2N_commute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_x_2R_commute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'yes'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on x operand of CNOT/X/X45/... - # gates on q0 commute with gates on q3 and could even be in parallel - # q3 is cnot control and thus z-commuting operand, of which there are none - # q0 is cnot target and thus x-commuting operand, i.e. x q0 and x45 q0 - # so: cnot commutes with later x q0 and x45 q0, making x q0 and x45 q0 available in parallel to q3 gates, - # while cnot has to be after x q3 and x45 q3, so intended result is that x q0 and x45 q0 get before cnot - # - # also rotation commutation is enabled so intended result as above should be result - k.gate("x", [3]); - k.gate("x45", [3]); - k.gate("cnot", [3,0]); - k.gate("x", [0]); - k.gate("x45", [0]); - - - p = ql.Program("test_cnot_x_2R_commute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - - def test_cnot_NN_noncommute_RAD(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'no'); - ql.set_option("scheduler_commute_rotations", 'no'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # the 2 cnots don't commute although a commute would shorten the circuit's latency - # the common qubit is q3 and it is target (x position) of the first and control (z position) of the second cnot - # this is a RAD (or ZAX) dependence between the cnots - # - # gates on q5 commute with cnot q0,q3 and could be in parallel - # but cnot q3,q5 doesn't commute with first cnot and q5 gates depend on it (and don't commute) - # so: shortening circuit is blocked by 2nd cnot not commuting with first and with gates - # - # commute options are both off - # circuit will be as input - k.gate("cnot", [0,3]); - k.gate("cnot", [3,5]); - k.gate("t", [5]); - k.gate("z", [5]); - - - p = ql.Program("test_cnot_NN_noncommute_RAD", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_2R_noncommute_RAD(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'yes'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # the 2 cnots don't commute although a commute would shorten the circuit's latency - # the common qubit is q3 and it is target (x position) of the first and control (z position) of the second cnot - # this is a RAD (or ZAX) dependence between the cnots - # - # gates on q5 commute with cnot q0,q3 and could be in parallel - # but cnot q3,q5 doesn't commute with first cnot and q5 gates depend on it (and don't commute) - # so: shortening circuit is blocked by 2nd cnot not commuting with first and with gates - # - # commute options are both on - # circuit will be as input - k.gate("cnot", [0,3]); - k.gate("cnot", [3,5]); - k.gate("t", [5]); - k.gate("z", [5]); - - - p = ql.Program("test_cnot_2R_noncommute_RAD", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_NN_noncommute_DAR(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'no'); - ql.set_option("scheduler_commute_rotations", 'no'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # the 2 cnots don't commute although a commute would shorten the circuit's latency - # the common qubit is q3 and it is control (z position) of the first and target (x position) of the second cnot - # this is a DAR (or XAZ) dependence between the cnots - # - # gates on q0 commute with cnot q3,q5 and could be in parallel - # but cnot q0,q3 doesn't commute with first cnot and q0 gates depend on it (and don't commute) - # so: shortening circuit is blocked by 2nd cnot not commuting with first and with gates - # - # commute options are both off - # circuit will be as input - k.gate("cnot", [3,5]); - k.gate("cnot", [0,3]); - k.gate("x45", [0]); - k.gate("x", [0]); - k.gate("x45", [0]); - - - p = ql.Program("test_cnot_NN_noncommute_DAR", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_2R_noncommute_DAR(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'yes'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # the 2 cnots don't commute although a commute would shorten the circuit's latency - # the common qubit is q3 and it is control (z position) of the first and target (x position) of the second cnot - # this is a DAR (or XAZ) dependence between the cnots - # - # gates on q0 commute with cnot q3,q5 and could be in parallel - # but cnot q0,q3 doesn't commute with first cnot and q0 gates depend on it (and don't commute) - # so: shortening circuit is blocked by 2nd cnot not commuting with first and with gates - # - # commute options are both on - # circuit will be as input - k.gate("cnot", [3,5]); - k.gate("cnot", [0,3]); - k.gate("x45", [0]); - k.gate("x", [0]); - k.gate("x45", [0]); - - - p = ql.Program("test_cnot_2R_noncommute_DAR", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_NN_controlcommute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'no'); - ql.set_option("scheduler_commute_rotations", 'no'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on control operand of CNOT - # without any commutation, the order is kept - k.gate("cnot", [3,0]); - k.gate("cnot", [3,6]); - k.gate("x45", [6]); - k.gate("x", [6]); - k.gate("cnot", [3,1]); - k.gate("x45", [1]); - k.gate("x", [1]); - k.gate("x45", [1]); - k.gate("x", [1]); - - - p = ql.Program("test_cnot_NN_controlcommute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_2N_controlcommute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'no'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on control operand of CNOT - # without rotation commutation, last one is most critical so cnot order is reversed wrt input order - k.gate("cnot", [3,0]); - k.gate("cnot", [3,6]); - k.gate("x45", [6]); - k.gate("x", [6]); - k.gate("cnot", [3,1]); - k.gate("x45", [1]); - k.gate("x", [1]); - k.gate("x45", [1]); - k.gate("x", [1]); - - - p = ql.Program("test_cnot_2N_controlcommute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_2R_controlcommute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'yes'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on control operand of CNOT - # with all commutation, all gates commute, so any result order is ok - k.gate("cnot", [3,0]); - k.gate("cnot", [3,6]); - k.gate("x45", [6]); - k.gate("x", [6]); - k.gate("cnot", [3,1]); - k.gate("x45", [1]); - k.gate("x", [1]); - k.gate("x45", [1]); - k.gate("x", [1]); - - - p = ql.Program("test_cnot_2R_controlcommute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_NN_targetcommute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'no'); - ql.set_option("scheduler_commute_rotations", 'no'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on target operand of CNOT - # without any commutation, the order is kept - k.gate("cnot", [0,3]); - k.gate("cnot", [6,3]); - k.gate("t", [6]); - k.gate("z", [6]); - k.gate("cnot", [1,3]); - k.gate("t", [1]); - k.gate("z", [1]); - k.gate("t", [1]); - k.gate("z", [1]); - - - p = ql.Program("test_cnot_NN_targetcommute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_2N_targetcommute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'no'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on target operand of CNOT - # without rotation commutation, last one is most critical so cnot order is reversed wrt input order - k.gate("cnot", [0,3]); - k.gate("cnot", [6,3]); - k.gate("t", [6]); - k.gate("z", [6]); - k.gate("cnot", [1,3]); - k.gate("t", [1]); - k.gate("z", [1]); - k.gate("t", [1]); - k.gate("z", [1]); - - - p = ql.Program("test_cnot_2N_targetcommute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_2R_targetcommute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'yes'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on target operand of CNOT - # with all commutation, all gates commute, so any result order is ok - k.gate("cnot", [0,3]); - k.gate("cnot", [6,3]); - k.gate("t", [6]); - k.gate("z", [6]); - k.gate("cnot", [1,3]); - k.gate("t", [1]); - k.gate("z", [1]); - k.gate("t", [1]); - k.gate("z", [1]); - - - p = ql.Program("test_cnot_2R_targetcommute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cz_NN_anycommute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'no'); - ql.set_option("scheduler_commute_rotations", 'no'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on both operands of CZ - # without any commutation, order is kept - k.gate("cz", [0,3]); - k.gate("cz", [3,6]); - k.gate("t", [6]); - k.gate("z", [6]); - k.gate("cz", [1,3]); - k.gate("t", [1]); - k.gate("z", [1]); - k.gate("t", [1]); - k.gate("z", [1]); - - - p = ql.Program("test_cz_NN_anycommute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cz_2N_anycommute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'no'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on both operands of CZ - # without rotation commutation, cz order is reversed wrt input because last one is most critical - k.gate("cz", [0,3]); - k.gate("cz", [3,6]); - k.gate("t", [6]); - k.gate("z", [6]); - k.gate("cz", [1,3]); - k.gate("t", [1]); - k.gate("z", [1]); - k.gate("t", [1]); - k.gate("z", [1]); - - - p = ql.Program("test_cz_2N_anycommute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cz_2R_anycommute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'yes'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on both operands of CZ - # with all commutation, all gates commute, so any result order is ok - k.gate("cz", [0,3]); - k.gate("cz", [3,6]); - k.gate("t", [6]); - k.gate("z", [6]); - k.gate("cz", [1,3]); - k.gate("t", [1]); - k.gate("z", [1]); - k.gate("t", [1]); - k.gate("z", [1]); - - - p = ql.Program("test_cz_2R_anycommute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_cnot_mixedcommute(self): - platf = ql.Platform("starmon", config) - - ql.set_option("scheduler_commute", 'yes'); - ql.set_option("scheduler_commute_rotations", 'yes'); - - nqubits = 7 - k = ql.Kernel("aKernel", platf, nqubits) - - # commute on mixture of operands of many CNOTs: - # the only dependences are those reflecting that - # each CNOT(a,b) must be before CNOT(b,c), since b is in common but in different positions (RAD), - # each CNOT(a,b) must be before CNOT(c,a), since a is in common but in different positions (DAR), - # all dep chains have length 3: - # cnot[0,*] -> cnot[2,*] -> cnot[5,*] - # cnot[0,*] -> cnot[3,*] -> cnot[6,*] - # cnot[1,*] -> cnot[3,*] -> cnot[6,*] - # cnot[1,*] -> cnot[4,*] -> cnot[6,*] - # so the end result should reflect those 3 bundles with cnots, one for each column above - # but after rc scheduling, the middle ones because of classical control constraints, causing 4 bundles - k.gate("cnot", [0,2]); - k.gate("cnot", [0,3]); - k.gate("cnot", [1,3]); - k.gate("cnot", [1,4]); - k.gate("cnot", [2,0]); - k.gate("cnot", [2,5]); - k.gate("cnot", [3,0]); - k.gate("cnot", [3,1]); - k.gate("cnot", [3,5]); - k.gate("cnot", [3,6]); - k.gate("cnot", [4,1]); - k.gate("cnot", [4,6]); - k.gate("cnot", [5,2]); - k.gate("cnot", [5,3]); - k.gate("cnot", [6,3]); - k.gate("cnot", [6,4]); - - - p = ql.Program("test_cnot_mixedcommute", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - -# def test_cnot_variations(self): -## platf = ql.Platform("starmon", config) -# ql.set_option("scheduler", 'ALAP'); -# ql.set_option("scheduler_commute", 'yes'); -# ql.set_option("vary_commutations", 'yes'); -# -# nqubits = 7 -# k = ql.Kernel("aKernel", platf, nqubits) -# -# for j in range(7): -# k.gate("x", [j]) -# # commute on mixture of operands of many CNOTs -# # basically, each CNOT(a,b) must ultimately be before CNOT(b,a) -# # in between, CNOT(a,b) commutes with CNOT(a,c) and CNOT(d,b) -# # there will be several commutation sets -# k.gate("cnot", [0,2]); -# k.gate("cnot", [0,3]); -# k.gate("cnot", [1,3]); -# k.gate("cnot", [1,4]); -# k.gate("cnot", [2,0]); -# k.gate("cnot", [2,5]); -# k.gate("cnot", [3,0]); -# k.gate("cnot", [3,1]); -# k.gate("cnot", [3,5]); -# k.gate("cnot", [3,6]); -# k.gate("cnot", [4,1]); -# k.gate("cnot", [4,6]); -# # k.gate("cnot", [5,2]); -# # k.gate("cnot", [5,3]); -# # k.gate("cnot", [6,3]); -# # k.gate("cnot", [6,4]); -# for j in range(7): -# k.gate("x", [j]) -# -# -# p = ql.Program("test_cnot_variations", platf, nqubits) -# p.add_kernel(k) -# p.compile() -# -# gold_fn = curdir + '/golden/'+ p.name + '_scheduled.qasm' -# qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') -# self.assertTrue( file_compare(qasm_fn, gold_fn) ) - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_dependence.py b/tests/test_dependence.py deleted file mode 100644 index 4adb9b7ef..000000000 --- a/tests/test_dependence.py +++ /dev/null @@ -1,210 +0,0 @@ -import os -from utils import file_compare -import unittest -from openql import openql as ql - -curdir = os.path.dirname(os.path.realpath(__file__)) -config_fn = os.path.join(curdir, 'test_config_default.json') -platf = ql.Platform("starmon", config_fn) - -output_dir = os.path.join(curdir, 'test_output') - -class Test_dependence(unittest.TestCase): - - def setUp(self): - ql.initialize() - ql.set_option('output_dir', output_dir) - ql.set_option('optimize', 'no') - ql.set_option('scheduler', 'ASAP') - ql.set_option('scheduler_commute', 'no') - ql.set_option('log_level', 'LOG_WARNING') - # ql.set_option('write_qasm_files', 'yes') - - # @unittest.expectedFailure - # @unittest.skip - def test_independent(self): - nqubits = 4 - # populate kernel - k = ql.Kernel("aKernel", platf, nqubits) - - for i in range(4): - k.prepz(i) - - # no dependence - k.cz(0, 1) - k.cz(2, 3) - - k.measure(0) - k.measure(1) - - - p = ql.Program("independent", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/test_independence.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - - # @unittest.skip - def test_WAW(self): - nqubits = 4 - # populate kernel - k = ql.Kernel("aKernel", platf, nqubits) - - for i in range(4): - k.prepz(i) - - # q1 dependence - k.cz(0, 1) - k.cz(2, 1) - - k.measure(0) - k.measure(1) - - - p = ql.Program("WAW", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/test_WAW_ASAP.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - - # @unittest.skip - def test_RAR_Control(self): - nqubits = 4 - - # populate kernel - k = ql.Kernel("aKernel", platf, nqubits) - - for i in range(4): - k.prepz(i) - - # q0 dependence - k.cz(0, 1) - k.cz(0, 2) - - k.measure(0) - k.measure(1) - - - p = ql.Program("RAR", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/test_RAR_Control_ASAP.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - - # @unittest.skip - def test_RAW(self): - - nqubits = 4 - - # populate kernel - k = ql.Kernel("aKernel", platf, nqubits) - - for i in range(4): - k.prepz(i) - - # q1 dependence - k.cz(0, 1) - k.cz(1, 2) - - k.measure(0) - k.measure(1) - - - p = ql.Program("RAW", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/test_RAW_ASAP.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - - # @unittest.skip - def test_WAR(self): - - nqubits = 4 - - # populate kernel - k = ql.Kernel("aKernel", platf, nqubits) - - for i in range(4): - k.prepz(i) - - # q0 dependence - k.cz(0, 1) - k.cz(2, 0) - - k.measure(0) - k.measure(1) - - - p = ql.Program("WAR", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/test_WAR_ASAP.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - - # @unittest.skip - def test_swap_single(self): - - nqubits = 4 - - # populate kernel - k = ql.Kernel("aKernel", platf, nqubits) - - k.gate("x", [0]); - k.gate("swap", [0, 1]) - k.gate("x", [0]) - - - p = ql.Program("swap_single", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/test_swap_single_ASAP.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - - # @unittest.skip - def test_swap_multi(self): - - nqubits = 5 - - # populate kernel - k = ql.Kernel("aKernel", platf, nqubits) - - # swap test with 2 qubit gates - k.gate("x", [0]) - k.gate("x", [1]) - k.gate("swap", [0, 1]) - k.gate("cz", [0, 2]) - k.gate("cz", [1, 4]) - - - p = ql.Program("swap_multi", platf, nqubits) - p.add_kernel(k) - p.compile() - - gold_fn = curdir + '/golden/test_swap_multi_ASAP.qasm' - qasm_fn = os.path.join(output_dir, p.name+'_scheduled.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_gate_decomposition.py b/tests/test_gate_decomposition.py deleted file mode 100644 index 9bcb48341..000000000 --- a/tests/test_gate_decomposition.py +++ /dev/null @@ -1,50 +0,0 @@ -from openql import openql as ql -import unittest -import os -from utils import file_compare - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') - - -class Tester(unittest.TestCase): - - @classmethod - def setUp(self): - ql.initialize() - ql.set_option('output_dir', output_dir) - ql.set_option('optimize', 'no') - ql.set_option('scheduler', 'ALAP') - ql.set_option('log_level', 'LOG_NOTHING') - - def test_decomposition(self): - config_fn = os.path.join(curdir, 'test_cfg_none.json') - platform = ql.Platform('platform_none', config_fn) - num_qubits = 17 - p = ql.Program('test_decomposition', platform, num_qubits) - - k = ql.Kernel('aKernel', platform, num_qubits) - - k.x(0) # x will be decomposed - k.gate("x", [0]); # x will be decomposed - k.gate("y", [0]); # decomposition not available, will use custom gate - k.gate("s", [1]); # decomposition as well as custom gate not available, will use default gate - k.gate("roty90", [0]) # any name can be used for composite gate - - k.gate("cnot", [0, 1] ) # decomposition overrules custom(=primitive) gate; decomposition uses specialized cz q0,q1 - k.gate("cnot", [2, 3] ) # cnot will be decomposed; decomposition falls back to default gate for cz q2,q3 - - # add the kernel to the program - p.add_kernel(k) - - # compile the program - p.compile() - - prog_name = "test_decomposition" - gold_fn = curdir + '/golden/' + prog_name +'_scheduled.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_scheduled.qasm') - self.assertTrue(file_compare(qasm_fn, gold_fn)) - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_gate_decomposition_cz.cc_backend.map b/tests/test_gate_decomposition_cz.cc_backend.map deleted file mode 100644 index 70158dee2..000000000 --- a/tests/test_gate_decomposition_cz.cc_backend.map +++ /dev/null @@ -1,48 +0,0 @@ -{ - "codewords": { - "data": { - "flux_0": [ - [ - 2, - "{type:cz,which:SE}" - ], - [ - 2, - "{type:cz,which:SE}" - ], - [ - 2, - "{type:cz,which:SE}" - ], - [ - 5, - "{type:park}" - ], - [ - 3, - "{type:cz,which:SW}" - ], - null, - [ - 4, - "{type:idle_z,which:NW}" - ], - [ - 1, - "{type:idle_z,which:NE}" - ] - ] - }, - "version": 1 - }, - "measurements": { - "data": null, - "nr-shots": null, - "version": 2 - }, - "openql": { - "backend": "cc", - "backend-version": "0.4.0", - "version": "0.11.1" - } -} diff --git a/tests/test_gate_decomposition_cz.cc_backend.vcd b/tests/test_gate_decomposition_cz.cc_backend.vcd deleted file mode 100644 index 86a4d3cab..000000000 --- a/tests/test_gate_decomposition_cz.cc_backend.vcd +++ /dev/null @@ -1,359 +0,0 @@ -$date today $end -$timescale 1 ns $end -$scope module kernel $end -$var string 20 0 kernel $end -$upscope $end -$scope module qubits $end -$var string 20 1 q0 $end -$var string 20 2 q1 $end -$var string 20 3 q2 $end -$var string 20 4 q3 $end -$var string 20 5 q4 $end -$var string 20 6 q5 $end -$var string 20 7 q6 $end -$var string 20 8 q7 $end -$var string 20 9 q8 $end -$var string 20 10 q9 $end -$var string 20 11 q10 $end -$var string 20 12 q11 $end -$var string 20 13 q12 $end -$var string 20 14 q13 $end -$var string 20 15 q14 $end -$var string 20 16 q15 $end -$var string 20 17 q16 $end -$upscope $end -$scope module sd.signal $end -$var string 20 18 ro_0-0 $end -$var string 20 19 ro_0-1 $end -$var string 20 20 ro_0-2 $end -$var string 20 21 ro_0-3 $end -$var string 20 22 ro_0-4 $end -$var string 20 23 ro_0-5 $end -$var string 20 24 ro_0-6 $end -$var string 20 25 ro_0-7 $end -$var string 20 26 ro_0-8 $end -$var string 20 27 ro_1-0 $end -$var string 20 28 ro_1-1 $end -$var string 20 29 ro_1-2 $end -$var string 20 30 ro_1-3 $end -$var string 20 31 ro_1-4 $end -$var string 20 32 ro_1-5 $end -$var string 20 33 ro_1-6 $end -$var string 20 34 ro_1-7 $end -$var string 20 35 ro_1-8 $end -$var string 20 36 ro_2-0 $end -$var string 20 37 ro_2-1 $end -$var string 20 38 ro_2-2 $end -$var string 20 39 ro_2-3 $end -$var string 20 40 ro_2-4 $end -$var string 20 41 ro_2-5 $end -$var string 20 42 ro_2-6 $end -$var string 20 43 ro_2-7 $end -$var string 20 44 ro_2-8 $end -$var string 20 45 mw_0-0 $end -$var string 20 46 mw_0-1 $end -$var string 20 47 mw_0-2 $end -$var string 20 48 mw_0-3 $end -$var string 20 49 mw_1-0 $end -$var string 20 50 mw_1-1 $end -$var string 20 51 mw_1-2 $end -$var string 20 52 mw_1-3 $end -$var string 20 53 mw_2-0 $end -$var string 20 54 mw_2-1 $end -$var string 20 55 mw_2-2 $end -$var string 20 56 mw_2-3 $end -$var string 20 57 mw_3-0 $end -$var string 20 58 mw_3-1 $end -$var string 20 59 mw_3-2 $end -$var string 20 60 mw_3-3 $end -$var string 20 61 mw_4-0 $end -$var string 20 62 mw_4-1 $end -$var string 20 63 mw_4-2 $end -$var string 20 64 mw_4-3 $end -$var string 20 65 flux_0-0 $end -$var string 20 66 flux_0-1 $end -$var string 20 67 flux_0-2 $end -$var string 20 68 flux_0-3 $end -$var string 20 69 flux_0-4 $end -$var string 20 70 flux_0-5 $end -$var string 20 71 flux_0-6 $end -$var string 20 72 flux_0-7 $end -$var string 20 73 flux_1-0 $end -$var string 20 74 flux_1-1 $end -$var string 20 75 flux_1-2 $end -$var string 20 76 flux_1-3 $end -$var string 20 77 flux_1-4 $end -$var string 20 78 flux_1-5 $end -$var string 20 79 flux_1-6 $end -$var string 20 80 flux_1-7 $end -$var string 20 81 flux_2-0 $end -$var string 20 82 flux_2-1 $end -$var string 20 83 flux_2-2 $end -$var string 20 84 flux_2-3 $end -$var string 20 85 flux_2-4 $end -$var string 20 86 flux_2-5 $end -$var string 20 87 flux_2-6 $end -$var string 20 88 flux_2-7 $end -$upscope $end -$scope module codewords $end -$var string 20 89 ro_0 $end -$var string 20 90 ro_1 $end -$var string 20 91 ro_2 $end -$var string 20 92 mw_0 $end -$var string 20 93 mw_1 $end -$var string 20 94 mw_2 $end -$var string 20 95 mw_3 $end -$var string 20 96 mw_4 $end -$var string 20 97 flux_0 $end -$var string 20 98 flux_1 $end -$var string 20 99 flux_2 $end -$upscope $end -$enddefinitions $end -#0 -skernel_0 0 -s_cz_sw_ne_park 9 -s_cz_sw_ne_park 11 -s_cz_sw_ne_park 12 -s2147516419={type:cz,which:SW} 65 -s2147516480={type:idle_z,which:NE} 67 -s2147518976={type:park} 68 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s0x80008a43 97 -s 98 -s 99 -#40 -s_cz_sw_ne_park 9 -s_cz_sw_ne_park 11 -s_cz_sw_ne_park 12 -s2147516419={type:cz,which:SW} 65 -s2147516480={type:idle_z,which:NE} 67 -s2147518976={type:park} 68 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s0x80008a43 97 -s 98 -s 99 -#80 -s_cz_se_nw_park 9 -s_cz_se_nw_park 11 -s_cz_se_nw_park 12 -s2147516418={type:cz,which:SE} 65 -s2147516736={type:park} 67 -s2147518464={type:idle_z,which:NW} 68 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s0x80008942 97 -s 98 -s 99 -#120 -s 9 -s_cz_sw_ne_park 10 -s 11 -s_cz_sw_ne_park 12 -s_cz_sw_ne_park 13 -s 65 -s2147516440={type:cz,which:SW} 66 -s 67 -s2147516928={type:idle_z,which:NE} 68 -s2147844096={type:park} 69 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s0x80058218 97 -s 98 -s 99 -#160 -s 10 -s_cz_sw_ne_park 12 -s 13 -s_cz_sw_ne_park 15 -s_cz_sw_ne_park 16 -s 66 -s2147517952={type:cz,which:SW} 68 -s 69 -s2151710720={type:idle_z,which:NE} 71 -s2315288576={type:park} 72 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s0x8a408600 97 -s 98 -s 99 -#200 -s_cz_sw_ne_park 12 -s_cz_sw_ne_park 15 -s_cz_sw_ne_park 16 -s2147517952={type:cz,which:SW} 68 -s2151710720={type:idle_z,which:NE} 71 -s2315288576={type:park} 72 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s0x8a408600 97 -s 98 -s 99 -#240 -s_cz_sw_ne_park 10 -s_cz_sw_ne_park 12 -s_cz_sw_ne_park 13 -s 15 -s 16 -s2147516440={type:cz,which:SW} 66 -s2147516928={type:idle_z,which:NE} 68 -s2147844096={type:park} 69 -s 71 -s 72 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s0x80058218 97 -s 98 -s 99 -#280 -s_cz_sw_ne_park 10 -s_cz_sw_ne_park 12 -s_cz_sw_ne_park 13 -s2147516440={type:cz,which:SW} 66 -s2147516928={type:idle_z,which:NE} 68 -s2147844096={type:park} 69 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s0x80058218 97 -s 98 -s 99 -#320 -s_cz_se_nw_park 10 -s_cz_se_nw_park 12 -s_cz_se_nw_park 13 -s2147516432={type:cz,which:SE} 66 -s2147518976={type:park} 68 -s2147778560={type:idle_z,which:NW} 69 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s0x80048a10 97 -s 98 -s 99 -#360 -s_cz_se_nw_park 10 -s_cz_se_nw_park 12 -s_cz_se_nw_park 13 -s2147516432={type:cz,which:SE} 66 -s2147518976={type:park} 68 -s2147778560={type:idle_z,which:NW} 69 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s0x80048a10 97 -s 98 -s 99 -#400 -s 10 -s_cz_se_nw 11 -s 12 -s_cz_sw_ne 13 -s_cz_se_nw 15 -s_cz_sw_ne 16 -s 66 -s2147516544={type:cz,which:SE} 67 -s 68 -s2147713024={type:cz,which:SW} 69 -s2164293632={type:idle_z,which:NW} 71 -s2181070848={type:idle_z,which:NE} 72 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s0x83038080 97 -s 98 -s 99 -#440 -s_cz_se_nw 11 -s_cz_sw_ne 13 -s_cz_se_nw 15 -s_cz_sw_ne 16 -s2147516544={type:cz,which:SE} 67 -s2147713024={type:cz,which:SW} 69 -s2164293632={type:idle_z,which:NW} 71 -s2181070848={type:idle_z,which:NE} 72 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s0x83038080 97 -s 98 -s 99 -#480 -s 0 -s 11 -s 13 -s 15 -s 16 -s 67 -s 69 -s 71 -s 72 -s 97 diff --git a/tests/test_gate_decomposition_cz.cc_backend.vq1asm b/tests/test_gate_decomposition_cz.cc_backend.vq1asm deleted file mode 100644 index 044bbe42c..000000000 --- a/tests/test_gate_decomposition_cz.cc_backend.vq1asm +++ /dev/null @@ -1,182 +0,0 @@ -# Program: 'test_gate_decomposition_cz' -# CC_BACKEND_VERSION 0.4.0 -# OPENQL_VERSION 0.11.1 -# Note: generated by OpenQL Central Controller backend -# -.CODE -# synchronous start and latency compensation - seq_bar # synchronization, delay set externally through SET_SEQ_BAR_CNT - seq_out 0x00000000,1 # allows monitoring actual start time using trace unit -# start of main loop that runs indefinitely -__mainLoop: # - seq_state 0 # clear Programmable Logic state - -### Block: 'kernel_0' -## Bundle 0: start_cycle=0: - # gate '_cz_sw_ne_park q[8], q[10], q[11]' - # slot=3, instrument='flux_0', group=0': signalValue='{type:cz,which:SW}' - # slot=3, instrument='flux_0', group=2': signalValue='{type:idle_z,which:NE}' - # slot=3, instrument='flux_0', group=3': signalValue='{type:park}' - # slot=3, instrument='flux_0', group=0: codeword=3 (static override): groupDigOut=0x00000003 - # slot=3, instrument='flux_0', group=2: codeword=1 (static override): groupDigOut=0x00000040 - # slot=3, instrument='flux_0', group=3: codeword=5 (static override): groupDigOut=0x00000a00 - # slot=3, instrument='flux_0': lastEndCycle=0, startCycle=0, instrMaxDurationInCycles=2 -[3] seq_out 0x80008a43,2 # cycle 0-2: code word/mask on 'flux_0' - -## Bundle 1: start_cycle=2: - # gate '_cz_sw_ne_park q[8], q[10], q[11]' - # slot=3, instrument='flux_0', group=0': signalValue='{type:cz,which:SW}' - # slot=3, instrument='flux_0', group=2': signalValue='{type:idle_z,which:NE}' - # slot=3, instrument='flux_0', group=3': signalValue='{type:park}' - # slot=3, instrument='flux_0', group=0: codeword=3 (static override): groupDigOut=0x00000003 - # slot=3, instrument='flux_0', group=2: codeword=1 (static override): groupDigOut=0x00000040 - # slot=3, instrument='flux_0', group=3: codeword=5 (static override): groupDigOut=0x00000a00 - # slot=3, instrument='flux_0': lastEndCycle=2, startCycle=2, instrMaxDurationInCycles=2 -[3] seq_out 0x80008a43,2 # cycle 2-4: code word/mask on 'flux_0' - -## Bundle 2: start_cycle=4: - # gate '_cz_se_nw_park q[8], q[11], q[10]' - # slot=3, instrument='flux_0', group=0': signalValue='{type:cz,which:SE}' - # slot=3, instrument='flux_0', group=3': signalValue='{type:idle_z,which:NW}' - # slot=3, instrument='flux_0', group=2': signalValue='{type:park}' - # slot=3, instrument='flux_0', group=0: codeword=2 (static override): groupDigOut=0x00000002 - # slot=3, instrument='flux_0', group=2: codeword=5 (static override): groupDigOut=0x00000140 - # slot=3, instrument='flux_0', group=3: codeword=4 (static override): groupDigOut=0x00000800 - # slot=3, instrument='flux_0': lastEndCycle=4, startCycle=4, instrMaxDurationInCycles=2 -[3] seq_out 0x80008942,2 # cycle 4-6: code word/mask on 'flux_0' - -## Bundle 3: start_cycle=6: - # gate '_cz_sw_ne_park q[9], q[11], q[12]' - # slot=3, instrument='flux_0', group=1': signalValue='{type:cz,which:SW}' - # slot=3, instrument='flux_0', group=3': signalValue='{type:idle_z,which:NE}' - # slot=3, instrument='flux_0', group=4': signalValue='{type:park}' - # slot=3, instrument='flux_0', group=1: codeword=3 (static override): groupDigOut=0x00000018 - # slot=3, instrument='flux_0', group=3: codeword=1 (static override): groupDigOut=0x00000200 - # slot=3, instrument='flux_0', group=4: codeword=5 (static override): groupDigOut=0x00050000 - # slot=3, instrument='flux_0': lastEndCycle=6, startCycle=6, instrMaxDurationInCycles=2 -[3] seq_out 0x80058218,2 # cycle 6-8: code word/mask on 'flux_0' - -## Bundle 4: start_cycle=8: - # gate '_cz_sw_ne_park q[11], q[14], q[15]' - # slot=3, instrument='flux_0', group=3': signalValue='{type:cz,which:SW}' - # slot=3, instrument='flux_0', group=6': signalValue='{type:idle_z,which:NE}' - # slot=3, instrument='flux_0', group=7': signalValue='{type:park}' - # slot=3, instrument='flux_0', group=3: codeword=3 (static override): groupDigOut=0x00000600 - # slot=3, instrument='flux_0', group=6: codeword=1 (static override): groupDigOut=0x00400000 - # slot=3, instrument='flux_0', group=7: codeword=5 (static override): groupDigOut=0x0a000000 - # slot=3, instrument='flux_0': lastEndCycle=8, startCycle=8, instrMaxDurationInCycles=2 -[3] seq_out 0x8a408600,2 # cycle 8-10: code word/mask on 'flux_0' - -## Bundle 5: start_cycle=10: - # gate '_cz_sw_ne_park q[11], q[14], q[15]' - # slot=3, instrument='flux_0', group=3': signalValue='{type:cz,which:SW}' - # slot=3, instrument='flux_0', group=6': signalValue='{type:idle_z,which:NE}' - # slot=3, instrument='flux_0', group=7': signalValue='{type:park}' - # slot=3, instrument='flux_0', group=3: codeword=3 (static override): groupDigOut=0x00000600 - # slot=3, instrument='flux_0', group=6: codeword=1 (static override): groupDigOut=0x00400000 - # slot=3, instrument='flux_0', group=7: codeword=5 (static override): groupDigOut=0x0a000000 - # slot=3, instrument='flux_0': lastEndCycle=10, startCycle=10, instrMaxDurationInCycles=2 -[3] seq_out 0x8a408600,2 # cycle 10-12: code word/mask on 'flux_0' - -## Bundle 6: start_cycle=12: - # gate '_cz_sw_ne_park q[9], q[11], q[12]' - # slot=3, instrument='flux_0', group=1': signalValue='{type:cz,which:SW}' - # slot=3, instrument='flux_0', group=3': signalValue='{type:idle_z,which:NE}' - # slot=3, instrument='flux_0', group=4': signalValue='{type:park}' - # slot=3, instrument='flux_0', group=1: codeword=3 (static override): groupDigOut=0x00000018 - # slot=3, instrument='flux_0', group=3: codeword=1 (static override): groupDigOut=0x00000200 - # slot=3, instrument='flux_0', group=4: codeword=5 (static override): groupDigOut=0x00050000 - # slot=3, instrument='flux_0': lastEndCycle=12, startCycle=12, instrMaxDurationInCycles=2 -[3] seq_out 0x80058218,2 # cycle 12-14: code word/mask on 'flux_0' - -## Bundle 7: start_cycle=14: - # gate '_cz_sw_ne_park q[9], q[11], q[12]' - # slot=3, instrument='flux_0', group=1': signalValue='{type:cz,which:SW}' - # slot=3, instrument='flux_0', group=3': signalValue='{type:idle_z,which:NE}' - # slot=3, instrument='flux_0', group=4': signalValue='{type:park}' - # slot=3, instrument='flux_0', group=1: codeword=3 (static override): groupDigOut=0x00000018 - # slot=3, instrument='flux_0', group=3: codeword=1 (static override): groupDigOut=0x00000200 - # slot=3, instrument='flux_0', group=4: codeword=5 (static override): groupDigOut=0x00050000 - # slot=3, instrument='flux_0': lastEndCycle=14, startCycle=14, instrMaxDurationInCycles=2 -[3] seq_out 0x80058218,2 # cycle 14-16: code word/mask on 'flux_0' - -## Bundle 8: start_cycle=16: - # gate '_cz_se_nw_park q[9], q[12], q[11]' - # slot=3, instrument='flux_0', group=1': signalValue='{type:cz,which:SE}' - # slot=3, instrument='flux_0', group=4': signalValue='{type:idle_z,which:NW}' - # slot=3, instrument='flux_0', group=3': signalValue='{type:park}' - # slot=3, instrument='flux_0', group=1: codeword=2 (static override): groupDigOut=0x00000010 - # slot=3, instrument='flux_0', group=3: codeword=5 (static override): groupDigOut=0x00000a00 - # slot=3, instrument='flux_0', group=4: codeword=4 (static override): groupDigOut=0x00040000 - # slot=3, instrument='flux_0': lastEndCycle=16, startCycle=16, instrMaxDurationInCycles=2 -[3] seq_out 0x80048a10,2 # cycle 16-18: code word/mask on 'flux_0' - -## Bundle 9: start_cycle=18: - # gate '_cz_se_nw_park q[9], q[12], q[11]' - # slot=3, instrument='flux_0', group=1': signalValue='{type:cz,which:SE}' - # slot=3, instrument='flux_0', group=4': signalValue='{type:idle_z,which:NW}' - # slot=3, instrument='flux_0', group=3': signalValue='{type:park}' - # slot=3, instrument='flux_0', group=1: codeword=2 (static override): groupDigOut=0x00000010 - # slot=3, instrument='flux_0', group=3: codeword=5 (static override): groupDigOut=0x00000a00 - # slot=3, instrument='flux_0', group=4: codeword=4 (static override): groupDigOut=0x00040000 - # slot=3, instrument='flux_0': lastEndCycle=18, startCycle=18, instrMaxDurationInCycles=2 -[3] seq_out 0x80048a10,2 # cycle 18-20: code word/mask on 'flux_0' - -## Bundle 10: start_cycle=20: - # gate '_cz_se_nw q[10], q[14]' - # slot=3, instrument='flux_0', group=2': signalValue='{type:cz,which:SE}' - # slot=3, instrument='flux_0', group=6': signalValue='{type:idle_z,which:NW}' - # gate '_cz_sw_ne q[12], q[15]' - # slot=3, instrument='flux_0', group=4': signalValue='{type:cz,which:SW}' - # slot=3, instrument='flux_0', group=7': signalValue='{type:idle_z,which:NE}' - # slot=3, instrument='flux_0', group=2: codeword=2 (static override): groupDigOut=0x00000080 - # slot=3, instrument='flux_0', group=4: codeword=3 (static override): groupDigOut=0x00030000 - # slot=3, instrument='flux_0', group=6: codeword=4 (static override): groupDigOut=0x01000000 - # slot=3, instrument='flux_0', group=7: codeword=1 (static override): groupDigOut=0x02000000 - # slot=3, instrument='flux_0': lastEndCycle=20, startCycle=20, instrMaxDurationInCycles=2 -[3] seq_out 0x83038080,2 # cycle 20-22: code word/mask on 'flux_0' - -## Bundle 11: start_cycle=22: - # gate '_cz_se_nw q[10], q[14]' - # slot=3, instrument='flux_0', group=2': signalValue='{type:cz,which:SE}' - # slot=3, instrument='flux_0', group=6': signalValue='{type:idle_z,which:NW}' - # gate '_cz_sw_ne q[12], q[15]' - # slot=3, instrument='flux_0', group=4': signalValue='{type:cz,which:SW}' - # slot=3, instrument='flux_0', group=7': signalValue='{type:idle_z,which:NE}' - # slot=3, instrument='flux_0', group=2: codeword=2 (static override): groupDigOut=0x00000080 - # slot=3, instrument='flux_0', group=4: codeword=3 (static override): groupDigOut=0x00030000 - # slot=3, instrument='flux_0', group=6: codeword=4 (static override): groupDigOut=0x01000000 - # slot=3, instrument='flux_0', group=7: codeword=1 (static override): groupDigOut=0x02000000 - # last bundle of kernel, will pad outputs to match durations -[2] seq_wait 24 # cycle 0-24: padding on 'ro_0' -[4] seq_wait 24 # cycle 0-24: padding on 'ro_1' -[5] seq_wait 24 # cycle 0-24: padding on 'ro_2' -[0] seq_wait 24 # cycle 0-24: padding on 'mw_0' -[1] seq_wait 24 # cycle 0-24: padding on 'mw_1' -[6] seq_wait 24 # cycle 0-24: padding on 'mw_2' -[7] seq_wait 24 # cycle 0-24: padding on 'mw_3' -[8] seq_wait 24 # cycle 0-24: padding on 'mw_4' - # slot=3, instrument='flux_0': lastEndCycle=22, startCycle=22, instrMaxDurationInCycles=2 -[3] seq_out 0x83038080,2 # cycle 22-24: code word/mask on 'flux_0' -[9] seq_wait 24 # cycle 0-24: padding on 'flux_1' -[10] seq_wait 24 # cycle 0-24: padding on 'flux_2' - -### Block end: 'kernel_0' -# finish program - seq_wait 1 - jmp @__mainLoop # loop indefinitely -.END -.DATAPATH -## Bundle 0: start_cycle=0: -## Bundle 1: start_cycle=2: -## Bundle 2: start_cycle=4: -## Bundle 3: start_cycle=6: -## Bundle 4: start_cycle=8: -## Bundle 5: start_cycle=10: -## Bundle 6: start_cycle=12: -## Bundle 7: start_cycle=14: -## Bundle 8: start_cycle=16: -## Bundle 9: start_cycle=18: -## Bundle 10: start_cycle=20: -## Bundle 11: start_cycle=22: -.END diff --git a/tests/test_gate_decomposition_cz.initial.cq b/tests/test_gate_decomposition_cz.initial.cq deleted file mode 100644 index ff28eac36..000000000 --- a/tests/test_gate_decomposition_cz.initial.cq +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by OpenQL 0.11.1 for program test_gate_decomposition_cz -version 1.2 - -pragma @ql.name("test_gate_decomposition_cz") - - -.kernel_0 - _cz_sw_ne_park q[8], q[10], q[11] - _cz_sw_ne_park q[8], q[10], q[11] - _cz_se_nw_park q[8], q[11], q[10] - _cz_sw_ne_park q[9], q[11], q[12] - _cz_sw_ne_park q[11], q[14], q[15] - _cz_sw_ne_park q[11], q[14], q[15] - _cz_se_nw q[10], q[14] - _cz_se_nw q[10], q[14] - _cz_sw_ne_park q[9], q[11], q[12] - _cz_sw_ne_park q[9], q[11], q[12] - _cz_se_nw_park q[9], q[12], q[11] - _cz_se_nw_park q[9], q[12], q[11] - _cz_sw_ne q[12], q[15] - _cz_sw_ne q[12], q[15] diff --git a/tests/test_gate_decomposition_cz.scheduled.cq b/tests/test_gate_decomposition_cz.scheduled.cq deleted file mode 100644 index f5a3ea81d..000000000 --- a/tests/test_gate_decomposition_cz.scheduled.cq +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by OpenQL 0.11.1 for program test_gate_decomposition_cz -version 1.2 - -pragma @ql.name("test_gate_decomposition_cz") - - -.kernel_0 - _cz_sw_ne_park q[8], q[10], q[11] - skip 1 - _cz_sw_ne_park q[8], q[10], q[11] - skip 1 - _cz_se_nw_park q[8], q[11], q[10] - skip 1 - _cz_sw_ne_park q[9], q[11], q[12] - skip 1 - _cz_sw_ne_park q[11], q[14], q[15] - skip 1 - _cz_sw_ne_park q[11], q[14], q[15] - skip 1 - _cz_sw_ne_park q[9], q[11], q[12] - skip 1 - _cz_sw_ne_park q[9], q[11], q[12] - skip 1 - _cz_se_nw_park q[9], q[12], q[11] - skip 1 - _cz_se_nw_park q[9], q[12], q[11] - skip 1 - { # start at cycle 20 - _cz_se_nw q[10], q[14] - _cz_sw_ne q[12], q[15] - } - skip 1 - { # start at cycle 22 - _cz_se_nw q[10], q[14] - _cz_sw_ne q[12], q[15] - } - skip 1 diff --git a/tests/test_mapper.py b/tests/test_mapper.py deleted file mode 100644 index 94a3d0689..000000000 --- a/tests/test_mapper.py +++ /dev/null @@ -1,687 +0,0 @@ -# tests for mapper -# -# -# tests combination of prescheduler, clifford, mapper, clifford and postscheduler in cc_light context -# by generating .qisa and comparing the generated one with a golden one after assembly -# -# assumes config files: test_mapper_rig.json, test_mapper_s7.json and test_mapper_s17.json -# -# written to avoid initial placement since that is not portable -# (although turning it on with options and enabling it by uncommenting first line of src/mapper.h would test it) -# for option assumptions, see setUp below -# see for more details, comment lines with each individual test below - -from openql import openql as ql -import os -import unittest -from utils import file_compare - - -curdir = os.path.dirname(os.path.realpath(__file__)) -output_dir = os.path.join(curdir, 'test_output') - -class Test_mapper(unittest.TestCase): - - def setUp(self): - ql.initialize() - # uses defaults of options in mapper branch except for output_dir and for maptiebreak - ql.set_option('output_dir', output_dir) # this uses output_dir set above - ql.set_option('maptiebreak', 'first') # this makes behavior deterministic to cmp with golden - # and deviates from default - - ql.set_option('log_level', 'LOG_NOTHING') - ql.set_option('optimize', 'no') - ql.set_option('use_default_gates', 'no') - ql.set_option('decompose_toffoli', 'no') - ql.set_option('scheduler', 'ALAP') - ql.set_option('scheduler_uniform', 'no') - ql.set_option('scheduler_commute', 'yes') - ql.set_option('prescheduler', 'yes') - ql.set_option('cz_mode', 'manual') - ql.set_option('print_dot_graphs', 'no') - - ql.set_option('clifford_premapper', 'yes') - ql.set_option('clifford_postmapper', 'yes') - ql.set_option('mapper', 'minextend') - ql.set_option('mapusemoves', 'yes') - ql.set_option('mapreverseswap', 'yes') - ql.set_option('mappathselect', 'all') - ql.set_option('maplookahead', 'noroutingfirst') - ql.set_option('maprecNN2q', 'no') - ql.set_option('mapselectmaxlevel', '0') - ql.set_option('mapselectmaxwidth', 'min') - - ql.set_option('write_qasm_files', 'no') - ql.set_option('write_report_files', 'no') - - - def test_mapper_maxcut(self): - # rigetti test copied from Venturelli's paper - v = 'maxcut' - config = os.path.join(curdir, "test_mapper_rig.json") - num_qubits = 8 - - # create and set platform - prog_name = "test_mapper_" + v - kernel_name = "kernel_" + v - starmon = ql.Platform("starmon", config) - prog = ql.Program(prog_name, starmon, num_qubits, 0) - k = ql.Kernel(kernel_name, starmon, num_qubits, 0) - - k.gate("x", [0]) - k.gate("x", [1]) - k.gate("x", [2]) - k.gate("x", [3]) - k.gate("x", [4]) - k.gate("x", [5]) - k.gate("x", [6]) - k.gate("x", [7]) - - k.gate("cz", [1,4]) - k.gate("cz", [1,3]) - k.gate("cz", [3,4]) - k.gate("cz", [3,7]) - k.gate("cz", [4,7]) - k.gate("cz", [6,7]) - k.gate("cz", [5,6]) - k.gate("cz", [1,5]) - - k.gate("x", [0]) - k.gate("x", [1]) - k.gate("x", [2]) - k.gate("x", [3]) - k.gate("x", [4]) - k.gate("x", [5]) - k.gate("x", [6]) - k.gate("x", [7]) - - prog.add_kernel(k) - prog.compile() - - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue(file_compare(qasm_fn, gold_fn)) - - - def test_mapper_oneNN(self): - # just check whether mapper works for trivial case - # parameters - v = 'oneNN' - config = "cc_light.s7" - num_qubits = 7 - - # create and set platform - prog_name = "test_mapper_" + v - kernel_name = "kernel_" + v - starmon = ql.Platform("starmon", config) - prog = ql.Program(prog_name, starmon, num_qubits, 0) - k = ql.Kernel(kernel_name, starmon, num_qubits, 0) - - k.gate("x", [0]) - k.gate("y", [1]) - k.gate("cnot", [2,5]) - - prog.add_kernel(k) - prog.compile() - - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue(file_compare(qasm_fn, gold_fn)) - - - def test_mapper_allNN(self): - # a list of all cnots that are NN in trivial/natural mapping (as in test_mapper_s7.json) - # (s7 is 3 rows: 2 data qubits (0 and 1), 3 ancillas (2 to 4), and 2 data qubits (5 and 6)) - # so no swaps are inserted and map is not changed - # also tests commutation of cnots in mapper and postscheduler - # parameters - v = 'allNN' - config = "cc_light.s7" - num_qubits = 7 - - # create and set platform - prog_name = "test_mapper_" + v - kernel_name = "kernel_" + v - starmon = ql.Platform("starmon", config) - prog = ql.Program(prog_name, starmon, num_qubits, 0) - k = ql.Kernel(kernel_name, starmon, num_qubits, 0) - - for j in range(7): - k.gate("x", [j]) - k.gate("cnot", [0,2]) - k.gate("cnot", [0,3]) - k.gate("cnot", [1,3]) - k.gate("cnot", [1,4]) - k.gate("cnot", [2,0]) - k.gate("cnot", [2,5]) - k.gate("cnot", [3,0]) - k.gate("cnot", [3,1]) - k.gate("cnot", [3,5]) - k.gate("cnot", [3,6]) - k.gate("cnot", [4,1]) - k.gate("cnot", [4,6]) - k.gate("cnot", [5,2]) - k.gate("cnot", [5,3]) - k.gate("cnot", [6,3]) - k.gate("cnot", [6,4]) - for j in range(7): - k.gate("x", [j]) - - prog.add_kernel(k) - prog.compile() - - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue(file_compare(qasm_fn, gold_fn)) - - def test_mapper_oneD2(self): - # one cnot with operands that are at distance 2 in s7 - # initial placement should find this - # otherwise ... - # there are 2 alternative paths - # in each path there are 2 alternative places to put the cnot - # this introduces 1 swap/move and so uses an ancilla - # parameters - v = 'oneD2' - config = "cc_light.s7" - num_qubits = 7 - - # create and set platform - prog_name = "test_mapper_" + v - kernel_name = "kernel_" + v - starmon = ql.Platform("starmon", config) - prog = ql.Program(prog_name, starmon, num_qubits, 0) - k = ql.Kernel(kernel_name, starmon, num_qubits, 0) - - k.gate("x", [2]) - k.gate("y", [3]) - k.gate("cnot", [2,3]) - k.gate("x", [2]) - k.gate("y", [3]) - - prog.add_kernel(k) - prog.compile() - - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue(file_compare(qasm_fn, gold_fn)) - - - def test_mapper_oneD4(self): - # one cnot with operands that are at distance 4 in s7 - # initial placement should find this - # otherwise ... - # there are 4 alternative paths - # in each path there are 4 alternative places to put the cnot - # this introduces 3 swaps/moves - # parameters - v = 'oneD4' - config = "cc_light.s7" - num_qubits = 7 - - # create and set platform - prog_name = "test_mapper_" + v - kernel_name = "kernel_" + v - starmon = ql.Platform("starmon", config) - prog = ql.Program(prog_name, starmon, num_qubits, 0) - k = ql.Kernel(kernel_name, starmon, num_qubits, 0) - - k.gate("x", [2]) - k.gate("y", [4]) - k.gate("cnot", [2,4]) - k.gate("x", [2]) - k.gate("y", [4]) - - prog.add_kernel(k) - prog.compile() - - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue(file_compare(qasm_fn, gold_fn)) - - - def test_mapper_allD(self): - # all possible cnots in s7, in lexicographic order - # there is no initial mapping that maps this right so initial placement cannot find it - # so the heuristics must act and insert swaps/moves - # parameters - v = 'allD' - config = "cc_light.s7" - num_qubits = 7 - - # create and set platform - prog_name = "test_mapper_" + v - kernel_name = "kernel_" + v - starmon = ql.Platform("starmon", config) - prog = ql.Program(prog_name, starmon, num_qubits, 0) - k = ql.Kernel(kernel_name, starmon, num_qubits, 0) - - for j in range(7): - k.gate("x", [j]) - - for i in range(7): - for j in range(7): - if (i != j): - k.gate("cnot", [i,j]) - - for j in range(7): - k.gate("x", [j]) - - prog.add_kernel(k) - prog.compile() - - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue(file_compare(qasm_fn, gold_fn)) - - - def test_mapper_allDopt(self): - # all possible cnots in s7, avoiding collisions: - # - the pair of possible CNOTs in both directions hopefully in parallel - # - these pairs ordered from low distance to high distance to avoid disturbance by swaps - # - and then as much as possible in opposite sides of the circuit to improve ILP - # idea is to get shortest latency circuit with all possible cnots - # there is no initial mapping that maps this right so initial placement cannot find it - # so the heuristics must act and insert swaps/moves - # parameters - v = 'allDopt' - config = "cc_light.s7" - num_qubits = 7 - - # create and set platform - prog_name = "test_mapper_" + v - kernel_name = "kernel_" + v - starmon = ql.Platform("starmon", config) - prog = ql.Program(prog_name, starmon, num_qubits, 0) - k = ql.Kernel(kernel_name, starmon, num_qubits, 0) - - for j in range(7): - k.gate("x", [j]) - k.gate("cnot", [0,3]); - k.gate("cnot", [3,0]); - k.gate("cnot", [6,4]); - k.gate("cnot", [4,6]); - k.gate("cnot", [3,1]); - k.gate("cnot", [1,3]); - k.gate("cnot", [5,2]); - k.gate("cnot", [2,5]); - k.gate("cnot", [1,4]); - k.gate("cnot", [4,1]); - k.gate("cnot", [3,5]); - k.gate("cnot", [5,3]); - k.gate("cnot", [6,3]); - k.gate("cnot", [3,6]); - k.gate("cnot", [2,0]); - k.gate("cnot", [0,2]); - k.gate("cnot", [0,1]); - k.gate("cnot", [1,0]); - k.gate("cnot", [3,4]); - k.gate("cnot", [4,3]); - k.gate("cnot", [1,6]); - k.gate("cnot", [6,1]); - k.gate("cnot", [6,5]); - k.gate("cnot", [5,6]); - k.gate("cnot", [3,2]); - k.gate("cnot", [2,3]); - k.gate("cnot", [5,0]); - k.gate("cnot", [0,5]); - k.gate("cnot", [0,6]); - k.gate("cnot", [6,0]); - k.gate("cnot", [1,5]); - k.gate("cnot", [5,1]); - k.gate("cnot", [0,4]); - k.gate("cnot", [4,0]); - k.gate("cnot", [6,2]); - k.gate("cnot", [2,6]); - k.gate("cnot", [2,1]); - k.gate("cnot", [1,2]); - k.gate("cnot", [5,4]); - k.gate("cnot", [4,5]); - k.gate("cnot", [2,4]); - k.gate("cnot", [4,2]); - for j in range(7): - k.gate("x", [j]) - - prog.add_kernel(k) - prog.compile() - - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue(file_compare(qasm_fn, gold_fn)) - - - def test_mapper_allIP(self): - # longest string of cnots with operands that could be at distance 1 in s7 - # matches intel NISQ application - # initial placement should find this - # and then no swaps are inserted - # otherwise ... - # the heuristics must act and insert swaps/moves - # parameters - v = 'allIP' - config = "cc_light.s7" - num_qubits = 7 - - # create and set platform - prog_name = "test_mapper_" + v - kernel_name = "kernel_" + v - starmon = ql.Platform("starmon", config) - prog = ql.Program(prog_name, starmon, num_qubits, 0) - k = ql.Kernel(kernel_name, starmon, num_qubits, 0) - - for j in range(7): - k.gate("x", [j]) - k.gate("cnot", [0,1]); - k.gate("cnot", [1,2]); - k.gate("cnot", [2,3]); - k.gate("cnot", [3,4]); - k.gate("cnot", [4,5]); - k.gate("cnot", [5,6]); - for j in range(7): - k.gate("x", [j]) - - prog.add_kernel(k) - prog.compile() - - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue(file_compare(qasm_fn, gold_fn)) - - - - def test_mapper_lingling5(self): - # parameters - # 'realistic' circuit - v = 'lingling5' - config = "cc_light.s17" - num_qubits = 17 - - # create and set platform - prog_name = "test_mapper_" + v - kernel_name = "kernel_" + v - starmon = ql.Platform("starmon", config) - prog = ql.Program(prog_name, starmon, num_qubits, 0) - k = ql.Kernel(kernel_name, starmon, num_qubits, 0) - - k.gate("prepz", [5]); - k.gate("prepz", [6]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("x", [6]); - k.gate("ym90", [6]); - k.gate("ym90", [0]); - k.gate("cz", [5,0]); - k.gate("ry90", [0]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [6,5]); - k.gate("ry90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [1,5]); - k.gate("ry90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [2,5]); - k.gate("ry90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [6,5]); - k.gate("ry90", [5]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("ym90", [3]); - k.gate("cz", [5,3]); - k.gate("ry90", [3]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("measure", [5]); - k.gate("measure", [6]); - - k.gate("prepz", [5]); - k.gate("prepz", [6]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("x", [6]); - k.gate("ym90", [6]); - k.gate("ym90", [1]); - k.gate("cz", [5,1]); - k.gate("ry90", [1]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [6,5]); - k.gate("ry90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [2,5]); - k.gate("ry90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [3,5]); - k.gate("ry90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [6,5]); - k.gate("ry90", [5]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("ym90", [4]); - k.gate("cz", [5,4]); - k.gate("ry90", [4]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("measure", [5]); - k.gate("measure", [6]); - - k.gate("prepz", [5]); - k.gate("prepz", [6]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("x", [6]); - k.gate("ym90", [6]); - k.gate("ym90", [2]); - k.gate("cz", [5,2]); - k.gate("ry90", [2]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [6,5]); - k.gate("ry90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [3,5]); - k.gate("ry90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [4,5]); - k.gate("ry90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [6,5]); - k.gate("ry90", [5]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("ym90", [0]); - k.gate("cz", [5,0]); - k.gate("ry90", [0]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("measure", [5]); - k.gate("measure", [6]); - - k.gate("prepz", [5]); - k.gate("prepz", [6]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("x", [6]); - k.gate("ym90", [6]); - k.gate("ym90", [3]); - k.gate("cz", [5,3]); - k.gate("ry90", [3]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [6,5]); - k.gate("ry90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [4,5]); - k.gate("ry90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [0,5]); - k.gate("ry90", [5]); - k.gate("ym90", [5]); - k.gate("cz", [6,5]); - k.gate("ry90", [5]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("ym90", [1]); - k.gate("cz", [5,1]); - k.gate("ry90", [1]); - k.gate("x", [5]); - k.gate("ym90", [5]); - k.gate("measure", [5]); - k.gate("measure", [6]); - - prog.add_kernel(k) - prog.compile() - - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue(file_compare(qasm_fn, gold_fn)) - - - - def test_mapper_lingling7(self): - # parameters - v = 'lingling7' - config = "cc_light.s17" - num_qubits = 17 - - # create and set platform - prog_name = "test_mapper_" + v - kernel_name = "kernel_" + v - starmon = ql.Platform("starmon", config) - prog = ql.Program(prog_name, starmon, num_qubits, 0) - k = ql.Kernel(kernel_name, starmon, num_qubits, 0) - - k.gate("prepz", [7]); - k.gate("prepz", [8]); - k.gate("x", [7]); - k.gate("ym90", [7]); - k.gate("ym90", [4]); - k.gate("cz", [7,4]); - k.gate("ry90", [4]); - k.gate("ym90", [8]); - k.gate("cz", [0,8]); - k.gate("ry90", [8]); - k.gate("ym90", [8]); - k.gate("cz", [7,8]); - k.gate("ry90", [8]); - k.gate("ym90", [6]); - k.gate("cz", [7,6]); - k.gate("ry90", [6]); - k.gate("ym90", [8]); - k.gate("cz", [2,8]); - k.gate("ry90", [8]); - k.gate("ym90", [3]); - k.gate("cz", [7,3]); - k.gate("ry90", [3]); - k.gate("ym90", [8]); - k.gate("cz", [4,8]); - k.gate("ry90", [8]); - k.gate("ym90", [8]); - k.gate("cz", [7,8]); - k.gate("ry90", [8]); - k.gate("ym90", [5]); - k.gate("cz", [7,5]); - k.gate("ry90", [5]); - k.gate("ym90", [8]); - k.gate("cz", [6,8]); - k.gate("ry90", [8]); - k.gate("x", [7]); - k.gate("ym90", [7]); - k.gate("measure", [7]); - k.gate("measure", [8]); - k.gate("prepz", [7]); - k.gate("prepz", [8]); - k.gate("x", [7]); - k.gate("ym90", [7]); - k.gate("ym90", [5]); - k.gate("cz", [7,5]); - k.gate("ry90", [5]); - k.gate("ym90", [8]); - k.gate("cz", [1,8]); - k.gate("ry90", [8]); - k.gate("ym90", [8]); - k.gate("cz", [7,8]); - k.gate("ry90", [8]); - k.gate("ym90", [6]); - k.gate("cz", [7,6]); - k.gate("ry90", [6]); - k.gate("ym90", [8]); - k.gate("cz", [2,8]); - k.gate("ry90", [8]); - k.gate("ym90", [3]); - k.gate("cz", [7,3]); - k.gate("ry90", [3]); - k.gate("ym90", [8]); - k.gate("cz", [5,8]); - k.gate("ry90", [8]); - k.gate("ym90", [8]); - k.gate("cz", [7,8]); - k.gate("ry90", [8]); - k.gate("ym90", [4]); - k.gate("cz", [7,4]); - k.gate("ry90", [4]); - k.gate("ym90", [8]); - k.gate("cz", [6,8]); - k.gate("ry90", [8]); - k.gate("x", [7]); - k.gate("ym90", [7]); - k.gate("measure", [7]); - k.gate("measure", [8]); - - k.gate("prepz", [7]); - k.gate("prepz", [8]); - k.gate("x", [7]); - k.gate("ym90", [7]); - k.gate("ym90", [1]); - k.gate("cz", [7,1]); - k.gate("ry90", [1]); - k.gate("ym90", [8]); - k.gate("cz", [2,8]); - k.gate("ry90", [8]); - k.gate("ym90", [8]); - k.gate("cz", [7,8]); - k.gate("ry90", [8]); - k.gate("ym90", [5]); - k.gate("cz", [7,5]); - k.gate("ry90", [5]); - k.gate("ym90", [8]); - k.gate("cz", [6,8]); - k.gate("ry90", [8]); - k.gate("ym90", [2]); - k.gate("cz", [7,2]); - k.gate("ry90", [2]); - k.gate("ym90", [8]); - k.gate("cz", [0,8]); - k.gate("ry90", [8]); - k.gate("ym90", [8]); - k.gate("cz", [7,8]); - k.gate("ry90", [8]); - k.gate("ym90", [6]); - k.gate("cz", [7,6]); - k.gate("ry90", [6]); - k.gate("ym90", [8]); - k.gate("cz", [4,8]); - k.gate("ry90", [8]); - k.gate("x", [7]); - k.gate("ym90", [7]); - k.gate("measure", [7]); - k.gate("measure", [8]); - - prog.add_kernel(k) - prog.compile() - - gold_fn = curdir + '/golden/' + prog_name +'_last.qasm' - qasm_fn = os.path.join(output_dir, prog_name+'_last.qasm') - self.assertTrue(file_compare(qasm_fn, gold_fn)) - - - -if __name__ == '__main__': - # ql.set_option('log_level', 'LOG_DEBUG') - unittest.main() diff --git a/tests/test_qi_example.cc_backend.map b/tests/test_qi_example.cc_backend.map deleted file mode 100644 index beef2f023..000000000 --- a/tests/test_qi_example.cc_backend.map +++ /dev/null @@ -1,82 +0,0 @@ -{ - "codewords": { - "data": { - "flux_0": [ - [ - 3, - "{type:cz,which:SW}" - ], - null, - [ - 1, - "{type:idle_z,which:NE}" - ], - [ - 5, - "{type:park}" - ] - ], - "mw_2": [ - [ - 2, - "{phi:90,theta:180,type:ge}" - ], - null, - [ - 4, - "{phi:90,theta:90,type:ge}" - ] - ], - "ro_0": [ - [ - 0, - "[dummy]" - ], - [ - 0, - "[dummy]" - ] - ], - "ro_1": [ - [ - 0, - "[dummy]" - ], - [ - 0, - "[dummy]" - ], - [ - 0, - "[dummy]" - ] - ] - }, - "version": 1 - }, - "measurements": { - "data": [ - { - "ro_0": [ - 1, - 4 - ], - "ro_1": [ - 0, - 2, - 3 - ] - } - ], - "nr-shots": { - "ro_0": 1, - "ro_1": 1 - }, - "version": 2 - }, - "openql": { - "backend": "cc", - "backend-version": "0.4.0", - "version": "0.11.1" - } -} diff --git a/tests/test_qi_example.cc_backend.vcd b/tests/test_qi_example.cc_backend.vcd deleted file mode 100644 index 913254d7a..000000000 --- a/tests/test_qi_example.cc_backend.vcd +++ /dev/null @@ -1,221 +0,0 @@ -$date today $end -$timescale 1 ns $end -$scope module kernel $end -$var string 20 0 kernel $end -$upscope $end -$scope module qubits $end -$var string 20 1 q0 $end -$var string 20 2 q1 $end -$var string 20 3 q2 $end -$var string 20 4 q3 $end -$var string 20 5 q4 $end -$var string 20 6 q5 $end -$var string 20 7 q6 $end -$var string 20 8 q7 $end -$var string 20 9 q8 $end -$var string 20 10 q9 $end -$var string 20 11 q10 $end -$var string 20 12 q11 $end -$var string 20 13 q12 $end -$var string 20 14 q13 $end -$var string 20 15 q14 $end -$var string 20 16 q15 $end -$var string 20 17 q16 $end -$upscope $end -$scope module sd.signal $end -$var string 20 18 ro_0-0 $end -$var string 20 19 ro_0-1 $end -$var string 20 20 ro_0-2 $end -$var string 20 21 ro_0-3 $end -$var string 20 22 ro_0-4 $end -$var string 20 23 ro_0-5 $end -$var string 20 24 ro_0-6 $end -$var string 20 25 ro_0-7 $end -$var string 20 26 ro_0-8 $end -$var string 20 27 ro_1-0 $end -$var string 20 28 ro_1-1 $end -$var string 20 29 ro_1-2 $end -$var string 20 30 ro_1-3 $end -$var string 20 31 ro_1-4 $end -$var string 20 32 ro_1-5 $end -$var string 20 33 ro_1-6 $end -$var string 20 34 ro_1-7 $end -$var string 20 35 ro_1-8 $end -$var string 20 36 ro_2-0 $end -$var string 20 37 ro_2-1 $end -$var string 20 38 ro_2-2 $end -$var string 20 39 ro_2-3 $end -$var string 20 40 ro_2-4 $end -$var string 20 41 ro_2-5 $end -$var string 20 42 ro_2-6 $end -$var string 20 43 ro_2-7 $end -$var string 20 44 ro_2-8 $end -$var string 20 45 mw_0-0 $end -$var string 20 46 mw_0-1 $end -$var string 20 47 mw_0-2 $end -$var string 20 48 mw_0-3 $end -$var string 20 49 mw_1-0 $end -$var string 20 50 mw_1-1 $end -$var string 20 51 mw_1-2 $end -$var string 20 52 mw_1-3 $end -$var string 20 53 mw_2-0 $end -$var string 20 54 mw_2-1 $end -$var string 20 55 mw_2-2 $end -$var string 20 56 mw_2-3 $end -$var string 20 57 mw_3-0 $end -$var string 20 58 mw_3-1 $end -$var string 20 59 mw_3-2 $end -$var string 20 60 mw_3-3 $end -$var string 20 61 mw_4-0 $end -$var string 20 62 mw_4-1 $end -$var string 20 63 mw_4-2 $end -$var string 20 64 mw_4-3 $end -$var string 20 65 flux_0-0 $end -$var string 20 66 flux_0-1 $end -$var string 20 67 flux_0-2 $end -$var string 20 68 flux_0-3 $end -$var string 20 69 flux_0-4 $end -$var string 20 70 flux_0-5 $end -$var string 20 71 flux_0-6 $end -$var string 20 72 flux_0-7 $end -$var string 20 73 flux_1-0 $end -$var string 20 74 flux_1-1 $end -$var string 20 75 flux_1-2 $end -$var string 20 76 flux_1-3 $end -$var string 20 77 flux_1-4 $end -$var string 20 78 flux_1-5 $end -$var string 20 79 flux_1-6 $end -$var string 20 80 flux_1-7 $end -$var string 20 81 flux_2-0 $end -$var string 20 82 flux_2-1 $end -$var string 20 83 flux_2-2 $end -$var string 20 84 flux_2-3 $end -$var string 20 85 flux_2-4 $end -$var string 20 86 flux_2-5 $end -$var string 20 87 flux_2-6 $end -$var string 20 88 flux_2-7 $end -$upscope $end -$scope module codewords $end -$var string 20 89 ro_0 $end -$var string 20 90 ro_1 $end -$var string 20 91 ro_2 $end -$var string 20 92 mw_0 $end -$var string 20 93 mw_1 $end -$var string 20 94 mw_2 $end -$var string 20 95 mw_3 $end -$var string 20 96 mw_4 $end -$var string 20 97 flux_0 $end -$var string 20 98 flux_1 $end -$var string 20 99 flux_2 $end -$upscope $end -$enddefinitions $end -#0 -skernel_0 0 -sprepz 1 -sprepz 2 -sprepz 3 -sprepz 4 -sprepz 5 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s 97 -s 98 -s 99 -#200000 -sry180 1 -s 2 -sry180 3 -s 4 -s 5 -s_cz_sw_ne_park 9 -s_cz_sw_ne_park 11 -s_cz_sw_ne_park 12 -s2147516418={phi:90,theta:180,type:ge} 53 -s2147516419={type:cz,which:SW} 65 -s2147516480={type:idle_z,which:NE} 67 -s2147518976={type:park} 68 -s 89 -s 90 -s 91 -s 92 -s 93 -s0x80008002 94 -s 95 -s 96 -s0x80008a43 97 -s 98 -s 99 -#200020 -s 1 -sry90 3 -s 53 -s2147778560={phi:90,theta:90,type:ge} 55 -s 89 -s 90 -s 91 -s 92 -s 93 -s0x80048000 94 -s 95 -s 96 -s 97 -s 98 -s 99 -#200040 -smeasure 1 -smeasure 2 -smeasure 3 -smeasure 4 -smeasure 5 -s 9 -s 11 -s 12 -s196608=[dummy] 18 -s327680=[dummy] 19 -s196608=[dummy] 27 -s327680=[dummy] 28 -s589824=[dummy] 29 -s 55 -s 65 -s 67 -s 68 -s0x00070000 89 -s0x000f0000 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s 97 -s 98 -s 99 -#200840 -s 0 -s 1 -s 2 -s 3 -s 4 -s 5 -s 18 -s 19 -s 27 -s 28 -s 29 -s 89 -s 90 -s 91 -s 92 -s 93 -s 94 -s 95 -s 96 -s 97 -s 98 -s 99 diff --git a/tests/test_qi_example.cc_backend.vq1asm b/tests/test_qi_example.cc_backend.vq1asm deleted file mode 100644 index 035488620..000000000 --- a/tests/test_qi_example.cc_backend.vq1asm +++ /dev/null @@ -1,93 +0,0 @@ -# Program: 'test_qi_example' -# CC_BACKEND_VERSION 0.4.0 -# OPENQL_VERSION 0.11.1 -# Note: generated by OpenQL Central Controller backend -# -.CODE -# synchronous start and latency compensation - seq_bar # synchronization, delay set externally through SET_SEQ_BAR_CNT - seq_out 0x00000000,1 # allows monitoring actual start time using trace unit -# start of main loop that runs indefinitely -__mainLoop: # - seq_state 0 # clear Programmable Logic state - -### Block: 'kernel_0' -## Bundle 0: start_cycle=0: - # gate 'prepz q[0]' - # gate 'prepz q[1]' - # gate 'prepz q[2]' - # gate 'prepz q[3]' - # gate 'prepz q[4]' - -## Bundle 1: start_cycle=10000: - # gate 'ry180 q[0], q[2]' - # slot=6, instrument='mw_2', group=0': signalValue='{phi:90,theta:180,type:ge}' - # gate '_cz_sw_ne_park q[8], q[10], q[11]' - # slot=3, instrument='flux_0', group=0': signalValue='{type:cz,which:SW}' - # slot=3, instrument='flux_0', group=2': signalValue='{type:idle_z,which:NE}' - # slot=3, instrument='flux_0', group=3': signalValue='{type:park}' - # slot=6, instrument='mw_2', group=0: codeword=2 (static override): groupDigOut=0x00000002 - # slot=3, instrument='flux_0', group=0: codeword=3 (static override): groupDigOut=0x00000003 - # slot=3, instrument='flux_0', group=2: codeword=1 (static override): groupDigOut=0x00000040 - # slot=3, instrument='flux_0', group=3: codeword=5 (static override): groupDigOut=0x00000a00 - # slot=6, instrument='mw_2': lastEndCycle=0, startCycle=10000, instrMaxDurationInCycles=1 -[6] seq_wait 10000 # cycle 0-10000: padding on 'mw_2' -[6] seq_out 0x80008002,1 # cycle 10000-10001: code word/mask on 'mw_2' - # slot=3, instrument='flux_0': lastEndCycle=0, startCycle=10000, instrMaxDurationInCycles=2 -[3] seq_wait 10000 # cycle 0-10000: padding on 'flux_0' -[3] seq_out 0x80008a43,2 # cycle 10000-10002: code word/mask on 'flux_0' - -## Bundle 2: start_cycle=10001: - # gate 'ry90 q[2]' - # slot=6, instrument='mw_2', group=2': signalValue='{phi:90,theta:90,type:ge}' - # slot=6, instrument='mw_2', group=2: codeword=4 (static override): groupDigOut=0x00040000 - # slot=6, instrument='mw_2': lastEndCycle=10001, startCycle=10001, instrMaxDurationInCycles=1 -[6] seq_out 0x80048000,1 # cycle 10001-10002: code word/mask on 'mw_2' - -## Bundle 3: start_cycle=10002: - # gate 'measure q[0], (bit)q[0]' - # slot=4, instrument='ro_1', group=0': signalValue='[dummy]' - # gate 'measure q[1], (bit)q[1]' - # slot=2, instrument='ro_0', group=0': signalValue='[dummy]' - # gate 'measure q[2], (bit)q[2]' - # slot=4, instrument='ro_1', group=1': signalValue='[dummy]' - # gate 'measure q[3], (bit)q[3]' - # slot=4, instrument='ro_1', group=2': signalValue='[dummy]' - # gate 'measure q[4], (bit)q[4]' - # slot=2, instrument='ro_0', group=1': signalValue='[dummy]' - - - - - - # slot=2, instrument='ro_0': lastEndCycle=0, startCycle=10002, instrMaxDurationInCycles=40 -[2] seq_wait 10002 # cycle 0-10002: padding on 'ro_0' -[2] seq_out 0x00070000,40 # cycle 10002-10042: code word/mask on 'ro_0' - # slot=4, instrument='ro_1': lastEndCycle=0, startCycle=10002, instrMaxDurationInCycles=40 -[4] seq_wait 10002 # cycle 0-10002: padding on 'ro_1' -[4] seq_out 0x000f0000,40 # cycle 10002-10042: code word/mask on 'ro_1' - -## Bundle 4: start_cycle=10042: - # last bundle of kernel, will pad outputs to match durations -[5] seq_wait 10042 # cycle 0-10042: padding on 'ro_2' -[0] seq_wait 10042 # cycle 0-10042: padding on 'mw_0' -[1] seq_wait 10042 # cycle 0-10042: padding on 'mw_1' -[6] seq_wait 40 # cycle 10002-10042: padding on 'mw_2' -[7] seq_wait 10042 # cycle 0-10042: padding on 'mw_3' -[8] seq_wait 10042 # cycle 0-10042: padding on 'mw_4' -[3] seq_wait 40 # cycle 10002-10042: padding on 'flux_0' -[9] seq_wait 10042 # cycle 0-10042: padding on 'flux_1' -[10] seq_wait 10042 # cycle 0-10042: padding on 'flux_2' - -### Block end: 'kernel_0' -# finish program - seq_wait 1 - jmp @__mainLoop # loop indefinitely -.END -.DATAPATH -## Bundle 0: start_cycle=0: -## Bundle 1: start_cycle=10000: -## Bundle 2: start_cycle=10001: -## Bundle 3: start_cycle=10002: -## Bundle 4: start_cycle=10042: -.END diff --git a/tests/test_qubits.py b/tests/test_qubits.py deleted file mode 100644 index 2f9f26403..000000000 --- a/tests/test_qubits.py +++ /dev/null @@ -1,90 +0,0 @@ -import os -from utils import file_compare -import unittest -from openql import openql as ql - -curdir = os.path.dirname(os.path.realpath(__file__)) -config_fn = os.path.join(curdir, 'test_config_default.json') -platf = ql.Platform("starmon", config_fn) - -output_dir = os.path.join(curdir, 'test_output') - - -class Test_qubits(unittest.TestCase): - - @classmethod - def setUp(self): - ql.initialize() - ql.set_option('output_dir', output_dir) - ql.set_option('optimize', 'no') - ql.set_option('scheduler', 'ALAP') - ql.set_option('log_level', 'LOG_WARNING') - # ql.set_option('write_qasm_files', 'yes') - - def test_1_qubit(self): - nqubits = 1 - - k = ql.Kernel("aKernel", platf, nqubits) - - # populate kernel - k.prepz(0) - k.x(0) - k.y(0) - k.rx90(0) - k.measure(0) - - p = ql.Program("1_qubit_program", platf, nqubits) - - p.add_kernel(k) # add kernel to program - p.compile() - - gold_fn = curdir + '/golden/test_1_qubit.qasm' - qasm_fn = os.path.join(output_dir, p.name+'.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_2_qubit(self): - nqubits = 3 - k = ql.Kernel("aKernel", platf, nqubits) - - # populate kernel - k.prepz(0) - k.prepz(1) - k.prepz(2) - k.cz(0, 1) - k.clifford(1, 2) - k.measure(2) - - p = ql.Program("2_qubit_program", platf, nqubits) - - p.add_kernel(k) # add kernel to program - p.compile() - - gold_fn = curdir + '/golden/test_2_qubit.qasm' - qasm_fn = os.path.join(output_dir, p.name+'.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - - def test_3_qubit(self): - nqubits = 3 - - k = ql.Kernel("aKernel", platf, nqubits) - - # populate kernel - k.prepz(0) - k.prepz(1) - k.prepz(2) - k.toffoli(0, 1, 2) - k.measure(2) - - p = ql.Program("3_qubit_program", platf, nqubits) - - p.add_kernel(k) # add kernel to program - - ql.set_option('decompose_toffoli', 'no') - p.compile() - - gold_fn = curdir + '/golden/test_3_qubit.qasm' - qasm_fn = os.path.join(output_dir, p.name+'.qasm') - self.assertTrue( file_compare(qasm_fn, gold_fn) ) - -if __name__ == '__main__': - unittest.main() diff --git a/tests/test_std_experiments_CCL.py b/tests/test_std_experiments_CCL.py deleted file mode 100644 index 138ba2d04..000000000 --- a/tests/test_std_experiments_CCL.py +++ /dev/null @@ -1,127 +0,0 @@ -import os -import numpy as np -import unittest -from openql import Kernel, Program -from openql import openql as ql - -curdir = os.path.dirname(os.path.realpath(__file__)) -platf = ql.Platform('seven_qubits_chip', 'cc_light') - -output_dir = os.path.join(curdir, 'test_output') - -ql.set_option('output_dir', output_dir) -ql.set_option('optimize', 'no') -ql.set_option('scheduler', 'ALAP') -ql.set_option('log_level', 'LOG_WARNING') - -@unittest.skip -class Test_single_qubit_seqs_CCL(unittest.TestCase): - - @classmethod - def setUp(self): - ql.initialize() - - def test_bug(self): - p = Program("bug", platf, 1) - - k = Kernel("bugKernel", platform=platf, qubit_count=1) - k.gate('rx180', [0]) - k.gate('measure', [0]) - - p.add_kernel(k) - p.compile() - - # Test that the generated code is valid - QISA_fn = os.path.join(output_dir, p.name+'.qisa') - assemble(QISA_fn) - - def test_allxy(self): - p = Program("AllXY", platf, 1) - # uppercase lowercase problems - - allXY = [['i', 'i'], ['rx180', 'rx180'], ['ry180', 'ry180'], - ['rx180', 'ry180'], ['ry180', 'rx180'], - ['rx90', 'i'], ['ry90', 'i'], ['rx90', 'ry90'], - ['ry90', 'rx90'], ['rx90', 'ry180'], ['ry90', 'rx180'], - ['rx180', 'ry90'], ['ry180', 'rx90'], ['rx90', 'rx180'], - ['rx180', 'rx90'], ['ry90', 'ry180'], ['ry180', 'ry90'], - ['rx180', 'i'], ['ry180', 'i'], ['rx90', 'rx90'], - ['ry90', 'ry90']] - - for i, xy in enumerate(allXY): - k = Kernel("allXY"+str(i), platf, 1) - k.prepz(0) - k.gate(xy[0], [0]) - k.gate(xy[1], [0]) - k.measure(0) - p.add_kernel(k) - - p.compile() - - # Test that the generated code is valid - GOLD_fn = os.path.join(curdir, 'golden', p.name + '.qisa') - QISA_fn = os.path.join(output_dir, p.name+'.qisa') - self.assertTrue(file_compare(QISA_fn, GOLD_fn)) - - def test_qasm_seq_echo(self): - nqubits = 1 - p = Program("Echo", platf, nqubits) - times = np.linspace(0, 20e3, 61) # in ns - # To prevent superslow workaround - times = np.linspace(0, 60, 61) # in ns - # this should be implicit - for tau in times: - # this is an invalid kernel name (contains '.') - # and will produce and invalid qasm - n = 'echo_tau_{}ns'.format(tau) - n = n.replace(".","_") - k = Kernel(n, platf, nqubits) - k.prepz(0) - k.rx90(0) - # This is a dirty hack that repeats the I gate - for j in range(int(tau/2)): - k.gate('i', [0]) - k.rx180(0) - for j in range(int(tau/2)): - k.gate('i', [0]) - k.rx90(0) - k.measure(0) - p.add_kernel(k) - - p.compile() - - # Test that the generated code is valid - GOLD_fn = os.path.join(curdir, 'golden', p.name + '.qisa') - QISA_fn = os.path.join(output_dir, p.name+'.qisa') - self.assertTrue(file_compare(QISA_fn, GOLD_fn)) - - def test_qasm_seq_butterfly(self): - nqubits = 1 - p = Program("Butterfly", platf, nqubits) - - k = Kernel('0', platf, nqubits) - k.prepz(0) - k.measure(0) - k.measure(0) - # what does the measurement tell us it is? - k.measure(0) - # what is the post measuremnet state - p.add_kernel(k) - - k = Kernel('1', platf, nqubits) - k.prepz(0) - k.measure(0) - k.x(0) - k.measure(0) - k.measure(0) - p.add_kernel(k) - p.compile() - - # Test that the generated code is valid - GOLD_fn = os.path.join(curdir, 'golden', p.name + '.qisa') - QISA_fn = os.path.join(output_dir, p.name+'.qisa') - self.assertTrue(file_compare(QISA_fn, GOLD_fn)) - -if __name__ == '__main__': - unittest.main() - diff --git a/tests/test_unitary.py b/tests/test_unitary.py deleted file mode 100644 index a81a6e499..000000000 --- a/tests/test_unitary.py +++ /dev/null @@ -1,1427 +0,0 @@ -import os -import unittest -from openql import openql as ql -from utils import file_compare -import re -import numpy as np -from qxelarator import qxelarator - -curdir = os.path.dirname(os.path.realpath(__file__)) -config_fn = os.path.join(curdir, 'test_cfg_none_simple.json') -platform = ql.Platform('platform_none', config_fn) -platform_qubits = 17 -output_dir = os.path.join(curdir, 'test_output') - -def to_bitstring(n, size=None): - small_bitstring = bin(n)[2:] - if size is None: - return small_bitstring - - assert(isinstance(size, int)) - assert((1 << size) > n) - assert(len(small_bitstring) <= size) - zeros = ''.join(['0' for _ in range(size - len(small_bitstring))]) - return zeros + small_bitstring - -def helper_prob(qubitstate): - return qubitstate.real**2+qubitstate.imag**2 - -@unittest.skipUnless(ql.Unitary.is_decompose_support_enabled(), "unitary decomposition support was disabled during OpenQL build") -class Test_conjugated_kernel(unittest.TestCase): - - @classmethod - def setUp(self): - ql.initialize() - ql.set_option('output_dir', output_dir) - ql.set_option('optimize', 'no') - ql.set_option('scheduler', 'ASAP') - ql.set_option('log_level', 'LOG_NOTHING') - # ql.set_option('write_qasm_files', 'yes') - - def test_bitstring(self): - self.assertEqual(to_bitstring(5), "101") - self.assertEqual(to_bitstring(5, size=6), "000101") - - with self.assertRaises(Exception): - res = to_bitstring(10, size=2) - - def test_unitary_basic(self): - num_qubits = 3 - p = ql.Program('test_unitary_pass', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - u = ql.Unitary('u1', [ complex(1.0, 0.0), complex(0.0, 0.0), - complex(0.0, 0.0), complex(0.0, 1.0)]) - u.decompose() - - k.gate("i", [0]) - k.gate("s", [0]) - k.gate(u, [2]) - - p.add_kernel(k) - p.compile() - - def test_unitary_called_hadamard(self): - num_qubits = 3 - p = ql.Program('test_unitary_called_hadamard', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - u = ql.Unitary('hadamard', [ complex(1.0, 0.0), complex(0.0, 0.0), - complex(0.0, 0.0), complex(0.0, 1.0)]) - u.decompose() - - k.gate(u, [2]) - - p.add_kernel(k) - p.compile() - - def test_unitary_wrongnumberofqubits(self): - num_qubits = 3 - p = ql.Program('test_unitary_pass', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - u = ql.Unitary('u1', [ complex(1.0, 0.0), complex(0.0, 0.0), - complex(0.0, 0.0), complex(0.0, 1.0)]) - k.gate("s", [0]) - - # adding un-decomposed u to kernel should raise error - with self.assertRaises(Exception) as cm: - k.gate(u, [1,2]) - - self.assertEqual(str(cm.exception).split('\n', maxsplit=1)[0], 'Unknown error: Unitary \'u1\' has been applied to the wrong number of qubits. Cannot be added to kernel! 2 and not 1') - -# def test_unitary_wrongnumberofqubits_toofew(self): -# num_qubits = 3 -# p = ql.Program('test_unitary_pass', platform, num_qubits) -# k = ql.Kernel('akernel', platform, num_qubits) -# -# -# u = ql.Unitary('u1', [-0.43874989-0.10659111j, -0.47325212+0.12917344j, -0.58227163+0.20750072j, -0.29075334+0.29807585j, -# 0.30168601-0.22307459j, 0.32626 +0.4534935j , -0.20523265-0.42403593j, -0.01012565+0.5701683j , -# -0.40954341-0.49946371j, 0.28560698-0.06740801j, 0.52146754+0.1833513j , -0.37248653+0.22891636j, -# 0.03113162-0.48703302j, -0.57180014+0.18486244j, 0.2943625 -0.06148912j, 0.55533888+0.04322811j]) -# # adding un-decomposed u to kernel should raise error -# with self.assertRaises(Exception) as cm: -# k.gate(u, [0]) -# -# self.assertEqual(str(cm.exception).split('\n', maxsplit=1)[0], 'Unknown error: Unitary \'u1\' has been applied to the wrong number of qubits. Cannot be added to kernel! 1 and not 2') - - def test_unitary_decompose_I(self): - num_qubits = 1 - p = ql.Program('test_unitary_I', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [ complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0) ] - u = ql.Unitary('u1', matrix) - u.decompose() - k.hadamard(0) - k.gate(u, [0]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - self.assertAlmostEqual(0.5*(helper_prob(matrix[0])+helper_prob(matrix[1])), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.5*(helper_prob(matrix[2])+helper_prob(matrix[3])), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - - def test_unitary_decompose_X(self): - num_qubits = 1 - p = ql.Program('test_unitary_X', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [ complex(0.0, 0.0), complex(1.0, 0.0), - complex(1.0, 0.0), complex(0.0, 0.0)] - u = ql.Unitary('u1', matrix) - u.decompose() - k.gate(u, [0]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[2]), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - - def test_unitary_decompose_Y(self): - num_qubits = 1 - p = ql.Program('test_unitary_Y', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [ complex(0.0, 0.0), complex(0.0, -1.0), - complex(0.0, 1.0), complex(0.0, 0.0)] - u = ql.Unitary('u1', matrix) - u.decompose() - k.gate(u, [0]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[2]), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - - def test_unitary_decompose_Z(self): - num_qubits = 1 - p = ql.Program('test_unitary_Z', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [ complex(1.0, 0.0), complex(0.0, 0.0), - complex(0.0, 0.0), complex(-1.0, 0.0)] - u = ql.Unitary('u1', matrix ) - u.decompose() - k.gate("hadamard", [0]) - k.gate(u, [0]) - k.gate("hadamard", [0]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - #HZH = X, so the result should be |0> + |1> - self.assertAlmostEqual(0, helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(1, helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - - - def test_unitary_decompose_IYZ(self): - num_qubits = 1 - p = ql.Program('test_unitary_IYZ', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - u = ql.Unitary('X', [ complex(0.0, 0.0), complex(1.0, 0.0), - complex(1.0, 0.0), complex(0.0, 0.0)]) - u.decompose() - k.gate(u, [0]) - u = ql.Unitary('Y', [ complex(0.0, 0.0), complex(0.0, -1.0), - complex(0.0, 1.0), complex(0.0, 0.0)]) - u.decompose() - k.gate(u, [0]) - u = ql.Unitary('Z', [ complex(1.0, 0.0), complex(0.0, 0.0), - complex(0.0, 0.0), complex(-1.0, 0.0)]) - u.decompose() - k.gate("hadamard", [0]) - k.gate(u, [0]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - #jXYZ = I, so this should change nothing about the state. - self.assertAlmostEqual(0.5, helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.5, helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - - def test_unitary_decompose_IYZ_differentorder(self): - num_qubits = 1 - p = ql.Program('test_unitary_IYZ', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - u = ql.Unitary('X', [ complex(0.0, 0.0), complex(1.0, 0.0), - complex(1.0, 0.0), complex(0.0, 0.0)]) - - u1 = ql.Unitary('y', [ complex(0.0, 0.0), complex(0.0, -1.0), - complex(0.0, 1.0), complex(0.0, 0.0)]) - - u2 = ql.Unitary('Z', [ complex(1.0, 0.0), complex(0.0, 0.0), - complex(0.0, 0.0), complex(-1.0, 0.0)]) - u.decompose() - u1.decompose() - u2.decompose() - - k.gate("hadamard", [0]) - k.gate(u, [0]) - k.gate(u1, [0]) - k.gate(u2, [0]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - #jXYZ = I, so this should change nothing about the state. - self.assertAlmostEqual(0.5, helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.5, helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - - def test_unitary_decompose_nonunitary(self): - num_qubits = 1 - p = ql.Program('test_unitary_nonunitary', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - u = ql.Unitary('WRONG', [ complex(0.0, 0.0), complex(0.0, 0.0), - complex(0.0, 0.0), complex(0.0, 0.0)]) - - with self.assertRaises(Exception) as cm: - u.decompose() - k.gate(u, [0]) - - add_kernel(k) - p.compile() - - self.assertEqual(str(cm.exception).split('\n\n', maxsplit=1)[0], "Unknown error: Error: Unitary 'WRONG' is not a unitary matrix. Cannot be decomposed!(0,0) (0,0)\n(0,0) (0,0)") - - # input for the unitary decomposition needs to be an array - def test_unitary_decompose_matrixinsteadofarray(self): - num_qubits = 1 - p = ql.Program('test_unitary_wrongtype', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - with self.assertRaises(TypeError) as cm: - u = ql.Unitary('TypeError', [[1, 0], [0,1]]) - - - - def test_unitary_decompose_2qubit_CNOT(self): - num_qubits = 2 - p = ql.Program('test_unitary_2qubitCNOT', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [ complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), - complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), - complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), - complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0)] - u = ql.Unitary('cnot',matrix) - u.decompose() - k.gate(u, [0, 1]) - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - - - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - #only two states are nonzero - self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[4]), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - - def test_unitary_decompose_2qubit_CNOT_2(self): - num_qubits = 2 - p = ql.Program('test_unitary_2qubitCNOT', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 0, 1, - 0, 0, 1, 0] - u = ql.Unitary('cnot2',matrix) - u.decompose() - k.x(1) - k.gate(u, [0, 1]) - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - - - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(1.0, helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - - - def test_non_90_degree_angle(self): - num_qubits = 2 - p = ql.Program('test_unitary_non_90_degree_angle', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [-0.43874989-0.10659111j, -0.47325212+0.12917344j, -0.58227163+0.20750072j, -0.29075334+0.29807585j, - 0.30168601-0.22307459j, 0.32626 +0.4534935j , -0.20523265-0.42403593j, -0.01012565+0.5701683j , - -0.40954341-0.49946371j, 0.28560698-0.06740801j, 0.52146754+0.1833513j , -0.37248653+0.22891636j, - 0.03113162-0.48703302j, -0.57180014+0.18486244j, 0.2943625 -0.06148912j, 0.55533888+0.04322811j] - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.gate(u1, [0,1]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[4]), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[8]), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[12]), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - - def test_usingqx_00(self): - num_qubits = 2 - p = ql.Program('test_usingqx00', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [-0.15050486+0.32164259j, -0.29086861+0.76699622j, - 0.17865218+0.18573699j, -0.31380116+0.19005417j, - -0.65629705+0.20915109j, 0.32782708+0.16363753j, - -0.54511727-0.21100055j, 0.0601221 -0.21446079j, - -0.38935965-0.47787084j, 0.30279699-0.10056307j, - 0.04076564+0.54046282j, -0.23847619+0.40939808j, - 0.13874319-0.01460122j, -0.27256915+0.12950497j, - -0.49774672+0.22449364j, 0.6159743 +0.46032394j] - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.gate(u1, [0,1]) - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[4]), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[8]), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[12]), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - - - - def test_usingqx_01(self): - num_qubits = 2 - p = ql.Program('test_usingqx01', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [-0.15050486+0.32164259j, -0.29086861+0.76699622j, - 0.17865218+0.18573699j, -0.31380116+0.19005417j, - -0.65629705+0.20915109j, 0.32782708+0.16363753j, - -0.54511727-0.21100055j, 0.0601221 -0.21446079j, - -0.38935965-0.47787084j, 0.30279699-0.10056307j, - 0.04076564+0.54046282j, -0.23847619+0.40939808j, - 0.13874319-0.01460122j, -0.27256915+0.12950497j, - -0.49774672+0.22449364j, 0.6159743 +0.46032394j] - - k.x(0) - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.gate(u1, [0,1]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - - self.assertAlmostEqual(helper_prob(matrix[1]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[5]), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[9]), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[13]), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - - - - def test_usingqx_10(self): - num_qubits = 2 - p = ql.Program('test_usingqx10', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [-0.15050486+0.32164259j, -0.29086861+0.76699622j, - 0.17865218+0.18573699j, -0.31380116+0.19005417j, - -0.65629705+0.20915109j, 0.32782708+0.16363753j, - -0.54511727-0.21100055j, 0.0601221 -0.21446079j, - -0.38935965-0.47787084j, 0.30279699-0.10056307j, - 0.04076564+0.54046282j, -0.23847619+0.40939808j, - 0.13874319-0.01460122j, -0.27256915+0.12950497j, - -0.49774672+0.22449364j, 0.6159743 +0.46032394j] - - - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.x(1) - k.gate(u1, [0,1]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(helper_prob(matrix[2]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[6]), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[10]), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[14]), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - - - - def test_usingqx_11(self): - num_qubits = 2 - p = ql.Program('test_usingqx11', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [-0.15050486+0.32164259j, -0.29086861+0.76699622j, - 0.17865218+0.18573699j, -0.31380116+0.19005417j, - -0.65629705+0.20915109j, 0.32782708+0.16363753j, - -0.54511727-0.21100055j, 0.0601221 -0.21446079j, - -0.38935965-0.47787084j, 0.30279699-0.10056307j, - 0.04076564+0.54046282j, -0.23847619+0.40939808j, - 0.13874319-0.01460122j, -0.27256915+0.12950497j, - -0.49774672+0.22449364j, 0.6159743 +0.46032394j] - - - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.x(0) - k.x(1) - k.gate(u1, [0,1]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(helper_prob(matrix[3]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[7]), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[11]), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[15]), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - - def test_usingqx_bellstate(self): - num_qubits = 2 - p = ql.Program('test_usingqxbellstate', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [-0.15050486+0.32164259j, -0.29086861+0.76699622j, - 0.17865218+0.18573699j, -0.31380116+0.19005417j, - -0.65629705+0.20915109j, 0.32782708+0.16363753j, - -0.54511727-0.21100055j, 0.0601221 -0.21446079j, - -0.38935965-0.47787084j, 0.30279699-0.10056307j, - 0.04076564+0.54046282j, -0.23847619+0.40939808j, - 0.13874319-0.01460122j, -0.27256915+0.12950497j, - -0.49774672+0.22449364j, 0.6159743 +0.46032394j] - - - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.hadamard(0) - k.cnot(0, 1) - - k.gate(u1, [0,1]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(0.5*helper_prob((matrix[0]+ matrix[3])), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.5*helper_prob((matrix[4]+matrix[7])), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.5*helper_prob((matrix[8]+ matrix[11])), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.5*helper_prob((matrix[12]+ matrix[15])), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - - - def test_usingqx_fullyentangled(self): - num_qubits = 2 - p = ql.Program('test_usingqxfullentangled', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [-0.15050486+0.32164259j, -0.29086861+0.76699622j, - 0.17865218+0.18573699j, -0.31380116+0.19005417j, - -0.65629705+0.20915109j, 0.32782708+0.16363753j, - -0.54511727-0.21100055j, 0.0601221 -0.21446079j, - -0.38935965-0.47787084j, 0.30279699-0.10056307j, - 0.04076564+0.54046282j, -0.23847619+0.40939808j, - 0.13874319-0.01460122j, -0.27256915+0.12950497j, - -0.49774672+0.22449364j, 0.6159743 +0.46032394j] - - - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.hadamard(0) - k.hadamard(1) - k.cnot(0, 1) - - k.gate(u1, [0,1]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(0.25*helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] )), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.25*helper_prob((matrix[4] + matrix[5] + matrix[6] + matrix[7] )), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.25*helper_prob((matrix[8] + matrix[9] + matrix[10]+ matrix[11])), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.25*helper_prob((matrix[12]+ matrix[13]+ matrix[14]+ matrix[15])), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - - def test_usingqx_fullyentangled_3qubit(self): - num_qubits = 3 - p = ql.Program('test_usingqxfullentangled_3qubit', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [-6.71424156e-01+0.20337111j, -1.99816541e-02+0.41660484j, - -1.54134851e-01+0.1944923j , 3.01737845e-01-0.27546267j, - 4.44627514e-02+0.09208708j, 2.15969389e-01+0.05602634j, - -4.34685756e-02-0.18679037j, -1.06595244e-02-0.09070964j, - -2.97602383e-01+0.04481956j, -2.02480684e-01-0.38012451j, - 2.82743377e-02+0.15314781j, -2.85687313e-01-0.15726268j, - -1.70730583e-04-0.153385j , 2.29149718e-01+0.30741448j, - 2.10312109e-01+0.49212858j, -3.59933779e-01-0.0825481j , - -2.53660227e-01+0.17691007j, 3.13791732e-01+0.27041001j, - -2.02215264e-01-0.11204691j, -8.86804543e-02+0.66976204j, - 7.33676579e-02-0.13082467j, -9.97863275e-02+0.01447563j, - -5.89120641e-02+0.4293754j , 3.27562664e-02+0.03619316j, - -1.13124674e-01-0.00735472j, 9.70967395e-02-0.24582965j, - -1.01309756e-01-0.39478792j, 1.63747452e-01-0.02575567j, - -3.55829560e-01+0.48277026j, 2.92508802e-01-0.34856674j, - -2.35490557e-01+0.20291125j, -2.05196931e-01+0.13496088j, - 1.00349815e-01-0.11576965j, 2.96991063e-01+0.12974051j, - -4.63456662e-01+0.26944686j, -3.95037450e-01-0.08454082j, - -4.48111249e-01+0.2913104j , -5.36978251e-02+0.25408623j, - 2.01534991e-01-0.12684844j, 6.37083728e-03+0.10506858j, - -3.22312837e-01-0.15860928j, 1.56365350e-01-0.10492928j, - 3.40842166e-01+0.16770422j, 3.86154376e-02-0.15216514j, - -2.21887101e-01-0.16990398j, -2.64609917e-01-0.06773659j, - -2.76899134e-02+0.12469262j, 2.53068805e-01+0.65839736j, - -1.47285402e-01+0.02010648j, -1.02440846e-01-0.36282662j, - -4.07092321e-01+0.18619875j, -1.51508597e-01+0.08507565j, - -1.60692869e-01-0.43953586j, 1.67488911e-01-0.42784326j, - -1.68066530e-01-0.1864466j , 3.03353139e-01-0.14152888j, - -3.65022492e-01+0.03013316j, 2.23190344e-01-0.25817333j, - 8.15042751e-02-0.23635981j, -1.36339839e-01+0.07858377j, - 3.21627053e-02+0.00460768j, -4.58271701e-01-0.15103882j, - 2.70920093e-01-0.42767654j, -3.77444900e-01-0.17163736j] - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.hadamard(0) - k.hadamard(1) - k.hadamard(2) - k.cnot(0, 1) - k.cnot(0, 2) - k.cnot(1, 2) - - k.gate(u1, [0,1, 2]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(0.125*helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7])), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[8] + matrix[9] + matrix[10]+ matrix[11]+ matrix[12]+ matrix[13]+ matrix[14]+ matrix[15])), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[16] + matrix[17]+ matrix[18]+ matrix[19]+ matrix[20]+ matrix[21]+ matrix[22]+ matrix[23])), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[24] + matrix[25]+ matrix[26]+ matrix[27]+ matrix[28]+ matrix[29]+ matrix[30]+ matrix[31])), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[32] + matrix[33]+ matrix[34]+ matrix[35]+ matrix[36]+ matrix[37]+ matrix[38]+ matrix[39])), helper_prob(state.get(to_bitstring(4, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[40] + matrix[41]+ matrix[42]+ matrix[43]+ matrix[44]+ matrix[45]+ matrix[46]+ matrix[47])), helper_prob(state.get(to_bitstring(5, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[48] + matrix[49]+ matrix[50]+ matrix[51]+ matrix[52]+ matrix[53]+ matrix[54]+ matrix[55])), helper_prob(state.get(to_bitstring(6, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[56] + matrix[57]+ matrix[58]+ matrix[59]+ matrix[60]+ matrix[61]+ matrix[62]+ matrix[63])), helper_prob(state.get(to_bitstring(7, size=platform_qubits), 0.)), 5) - - def test_usingqx_fullyentangled_4qubit(self): - num_qubits = 4 - p = ql.Program('test_usingqxfullentangled_4qubit', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [-0.11921901-0.30382154j, -0.10645804-0.11760155j, -0.09639953-0.0353926j , -0.32605797+0.19552924j, 0.0168262 -0.26748208j, -0.17808469+0.25265196j, -0.24676084-0.23228431j, -0.02960302+0.23697569j, - -0.12435741-0.07223017j, 0.00178745+0.14813263j, -0.11173158+0.26636089j, 0.27656908+0.05229833j, -0.02964214-0.01505502j, -0.26959616+0.23274949j, -0.18183627-0.04041783j, 0.05385991-0.05587908j, - 0.17894461-0.25668366j, -0.01553181-0.07446613j, 0.1876467 -0.49135878j, -0.18292006-0.04599956j, -0.01618695+0.21951951j, 0.06003169-0.12728871j, -0.04276406+0.08327372j, 0.30102765+0.18403071j, - -0.08122018-0.08375638j, -0.02971758+0.09096399j, 0.10753511-0.03359547j, -0.1596309 +0.20649279j, -0.13684564+0.29450386j, 0.20557421+0.24856224j, 0.0683444 +0.01780095j, -0.22317907-0.12123145j, - -0.0323504 -0.02668934j, 0.08743777-0.49956832j, -0.30202031-0.22517221j, -0.10642491-0.11883126j, -0.13756817-0.20632933j, 0.02593802+0.00583978j, 0.05130972+0.06678859j, -0.10426135-0.14411822j, - 0.12318252+0.28583957j, 0.04903179-0.31898637j, -0.07650819-0.07261235j, -0.22918932-0.28329527j, -0.26553775+0.04563403j, -0.07728053+0.14952931j, -0.10271285-0.00216319j, -0.09000117+0.09055528j, - -0.15385903+0.01767834j, 0.42229431-0.05610483j, -0.11330491-0.05458018j, 0.01740815-0.01605897j, -0.11908997-0.01830574j, 0.21139794-0.10602858j, -0.23249721-0.25516076j, -0.29066084-0.19129198j, - 0.21273108-0.14369238j, -0.20662513+0.14463032j, 0.2512466 -0.20356141j, 0.0869495 +0.24425667j, 0.09736427-0.03954332j, 0.1446303 +0.14263171j, -0.25679664+0.09389641j, -0.04020309-0.19362247j, - 0.12577257-0.14527364j, 0.00371525+0.14235318j, -0.22416134+0.02069087j, 0.03851418-0.05351593j, -0.00289848-0.33289946j, 0.15454716-0.126633j , -0.08996296-0.09119411j, -0.00804455-0.19149767j, - -0.13311475-0.47100304j, -0.13920624-0.16994321j, -0.05030304+0.16820614j, 0.05770089-0.15422191j, -0.23739468-0.05651883j, 0.19202883+0.03893001j, 0.48514604+0.01905479j, -0.01593819-0.06475285j, - 0.31543713+0.41579542j, -0.08776349+0.24207219j, -0.07984699-0.12818844j, 0.00359655+0.02677178j, -0.12110453-0.25327887j, -0.21175671-0.1650074j , -0.14570465-0.05140668j, 0.06873883-0.01768705j, - -0.13804809-0.16458822j, 0.15096981-0.02802171j, -0.05750448-0.18911017j, -0.01552104+0.03159908j, -0.0482418 +0.09434822j, 0.1336447 +0.22030451j, -0.3771364 -0.17773263j, 0.16023381+0.26613455j, - 0.12688452-0.07290393j, 0.14834649+0.08064162j, -0.06224533+0.04404318j, 0.03464369+0.19965444j, -0.38140629-0.18927599j, -0.19710535-0.178657j , -0.0507885 +0.19579635j, 0.11741615+0.13922702j, - 0.2673399 -0.01439493j, 0.10844591-0.19799688j, 0.01177533+0.031846j , -0.07643954+0.25870281j, 0.28971442-0.25385986j, -0.23713666+0.01838019j, 0.1731864 -0.09372299j, -0.36912353-0.02243029j, - 0.03562803-0.09449815j, 0.13578229-0.19205153j, 0.21279127+0.14541266j, -0.20195524+0.187477j , -0.06326783+0.0134827j , 0.26953438-0.11153784j, -0.28939961-0.08995754j, 0.20662437-0.15535337j, - -0.03615272+0.00848631j, 0.14124129-0.10250932j, 0.08990493-0.13010897j, -0.04547667+0.17579099j, -0.01292137+0.10354402j, -0.21338733-0.11928412j, 0.19733294+0.12876129j, 0.35162495+0.45226713j, - 0.17112722-0.18496045j, -0.34024071-0.09520237j, 0.18864652-0.07147408j, 0.31340662+0.24027412j, -0.0720874 -0.11081564j, 0.08727975+0.02830958j, -0.07584662-0.22555917j, 0.07086867-0.27714915j, - -0.19116148-0.02164144j, -0.24831911+0.1055229j , -0.09939105-0.24800283j, -0.15274706-0.12267535j, 0.05237777-0.09974669j, -0.18435891-0.1737002j , -0.20884292+0.1076081j , -0.31368958-0.02539025j, - 0.03436293-0.19794965j, 0.11892581-0.17440358j, -0.03488877+0.02305411j, 0.29835292-0.08836461j, 0.07893495-0.16881403j, 0.21025843+0.13204032j, 0.17194288-0.06285539j, -0.0500497 +0.35833208j, - -0.14979745-0.07567974j, 0.00193804+0.04092128j, -0.07528403-0.18508153j, -0.16873521-0.09470809j, 0.50335605+0.00445803j, 0.11671956+0.30273552j, 0.10253226-0.13365319j, 0.16676135+0.18345473j, - -0.10096334-0.24031019j, -0.18452241+0.05766426j, 0.18102499-0.13532486j, 0.06252468-0.18030042j, -0.00591499+0.07587582j, -0.35209025-0.12186396j, -0.25282963-0.26651504j, -0.13074882+0.14059941j, - 0.18125386-0.03889917j, 0.06983104-0.3425076j , 0.37124455-0.00305632j, 0.04469806-0.31220629j, 0.16501585+0.00125887j, 0.15895714-0.14115809j, -0.01515444+0.06836136j, 0.03934186+0.13425449j, - 0.0513499 +0.21915368j, 0.00089628-0.3044611j , 0.05443815-0.05530296j, 0.12091374-0.16717579j, -0.06795704-0.2515947j , -0.43324316+0.13138954j, 0.03753289-0.00666299j, 0.16823686-0.22736152j, - -0.00567807+0.05485941j, -0.11705816+0.39078352j, 0.29136164+0.18699453j, -0.09255109+0.08923507j, 0.11214398+0.00806872j, 0.02971631+0.05584961j, 0.2561 +0.22302638j, 0.12491596+0.01725833j, - 0.23473354-0.19203316j, -0.09144197-0.04827201j, -0.0630975 -0.16831612j, 0.01497053+0.11121057j, 0.1426864 -0.15815582j, 0.21509872-0.0821851j , 0.00650273+0.42560079j, -0.15721229+0.09919403j, - 0.18076365-0.05697395j, -0.10596487+0.23118383j, 0.30913352+0.24695589j, -0.03403863-0.01778209j, -0.07783213-0.25923847j, 0.06847369-0.2460447j , -0.24223779-0.10590238j, 0.15920784+0.21435437j, - 0.26632193-0.02864663j, 0.06457043+0.0577428j , -0.38792984+0.08474334j, 0.00944311+0.22274564j, 0.11762823+0.36687658j, -0.1058428 -0.2103637j , -0.12970051-0.27031414j, 0.12684307+0.08398822j, - 0.06711923+0.23195763j, -0.04537262+0.26478843j, 0.10253668-0.07706414j, -0.13531665-0.27150259j, -0.09124132-0.23306839j, -0.08631867+0.17221145j, 0.17654328-0.10341264j, 0.11171903-0.05824829j, - 0.04708668-0.13436316j, -0.10544253+0.07083904j, 0.04191629+0.28190845j, -0.4212947 -0.28704399j, 0.10278485+0.05713015j, 0.02057009-0.19126408j, 0.04856717+0.26648423j, 0.05388858-0.32433511j, - -0.09408669-0.12159016j, -0.01355394+0.04757554j, 0.10925003-0.0453999j , -0.02512057-0.23836324j, 0.31375479-0.0993564j , -0.14702106+0.33395328j, -0.1608029 +0.11439592j, -0.11028577-0.0093615j , - -0.08440005-0.12376623j, 0.12932188+0.09711828j, 0.18574716-0.06392924j, -0.13048059+0.0287961j , -0.29552716-0.08768809j, -0.02439943-0.01548155j, 0.07775135+0.00727332j, 0.1561534 -0.06489038j, - 0.46665242-0.07708219j, -0.05251139+0.37781248j, -0.3549081 -0.10086123j, 0.11180645-0.40408473j, 0.03031085+0.16928711j, 0.1190129 -0.10061168j, 0.0318046 -0.12504866j, 0.08689947+0.07223655j] - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.hadamard(0) - k.hadamard(1) - k.hadamard(2) - k.hadamard(3) - k.cnot(0, 1) - k.cnot(0, 2) - k.cnot(0, 3) - k.cnot(1, 2) - k.cnot(1, 3) - k.cnot(2, 3) - - k.gate(u1, [0, 1, 2, 3]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(0.0625*helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7] + matrix[8] + matrix[9] + matrix[10]+ matrix[11]+ matrix[12]+ matrix[13]+ matrix[14]+ matrix[15])), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[16] + matrix[17]+ matrix[18]+ matrix[19]+ matrix[20]+ matrix[21]+ matrix[22]+ matrix[23]+ matrix[24] + matrix[25]+ matrix[26]+ matrix[27]+ matrix[28]+ matrix[29]+ matrix[30]+ matrix[31])), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[32] + matrix[33]+ matrix[34]+ matrix[35]+ matrix[36]+ matrix[37]+ matrix[38]+ matrix[39]+ matrix[40] + matrix[41]+ matrix[42]+ matrix[43]+ matrix[44]+ matrix[45]+ matrix[46]+ matrix[47])), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[48] + matrix[49]+ matrix[50]+ matrix[51]+ matrix[52]+ matrix[53]+ matrix[54]+ matrix[55]+ matrix[56] + matrix[57]+ matrix[58]+ matrix[59]+ matrix[60]+ matrix[61]+ matrix[62]+ matrix[63])), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[64] + matrix[65]+ matrix[66]+ matrix[67]+ matrix[68]+ matrix[69]+ matrix[70]+ matrix[71]+ matrix[72] + matrix[73]+ matrix[74]+ matrix[75]+ matrix[76]+ matrix[77]+ matrix[78]+ matrix[79])), helper_prob(state.get(to_bitstring(4, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[80] + matrix[81]+ matrix[82]+ matrix[83]+ matrix[84]+ matrix[85]+ matrix[86]+ matrix[87]+ matrix[88] + matrix[89]+ matrix[90]+ matrix[91]+ matrix[92]+ matrix[93]+ matrix[94]+ matrix[95])), helper_prob(state.get(to_bitstring(5, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[96] + matrix[97]+ matrix[98]+ matrix[99]+ matrix[100]+ matrix[101]+ matrix[102]+ matrix[103]+ matrix[104] + matrix[105]+ matrix[106]+ matrix[107]+ matrix[108]+ matrix[109]+ matrix[110]+ matrix[111])), helper_prob(state.get(to_bitstring(6, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[112] + matrix[113]+ matrix[114]+ matrix[115]+ matrix[116]+ matrix[117]+ matrix[118]+ matrix[119]+ matrix[120] + matrix[121]+ matrix[122]+ matrix[123]+ matrix[124]+ matrix[125]+ matrix[126]+ matrix[127])), helper_prob(state.get(to_bitstring(7, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[128] + matrix[129]+ matrix[130]+ matrix[131]+ matrix[132]+ matrix[133]+ matrix[134]+ matrix[135]+ matrix[136] + matrix[137]+ matrix[138]+ matrix[139]+ matrix[140]+ matrix[141]+ matrix[142]+ matrix[143])), helper_prob(state.get(to_bitstring(8, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[144] + matrix[145]+ matrix[146]+ matrix[147]+ matrix[148]+ matrix[149]+ matrix[150]+ matrix[151]+ matrix[152] + matrix[153]+ matrix[154]+ matrix[155]+ matrix[156]+ matrix[157]+ matrix[158]+ matrix[159])), helper_prob(state.get(to_bitstring(9, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[160] + matrix[161]+ matrix[162]+ matrix[163]+ matrix[164]+ matrix[165]+ matrix[166]+ matrix[167]+ matrix[168] + matrix[169]+ matrix[170]+ matrix[171]+ matrix[172]+ matrix[173]+ matrix[174]+ matrix[175])), helper_prob(state.get(to_bitstring(10, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[176] + matrix[177]+ matrix[178]+ matrix[179]+ matrix[180]+ matrix[181]+ matrix[182]+ matrix[183]+ matrix[184] + matrix[185]+ matrix[186]+ matrix[187]+ matrix[188]+ matrix[189]+ matrix[190]+ matrix[191])), helper_prob(state.get(to_bitstring(11, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[192] + matrix[193]+ matrix[194]+ matrix[195]+ matrix[196]+ matrix[197]+ matrix[198]+ matrix[199]+ matrix[200] + matrix[201]+ matrix[202]+ matrix[203]+ matrix[204]+ matrix[205]+ matrix[206]+ matrix[207])), helper_prob(state.get(to_bitstring(12, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[208] + matrix[209]+ matrix[210]+ matrix[211]+ matrix[212]+ matrix[213]+ matrix[214]+ matrix[215]+ matrix[216] + matrix[217]+ matrix[218]+ matrix[219]+ matrix[220]+ matrix[221]+ matrix[222]+ matrix[223])), helper_prob(state.get(to_bitstring(13, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[224] + matrix[225]+ matrix[226]+ matrix[227]+ matrix[228]+ matrix[229]+ matrix[230]+ matrix[231]+ matrix[232] + matrix[233]+ matrix[234]+ matrix[235]+ matrix[236]+ matrix[237]+ matrix[238]+ matrix[239])), helper_prob(state.get(to_bitstring(14, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[240] + matrix[241]+ matrix[242]+ matrix[243]+ matrix[244]+ matrix[245]+ matrix[246]+ matrix[247]+ matrix[248] + matrix[249]+ matrix[250]+ matrix[251]+ matrix[252]+ matrix[253]+ matrix[254]+ matrix[255])), helper_prob(state.get(to_bitstring(15, size=platform_qubits), 0.)), 5) - - - - def test_usingqx_fullyentangled_5qubit(self): - num_qubits = 5 - p = ql.Program('test_usingqxfullentangled_5qubit', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [ 0.31869031-9.28734622e-02j, 0.38980148+2.14592427e-01j, 0.20279154-1.56580826e-01j, 0.00210273-2.83970875e-01j, -0.04010672-9.26812940e-02j, 0.15747049+6.08283291e-02j, -0.05274772-6.45225841e-02j, 0.05909439-3.23496026e-02j, 0.07868009+6.77298732e-02j, 0.11290142+2.48468763e-02j, 0.10092033-7.03646679e-02j, -0.03557972-3.39117261e-02j, 0.02241562+1.02714684e-02j, -0.04088796-1.12143173e-01j, -0.00144015+1.83925572e-02j, -0.1257948 -1.15394681e-01j, 0.13531631-1.84271421e-01j, 0.11293592-1.44170392e-01j, -0.06985893-1.36606289e-01j, -0.08924113-6.35923942e-02j, 0.19393965-6.35656579e-02j, -0.02153233-2.76955143e-01j, -0.12094999+1.05716669e-01j, -0.00624879+1.27471575e-01j, -0.13608981-1.22140261e-01j, -0.08243959-1.72734247e-02j, 0.06562052+1.12197102e-01j, -0.01102025-1.53811069e-01j, 0.13576338-8.95540026e-02j, 0.05730484-5.62973657e-02j, -0.08835493-4.13159024e-02j, -0.04533295+3.70144188e-02j, 0.04116657+1.58298973e-01j, 0.22270976-1.18654603e-01j, - 0.09219815+8.41433858e-02j, -0.0227499 +2.33343627e-01j, -0.13334752-6.98059663e-02j, -0.07967301-6.54413909e-02j, -0.09158972-7.03627564e-02j, -0.02332636-1.58060290e-02j, 0.23523954-3.48258461e-02j, 0.21329683+6.37364245e-02j, 0.25821394+1.30648709e-03j, -0.1118809 -1.95903237e-01j, -0.07887212-8.81857936e-02j, 0.047632 +9.40535593e-02j, -0.11726632+5.65815234e-02j, 0.08229469-4.38047420e-02j, 0.03117762+1.08469602e-01j, 0.16064616-1.30734886e-01j, 0.22181279-3.31211823e-02j, 0.07309884-2.01468425e-01j, -0.28437382+6.38292807e-02j, -0.23661479+1.17105208e-01j, -0.10436123-5.56443645e-02j, 0.20587544+1.99848797e-02j, 0.20705551+1.75496198e-02j, 0.01791984-8.31956939e-02j, 0.09737992+6.64713628e-03j, 0.0617566 -7.11998970e-02j, 0.03073603-7.25651496e-02j, -0.12056479-1.55358931e-01j, -0.09661589+4.90232280e-03j, 0.03110935-1.72748422e-01j, 0.01473304+3.62629583e-01j, 0.11031868-3.67435519e-03j, 0.04301239-1.64601498e-01j, -0.16432353+7.52258615e-02j, - -0.00648176+6.66215752e-02j, 0.1257427 -3.71759618e-02j, -0.07793634-7.01586304e-02j, 0.0571156 +2.67410653e-01j, -0.00880782+2.09982981e-01j, -0.04961517-6.86953748e-02j, -0.15766986-1.12761472e-01j, -0.07076146-3.12372790e-02j, -0.08715236+9.29279186e-02j, 0.03843817+1.13545744e-01j, -0.10838483-1.19949631e-02j, -0.06342622+1.73231077e-01j, 0.23221532-4.28875040e-02j, 0.16514567-4.90633428e-02j, -0.0109654 +6.37891447e-02j, 0.02171279+5.89435085e-02j, 0.0199925 -2.96609865e-01j, 0.16702912+8.82996853e-02j, 0.19820571+5.01863737e-02j, -0.01237253-1.21196566e-01j, 0.11042294-2.16811518e-01j, -0.01004066-2.36556101e-01j, -0.1286729 -4.01294536e-03j, -0.11254789+5.56025311e-02j, -0.18328088-1.46524167e-02j, -0.13640243-3.71920766e-02j, -0.03793125+9.57786229e-02j, 0.07600542+1.53449546e-01j, -0.12371969+2.19599454e-01j, 0.18106889-3.10905810e-02j, -0.12698597+7.45431556e-02j, 0.02402161-1.66514384e-02j, -0.1431313 +4.63501164e-02j, 0.13656065-8.55748891e-02j, - -0.2085481 -3.99831111e-02j, -0.05354994+8.14822771e-02j, 0.22188566+8.04753102e-02j, -0.09702996-1.54653045e-01j, -0.1018562 -1.01790676e-01j, -0.00335582+2.52475965e-01j, -0.04858119-1.52409323e-01j, 0.09335149-3.90325714e-02j, 0.08277598-4.08970043e-02j, 0.08119049+5.11051755e-02j, -0.01223217+6.17029648e-04j, -0.15137858-9.30742653e-03j, 0.1064706 +3.35870801e-02j, -0.04014048+1.33388615e-01j, -0.04315986+1.74367473e-01j, -0.04774817-9.82134162e-02j, -0.08203436+7.74038565e-02j, -0.2339137 +1.62306949e-01j, 0.11791971+2.08966161e-01j, -0.07867189-4.18549851e-02j, -0.17291904+9.47505092e-02j, 0.23630015-3.07786925e-01j, -0.09104365-1.33230919e-01j, 0.07679465+1.45726380e-01j, 0.09397243-9.26081447e-02j, -0.16092509+7.38633830e-02j, -0.02289017+1.59777790e-01j, 0.12053722+6.55620680e-02j, 0.12646833+1.04585433e-01j, 0.0264461 +1.92009889e-01j, 0.28749442+1.11327480e-01j, 0.15837267+6.12698488e-02j, 0.18181681-5.61278874e-02j, 0.07897084-1.17114924e-01j, - 0.19787494-1.67863968e-01j, 0.03852499-4.21534504e-02j, -0.14091989-1.27321872e-01j, -0.01747868-2.27419946e-01j, -0.02073576-6.24641146e-02j, -0.14241142+2.28697604e-02j, 0.15468346+2.08734157e-02j, 0.04505001-9.46333157e-02j, -0.09148317-2.26152985e-01j, 0.08577989+2.30863031e-01j, -0.08152502-8.74340592e-02j, -0.06465018-7.35108360e-02j, -0.21595512-8.66695180e-03j, 0.03304541-1.91886499e-01j, 0.04448112+3.67289455e-02j, 0.01969849-5.34777195e-02j, -0.03209367+3.02797601e-02j, 0.17389718+1.19098672e-01j, -0.10192559-3.02362398e-01j, -0.10224653-8.09241417e-02j, -0.12601597-6.86631211e-02j, 0.11275009+1.40915100e-01j, 0.03214418+1.48701215e-01j, -0.11571373+3.57083353e-02j, 0.03222285-5.19221441e-02j, -0.00250593+7.32186819e-02j, -0.15549573+1.77404851e-01j, 0.08568275+1.02973155e-01j, 0.11314133-2.13171498e-01j, 0.22748546-5.69951563e-02j, 0.14929197+1.31715414e-01j, -0.16301646+3.65045553e-03j, 0.13494125+2.31602145e-01j, 0.24267648-1.77780817e-01j, - -0.00736974+7.72680290e-02j, -0.04867011+1.22605525e-01j, 0.05051748+8.06196677e-02j, -0.01749415+6.33486594e-02j, 0.06408343-4.51492484e-02j, -0.02543799-1.33253676e-01j, -0.05785745-4.71803669e-02j, -0.24358675-1.18083337e-02j, 0.00061111-5.96573111e-03j, 0.17487681-8.55625475e-02j, 0.13181372-5.47918839e-02j, -0.14072394+1.08475923e-01j, 0.05919593+1.78284217e-01j, -0.00292253-2.17168452e-02j, 0.19948189-1.95177980e-01j, -0.11146926-1.55684600e-01j, 0.02692391-9.18282632e-02j, -0.03804582-7.62499524e-02j, 0.18562866+1.41900953e-01j, 0.15468899+7.03401694e-03j, 0.10617502+2.96183301e-01j, 0.12124371+1.42279327e-02j, -0.12974516+1.87600027e-01j, -0.23270386+1.59618723e-01j, -0.14928652-8.27397154e-02j, 0.06670844+6.35681954e-02j, 0.03466266+1.89244901e-01j, -0.00961646-1.02903972e-01j, 0.19899344-2.38199195e-01j, -0.16594523-4.43067845e-02j, 0.27258801-7.49570862e-02j, 0.08182091+2.03334342e-02j, -0.02454051-4.82668158e-02j, -0.08557127+3.04552132e-02j, - 0.01303575+8.88057122e-02j, 0.13253621+5.05712004e-02j, 0.07763894+1.13841327e-01j, -0.28730914-4.49839630e-02j, 0.07031891-3.38973984e-03j, -0.04794523-1.67972335e-01j, -0.18102171+2.08760542e-01j, -0.08845631-9.70771934e-02j, 0.03546718+4.80846877e-02j, -0.08866794-5.19207245e-02j, -0.15099182-9.77070105e-02j, -0.05473901+2.33013978e-01j, -0.04645356-8.89489153e-02j, 0.07548625+1.80517821e-01j, 0.16840691+2.15268260e-01j, -0.09962074-7.35772706e-03j, -0.10104245+1.74017433e-02j, -0.09302095-1.10945928e-01j, -0.035157 +2.50873519e-02j, 0.10622507+1.29398421e-01j, -0.20965829-4.55862887e-02j, 0.05220909+6.66834897e-02j, -0.09672108+1.09403436e-01j, 0.12697788-6.19212188e-02j, 0.05729917+1.44378294e-01j, -0.15808366-3.82581632e-02j, 0.10716098-4.62942406e-02j, 0.24961573+1.32840816e-01j, 0.0627808 +2.39056706e-02j, 0.18311487+7.98582936e-03j, 0.02661541+7.40701198e-02j, 0.04699528+1.88767961e-01j, 0.04750332-2.25995642e-02j, 0.07193907+5.68042859e-02j, - -0.02763382-3.43370436e-02j, 0.11205088-1.98370084e-02j, -0.11424545+1.14269285e-03j, 0.06885854-2.09915302e-01j, -0.05625496-2.88701666e-01j, -0.08183393+2.31774294e-01j, -0.09301037-4.03842722e-02j, -0.06069309+2.57502142e-02j, -0.18634877+9.85377377e-02j, 0.01474395+9.22414287e-02j, 0.04147054-1.74520016e-01j, 0.06794102-1.59508183e-01j, -0.13292245-5.38490513e-02j, -0.18753702+2.82751900e-01j, 0.00899866-2.80951474e-01j, 0.20377748+8.19207845e-02j, -0.14028603-1.39624056e-01j, 0.10741114+2.60308736e-02j, -0.22833573+6.02730469e-02j, 0.16071761-1.25615817e-01j, 0.08060865-5.81044643e-03j, 0.16141495-4.86994019e-02j, 0.11263654-1.87107794e-02j, 0.06859488-1.90280093e-01j, 0.10733862+4.45380867e-02j, -0.11489398-2.10578670e-01j, -0.0864833 -1.73958604e-01j, 0.12293904-1.50703768e-01j, -0.00629652+2.98133822e-02j, 0.16452648+7.76415767e-02j, 0.16219009+2.46017766e-01j, -0.04582374-1.16806045e-01j, 0.15109013+9.45671154e-03j, 0.04773975-1.54745106e-01j, - 0.21822796-1.87975523e-03j, 0.16596711-1.31539539e-01j, 0.25621724-4.31460990e-02j, 0.23071937+1.38086347e-01j, 0.10615413-1.24941186e-01j, 0.00343902+5.79927212e-02j, 0.10569282-2.64952183e-01j, -0.13601637+5.39259774e-02j, -0.13182901+9.15307749e-02j, 0.03524551-1.35956850e-01j, 0.0957622 -1.71837228e-02j, -0.03707841-5.40514827e-02j, -0.05729147-7.33164458e-02j, -0.18631267+1.00759871e-01j, -0.02434746-2.22824245e-02j, -0.02570765-3.90074186e-02j, 0.17946901+1.86288095e-02j, 0.07742897+3.19064602e-02j, -0.17538437+2.18666227e-01j, 0.10029635-8.92554711e-03j, -0.13379504-1.03683797e-02j, -0.11115363-4.48983441e-02j, 0.00163172-2.05325390e-02j, 0.02753729-1.28591197e-01j, 0.01933548+2.37393316e-01j, 0.07102201-1.19729329e-01j, -0.07517562+7.47947883e-02j, -0.03383077-1.23796732e-01j, -0.05575669-2.97673975e-02j, -0.04860924+1.02986531e-01j, 0.11384071+2.36429953e-01j, -0.26355793+1.30580300e-02j, -0.2665541 +6.72995742e-02j, -0.04663019-5.64857364e-03j, - 0.15703188+2.25734925e-02j, -0.02611337-4.94904084e-03j, 0.31897764+7.13870567e-02j, 0.15501272-1.48107261e-01j, 0.18034006-2.37497106e-01j, 0.21350438-8.08313917e-02j, 0.0620688 +5.98457145e-02j, -0.04996277+1.09069384e-02j, -0.09282843-5.59942293e-02j, -0.05363359+4.83839918e-02j, -0.20946404-1.85419524e-01j, -0.05481421+8.78420662e-02j, -0.19261214-1.04875021e-01j, -0.00083685-2.70091261e-02j, -0.17618069+8.47803615e-02j, 0.16055652+5.98821538e-03j, -0.0635621 +8.16228775e-02j, -0.22507829-4.14268948e-02j, -0.00791737+7.40481825e-02j, 0.19970347-1.15972939e-01j, -0.08619572+1.19678540e-01j, -0.184931 -1.13524848e-01j, 0.04824348-5.85668978e-02j, -0.22446284+1.11472258e-02j, 0.09629746-1.88788542e-01j, -0.18228537-3.89615785e-04j, 0.09084756+4.78058679e-02j, -0.00889583-1.74554680e-01j, -0.07447697-4.48823321e-02j, -0.05076077-6.24206002e-02j, -0.14050658+8.38982646e-02j, 0.07428934-6.30440232e-02j, 0.05701074-1.00819168e-01j, 0.07009481+8.11789378e-02j, - -0.01155395+2.46650660e-01j, 0.25264038-1.98419236e-01j, -0.09155521-2.79616998e-02j, 0.06750545-1.52831769e-01j, 0.1068504 -1.78545409e-01j, -0.06203486+2.86380485e-02j, 0.23067545-1.23638547e-01j, -0.02397582+2.15643846e-01j, 0.01810979+1.08067552e-01j, 0.09130261-4.68850866e-02j, 0.13093158-1.51875212e-01j, 0.25207024+5.80216347e-02j, 0.02600999-1.27799785e-01j, 0.03509714-5.46256940e-02j, 0.04362407-3.07563727e-02j, 0.12488249+6.70881126e-02j, 0.05539679+1.15790184e-01j, 0.23107124-9.66168589e-02j, -0.09977799-9.88045601e-02j, -0.05633534+2.79762650e-01j, -0.02304281-2.42282613e-02j, 0.1276518 -2.32550502e-02j, 0.25634814-3.02429796e-02j, 0.30827737-2.19288542e-01j, -0.02512791+2.13783374e-01j, 0.15453741-7.04163688e-02j, -0.21441715+2.05959415e-01j, -0.02827968+4.71161636e-02j, -0.03837343+6.70595235e-02j, -0.07854483-3.12796395e-02j, -0.03615927+1.10733671e-01j, 0.21779074-1.39489256e-01j, 0.06619192+5.38352432e-02j, -0.0680216 -1.05456770e-01j, - -0.10316128+1.32947183e-01j, -0.06345699-1.85555087e-01j, -0.00893067+1.52852423e-01j, 0.03135864+1.10423220e-01j, -0.182351 +2.77954961e-02j, -0.09252137+1.09061091e-01j, -0.0797695 +1.15176285e-02j, 0.05051009+2.57152535e-01j, 0.09344185-1.12906975e-01j, 0.04587659+8.90786692e-02j, -0.02471718+4.53344925e-02j, -0.08880236+3.62673481e-02j, -0.05981018+9.78912466e-02j, -0.00118743-5.07702805e-02j, -0.08119522+5.16043940e-02j, 0.11854883+9.79110177e-02j, 0.28543526-8.57540624e-02j, 0.28069514+2.00242562e-01j, -0.01036913-1.12897546e-01j, -0.08470073+1.91009156e-02j, 0.01428585+7.92620224e-02j, -0.15567322-4.85322282e-02j, 0.14203257-2.97248067e-01j, 0.15075682-1.33294241e-01j, 0.08107944-6.10561974e-02j, 0.07558358-3.29486035e-02j, -0.04042877-2.49142675e-02j, 0.05557881-1.93956804e-01j, -0.00589446+9.44678255e-02j, 0.1653676 -4.08479951e-02j, 0.14382039+1.57269491e-02j, -0.22311804-8.79699173e-02j, 0.09825566+1.52084444e-02j, 0.00938452-3.15649024e-01j, - -0.03982978+1.22637508e-01j, -0.15670677-1.93426126e-01j, 0.22741559-4.39643322e-02j, -0.13362661-9.94353174e-02j, -0.09445278+4.93195562e-02j, -0.04684833-8.59308253e-02j, 0.08890091-1.16876390e-01j, -0.18726614+7.50813913e-02j, -0.01806267-2.00321404e-02j, 0.09338316-1.69711164e-01j, -0.03114173+1.43744729e-01j, -0.01515641+7.72217128e-02j, 0.21301431+5.92330407e-02j, 0.12250555+1.16784140e-01j, 0.0492589 +1.82225369e-01j, 0.09296806+1.58772507e-02j, -0.06700279+7.86869873e-02j, -0.02389099-5.36170682e-02j, 0.00545649-1.25491880e-03j, 0.09228983+2.64561438e-01j, -0.08125859-3.27415023e-02j, -0.03769576-2.64763488e-01j, 0.0914594 +1.90133579e-01j, -0.27352411+6.32203214e-02j, -0.00087467-8.61094525e-02j, 0.13735927+8.73538830e-03j, -0.08484748+1.68213884e-01j, -0.07040327-1.76254392e-01j, -0.08363638-8.30902369e-02j, 0.14643814+6.63711322e-02j, -0.31659998-1.04317904e-01j, 0.07830602+2.93183609e-02j, 0.11041879+1.50347028e-01j, -0.00433818-1.72946523e-01j, - -0.15422074+9.38342826e-02j, -0.14194574+3.64105744e-02j, 0.06297505+7.88548664e-02j, 0.01106598-2.65402837e-01j, 0.07164956-8.12953528e-02j, -0.12514039-1.84403896e-01j, -0.17295559+3.58171829e-02j, -0.03655755-7.10559195e-02j, -0.03821694-1.10973040e-01j, 0.18546141+1.10662839e-01j, -0.10195195+1.32367694e-01j, -0.05016084+2.78628720e-02j, -0.19079393+1.40041256e-02j, 0.07878861-3.38112621e-02j, 0.13730204+1.52897765e-01j, 0.11815899+3.49910958e-02j, -0.02648579-1.03280312e-01j, 0.11970226-2.50844123e-01j, 0.10406627-9.12689026e-02j, 0.07247411-2.51491332e-01j, 0.06550999-2.94078974e-01j, -0.12079469-5.00355065e-02j, 0.06000345-1.02467349e-01j, 0.08823557+3.66136284e-02j, 0.02291526+3.63437115e-02j, -0.07124433+2.31676270e-01j, 0.17493588+5.98421039e-02j, -0.17824122-1.97944096e-02j, -0.00491994-9.10500757e-02j, 0.19633245+6.47815099e-02j, -0.03770238-7.48581318e-02j, -0.18402244+9.04322714e-02j, -0.2842845 -1.40285725e-01j, 0.00138785+1.08042021e-01j, - 0.16088797+2.75183648e-01j, -0.0865634 -7.36993417e-02j, 0.05178655+5.29576072e-02j, -0.05123872-1.29090313e-02j, -0.03079395-1.69557846e-01j, 0.23219467-7.71729365e-03j, -0.01135984-6.49120093e-02j, 0.08717993-9.71885487e-02j, -0.02043387+1.16518568e-01j, -0.08256357+1.23302259e-02j, 0.13742387-2.00583302e-01j, 0.11087765+2.22213806e-02j, 0.10703254+3.53681589e-02j, -0.04998617+7.13667998e-02j, -0.2463513 -2.30198030e-01j, 0.09831487+1.92709068e-01j, 0.10999549+1.28740664e-01j, -0.04056669+9.08016920e-02j, -0.03342728-9.92407179e-02j, 0.09352449-4.93911914e-02j, -0.11841153-8.25481366e-02j, -0.0263205 +1.91245810e-01j, -0.15521225-6.80613837e-02j, 0.18223827-2.68908129e-01j, 0.0411945 +1.12072453e-01j, -0.02954085+6.34315408e-02j, -0.01019486-1.24389083e-01j, 0.19174201-7.05812742e-02j, 0.19351232+1.42610666e-02j, 0.12937332-1.45006522e-01j, 0.01111355+1.11974478e-01j, 0.25163849+7.58955475e-02j, 0.06967535+1.51710939e-01j, -0.26064587+5.85797495e-02j, - -0.05364486-8.37537594e-02j, 0.02473011+1.57624180e-01j, 0.0788524 +4.24067733e-02j, -0.05353458-3.59527188e-02j, 0.24630053-3.09146961e-01j, 0.12673895+2.54501080e-02j, 0.13328446+1.27420821e-01j, -0.03311185+8.64376474e-02j, -0.10126181-3.33404906e-02j, 0.05819512-2.42452607e-01j, 0.12966928+1.92345459e-01j, -0.10237172+7.87217786e-02j, -0.12008 +8.02686485e-02j, 0.11309599+3.47582961e-02j, 0.16921731-6.49645604e-02j, 0.10847358+1.32814258e-01j, 0.09620142+8.29342007e-02j, -0.03836254+1.18815716e-01j, 0.10334279-1.21404737e-02j, -0.19366239-5.73423731e-02j, 0.11445103-7.69154143e-02j, 0.10345336+3.42165082e-02j, 0.0870257 +5.06977361e-02j, -0.0262899 +4.49013808e-02j, -0.0367388 +1.36360059e-02j, 0.00976608-1.86860241e-01j, 0.15386709+1.46930831e-01j, 0.11249562+2.57278918e-02j, 0.08496388-1.11776874e-01j, -0.07162906-1.41500632e-02j, 0.076649 -2.72671417e-01j, 0.12029408-2.43316647e-01j, 0.29672048-6.39702972e-02j, 0.1939962 -1.55753156e-02j, - 0.08677801+1.96162231e-01j, 0.1237203 -9.61956522e-02j, -0.16119964+3.89474786e-02j, 0.09207276-2.54823411e-01j, 0.03475803-5.50657361e-02j, -0.21263069-7.05923500e-02j, -0.06092331+4.49331302e-02j, -0.02461632+3.39504695e-02j, 0.0345771 +2.39801010e-01j, 0.00891307+1.12739196e-01j, 0.13060822-1.11694609e-01j, 0.09803224+1.73134288e-01j, -0.07234639+1.28840723e-02j, 0.11471256+3.77081748e-02j, 0.26422031-1.58104940e-01j, 0.02654836-1.38859272e-01j, -0.04278432-1.46473478e-02j, 0.28242235-5.27977137e-02j, -0.13193171+1.21081065e-01j, 0.06133633-4.22267064e-02j, -0.08280452+2.04720842e-02j, 0.02083153+5.42313877e-02j, 0.12016721+1.60501416e-01j, -0.12225807-2.76668735e-01j, 0.02102305+9.09998231e-02j, 0.11747776+3.62319311e-01j, 0.09912628+1.50849159e-02j, -0.15640258+2.48010133e-02j, 0.0546514 +2.59861755e-02j, -0.01002552+6.65787181e-02j, -0.02898995+9.89915581e-02j, -0.00717829-1.37245312e-01j, 0.00055712+1.86303843e-01j, 0.04400996+1.19535156e-01j, - 0.05636026-2.16779961e-01j, -0.05913502-2.77370485e-01j, 0.20737913+2.02848948e-01j, -0.07528717+7.93840780e-02j, 0.05451348+1.33425914e-01j, -0.12290648+7.58881312e-02j, 0.10321466+1.24983234e-01j, 0.13371569-1.00033395e-01j, -0.05791197+2.68575587e-02j, 0.04652659+4.60658211e-02j, 0.00131806+5.92140285e-02j, -0.13481008+2.31672893e-02j, -0.13689412+1.17954022e-01j, 0.04998811-2.02833835e-02j, -0.14165519+3.56756720e-01j, -0.07856852+6.35118506e-02j, 0.05564543-9.74922249e-02j, -0.21743105-5.41409515e-02j, -0.16217875+7.97524864e-02j, -0.19486651-9.99801439e-02j, 0.19124263-4.71432152e-02j, 0.01035372+4.63843919e-02j, -0.07218978+1.32977797e-01j, -0.21002818-1.31679835e-01j, 0.05305256-1.54340691e-02j, -0.19401635+6.69582303e-02j, 0.05139607+1.93092981e-01j, -0.09946416+4.37566125e-02j, 0.10192397-4.16617603e-02j, -0.12405403-9.78811063e-02j, 0.05812519-3.95372746e-05j, 0.00099002-1.14739425e-02j, 0.05247123-8.40118490e-02j, 0.04501583+1.44968196e-01j, - 0.03301905-4.80048648e-02j, 0.02823323-1.78191318e-02j, 0.08196271-6.89791351e-03j, 0.02038618+7.47434818e-02j, -0.0372285 +4.85572384e-02j, 0.03293172+1.46606707e-02j, -0.18339563+6.37443359e-02j, -0.11214925-1.13505125e-01j, -0.06063048+1.45448526e-01j, 0.34233663-3.24467430e-01j, 0.07664073-1.44247607e-01j, -0.28993637+1.68069982e-01j, -0.18237161+2.05640159e-01j, 0.05552109+1.44200044e-01j, -0.08757971-2.66443942e-01j, 0.1558971 +2.49096061e-02j, -0.16421838+3.76276364e-02j, 0.08841799+3.97688126e-02j, 0.06127403+8.79601343e-02j, -0.11912802+9.38176361e-02j, -0.01512363+1.98779455e-01j, -0.10425168-2.89846412e-02j, 0.16046822-1.77676457e-02j, 0.04871864-4.15742404e-02j, 0.19325653-1.69328440e-01j, -0.059617 +1.87459639e-02j, -0.23497369+7.78523444e-02j, 0.03611522+4.96031106e-02j, 0.02849174+1.81422119e-01j, -0.13379238-1.46097376e-01j, 0.13609017-3.86016200e-02j, -0.13135849-9.04921922e-02j, 0.1333314 +1.02431026e-01j, 0.23331259-1.23168916e-02j, - 0.05106233+7.45228667e-02j, 0.12189655+6.42850380e-02j, 0.04943332+2.95462475e-02j, -0.00657986+8.06994964e-02j, 0.3267687 +8.99736406e-02j, -0.14260504+1.75648292e-01j, 0.23063331+1.78219849e-01j, 0.10883261+1.28389828e-01j, -0.10597288-1.40386755e-01j, 0.01512138+5.26532655e-02j, -0.24270928-2.39424278e-01j, 0.08582485+1.81061208e-01j, 0.15870471+3.82006536e-03j, -0.14205944-7.88677962e-02j, 0.26780226+1.17371947e-01j, -0.05734894+1.19255894e-01j, -0.00708958-3.87661515e-02j, -0.0123964 +1.17519163e-01j, -0.05307584+9.65095189e-02j, -0.04746522+6.19590573e-02j, -0.03677784-2.76400184e-02j, 0.14375332+9.66259420e-02j, -0.09175759-1.16174795e-01j, -0.03764456-1.92660525e-02j, -0.14188024+1.51742465e-01j, -0.00855281-6.80432250e-02j, -0.13963677+6.77341017e-02j, 0.27226725-5.95170973e-03j, 0.07653268+6.86308978e-02j, -0.18769106+2.15711501e-01j, 0.16136537-4.42590061e-02j, -0.26360596+1.04686372e-01j, -0.09155045-8.77382640e-02j, -0.09151231+4.28425508e-02j, - -0.06373803+3.71389234e-03j, 0.12982765+1.93272289e-01j, -0.00676779+9.13731987e-02j, -0.15669531-1.03446811e-01j, 0.13876435+1.73790050e-01j, 0.03724986-6.80542715e-02j, 0.13536485+2.06818477e-02j, 0.2134622 +7.76124343e-02j, -0.21930729-1.35324670e-02j, -0.15870289-1.47418944e-01j, -0.10525782-3.21051509e-02j, 0.02651126-7.35636015e-02j, 0.21299852-4.88944015e-02j, 0.1520081 +1.18419448e-01j, 0.02837817-1.66734491e-02j, -0.05583337+7.15315919e-02j, 0.00827433-9.71346050e-02j, -0.10828369+1.50029916e-01j, -0.05569338+1.56736408e-01j, -0.10498402-3.01603733e-02j, 0.01972677-3.28801228e-02j, -0.02545466-4.69757450e-02j, 0.23575113-6.13720081e-02j, -0.29064723+8.84431226e-02j, -0.07433566+3.29740230e-02j, 0.07812021-1.02151861e-01j, -0.0425074 +1.72860999e-01j, 0.18038703-4.84824047e-02j, 0.06760615-1.08861841e-01j, 0.25746276+7.60469955e-02j, -0.01916844-4.17126464e-02j, 0.05801 +5.47708435e-02j, -0.01089018+7.64307991e-02j, -0.01047013+4.46021957e-01j, - 0.1335352 -7.65699052e-02j, 0.04482942-4.66701163e-02j, 0.078575 -6.73430309e-02j, -0.16287533+3.68253915e-02j, -0.00326996+8.45469473e-03j, -0.30822025+1.56452958e-01j, 0.05607748+2.71034262e-02j, -0.15156807-3.99754306e-02j, -0.11732098-2.62196417e-01j, -0.12910811+1.37840055e-01j, -0.11324172+4.51349322e-02j, -0.07238787+1.95625832e-01j, 0.20782018-1.53159222e-01j, -0.0029301 -2.05737302e-02j, -0.06307179-7.76953233e-02j, 0.09180174-3.94918551e-02j, 0.09905065+1.64050652e-01j, 0.02119278-1.28555941e-01j, -0.13011198+7.50039022e-02j, 0.00364899+1.56741679e-01j, 0.12967172-4.59481445e-02j, 0.04371742-9.22641848e-02j, 0.01217403+1.42468441e-01j, -0.03321802-6.06556050e-02j, -0.33791815+2.19614336e-02j, -0.02079545-1.62357371e-01j, -0.06115126-1.31463603e-01j, -0.0408845 -1.17685338e-01j, -0.00096192-1.80065774e-04j, 0.11813011+6.17214729e-03j, 0.00417459-8.29797298e-02j, 0.08729658+2.67707592e-01j, -0.01118896-8.32911057e-02j, 0.03707148-5.83134279e-02j, - -0.12156735+2.64457587e-01j, -0.02989997-5.84706432e-02j, 0.03302162-6.01695667e-02j, 0.05437034-9.13677674e-02j, 0.10179674+1.40846743e-01j, -0.16635965+1.27949594e-01j, 0.1454272 -1.12363084e-01j, -0.11077774-1.22746452e-01j, -0.00185723-4.56720198e-02j, 0.02600582-8.89150489e-02j, -0.227494 -6.67592408e-02j, 0.08533135-1.88751082e-01j, -0.22714608+1.14661652e-01j, -0.02690036-1.30865882e-01j, -0.10121037-6.45046877e-02j, 0.01443838-2.37190078e-02j, -0.02303954-1.61468225e-01j, 0.06055609-2.63250332e-01j, 0.13332186+2.20700929e-01j, -0.02063736+2.65142722e-01j, 0.08332522+5.90342871e-03j, 0.1721038 -2.09054691e-01j, -0.15490146-9.27267743e-02j, 0.00453307-3.86153521e-02j, -0.02048122+3.02503499e-01j, 0.01458757-4.21067447e-02j, 0.32754022-3.88409256e-03j, 0.13811814-1.38612894e-01j, -0.12084009+3.73954159e-02j, 0.07102218-2.06344326e-02j, 0.11515796+1.13122542e-01j, -0.08863491-1.39456440e-01j, -0.17917237-4.99661020e-02j, 0.04442141+1.63664359e-01j, - 0.13732508-1.50992137e-01j, -0.05139775+8.97494329e-02j, 0.08732507+1.98929252e-01j, 0.05072904-2.99507910e-02j, 0.07108474+1.65205788e-02j, 0.0194683 -8.78868281e-02j, 0.09380987-4.44516495e-02j, 0.17168417+3.91109903e-02j, -0.04639245+2.60582960e-01j, 0.05875205+2.56753485e-01j, -0.07728994-3.17930589e-02j, 0.0452049 -1.76709840e-02j, 0.00134074-7.72090938e-02j, 0.20413611-1.94606554e-02j, -0.01910068+1.39711619e-01j, 0.0356499 +1.37434345e-01j, 0.30794216-1.09704366e-01j, 0.05284195-5.64409889e-02j, -0.08984104+6.94748250e-02j, 0.02163001+1.03288462e-01j, 0.03915384-9.81971938e-02j, -0.06670679+5.81276525e-02j, -0.11508668+9.47872135e-02j, -0.0354503 -3.13816097e-01j, -0.10991197+8.71705953e-02j, 0.06963248-5.65881100e-03j, 0.06577731-1.54696868e-01j, 0.15321403-6.74125684e-03j, 0.08071347+4.48458418e-01j, 0.03395331+1.27262600e-01j, 0.04183345+4.00904175e-03j, -0.01187089-2.21527903e-02j, -0.01851325-1.47271834e-02j, -0.23601169-8.54312072e-02j, - 0.11541862-1.04823473e-01j, -0.11268181-3.21825004e-02j, -0.09001661-1.37514659e-01j, -0.11748964-2.64871993e-02j, -0.0523941 -4.95790343e-02j, 0.1465224 -1.03971485e-01j, 0.18034942+7.79615744e-02j, 0.0936947 -2.22585205e-01j, 0.16751339+8.86578713e-02j, 0.19444547+1.21567778e-02j, 0.04771682+2.78729300e-02j, 0.19635398+9.50820346e-02j, 0.05185621+1.76230346e-01j, 0.07939533-2.18013091e-02j, -0.03596743-9.94674395e-03j, -0.28690236+7.06630196e-02j, -0.01620677+1.20756724e-01j, -0.11835929+3.00001593e-02j, -0.09989775+8.70560634e-02j, 0.0627832 -9.47387901e-02j, -0.09171898+2.82637561e-02j, 0.23849114+8.96858167e-02j, -0.24665889+2.03994686e-02j, 0.22245419-4.30604068e-04j, -0.0820849 -2.36258787e-01j, -0.11703521-6.52100265e-02j, 0.05282283-4.48185202e-02j, 0.02544553-7.56696642e-02j, 0.0320835 +2.09744844e-01j, 0.02707166+2.74207623e-01j, 0.14071592+1.51271647e-02j, 0.0599873 -2.12130726e-02j, -0.1323865 +1.32285712e-01j, -0.0634149 -1.88468438e-01j, - -0.25236535-9.40009628e-02j, 0.05804886-1.24296266e-02j, 0.01463484-1.92411356e-01j, 0.02901968-1.95938408e-01j, 0.05900759-5.70542063e-02j, 0.0039289 +1.79168231e-01j, 0.21463779+6.06068544e-02j, 0.02601461+3.44313390e-02j, -0.06804777-1.37777019e-01j, -0.04134655-7.71930937e-02j, 0.26993183+7.04042029e-03j, -0.22478871-1.11219112e-01j, 0.02216198+8.72296592e-03j, 0.00900783-1.81402113e-01j, -0.12568783+5.40727822e-02j, 0.20728804+1.49611785e-01j, -0.1540311 -1.04748775e-01j, 0.11524429+1.78469618e-01j, -0.01784981-2.05987600e-01j, -0.04310959+6.72693611e-02j, 0.09204926+1.24870358e-01j, 0.23044143-1.67687891e-01j, -0.04829998+6.96651901e-03j, -0.09200799-1.69548082e-01j, -0.08599541-5.05360845e-02j, 0.05605567-1.23777989e-02j, 0.09183321+2.03716921e-01j, 0.06046671+1.88609777e-01j, -0.35443088-2.50139768e-01j, -0.10418443+1.53252364e-01j, 0.02878444+4.48922173e-02j, -0.07655359-8.92321321e-03j, 0.06322981-5.98952645e-03j, -0.05895737-7.06273994e-02j, - 0.045825 +3.45008534e-02j, -0.0356972 +7.58719989e-03j, -0.18135564+2.31658738e-02j, -0.11367649-1.11799943e-01j, -0.02278714-7.26386363e-03j, 0.00527786+1.70825935e-01j, 0.08659992-2.45702546e-02j, -0.16132867-1.40266073e-01j, -0.16275372+1.57528240e-01j, 0.10098732-4.90008453e-02j, -0.14020292-1.26389028e-01j, -0.13387933-1.77044519e-01j, 0.15233209+1.56396670e-01j, -0.01186549+1.66770551e-01j, -0.05911019-9.37506242e-02j, -0.11032036+2.22422316e-01j, -0.32768772+1.23945218e-01j, 0.11693884+1.01153011e-01j, 0.06380873+2.73797332e-02j, -0.15242003-1.78297868e-01j, 0.08576241-9.81537390e-02j, -0.05483774+2.39049552e-02j, 0.08818984-4.80048981e-02j, 0.13795202+3.39576952e-02j, 0.15420435+1.04809134e-01j, -0.1475717 -8.35910546e-02j, 0.25587669-9.78491595e-02j, 0.12582976+1.06377618e-01j, -0.04885733+5.85877129e-02j, 0.02768058-8.97097222e-02j, -0.09572117-3.14848747e-03j, -0.09107239-1.48042190e-01j, 0.02633147+1.28206292e-02j, -0.00231722+2.40935942e-01j, - 0.08505098+4.43364674e-02j, 0.0454237 -1.20532432e-01j, -0.17493652+1.27595262e-01j, 0.01816818-1.93108598e-01j, -0.17931339+1.06943524e-01j, -0.10671963+1.39014451e-05j, 0.11498691+1.93066834e-02j, 0.23000235+1.04393237e-01j, -0.18572715-1.37399401e-01j, 0.13220069-3.09402657e-02j, 0.02990116+1.12157118e-02j, -0.02942283-1.36235506e-03j, -0.13275055-2.01044204e-02j, -0.05513657-1.15044942e-01j, -0.07453253+1.24162429e-01j, 0.19348874+1.65304419e-01j, -0.01684765-8.28080868e-02j, -0.06982499+2.38660768e-02j, -0.29603023-1.04892178e-01j, 0.31520605-5.80965984e-02j, -0.16452607-3.29924630e-02j, 0.13918688+1.34255787e-01j, 0.1461848 -5.91517992e-02j, 0.05246915+2.47209477e-02j, 0.09600898+4.48951448e-02j, -0.03040775+2.25636252e-01j, -0.03104364-1.03378328e-02j, 0.12457642-1.13129265e-02j, 0.25722645-1.07390381e-01j, 0.12453095-1.46405362e-01j, -0.20675192+5.37923723e-02j, -0.08581718-3.76855478e-02j, 0.12881044-7.30139037e-02j, 0.0330913 -1.45171188e-02j, - 0.04964024-2.63320298e-01j, -0.06851158+3.25029578e-01j, -0.06736655+3.31741867e-02j, 0.10672767-1.33657818e-02j, -0.03911025+2.71696686e-03j, 0.18376597-2.21089267e-01j, -0.02949093-2.24178456e-02j, -0.07672718+8.63619859e-02j, 0.09011718+1.34863000e-01j, -0.03532004+2.01221708e-02j, -0.0175005 +6.62198244e-02j, 0.17146927+8.06205588e-02j, -0.09194709+3.45310559e-02j, 0.05919149+8.90830332e-03j, -0.03890834+6.41903709e-02j, -0.13501504-3.99845589e-02j, -0.10279042+1.03768681e-01j, -0.05259741-5.87714457e-02j, -0.11719418-2.08936502e-02j, 0.09836174-5.44608131e-02j, -0.22877539+2.08355637e-01j, 0.04941838-9.51260734e-02j, -0.06203396+2.28604981e-02j, 0.12098849-1.44576480e-02j, -0.08451115-1.43356466e-01j, 0.15635672-1.46530151e-02j, -0.20437704-3.79884112e-02j, -0.19636121-1.71501698e-02j, 0.07255917-2.20625252e-01j, -0.28061719+7.71279703e-02j, -0.02084913-1.12045005e-01j, 0.04322484+8.40757110e-03j, 0.06080093-9.41283647e-03j, -0.08052508-4.49212849e-03j, - 0.35296504-9.29569583e-02j, 0.30139399+2.02446885e-01j, -0.1043556 -1.29299775e-01j, 0.19156652+1.16499747e-02j, 0.20865974-1.46798336e-01j, -0.13729311-1.50569340e-02j, 0.02152623+1.61941611e-01j, 0.05963193-1.30770158e-01j, 0.06462617-1.66387108e-01j, -0.11403091-8.19783097e-02j, -0.17890047-3.87091987e-02j, 0.05041442+2.34797464e-02j, 0.33716094-2.18366246e-01j, 0.04749898+7.95121529e-02j, -0.14276611+5.91160893e-03j, 0.0727171 -6.38166930e-02j, -0.03268621+7.25536789e-02j, -0.00994355-5.45862875e-02j, -0.10977213+1.11554079e-01j, 0.01783962-2.78702484e-01j, -0.00306595+2.65697928e-02j, 0.1392672 -1.06298955e-01j, -0.10153158-8.24641251e-02j, -0.2693985 +6.47512729e-02j, 0.03236581+4.07523974e-02j, -0.14424473+2.51731413e-01j, -0.01873542-2.47536237e-02j, -0.01356796-8.16033886e-02j, -0.07272296-1.47884513e-01j, 0.01967111-1.46373935e-01j, 0.23073323-8.09684340e-02j, 0.14428689+1.18128043e-01j, -0.06420706+1.47110727e-01j, -0.014288 -1.01535529e-01j, - 0.05505723+1.85830802e-02j, 0.00835002+2.95374366e-02j, 0.00710951+4.40654128e-02j, 0.17926977-3.38549657e-01j] - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.gate(u1, [0, 1, 2, 3, 4]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - - self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[32]), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[64]), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[96]), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[128]), helper_prob(state.get(to_bitstring(4, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[160]), helper_prob(state.get(to_bitstring(5, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[192]), helper_prob(state.get(to_bitstring(6, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[224]), helper_prob(state.get(to_bitstring(7, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[256]), helper_prob(state.get(to_bitstring(8, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[288]), helper_prob(state.get(to_bitstring(9, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[320]), helper_prob(state.get(to_bitstring(10, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[352]), helper_prob(state.get(to_bitstring(11, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[384]), helper_prob(state.get(to_bitstring(12, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[416]), helper_prob(state.get(to_bitstring(13, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[448]), helper_prob(state.get(to_bitstring(14, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[480]), helper_prob(state.get(to_bitstring(15, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[512]), helper_prob(state.get(to_bitstring(16, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[544]), helper_prob(state.get(to_bitstring(17, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[576]), helper_prob(state.get(to_bitstring(18, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[608]), helper_prob(state.get(to_bitstring(19, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[640]), helper_prob(state.get(to_bitstring(20, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[672]), helper_prob(state.get(to_bitstring(21, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[704]), helper_prob(state.get(to_bitstring(22, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[736]), helper_prob(state.get(to_bitstring(23, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[768]), helper_prob(state.get(to_bitstring(24, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[800]), helper_prob(state.get(to_bitstring(25, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[832]), helper_prob(state.get(to_bitstring(26, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[864]), helper_prob(state.get(to_bitstring(27, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[896]), helper_prob(state.get(to_bitstring(28, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[928]), helper_prob(state.get(to_bitstring(29, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[960]), helper_prob(state.get(to_bitstring(30, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[992]), helper_prob(state.get(to_bitstring(31, size=platform_qubits), 0.)), 5) - - - def test_usingqx_fullyentangled_5qubit_10011(self): - num_qubits = 5 - p = ql.Program('test_usingqxfullentangled_5qubit_10011', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [ 0.31869031-9.28734622e-02j, 0.38980148+2.14592427e-01j, 0.20279154-1.56580826e-01j, 0.00210273-2.83970875e-01j, -0.04010672-9.26812940e-02j, 0.15747049+6.08283291e-02j, -0.05274772-6.45225841e-02j, 0.05909439-3.23496026e-02j, 0.07868009+6.77298732e-02j, 0.11290142+2.48468763e-02j, 0.10092033-7.03646679e-02j, -0.03557972-3.39117261e-02j, 0.02241562+1.02714684e-02j, -0.04088796-1.12143173e-01j, -0.00144015+1.83925572e-02j, -0.1257948 -1.15394681e-01j, 0.13531631-1.84271421e-01j, 0.11293592-1.44170392e-01j, -0.06985893-1.36606289e-01j, -0.08924113-6.35923942e-02j, 0.19393965-6.35656579e-02j, -0.02153233-2.76955143e-01j, -0.12094999+1.05716669e-01j, -0.00624879+1.27471575e-01j, -0.13608981-1.22140261e-01j, -0.08243959-1.72734247e-02j, 0.06562052+1.12197102e-01j, -0.01102025-1.53811069e-01j, 0.13576338-8.95540026e-02j, 0.05730484-5.62973657e-02j, -0.08835493-4.13159024e-02j, -0.04533295+3.70144188e-02j, 0.04116657+1.58298973e-01j, 0.22270976-1.18654603e-01j, - 0.09219815+8.41433858e-02j, -0.0227499 +2.33343627e-01j, -0.13334752-6.98059663e-02j, -0.07967301-6.54413909e-02j, -0.09158972-7.03627564e-02j, -0.02332636-1.58060290e-02j, 0.23523954-3.48258461e-02j, 0.21329683+6.37364245e-02j, 0.25821394+1.30648709e-03j, -0.1118809 -1.95903237e-01j, -0.07887212-8.81857936e-02j, 0.047632 +9.40535593e-02j, -0.11726632+5.65815234e-02j, 0.08229469-4.38047420e-02j, 0.03117762+1.08469602e-01j, 0.16064616-1.30734886e-01j, 0.22181279-3.31211823e-02j, 0.07309884-2.01468425e-01j, -0.28437382+6.38292807e-02j, -0.23661479+1.17105208e-01j, -0.10436123-5.56443645e-02j, 0.20587544+1.99848797e-02j, 0.20705551+1.75496198e-02j, 0.01791984-8.31956939e-02j, 0.09737992+6.64713628e-03j, 0.0617566 -7.11998970e-02j, 0.03073603-7.25651496e-02j, -0.12056479-1.55358931e-01j, -0.09661589+4.90232280e-03j, 0.03110935-1.72748422e-01j, 0.01473304+3.62629583e-01j, 0.11031868-3.67435519e-03j, 0.04301239-1.64601498e-01j, -0.16432353+7.52258615e-02j, - -0.00648176+6.66215752e-02j, 0.1257427 -3.71759618e-02j, -0.07793634-7.01586304e-02j, 0.0571156 +2.67410653e-01j, -0.00880782+2.09982981e-01j, -0.04961517-6.86953748e-02j, -0.15766986-1.12761472e-01j, -0.07076146-3.12372790e-02j, -0.08715236+9.29279186e-02j, 0.03843817+1.13545744e-01j, -0.10838483-1.19949631e-02j, -0.06342622+1.73231077e-01j, 0.23221532-4.28875040e-02j, 0.16514567-4.90633428e-02j, -0.0109654 +6.37891447e-02j, 0.02171279+5.89435085e-02j, 0.0199925 -2.96609865e-01j, 0.16702912+8.82996853e-02j, 0.19820571+5.01863737e-02j, -0.01237253-1.21196566e-01j, 0.11042294-2.16811518e-01j, -0.01004066-2.36556101e-01j, -0.1286729 -4.01294536e-03j, -0.11254789+5.56025311e-02j, -0.18328088-1.46524167e-02j, -0.13640243-3.71920766e-02j, -0.03793125+9.57786229e-02j, 0.07600542+1.53449546e-01j, -0.12371969+2.19599454e-01j, 0.18106889-3.10905810e-02j, -0.12698597+7.45431556e-02j, 0.02402161-1.66514384e-02j, -0.1431313 +4.63501164e-02j, 0.13656065-8.55748891e-02j, - -0.2085481 -3.99831111e-02j, -0.05354994+8.14822771e-02j, 0.22188566+8.04753102e-02j, -0.09702996-1.54653045e-01j, -0.1018562 -1.01790676e-01j, -0.00335582+2.52475965e-01j, -0.04858119-1.52409323e-01j, 0.09335149-3.90325714e-02j, 0.08277598-4.08970043e-02j, 0.08119049+5.11051755e-02j, -0.01223217+6.17029648e-04j, -0.15137858-9.30742653e-03j, 0.1064706 +3.35870801e-02j, -0.04014048+1.33388615e-01j, -0.04315986+1.74367473e-01j, -0.04774817-9.82134162e-02j, -0.08203436+7.74038565e-02j, -0.2339137 +1.62306949e-01j, 0.11791971+2.08966161e-01j, -0.07867189-4.18549851e-02j, -0.17291904+9.47505092e-02j, 0.23630015-3.07786925e-01j, -0.09104365-1.33230919e-01j, 0.07679465+1.45726380e-01j, 0.09397243-9.26081447e-02j, -0.16092509+7.38633830e-02j, -0.02289017+1.59777790e-01j, 0.12053722+6.55620680e-02j, 0.12646833+1.04585433e-01j, 0.0264461 +1.92009889e-01j, 0.28749442+1.11327480e-01j, 0.15837267+6.12698488e-02j, 0.18181681-5.61278874e-02j, 0.07897084-1.17114924e-01j, - 0.19787494-1.67863968e-01j, 0.03852499-4.21534504e-02j, -0.14091989-1.27321872e-01j, -0.01747868-2.27419946e-01j, -0.02073576-6.24641146e-02j, -0.14241142+2.28697604e-02j, 0.15468346+2.08734157e-02j, 0.04505001-9.46333157e-02j, -0.09148317-2.26152985e-01j, 0.08577989+2.30863031e-01j, -0.08152502-8.74340592e-02j, -0.06465018-7.35108360e-02j, -0.21595512-8.66695180e-03j, 0.03304541-1.91886499e-01j, 0.04448112+3.67289455e-02j, 0.01969849-5.34777195e-02j, -0.03209367+3.02797601e-02j, 0.17389718+1.19098672e-01j, -0.10192559-3.02362398e-01j, -0.10224653-8.09241417e-02j, -0.12601597-6.86631211e-02j, 0.11275009+1.40915100e-01j, 0.03214418+1.48701215e-01j, -0.11571373+3.57083353e-02j, 0.03222285-5.19221441e-02j, -0.00250593+7.32186819e-02j, -0.15549573+1.77404851e-01j, 0.08568275+1.02973155e-01j, 0.11314133-2.13171498e-01j, 0.22748546-5.69951563e-02j, 0.14929197+1.31715414e-01j, -0.16301646+3.65045553e-03j, 0.13494125+2.31602145e-01j, 0.24267648-1.77780817e-01j, - -0.00736974+7.72680290e-02j, -0.04867011+1.22605525e-01j, 0.05051748+8.06196677e-02j, -0.01749415+6.33486594e-02j, 0.06408343-4.51492484e-02j, -0.02543799-1.33253676e-01j, -0.05785745-4.71803669e-02j, -0.24358675-1.18083337e-02j, 0.00061111-5.96573111e-03j, 0.17487681-8.55625475e-02j, 0.13181372-5.47918839e-02j, -0.14072394+1.08475923e-01j, 0.05919593+1.78284217e-01j, -0.00292253-2.17168452e-02j, 0.19948189-1.95177980e-01j, -0.11146926-1.55684600e-01j, 0.02692391-9.18282632e-02j, -0.03804582-7.62499524e-02j, 0.18562866+1.41900953e-01j, 0.15468899+7.03401694e-03j, 0.10617502+2.96183301e-01j, 0.12124371+1.42279327e-02j, -0.12974516+1.87600027e-01j, -0.23270386+1.59618723e-01j, -0.14928652-8.27397154e-02j, 0.06670844+6.35681954e-02j, 0.03466266+1.89244901e-01j, -0.00961646-1.02903972e-01j, 0.19899344-2.38199195e-01j, -0.16594523-4.43067845e-02j, 0.27258801-7.49570862e-02j, 0.08182091+2.03334342e-02j, -0.02454051-4.82668158e-02j, -0.08557127+3.04552132e-02j, - 0.01303575+8.88057122e-02j, 0.13253621+5.05712004e-02j, 0.07763894+1.13841327e-01j, -0.28730914-4.49839630e-02j, 0.07031891-3.38973984e-03j, -0.04794523-1.67972335e-01j, -0.18102171+2.08760542e-01j, -0.08845631-9.70771934e-02j, 0.03546718+4.80846877e-02j, -0.08866794-5.19207245e-02j, -0.15099182-9.77070105e-02j, -0.05473901+2.33013978e-01j, -0.04645356-8.89489153e-02j, 0.07548625+1.80517821e-01j, 0.16840691+2.15268260e-01j, -0.09962074-7.35772706e-03j, -0.10104245+1.74017433e-02j, -0.09302095-1.10945928e-01j, -0.035157 +2.50873519e-02j, 0.10622507+1.29398421e-01j, -0.20965829-4.55862887e-02j, 0.05220909+6.66834897e-02j, -0.09672108+1.09403436e-01j, 0.12697788-6.19212188e-02j, 0.05729917+1.44378294e-01j, -0.15808366-3.82581632e-02j, 0.10716098-4.62942406e-02j, 0.24961573+1.32840816e-01j, 0.0627808 +2.39056706e-02j, 0.18311487+7.98582936e-03j, 0.02661541+7.40701198e-02j, 0.04699528+1.88767961e-01j, 0.04750332-2.25995642e-02j, 0.07193907+5.68042859e-02j, - -0.02763382-3.43370436e-02j, 0.11205088-1.98370084e-02j, -0.11424545+1.14269285e-03j, 0.06885854-2.09915302e-01j, -0.05625496-2.88701666e-01j, -0.08183393+2.31774294e-01j, -0.09301037-4.03842722e-02j, -0.06069309+2.57502142e-02j, -0.18634877+9.85377377e-02j, 0.01474395+9.22414287e-02j, 0.04147054-1.74520016e-01j, 0.06794102-1.59508183e-01j, -0.13292245-5.38490513e-02j, -0.18753702+2.82751900e-01j, 0.00899866-2.80951474e-01j, 0.20377748+8.19207845e-02j, -0.14028603-1.39624056e-01j, 0.10741114+2.60308736e-02j, -0.22833573+6.02730469e-02j, 0.16071761-1.25615817e-01j, 0.08060865-5.81044643e-03j, 0.16141495-4.86994019e-02j, 0.11263654-1.87107794e-02j, 0.06859488-1.90280093e-01j, 0.10733862+4.45380867e-02j, -0.11489398-2.10578670e-01j, -0.0864833 -1.73958604e-01j, 0.12293904-1.50703768e-01j, -0.00629652+2.98133822e-02j, 0.16452648+7.76415767e-02j, 0.16219009+2.46017766e-01j, -0.04582374-1.16806045e-01j, 0.15109013+9.45671154e-03j, 0.04773975-1.54745106e-01j, - 0.21822796-1.87975523e-03j, 0.16596711-1.31539539e-01j, 0.25621724-4.31460990e-02j, 0.23071937+1.38086347e-01j, 0.10615413-1.24941186e-01j, 0.00343902+5.79927212e-02j, 0.10569282-2.64952183e-01j, -0.13601637+5.39259774e-02j, -0.13182901+9.15307749e-02j, 0.03524551-1.35956850e-01j, 0.0957622 -1.71837228e-02j, -0.03707841-5.40514827e-02j, -0.05729147-7.33164458e-02j, -0.18631267+1.00759871e-01j, -0.02434746-2.22824245e-02j, -0.02570765-3.90074186e-02j, 0.17946901+1.86288095e-02j, 0.07742897+3.19064602e-02j, -0.17538437+2.18666227e-01j, 0.10029635-8.92554711e-03j, -0.13379504-1.03683797e-02j, -0.11115363-4.48983441e-02j, 0.00163172-2.05325390e-02j, 0.02753729-1.28591197e-01j, 0.01933548+2.37393316e-01j, 0.07102201-1.19729329e-01j, -0.07517562+7.47947883e-02j, -0.03383077-1.23796732e-01j, -0.05575669-2.97673975e-02j, -0.04860924+1.02986531e-01j, 0.11384071+2.36429953e-01j, -0.26355793+1.30580300e-02j, -0.2665541 +6.72995742e-02j, -0.04663019-5.64857364e-03j, - 0.15703188+2.25734925e-02j, -0.02611337-4.94904084e-03j, 0.31897764+7.13870567e-02j, 0.15501272-1.48107261e-01j, 0.18034006-2.37497106e-01j, 0.21350438-8.08313917e-02j, 0.0620688 +5.98457145e-02j, -0.04996277+1.09069384e-02j, -0.09282843-5.59942293e-02j, -0.05363359+4.83839918e-02j, -0.20946404-1.85419524e-01j, -0.05481421+8.78420662e-02j, -0.19261214-1.04875021e-01j, -0.00083685-2.70091261e-02j, -0.17618069+8.47803615e-02j, 0.16055652+5.98821538e-03j, -0.0635621 +8.16228775e-02j, -0.22507829-4.14268948e-02j, -0.00791737+7.40481825e-02j, 0.19970347-1.15972939e-01j, -0.08619572+1.19678540e-01j, -0.184931 -1.13524848e-01j, 0.04824348-5.85668978e-02j, -0.22446284+1.11472258e-02j, 0.09629746-1.88788542e-01j, -0.18228537-3.89615785e-04j, 0.09084756+4.78058679e-02j, -0.00889583-1.74554680e-01j, -0.07447697-4.48823321e-02j, -0.05076077-6.24206002e-02j, -0.14050658+8.38982646e-02j, 0.07428934-6.30440232e-02j, 0.05701074-1.00819168e-01j, 0.07009481+8.11789378e-02j, - -0.01155395+2.46650660e-01j, 0.25264038-1.98419236e-01j, -0.09155521-2.79616998e-02j, 0.06750545-1.52831769e-01j, 0.1068504 -1.78545409e-01j, -0.06203486+2.86380485e-02j, 0.23067545-1.23638547e-01j, -0.02397582+2.15643846e-01j, 0.01810979+1.08067552e-01j, 0.09130261-4.68850866e-02j, 0.13093158-1.51875212e-01j, 0.25207024+5.80216347e-02j, 0.02600999-1.27799785e-01j, 0.03509714-5.46256940e-02j, 0.04362407-3.07563727e-02j, 0.12488249+6.70881126e-02j, 0.05539679+1.15790184e-01j, 0.23107124-9.66168589e-02j, -0.09977799-9.88045601e-02j, -0.05633534+2.79762650e-01j, -0.02304281-2.42282613e-02j, 0.1276518 -2.32550502e-02j, 0.25634814-3.02429796e-02j, 0.30827737-2.19288542e-01j, -0.02512791+2.13783374e-01j, 0.15453741-7.04163688e-02j, -0.21441715+2.05959415e-01j, -0.02827968+4.71161636e-02j, -0.03837343+6.70595235e-02j, -0.07854483-3.12796395e-02j, -0.03615927+1.10733671e-01j, 0.21779074-1.39489256e-01j, 0.06619192+5.38352432e-02j, -0.0680216 -1.05456770e-01j, - -0.10316128+1.32947183e-01j, -0.06345699-1.85555087e-01j, -0.00893067+1.52852423e-01j, 0.03135864+1.10423220e-01j, -0.182351 +2.77954961e-02j, -0.09252137+1.09061091e-01j, -0.0797695 +1.15176285e-02j, 0.05051009+2.57152535e-01j, 0.09344185-1.12906975e-01j, 0.04587659+8.90786692e-02j, -0.02471718+4.53344925e-02j, -0.08880236+3.62673481e-02j, -0.05981018+9.78912466e-02j, -0.00118743-5.07702805e-02j, -0.08119522+5.16043940e-02j, 0.11854883+9.79110177e-02j, 0.28543526-8.57540624e-02j, 0.28069514+2.00242562e-01j, -0.01036913-1.12897546e-01j, -0.08470073+1.91009156e-02j, 0.01428585+7.92620224e-02j, -0.15567322-4.85322282e-02j, 0.14203257-2.97248067e-01j, 0.15075682-1.33294241e-01j, 0.08107944-6.10561974e-02j, 0.07558358-3.29486035e-02j, -0.04042877-2.49142675e-02j, 0.05557881-1.93956804e-01j, -0.00589446+9.44678255e-02j, 0.1653676 -4.08479951e-02j, 0.14382039+1.57269491e-02j, -0.22311804-8.79699173e-02j, 0.09825566+1.52084444e-02j, 0.00938452-3.15649024e-01j, - -0.03982978+1.22637508e-01j, -0.15670677-1.93426126e-01j, 0.22741559-4.39643322e-02j, -0.13362661-9.94353174e-02j, -0.09445278+4.93195562e-02j, -0.04684833-8.59308253e-02j, 0.08890091-1.16876390e-01j, -0.18726614+7.50813913e-02j, -0.01806267-2.00321404e-02j, 0.09338316-1.69711164e-01j, -0.03114173+1.43744729e-01j, -0.01515641+7.72217128e-02j, 0.21301431+5.92330407e-02j, 0.12250555+1.16784140e-01j, 0.0492589 +1.82225369e-01j, 0.09296806+1.58772507e-02j, -0.06700279+7.86869873e-02j, -0.02389099-5.36170682e-02j, 0.00545649-1.25491880e-03j, 0.09228983+2.64561438e-01j, -0.08125859-3.27415023e-02j, -0.03769576-2.64763488e-01j, 0.0914594 +1.90133579e-01j, -0.27352411+6.32203214e-02j, -0.00087467-8.61094525e-02j, 0.13735927+8.73538830e-03j, -0.08484748+1.68213884e-01j, -0.07040327-1.76254392e-01j, -0.08363638-8.30902369e-02j, 0.14643814+6.63711322e-02j, -0.31659998-1.04317904e-01j, 0.07830602+2.93183609e-02j, 0.11041879+1.50347028e-01j, -0.00433818-1.72946523e-01j, - -0.15422074+9.38342826e-02j, -0.14194574+3.64105744e-02j, 0.06297505+7.88548664e-02j, 0.01106598-2.65402837e-01j, 0.07164956-8.12953528e-02j, -0.12514039-1.84403896e-01j, -0.17295559+3.58171829e-02j, -0.03655755-7.10559195e-02j, -0.03821694-1.10973040e-01j, 0.18546141+1.10662839e-01j, -0.10195195+1.32367694e-01j, -0.05016084+2.78628720e-02j, -0.19079393+1.40041256e-02j, 0.07878861-3.38112621e-02j, 0.13730204+1.52897765e-01j, 0.11815899+3.49910958e-02j, -0.02648579-1.03280312e-01j, 0.11970226-2.50844123e-01j, 0.10406627-9.12689026e-02j, 0.07247411-2.51491332e-01j, 0.06550999-2.94078974e-01j, -0.12079469-5.00355065e-02j, 0.06000345-1.02467349e-01j, 0.08823557+3.66136284e-02j, 0.02291526+3.63437115e-02j, -0.07124433+2.31676270e-01j, 0.17493588+5.98421039e-02j, -0.17824122-1.97944096e-02j, -0.00491994-9.10500757e-02j, 0.19633245+6.47815099e-02j, -0.03770238-7.48581318e-02j, -0.18402244+9.04322714e-02j, -0.2842845 -1.40285725e-01j, 0.00138785+1.08042021e-01j, - 0.16088797+2.75183648e-01j, -0.0865634 -7.36993417e-02j, 0.05178655+5.29576072e-02j, -0.05123872-1.29090313e-02j, -0.03079395-1.69557846e-01j, 0.23219467-7.71729365e-03j, -0.01135984-6.49120093e-02j, 0.08717993-9.71885487e-02j, -0.02043387+1.16518568e-01j, -0.08256357+1.23302259e-02j, 0.13742387-2.00583302e-01j, 0.11087765+2.22213806e-02j, 0.10703254+3.53681589e-02j, -0.04998617+7.13667998e-02j, -0.2463513 -2.30198030e-01j, 0.09831487+1.92709068e-01j, 0.10999549+1.28740664e-01j, -0.04056669+9.08016920e-02j, -0.03342728-9.92407179e-02j, 0.09352449-4.93911914e-02j, -0.11841153-8.25481366e-02j, -0.0263205 +1.91245810e-01j, -0.15521225-6.80613837e-02j, 0.18223827-2.68908129e-01j, 0.0411945 +1.12072453e-01j, -0.02954085+6.34315408e-02j, -0.01019486-1.24389083e-01j, 0.19174201-7.05812742e-02j, 0.19351232+1.42610666e-02j, 0.12937332-1.45006522e-01j, 0.01111355+1.11974478e-01j, 0.25163849+7.58955475e-02j, 0.06967535+1.51710939e-01j, -0.26064587+5.85797495e-02j, - -0.05364486-8.37537594e-02j, 0.02473011+1.57624180e-01j, 0.0788524 +4.24067733e-02j, -0.05353458-3.59527188e-02j, 0.24630053-3.09146961e-01j, 0.12673895+2.54501080e-02j, 0.13328446+1.27420821e-01j, -0.03311185+8.64376474e-02j, -0.10126181-3.33404906e-02j, 0.05819512-2.42452607e-01j, 0.12966928+1.92345459e-01j, -0.10237172+7.87217786e-02j, -0.12008 +8.02686485e-02j, 0.11309599+3.47582961e-02j, 0.16921731-6.49645604e-02j, 0.10847358+1.32814258e-01j, 0.09620142+8.29342007e-02j, -0.03836254+1.18815716e-01j, 0.10334279-1.21404737e-02j, -0.19366239-5.73423731e-02j, 0.11445103-7.69154143e-02j, 0.10345336+3.42165082e-02j, 0.0870257 +5.06977361e-02j, -0.0262899 +4.49013808e-02j, -0.0367388 +1.36360059e-02j, 0.00976608-1.86860241e-01j, 0.15386709+1.46930831e-01j, 0.11249562+2.57278918e-02j, 0.08496388-1.11776874e-01j, -0.07162906-1.41500632e-02j, 0.076649 -2.72671417e-01j, 0.12029408-2.43316647e-01j, 0.29672048-6.39702972e-02j, 0.1939962 -1.55753156e-02j, - 0.08677801+1.96162231e-01j, 0.1237203 -9.61956522e-02j, -0.16119964+3.89474786e-02j, 0.09207276-2.54823411e-01j, 0.03475803-5.50657361e-02j, -0.21263069-7.05923500e-02j, -0.06092331+4.49331302e-02j, -0.02461632+3.39504695e-02j, 0.0345771 +2.39801010e-01j, 0.00891307+1.12739196e-01j, 0.13060822-1.11694609e-01j, 0.09803224+1.73134288e-01j, -0.07234639+1.28840723e-02j, 0.11471256+3.77081748e-02j, 0.26422031-1.58104940e-01j, 0.02654836-1.38859272e-01j, -0.04278432-1.46473478e-02j, 0.28242235-5.27977137e-02j, -0.13193171+1.21081065e-01j, 0.06133633-4.22267064e-02j, -0.08280452+2.04720842e-02j, 0.02083153+5.42313877e-02j, 0.12016721+1.60501416e-01j, -0.12225807-2.76668735e-01j, 0.02102305+9.09998231e-02j, 0.11747776+3.62319311e-01j, 0.09912628+1.50849159e-02j, -0.15640258+2.48010133e-02j, 0.0546514 +2.59861755e-02j, -0.01002552+6.65787181e-02j, -0.02898995+9.89915581e-02j, -0.00717829-1.37245312e-01j, 0.00055712+1.86303843e-01j, 0.04400996+1.19535156e-01j, - 0.05636026-2.16779961e-01j, -0.05913502-2.77370485e-01j, 0.20737913+2.02848948e-01j, -0.07528717+7.93840780e-02j, 0.05451348+1.33425914e-01j, -0.12290648+7.58881312e-02j, 0.10321466+1.24983234e-01j, 0.13371569-1.00033395e-01j, -0.05791197+2.68575587e-02j, 0.04652659+4.60658211e-02j, 0.00131806+5.92140285e-02j, -0.13481008+2.31672893e-02j, -0.13689412+1.17954022e-01j, 0.04998811-2.02833835e-02j, -0.14165519+3.56756720e-01j, -0.07856852+6.35118506e-02j, 0.05564543-9.74922249e-02j, -0.21743105-5.41409515e-02j, -0.16217875+7.97524864e-02j, -0.19486651-9.99801439e-02j, 0.19124263-4.71432152e-02j, 0.01035372+4.63843919e-02j, -0.07218978+1.32977797e-01j, -0.21002818-1.31679835e-01j, 0.05305256-1.54340691e-02j, -0.19401635+6.69582303e-02j, 0.05139607+1.93092981e-01j, -0.09946416+4.37566125e-02j, 0.10192397-4.16617603e-02j, -0.12405403-9.78811063e-02j, 0.05812519-3.95372746e-05j, 0.00099002-1.14739425e-02j, 0.05247123-8.40118490e-02j, 0.04501583+1.44968196e-01j, - 0.03301905-4.80048648e-02j, 0.02823323-1.78191318e-02j, 0.08196271-6.89791351e-03j, 0.02038618+7.47434818e-02j, -0.0372285 +4.85572384e-02j, 0.03293172+1.46606707e-02j, -0.18339563+6.37443359e-02j, -0.11214925-1.13505125e-01j, -0.06063048+1.45448526e-01j, 0.34233663-3.24467430e-01j, 0.07664073-1.44247607e-01j, -0.28993637+1.68069982e-01j, -0.18237161+2.05640159e-01j, 0.05552109+1.44200044e-01j, -0.08757971-2.66443942e-01j, 0.1558971 +2.49096061e-02j, -0.16421838+3.76276364e-02j, 0.08841799+3.97688126e-02j, 0.06127403+8.79601343e-02j, -0.11912802+9.38176361e-02j, -0.01512363+1.98779455e-01j, -0.10425168-2.89846412e-02j, 0.16046822-1.77676457e-02j, 0.04871864-4.15742404e-02j, 0.19325653-1.69328440e-01j, -0.059617 +1.87459639e-02j, -0.23497369+7.78523444e-02j, 0.03611522+4.96031106e-02j, 0.02849174+1.81422119e-01j, -0.13379238-1.46097376e-01j, 0.13609017-3.86016200e-02j, -0.13135849-9.04921922e-02j, 0.1333314 +1.02431026e-01j, 0.23331259-1.23168916e-02j, - 0.05106233+7.45228667e-02j, 0.12189655+6.42850380e-02j, 0.04943332+2.95462475e-02j, -0.00657986+8.06994964e-02j, 0.3267687 +8.99736406e-02j, -0.14260504+1.75648292e-01j, 0.23063331+1.78219849e-01j, 0.10883261+1.28389828e-01j, -0.10597288-1.40386755e-01j, 0.01512138+5.26532655e-02j, -0.24270928-2.39424278e-01j, 0.08582485+1.81061208e-01j, 0.15870471+3.82006536e-03j, -0.14205944-7.88677962e-02j, 0.26780226+1.17371947e-01j, -0.05734894+1.19255894e-01j, -0.00708958-3.87661515e-02j, -0.0123964 +1.17519163e-01j, -0.05307584+9.65095189e-02j, -0.04746522+6.19590573e-02j, -0.03677784-2.76400184e-02j, 0.14375332+9.66259420e-02j, -0.09175759-1.16174795e-01j, -0.03764456-1.92660525e-02j, -0.14188024+1.51742465e-01j, -0.00855281-6.80432250e-02j, -0.13963677+6.77341017e-02j, 0.27226725-5.95170973e-03j, 0.07653268+6.86308978e-02j, -0.18769106+2.15711501e-01j, 0.16136537-4.42590061e-02j, -0.26360596+1.04686372e-01j, -0.09155045-8.77382640e-02j, -0.09151231+4.28425508e-02j, - -0.06373803+3.71389234e-03j, 0.12982765+1.93272289e-01j, -0.00676779+9.13731987e-02j, -0.15669531-1.03446811e-01j, 0.13876435+1.73790050e-01j, 0.03724986-6.80542715e-02j, 0.13536485+2.06818477e-02j, 0.2134622 +7.76124343e-02j, -0.21930729-1.35324670e-02j, -0.15870289-1.47418944e-01j, -0.10525782-3.21051509e-02j, 0.02651126-7.35636015e-02j, 0.21299852-4.88944015e-02j, 0.1520081 +1.18419448e-01j, 0.02837817-1.66734491e-02j, -0.05583337+7.15315919e-02j, 0.00827433-9.71346050e-02j, -0.10828369+1.50029916e-01j, -0.05569338+1.56736408e-01j, -0.10498402-3.01603733e-02j, 0.01972677-3.28801228e-02j, -0.02545466-4.69757450e-02j, 0.23575113-6.13720081e-02j, -0.29064723+8.84431226e-02j, -0.07433566+3.29740230e-02j, 0.07812021-1.02151861e-01j, -0.0425074 +1.72860999e-01j, 0.18038703-4.84824047e-02j, 0.06760615-1.08861841e-01j, 0.25746276+7.60469955e-02j, -0.01916844-4.17126464e-02j, 0.05801 +5.47708435e-02j, -0.01089018+7.64307991e-02j, -0.01047013+4.46021957e-01j, - 0.1335352 -7.65699052e-02j, 0.04482942-4.66701163e-02j, 0.078575 -6.73430309e-02j, -0.16287533+3.68253915e-02j, -0.00326996+8.45469473e-03j, -0.30822025+1.56452958e-01j, 0.05607748+2.71034262e-02j, -0.15156807-3.99754306e-02j, -0.11732098-2.62196417e-01j, -0.12910811+1.37840055e-01j, -0.11324172+4.51349322e-02j, -0.07238787+1.95625832e-01j, 0.20782018-1.53159222e-01j, -0.0029301 -2.05737302e-02j, -0.06307179-7.76953233e-02j, 0.09180174-3.94918551e-02j, 0.09905065+1.64050652e-01j, 0.02119278-1.28555941e-01j, -0.13011198+7.50039022e-02j, 0.00364899+1.56741679e-01j, 0.12967172-4.59481445e-02j, 0.04371742-9.22641848e-02j, 0.01217403+1.42468441e-01j, -0.03321802-6.06556050e-02j, -0.33791815+2.19614336e-02j, -0.02079545-1.62357371e-01j, -0.06115126-1.31463603e-01j, -0.0408845 -1.17685338e-01j, -0.00096192-1.80065774e-04j, 0.11813011+6.17214729e-03j, 0.00417459-8.29797298e-02j, 0.08729658+2.67707592e-01j, -0.01118896-8.32911057e-02j, 0.03707148-5.83134279e-02j, - -0.12156735+2.64457587e-01j, -0.02989997-5.84706432e-02j, 0.03302162-6.01695667e-02j, 0.05437034-9.13677674e-02j, 0.10179674+1.40846743e-01j, -0.16635965+1.27949594e-01j, 0.1454272 -1.12363084e-01j, -0.11077774-1.22746452e-01j, -0.00185723-4.56720198e-02j, 0.02600582-8.89150489e-02j, -0.227494 -6.67592408e-02j, 0.08533135-1.88751082e-01j, -0.22714608+1.14661652e-01j, -0.02690036-1.30865882e-01j, -0.10121037-6.45046877e-02j, 0.01443838-2.37190078e-02j, -0.02303954-1.61468225e-01j, 0.06055609-2.63250332e-01j, 0.13332186+2.20700929e-01j, -0.02063736+2.65142722e-01j, 0.08332522+5.90342871e-03j, 0.1721038 -2.09054691e-01j, -0.15490146-9.27267743e-02j, 0.00453307-3.86153521e-02j, -0.02048122+3.02503499e-01j, 0.01458757-4.21067447e-02j, 0.32754022-3.88409256e-03j, 0.13811814-1.38612894e-01j, -0.12084009+3.73954159e-02j, 0.07102218-2.06344326e-02j, 0.11515796+1.13122542e-01j, -0.08863491-1.39456440e-01j, -0.17917237-4.99661020e-02j, 0.04442141+1.63664359e-01j, - 0.13732508-1.50992137e-01j, -0.05139775+8.97494329e-02j, 0.08732507+1.98929252e-01j, 0.05072904-2.99507910e-02j, 0.07108474+1.65205788e-02j, 0.0194683 -8.78868281e-02j, 0.09380987-4.44516495e-02j, 0.17168417+3.91109903e-02j, -0.04639245+2.60582960e-01j, 0.05875205+2.56753485e-01j, -0.07728994-3.17930589e-02j, 0.0452049 -1.76709840e-02j, 0.00134074-7.72090938e-02j, 0.20413611-1.94606554e-02j, -0.01910068+1.39711619e-01j, 0.0356499 +1.37434345e-01j, 0.30794216-1.09704366e-01j, 0.05284195-5.64409889e-02j, -0.08984104+6.94748250e-02j, 0.02163001+1.03288462e-01j, 0.03915384-9.81971938e-02j, -0.06670679+5.81276525e-02j, -0.11508668+9.47872135e-02j, -0.0354503 -3.13816097e-01j, -0.10991197+8.71705953e-02j, 0.06963248-5.65881100e-03j, 0.06577731-1.54696868e-01j, 0.15321403-6.74125684e-03j, 0.08071347+4.48458418e-01j, 0.03395331+1.27262600e-01j, 0.04183345+4.00904175e-03j, -0.01187089-2.21527903e-02j, -0.01851325-1.47271834e-02j, -0.23601169-8.54312072e-02j, - 0.11541862-1.04823473e-01j, -0.11268181-3.21825004e-02j, -0.09001661-1.37514659e-01j, -0.11748964-2.64871993e-02j, -0.0523941 -4.95790343e-02j, 0.1465224 -1.03971485e-01j, 0.18034942+7.79615744e-02j, 0.0936947 -2.22585205e-01j, 0.16751339+8.86578713e-02j, 0.19444547+1.21567778e-02j, 0.04771682+2.78729300e-02j, 0.19635398+9.50820346e-02j, 0.05185621+1.76230346e-01j, 0.07939533-2.18013091e-02j, -0.03596743-9.94674395e-03j, -0.28690236+7.06630196e-02j, -0.01620677+1.20756724e-01j, -0.11835929+3.00001593e-02j, -0.09989775+8.70560634e-02j, 0.0627832 -9.47387901e-02j, -0.09171898+2.82637561e-02j, 0.23849114+8.96858167e-02j, -0.24665889+2.03994686e-02j, 0.22245419-4.30604068e-04j, -0.0820849 -2.36258787e-01j, -0.11703521-6.52100265e-02j, 0.05282283-4.48185202e-02j, 0.02544553-7.56696642e-02j, 0.0320835 +2.09744844e-01j, 0.02707166+2.74207623e-01j, 0.14071592+1.51271647e-02j, 0.0599873 -2.12130726e-02j, -0.1323865 +1.32285712e-01j, -0.0634149 -1.88468438e-01j, - -0.25236535-9.40009628e-02j, 0.05804886-1.24296266e-02j, 0.01463484-1.92411356e-01j, 0.02901968-1.95938408e-01j, 0.05900759-5.70542063e-02j, 0.0039289 +1.79168231e-01j, 0.21463779+6.06068544e-02j, 0.02601461+3.44313390e-02j, -0.06804777-1.37777019e-01j, -0.04134655-7.71930937e-02j, 0.26993183+7.04042029e-03j, -0.22478871-1.11219112e-01j, 0.02216198+8.72296592e-03j, 0.00900783-1.81402113e-01j, -0.12568783+5.40727822e-02j, 0.20728804+1.49611785e-01j, -0.1540311 -1.04748775e-01j, 0.11524429+1.78469618e-01j, -0.01784981-2.05987600e-01j, -0.04310959+6.72693611e-02j, 0.09204926+1.24870358e-01j, 0.23044143-1.67687891e-01j, -0.04829998+6.96651901e-03j, -0.09200799-1.69548082e-01j, -0.08599541-5.05360845e-02j, 0.05605567-1.23777989e-02j, 0.09183321+2.03716921e-01j, 0.06046671+1.88609777e-01j, -0.35443088-2.50139768e-01j, -0.10418443+1.53252364e-01j, 0.02878444+4.48922173e-02j, -0.07655359-8.92321321e-03j, 0.06322981-5.98952645e-03j, -0.05895737-7.06273994e-02j, - 0.045825 +3.45008534e-02j, -0.0356972 +7.58719989e-03j, -0.18135564+2.31658738e-02j, -0.11367649-1.11799943e-01j, -0.02278714-7.26386363e-03j, 0.00527786+1.70825935e-01j, 0.08659992-2.45702546e-02j, -0.16132867-1.40266073e-01j, -0.16275372+1.57528240e-01j, 0.10098732-4.90008453e-02j, -0.14020292-1.26389028e-01j, -0.13387933-1.77044519e-01j, 0.15233209+1.56396670e-01j, -0.01186549+1.66770551e-01j, -0.05911019-9.37506242e-02j, -0.11032036+2.22422316e-01j, -0.32768772+1.23945218e-01j, 0.11693884+1.01153011e-01j, 0.06380873+2.73797332e-02j, -0.15242003-1.78297868e-01j, 0.08576241-9.81537390e-02j, -0.05483774+2.39049552e-02j, 0.08818984-4.80048981e-02j, 0.13795202+3.39576952e-02j, 0.15420435+1.04809134e-01j, -0.1475717 -8.35910546e-02j, 0.25587669-9.78491595e-02j, 0.12582976+1.06377618e-01j, -0.04885733+5.85877129e-02j, 0.02768058-8.97097222e-02j, -0.09572117-3.14848747e-03j, -0.09107239-1.48042190e-01j, 0.02633147+1.28206292e-02j, -0.00231722+2.40935942e-01j, - 0.08505098+4.43364674e-02j, 0.0454237 -1.20532432e-01j, -0.17493652+1.27595262e-01j, 0.01816818-1.93108598e-01j, -0.17931339+1.06943524e-01j, -0.10671963+1.39014451e-05j, 0.11498691+1.93066834e-02j, 0.23000235+1.04393237e-01j, -0.18572715-1.37399401e-01j, 0.13220069-3.09402657e-02j, 0.02990116+1.12157118e-02j, -0.02942283-1.36235506e-03j, -0.13275055-2.01044204e-02j, -0.05513657-1.15044942e-01j, -0.07453253+1.24162429e-01j, 0.19348874+1.65304419e-01j, -0.01684765-8.28080868e-02j, -0.06982499+2.38660768e-02j, -0.29603023-1.04892178e-01j, 0.31520605-5.80965984e-02j, -0.16452607-3.29924630e-02j, 0.13918688+1.34255787e-01j, 0.1461848 -5.91517992e-02j, 0.05246915+2.47209477e-02j, 0.09600898+4.48951448e-02j, -0.03040775+2.25636252e-01j, -0.03104364-1.03378328e-02j, 0.12457642-1.13129265e-02j, 0.25722645-1.07390381e-01j, 0.12453095-1.46405362e-01j, -0.20675192+5.37923723e-02j, -0.08581718-3.76855478e-02j, 0.12881044-7.30139037e-02j, 0.0330913 -1.45171188e-02j, - 0.04964024-2.63320298e-01j, -0.06851158+3.25029578e-01j, -0.06736655+3.31741867e-02j, 0.10672767-1.33657818e-02j, -0.03911025+2.71696686e-03j, 0.18376597-2.21089267e-01j, -0.02949093-2.24178456e-02j, -0.07672718+8.63619859e-02j, 0.09011718+1.34863000e-01j, -0.03532004+2.01221708e-02j, -0.0175005 +6.62198244e-02j, 0.17146927+8.06205588e-02j, -0.09194709+3.45310559e-02j, 0.05919149+8.90830332e-03j, -0.03890834+6.41903709e-02j, -0.13501504-3.99845589e-02j, -0.10279042+1.03768681e-01j, -0.05259741-5.87714457e-02j, -0.11719418-2.08936502e-02j, 0.09836174-5.44608131e-02j, -0.22877539+2.08355637e-01j, 0.04941838-9.51260734e-02j, -0.06203396+2.28604981e-02j, 0.12098849-1.44576480e-02j, -0.08451115-1.43356466e-01j, 0.15635672-1.46530151e-02j, -0.20437704-3.79884112e-02j, -0.19636121-1.71501698e-02j, 0.07255917-2.20625252e-01j, -0.28061719+7.71279703e-02j, -0.02084913-1.12045005e-01j, 0.04322484+8.40757110e-03j, 0.06080093-9.41283647e-03j, -0.08052508-4.49212849e-03j, - 0.35296504-9.29569583e-02j, 0.30139399+2.02446885e-01j, -0.1043556 -1.29299775e-01j, 0.19156652+1.16499747e-02j, 0.20865974-1.46798336e-01j, -0.13729311-1.50569340e-02j, 0.02152623+1.61941611e-01j, 0.05963193-1.30770158e-01j, 0.06462617-1.66387108e-01j, -0.11403091-8.19783097e-02j, -0.17890047-3.87091987e-02j, 0.05041442+2.34797464e-02j, 0.33716094-2.18366246e-01j, 0.04749898+7.95121529e-02j, -0.14276611+5.91160893e-03j, 0.0727171 -6.38166930e-02j, -0.03268621+7.25536789e-02j, -0.00994355-5.45862875e-02j, -0.10977213+1.11554079e-01j, 0.01783962-2.78702484e-01j, -0.00306595+2.65697928e-02j, 0.1392672 -1.06298955e-01j, -0.10153158-8.24641251e-02j, -0.2693985 +6.47512729e-02j, 0.03236581+4.07523974e-02j, -0.14424473+2.51731413e-01j, -0.01873542-2.47536237e-02j, -0.01356796-8.16033886e-02j, -0.07272296-1.47884513e-01j, 0.01967111-1.46373935e-01j, 0.23073323-8.09684340e-02j, 0.14428689+1.18128043e-01j, -0.06420706+1.47110727e-01j, -0.014288 -1.01535529e-01j, - 0.05505723+1.85830802e-02j, 0.00835002+2.95374366e-02j, 0.00710951+4.40654128e-02j, 0.17926977-3.38549657e-01j] - - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.x(4) - k.x(1) - k.x(0) - k.gate(u1, [0, 1, 2, 3, 4]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - - self.assertAlmostEqual(helper_prob(matrix[19+0]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+32]), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+64]), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+96]), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+128]), helper_prob(state.get(to_bitstring(4, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+160]), helper_prob(state.get(to_bitstring(5, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+192]), helper_prob(state.get(to_bitstring(6, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+224]), helper_prob(state.get(to_bitstring(7, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+256]), helper_prob(state.get(to_bitstring(8, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+288]), helper_prob(state.get(to_bitstring(9, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+320]), helper_prob(state.get(to_bitstring(10, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+352]), helper_prob(state.get(to_bitstring(11, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+384]), helper_prob(state.get(to_bitstring(12, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+416]), helper_prob(state.get(to_bitstring(13, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+448]), helper_prob(state.get(to_bitstring(14, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+480]), helper_prob(state.get(to_bitstring(15, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+512]), helper_prob(state.get(to_bitstring(16, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+544]), helper_prob(state.get(to_bitstring(17, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+576]), helper_prob(state.get(to_bitstring(18, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+608]), helper_prob(state.get(to_bitstring(19, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+640]), helper_prob(state.get(to_bitstring(20, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+672]), helper_prob(state.get(to_bitstring(21, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+704]), helper_prob(state.get(to_bitstring(22, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+736]), helper_prob(state.get(to_bitstring(23, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+768]), helper_prob(state.get(to_bitstring(24, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+800]), helper_prob(state.get(to_bitstring(25, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+832]), helper_prob(state.get(to_bitstring(26, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+864]), helper_prob(state.get(to_bitstring(27, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+896]), helper_prob(state.get(to_bitstring(28, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+928]), helper_prob(state.get(to_bitstring(29, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+960]), helper_prob(state.get(to_bitstring(30, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[19+992]), helper_prob(state.get(to_bitstring(31, size=platform_qubits), 0.)), 5) - - def test_adding2tothepower6unitary(self): - num_qubits = 6 - p = ql.Program('test_6qubitjustadding', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [ 3.66034993e-01+2.16918726e-01j, 4.63119758e-02-1.25284236e-01j, 3.23689480e-01-1.67028180e-02j, -4.01291192e-02-1.53117445e-01j, 1.84825403e-01-3.19144463e-02j, 5.62152150e-03-1.90239447e-02j, -1.37878659e-01-9.85388790e-02j, -4.12560667e-02+2.40591696e-02j, 1.70864304e-02-9.30023497e-02j, 3.56649947e-02-4.69203339e-02j, -3.83183754e-02+5.12024751e-02j, -1.96496357e-02+2.63675889e-02j, -1.43417236e-01+2.87083079e-02j, -7.64191581e-02+8.10632958e-03j, -5.44376216e-02+3.71068995e-02j, 7.89219612e-02+6.00438590e-02j, 2.32485473e-01-2.61279978e-03j, 3.13800342e-02+1.24253833e-02j, -3.80054586e-03-1.73877756e-02j, -7.12322896e-03+9.73966530e-02j, -1.22838320e-02-6.80562063e-02j, 1.04704708e-01+4.17530991e-02j, -1.45411627e-02-4.56578204e-03j, -3.91129910e-02+8.17248378e-02j, 6.36557074e-02+2.21470313e-02j, 1.10349909e-01-1.21376682e-02j, -4.78526826e-02+5.49355237e-02j, -1.20516087e-01+4.01182200e-03j, 9.38275660e-02+2.24713754e-02j, 8.93979520e-02+5.13816205e-03j, - -4.59396339e-02+1.59721722e-02j, -4.28884340e-03-4.63622637e-02j, 6.12649865e-02-1.22841538e-01j, -5.65913752e-02-6.08971314e-02j, -2.32312060e-02-1.65654059e-02j, 1.41147598e-02+4.73394414e-02j, -4.33854823e-02-1.51947091e-01j, -8.13427974e-02+2.99813808e-02j, -1.17417843e-01+1.90630710e-01j, -1.90231845e-02-8.35713650e-02j, -1.22044267e-01-7.47225397e-02j, -3.60683906e-02+6.78243340e-02j, -7.19769659e-02-2.89274301e-03j, 3.35704664e-02-6.57183304e-02j, -1.77382032e-01-2.84971997e-02j, 1.33681237e-01+1.01754278e-01j, 6.82852215e-02+9.51310080e-03j, 7.78691038e-02+2.00563796e-02j, 1.72520999e-02-4.06637398e-02j, -1.01923775e-02+5.59753174e-03j, 3.10544397e-02+1.61785537e-02j, 8.93474575e-03+6.24199961e-03j, 2.81125596e-02-3.97444226e-02j, 1.51177344e-01+2.05815209e-01j, -5.34831140e-02+1.77651158e-01j, -4.40789322e-02-2.71929907e-02j, -9.66417470e-02-6.07156542e-02j, 1.08161080e-01+1.20076484e-01j, 8.21245796e-02-2.30271819e-02j, -8.84132928e-03-5.48481546e-02j, - -5.14895797e-02-1.37500021e-02j, -1.51874055e-02+6.32818901e-02j, 4.75397973e-02-7.13568201e-03j, 3.13807800e-02-1.14525719e-02j, 1.01592567e-01+1.60695903e-01j, 1.27305395e-01+1.95561563e-01j, 1.12090718e-01-6.51290458e-02j, -1.01825786e-04-1.81692203e-02j, 1.54924689e-01+2.64139117e-02j, 9.26041281e-02-1.10472514e-01j, 1.14444819e-01-2.07202663e-02j, 6.75494235e-03-7.42645200e-02j, 7.77019424e-02+7.23999587e-03j, -1.97577945e-02-1.21556587e-01j, -1.53460462e-01-6.09952436e-02j, 4.01985175e-02+6.32614480e-02j, -6.20026282e-02-1.35839473e-01j, 1.29200169e-01+3.78332216e-03j, -2.59883114e-02-9.05275193e-03j, 8.17860302e-02-3.48868665e-02j, -1.60053834e-01-2.02916150e-01j, 4.82858885e-02+1.09125088e-02j, -1.24753204e-02-1.22518525e-01j, -5.80857579e-02-4.19993263e-02j, 2.28396669e-02-8.40966881e-02j, 6.32309194e-02-1.34709187e-01j, -9.62511113e-02-7.66908701e-02j, -9.03694102e-02+1.30290490e-01j, -1.46952433e-01+1.04814111e-01j, -2.72713771e-02+9.46774405e-02j, - 6.43591466e-02+4.89870962e-03j, 4.75376946e-04+3.50098669e-02j, -1.49839101e-01+4.44685559e-02j, 3.36051502e-02-1.73310171e-02j, 6.33484348e-02+4.71325034e-02j, -2.17711578e-02+1.31801429e-02j, 1.74906999e-01+1.53006903e-01j, 8.86273947e-02+1.97117753e-01j, 2.80636110e-02-1.05335854e-01j, -2.55400957e-02+3.13987536e-03j, 1.90502728e-01-5.65463143e-02j, -4.83648932e-02+9.12606941e-02j, 5.98563090e-02-7.02341588e-02j, -8.94163863e-03+3.75629282e-02j, 7.28101901e-02+7.14544903e-02j, -6.45875285e-03-3.09883105e-02j, 8.81396901e-03+1.99334329e-01j, 7.90997911e-03-6.52739372e-02j, -6.22843622e-02+1.28419510e-02j, -9.96405825e-02+3.88022827e-02j, 2.56561292e-02-2.23919910e-02j, 6.96886035e-02+3.51775332e-02j, -3.51521748e-02+3.76936524e-02j, 9.75324023e-03+6.65739416e-02j, -6.83377964e-02-6.68801536e-02j, 5.26199194e-03-6.98174024e-02j, -3.18191450e-02-8.73246712e-02j, 7.65668019e-02-2.22700208e-01j, 1.39633338e-01+1.29785687e-01j, 7.76075375e-03+1.07250473e-01j, - 5.43176815e-03+1.07893416e-01j, 8.87283358e-02-2.63757540e-02j, 5.90762011e-03+1.21098716e-01j, -5.31234979e-02-7.38219329e-02j, -6.99676596e-02+1.83616052e-02j, -1.13045510e-01-1.38358191e-01j, -6.40257276e-02-1.33332243e-02j, -5.05842389e-02+1.17327054e-01j, 2.19460719e-01+1.53618876e-01j, -1.98098237e-01-1.83046859e-01j, 2.55895738e-01-1.22287636e-01j, 2.24304159e-02+3.12955813e-02j, 8.10330744e-02+9.09937415e-02j, -8.69829415e-02-1.31156605e-01j, 7.13752017e-02+3.22771841e-02j, -1.09383893e-01+2.78555202e-02j, 6.08603366e-03+1.30630331e-01j, -1.38543382e-01-1.32609733e-01j, 8.11354396e-02-1.56139915e-02j, -2.46721034e-02-6.17177733e-02j, 1.17317415e-01+1.46270026e-01j, 1.57044029e-02+2.81859378e-04j, 7.34343516e-02+1.32166441e-02j, -1.94047136e-02+3.71747664e-03j, 1.67740714e-02+1.55308704e-01j, -2.30281717e-01-1.13574589e-02j, 6.66702774e-02-3.44728569e-02j, 6.64536670e-02-4.11020927e-02j, -5.89556075e-02+1.21648953e-01j, -1.33381018e-01+1.11575280e-01j, - -2.04297207e-02-1.44361996e-01j, -1.36404986e-01+1.75670409e-02j, 9.04729266e-02-2.05525311e-02j, -8.54217517e-02+8.81964403e-02j, 4.08009950e-02-4.65066696e-02j, 1.28598663e-01-1.26135509e-03j, -5.88955587e-02-2.16365675e-01j, -5.91081138e-02+3.93697458e-02j, 1.25841320e-01-6.59751293e-02j, 6.64938943e-02+5.27045503e-02j, 1.82761546e-01+9.47007410e-02j, -9.47093986e-02-4.42715353e-03j, 2.14782709e-02+1.08386929e-02j, -1.64295853e-03-6.85829980e-02j, 3.15183688e-02-2.83403844e-02j, 1.32010033e-02-1.35335939e-02j, 1.17740974e-01-4.02249320e-02j, -7.12640244e-03+4.92657515e-02j, 6.62000134e-02-6.58330394e-02j, -8.27247973e-02+5.46860857e-03j, -6.85927353e-02+1.60810901e-02j, 5.28608831e-02-4.24129436e-02j, 7.90603356e-02+5.78672352e-02j, 3.73193949e-02-4.61190576e-02j, 4.91693254e-02-1.00191521e-01j, -8.30279823e-02-4.53136772e-02j, 8.52488016e-02-9.43347617e-03j, -3.36847083e-02+4.29105012e-02j, 1.17835217e-01-1.03615646e-02j, 9.03099416e-03+1.23603737e-01j, - -8.85120477e-02+5.98128080e-02j, -1.07646777e-01-1.06745536e-01j, 2.85703816e-02-1.32915304e-02j, 6.54799867e-02-1.05639352e-01j, 1.56220180e-01-1.94186883e-02j, -8.98506499e-02+1.20794812e-02j, -3.34699800e-02+3.97067051e-02j, -1.13133666e-01+1.39529758e-02j, 3.82233228e-02-6.51392562e-03j, 1.16912282e-01-7.57853365e-02j, -3.02029062e-02+2.03203809e-03j, -7.05833281e-02-3.72791361e-02j, 1.18487986e-01+3.41305694e-02j, 1.90369334e-01-4.23433077e-02j, 1.78329157e-01-2.46079024e-03j, 1.42514615e-02-5.00931284e-02j, 6.22258069e-03+2.71254537e-01j, -1.05493042e-01+4.81011019e-02j, 1.63685462e-01+3.54417709e-02j, -7.92557707e-02+3.37712908e-02j, -6.89388107e-02+9.52917547e-05j, -5.98463661e-02+9.39029791e-02j, 7.83393843e-02+4.48842194e-02j, -4.03889441e-02+1.58463043e-02j, 4.69349327e-02+7.36054463e-02j, -1.23002359e-01+3.56702348e-02j, -8.08745549e-02-9.36340081e-02j, -1.53111649e-01-1.30519031e-01j, -4.55188428e-02-2.63939035e-02j, -5.13289900e-02+3.12841022e-02j, - -7.22190692e-03+9.84746771e-02j, -4.23305508e-02-4.16100064e-02j, 9.70155024e-02-5.10653722e-02j, -1.52262614e-02+9.70290076e-02j, -4.95065203e-02-4.71260667e-02j, 2.63361010e-01+5.88816734e-02j, -3.58878585e-02-2.50486879e-03j, -2.14856796e-01-7.75726911e-02j, -9.45755082e-02-1.02420516e-01j, -1.45089067e-01-1.73675325e-02j, -1.28612734e-01+2.62396621e-02j, -1.27273026e-01-2.41474716e-02j, -1.08532484e-01-7.70550142e-02j, -6.11361542e-02+5.21576989e-02j, -1.49885849e-01+6.33951444e-02j, 1.39221310e-01+4.74904068e-02j, 7.98734756e-03+1.21834984e-01j, -6.70609516e-02+1.03519222e-01j, 9.84581689e-02-1.90608636e-02j, -4.20985103e-04-5.34460521e-02j, 4.61698910e-02-5.36918570e-02j, -1.80638508e-02-5.52001591e-02j, 3.26902700e-02+1.03032250e-01j, 2.19231364e-01+5.34459046e-03j, 2.02344664e-01+8.05112282e-02j, 1.12050260e-01-9.47627052e-02j, 5.01092383e-02+2.80856107e-02j, 1.54394724e-01-2.02727577e-02j, -1.28311863e-02-1.32251018e-02j, 1.24297206e-01+5.16860223e-02j, - -2.40603762e-02+2.74847000e-03j, -7.65154347e-02-6.29854246e-02j, 1.90751859e-01-5.75903679e-02j, 1.31040663e-02-6.01812829e-02j, 3.98490344e-02-8.53582487e-03j, -9.87057147e-03+8.47414791e-02j, 4.96880859e-02+1.52103456e-02j, -2.34893852e-02+2.41581495e-02j, -6.29676487e-02+8.60622743e-02j, 3.33756353e-03+2.80774648e-02j, -6.00395642e-02-1.05197812e-01j, 8.12528420e-02+7.93631414e-02j, -2.07420548e-02+1.38374365e-01j, 5.36463694e-02-3.94927621e-03j, -1.96804868e-02+7.52059881e-02j, -3.71609399e-02+2.89964329e-02j, 1.54225234e-01+1.66400526e-01j, -4.28794858e-02+3.77165370e-02j, -4.72161861e-02+1.05193382e-01j, 1.88483774e-02+7.86924100e-02j, -3.05826462e-02+1.63053493e-01j, 6.64422544e-02+1.30615029e-01j, 1.19393774e-01+1.07635386e-01j, 1.15236137e-01+4.54248967e-02j, 8.36065560e-02-1.16369074e-01j, -7.31696969e-02+3.27398301e-02j, 1.04035711e-02+6.94251001e-02j, -1.12999867e-02-3.91635996e-02j, -6.25688782e-02+1.10951995e-01j, 6.06383062e-02+1.30678577e-01j, - 3.87713914e-02-2.56890752e-02j, -2.12352952e-02+7.46470611e-02j, 3.81665661e-02-4.66485675e-03j, 9.83793872e-02-5.47848105e-02j, -7.89298421e-02+9.89548326e-03j, 8.09874389e-02+2.88991618e-02j, -2.84479799e-02-3.95612619e-02j, 5.96981585e-02-1.18286529e-01j, 6.23627334e-02+1.26721441e-01j, -3.10124832e-02-1.84640556e-02j, 1.03597375e-01-1.34393931e-01j, -1.17812622e-02-6.89229414e-02j, -1.44678634e-01+2.03634696e-02j, -1.92499694e-02+3.83736754e-02j, -1.54185344e-02+1.54256354e-02j, -6.22128278e-02-6.06971077e-02j, -1.54442796e-01-4.55965667e-02j, -1.17280933e-02-2.96076710e-02j, 3.61636242e-01-3.68311909e-02j, 1.62232374e-03-2.46211943e-01j, -4.92385971e-02-8.23015443e-03j, -1.45369403e-01-1.29391236e-02j, -5.95406360e-02-2.40696609e-02j, 1.05369118e-01+3.57907856e-02j, 1.54655257e-01-4.92247169e-02j, -1.92329144e-01+2.80700834e-02j, 7.34014412e-02-6.83985774e-02j, 1.59129968e-01+2.24675645e-02j, 4.50009905e-02+8.28684110e-02j, -1.55862846e-01+1.38581516e-01j, - -5.75055241e-02+2.76394588e-03j, -2.51204024e-01-1.28699277e-01j, -4.06946336e-02+7.17282849e-03j, -5.60177740e-02-2.97766068e-02j, 5.20270958e-02-1.24980073e-01j, -2.70809079e-02-7.62240935e-02j, -9.13895753e-02+3.09052839e-02j, -2.58735369e-02+5.60249825e-02j, -1.47477861e-02+6.08183848e-02j, 4.89102367e-02-2.32083741e-04j, 4.26959278e-02+7.86994426e-02j, -5.37737809e-02+4.29931841e-02j, -7.51527527e-02+1.05047426e-02j, -7.92092909e-02-6.76905017e-02j, -1.53434244e-02+5.39639561e-02j, 1.02041990e-01+1.20369368e-01j, 3.16941445e-03+9.84779820e-02j, 4.50698004e-02+8.95480278e-03j, -3.06674727e-02-3.23950934e-02j, -7.67166598e-02+5.80876145e-03j, 4.03226297e-02+5.02470157e-02j, 9.20435646e-02+6.16208640e-02j, 4.53349090e-02-6.97415185e-02j, -1.43676770e-01+3.16896179e-02j, -5.70956416e-03+1.14461269e-01j, 3.36727523e-02+3.46621803e-02j, -1.28349306e-01+6.15831113e-02j, 2.92131791e-02-1.11494758e-01j, 6.78039246e-02+5.74136771e-02j, -7.37065550e-02-1.55476166e-02j, - 2.56255331e-02-4.43527889e-02j, 3.60829775e-02+1.48859744e-02j, -3.26999034e-02+1.41339655e-01j, 7.33897143e-02-5.13214915e-02j, -3.90630444e-02+7.98559328e-02j, 2.68903082e-02+5.83120382e-02j, 1.14205526e-01-3.53133007e-02j, 1.67581969e-01-2.17414475e-02j, -8.47370959e-02-1.03605182e-01j, -1.02980585e-01+1.87241569e-01j, 4.88560456e-02-1.87154362e-02j, 9.14764037e-04+6.72307848e-02j, 1.54753913e-02+6.22097288e-02j, -2.66815276e-02+7.33037713e-02j, 7.26024183e-03-1.57891621e-01j, 1.61465938e-02-6.23853508e-02j, -1.58906775e-02+9.22861340e-02j, 1.09187430e-01+1.22305747e-03j, 2.04879819e-02+6.30194559e-02j, -4.91774816e-02+1.98730477e-01j, 7.71514495e-02-8.70875038e-03j, 1.57479965e-01+1.04217181e-01j, 4.23884657e-02+9.41224038e-02j, 1.23866904e-01+2.54965114e-01j, -4.96733375e-03-4.34545446e-02j, 1.66863425e-01+1.03216014e-01j, 1.22161732e-02+1.74410123e-01j, 7.56016604e-02+1.14041093e-02j, 1.29416658e-01-1.07683681e-01j, 8.49692580e-03-9.98225347e-02j, - -2.53682806e-03-1.99317517e-01j, 1.32776926e-01+6.57308336e-02j, 2.48792835e-02-2.64841453e-01j, 1.03428049e-01+9.65965570e-02j, -1.51241974e-01-5.72183934e-03j, 1.88201884e-02+9.78051235e-02j, -3.52125401e-03-9.10550190e-02j, -1.21382845e-02-5.61863132e-02j, -2.72633341e-03+3.66383373e-02j, 1.31161516e-01-1.26913372e-02j, 3.46525801e-02-8.46938669e-02j, 1.17489600e-01-1.27053502e-01j, -7.75126317e-02+3.30270148e-02j, -7.85367649e-03-1.59325461e-02j, -2.04527534e-02-1.50973103e-01j, 1.19070061e-01+2.74181755e-02j, -1.24892455e-01-2.71536222e-02j, -8.38973196e-02-2.83671293e-03j, -9.23824862e-02-1.17795710e-01j, -2.12548944e-02+5.61017801e-02j, 1.45278490e-01-9.56859548e-03j, -1.82863761e-03+4.39439680e-02j, -5.97226268e-02-3.11260187e-02j, -4.76076983e-02-2.13141614e-02j, -4.54603071e-02-1.87085243e-02j, 1.40969780e-01-1.09754704e-01j, -1.01455639e-01+7.71777346e-02j, 1.48752797e-02-1.32375476e-01j, -9.40626155e-02+7.11577906e-02j, -2.12131838e-02-7.11116567e-02j, - 1.11184697e-01+1.35340762e-01j, -1.67713585e-01-2.00603909e-02j, 6.69071941e-02+4.20345476e-02j, -6.05717732e-03-9.68103657e-02j, -4.66999484e-02-8.16202516e-02j, -8.45240798e-02+5.60371406e-02j, 1.26572662e-01+4.52015693e-02j, 1.15084298e-01+1.80329121e-02j, -8.19534585e-02+9.92455558e-02j, 5.82837845e-02-9.60191435e-02j, 1.40466777e-01-9.50202996e-02j, 5.11287771e-02-2.53675878e-02j, 2.47544744e-02+2.06020479e-02j, -3.65720656e-03-4.94804816e-02j, -1.41559984e-02+1.67809139e-01j, 3.40859417e-02+1.36896363e-02j, -4.29813547e-02+1.10736905e-01j, 1.27523603e-01+2.07169069e-02j, 1.47572639e-01-4.16243755e-02j, 5.26379357e-02+6.25793319e-02j, 1.49109608e-01+1.47242665e-01j, -6.65329123e-02+3.26931942e-02j, 1.91342477e-01+6.13849533e-02j, -3.48863201e-02+1.16221687e-01j, -1.84725165e-02+8.88063853e-02j, -1.46651117e-01-8.03755334e-02j, 3.18322341e-01+1.28855771e-01j, -7.34176530e-02+6.28676759e-02j, 6.59855007e-02-4.02354168e-03j, -1.14723570e-02-1.41192022e-03j, - 1.31986821e-02+8.66384236e-02j, -2.06143698e-02-1.06385925e-01j, -1.29887505e-01-5.82215934e-02j, 3.55333019e-02+1.72976962e-01j, -4.43318809e-02+7.50029900e-02j, 2.42008445e-02+3.81880311e-02j, 9.24309092e-02+2.08369499e-02j, -1.73024821e-01+5.21566745e-03j, 2.19700726e-01+1.17537260e-01j, 1.63993038e-01+7.53919556e-02j, 7.07529823e-02+3.32108419e-02j, 8.06363236e-02+5.69884702e-02j, 6.53884989e-02-6.06009350e-02j, 1.02796574e-01+7.41913070e-02j, 3.21527509e-02-3.68525050e-02j, 5.23724001e-02+6.69483928e-02j, 1.40581761e-02+7.70120060e-02j, 7.42821790e-02+7.73759929e-02j, 1.03095422e-01-7.83293200e-02j, -5.98649602e-02-9.76718764e-02j, -8.58898366e-02-1.20654270e-01j, 9.76478031e-02-2.49354014e-02j, -3.33481195e-02+1.59120400e-02j, -1.04779024e-02-9.02867422e-02j, -3.68342490e-02+6.83856814e-03j, -5.03744003e-02+2.55842171e-02j, -1.72672267e-02+2.47688542e-02j, -1.81408876e-02-7.60577495e-03j, 6.15478341e-02+9.21537711e-03j, -9.54714639e-02+4.91095211e-02j, - -3.28772457e-02-1.07419632e-02j, 7.91895326e-02-1.16514331e-01j, -3.28981168e-02+6.24741888e-03j, -8.74370047e-02-1.34809532e-02j, -3.78068572e-02-2.85542044e-01j, 2.27133052e-02+8.76888751e-02j, 9.11283724e-03+1.95425832e-02j, 6.35536375e-02-6.45304136e-02j, -6.05664346e-02-8.13326951e-02j, 9.51930052e-02-6.52573951e-02j, -5.72679924e-02+8.44254015e-02j, -3.90623628e-02-3.15090263e-02j, 1.02656566e-01-1.53783548e-02j, -2.90858731e-02+3.83758991e-02j, 4.00015008e-02+9.29419353e-03j, 2.16293344e-02-6.15080785e-02j, -3.94283903e-02-2.86725847e-02j, -9.82554318e-02-3.05356109e-02j, 1.43678779e-01+1.66757227e-01j, 4.33669816e-02+2.09725691e-02j, 6.09968565e-02+1.35896205e-01j, 1.86428835e-02-1.07078161e-02j, 3.59210771e-02-4.96728908e-02j, -3.09977809e-02+4.20063574e-02j, -3.36483096e-02+4.06648103e-03j, -6.78492085e-02+3.60589692e-02j, -4.57256782e-02+2.29382640e-02j, 8.41604265e-02-1.21627615e-01j, 1.23159551e-02-4.33185856e-02j, 2.92901980e-02+7.68246203e-02j, - 3.57537713e-02+1.13757740e-01j, 6.61076239e-03+2.35766830e-03j, -2.50170508e-02+2.02216570e-01j, 1.90226197e-02-9.30319796e-02j, 3.52294231e-02+1.98930350e-01j, 6.47480042e-02-7.71035915e-02j, 1.06576071e-01+1.60636469e-01j, -1.84106675e-01+1.48367027e-02j, -2.26634183e-02-6.05001248e-02j, -4.09795810e-02+4.28997415e-02j, 1.18647136e-01+2.84135141e-02j, 1.05658964e-01+1.11901959e-01j, 1.55385384e-01+1.23916786e-01j, 2.50437539e-02+2.39415647e-01j, -3.10447452e-02+7.27368239e-02j, 2.03285504e-02-9.59860836e-02j, -3.39711391e-03-8.06167738e-02j, -1.36708865e-01+1.58365544e-01j, -7.63968104e-02-4.54852761e-02j, -1.34493163e-01-1.62060048e-01j, 1.37630857e-01-5.97073184e-02j, 1.26456118e-01-8.53282313e-02j, -1.44090748e-01-6.48238553e-02j, 1.14527429e-02-8.90366168e-02j, 1.26772282e-01+1.50468306e-01j, 1.09521345e-01+5.79354942e-03j, -6.36493029e-03+1.04114079e-01j, -3.46448312e-02+1.55499200e-01j, -1.91801782e-02-5.55803895e-02j, -1.09747875e-01+1.16908867e-01j, - -5.98737364e-02+6.92798355e-02j, -7.70045009e-02+8.69529376e-02j, 1.41838471e-01+1.57609972e-01j, 1.05064988e-01+1.27448858e-01j, -5.58481223e-02+1.18970561e-01j, 3.11104760e-02+7.09377243e-03j, 1.17401170e-01-1.29171507e-01j, -9.23143689e-02-6.32936915e-02j, -1.57360238e-02-3.48087654e-03j, -3.68085794e-02-6.90240362e-02j, 3.72129634e-01+1.05885225e-01j, 1.47539078e-01-1.02019375e-01j, 9.10168034e-02-9.45885626e-02j, -6.41230394e-02+5.23466780e-02j, 2.09042766e-01-5.04017256e-02j, -8.18752152e-02-1.67729197e-01j, 2.43479176e-02-3.15791155e-02j, -3.54894844e-02-2.06208641e-01j, 9.79597853e-02+1.27225349e-01j, -3.87549084e-02-2.32046371e-02j, -6.29155767e-02+1.93572123e-02j, 2.80668515e-02+5.94461601e-02j, -6.79156216e-03+3.34189314e-02j, -8.17558519e-02-9.72531723e-02j, -6.93388764e-02+9.75765597e-02j, 1.13872557e-01+5.43605204e-02j, 4.98782889e-03-1.43108491e-01j, 2.50693943e-02-1.18651968e-01j, -8.42094212e-02+3.40094201e-02j, -1.93122748e-03+1.26278033e-01j, - 7.21626311e-02+4.14478810e-02j, 1.30623663e-01+2.44967192e-04j, 9.43901041e-03-9.97110706e-02j, -2.92711792e-03+1.03468344e-01j, -2.26707613e-01+3.41895256e-04j, -1.29510144e-01+1.87631777e-02j, -1.89888081e-04-2.55952955e-02j, -8.26946001e-02+6.13660772e-02j, -1.11228037e-02-1.58220779e-01j, 7.61250434e-02+2.67080152e-02j, 9.25782693e-02+6.13248807e-03j, 2.59736432e-02-2.37141043e-02j, -2.91932014e-02-2.25217711e-02j, -5.16699426e-03-1.36738487e-01j, -2.79601717e-02-4.16723747e-02j, -7.06047980e-02+1.66551658e-02j, 3.72096502e-02+3.30948726e-02j, -1.61133828e-02-1.31037806e-01j, 2.48425980e-02+1.25040461e-01j, 1.24479311e-02+4.85744755e-03j, -6.81173401e-02+7.38703130e-02j, -4.93754225e-02+1.06791006e-01j, -7.68461360e-02-4.01290044e-02j, 1.51095443e-02+6.82241087e-02j, -1.36934200e-01+1.03824672e-01j, 2.64272936e-02-2.80269677e-02j, -8.63367945e-02-3.13888054e-02j, -2.25404421e-04+7.88537649e-02j, 6.92346834e-03+3.17886627e-02j, 5.86120252e-02-2.00444048e-01j, - -6.88131527e-02+3.50491144e-02j, 2.62520589e-02+1.58407829e-02j, 1.66265278e-03-1.03532297e-02j, 7.69386002e-02-2.67185303e-02j, 1.01084098e-02+3.79223130e-03j, -7.29521430e-02+9.08482588e-02j, -4.61024420e-02+1.94411467e-01j, 1.53468094e-03+1.86350862e-02j, 7.27775150e-02-2.59153001e-02j, -2.05928168e-02-4.88869881e-02j, 1.26185139e-01+3.10908628e-02j, 5.16540196e-02-4.63561741e-02j, -4.00987002e-02-4.88168980e-02j, 2.74709517e-02+1.12099875e-01j, 7.06457783e-02+5.46480806e-02j, 3.46431872e-02+7.06736324e-03j, 5.62921199e-03+1.52252805e-01j, -1.05318693e-01-6.42034872e-02j, 2.61399114e-01+3.12581452e-02j, 1.42549889e-01-7.20539802e-03j, -4.01513611e-02-1.09584788e-01j, 2.32103459e-02-3.08901316e-02j, -8.87718807e-02-4.81598900e-02j, 3.88078001e-02-1.48971115e-03j, 8.20382929e-03-1.60908451e-01j, 1.53171161e-01+9.34285397e-02j, -9.84955476e-02-3.77925732e-04j, 1.15359466e-01+1.53988904e-01j, -3.53067842e-02+2.22448115e-02j, -2.76010476e-02-1.02685489e-01j, - 6.47338872e-02+3.21032179e-02j, -6.25630438e-02-9.57348589e-02j, -1.06676085e-01-6.02328785e-02j, 6.32336003e-02+9.18568053e-02j, 4.22806111e-02+3.67386778e-02j, 3.34450227e-02-9.49873539e-02j, -9.25500440e-02+7.10428902e-02j, 5.83735994e-02-1.98170082e-01j, -9.31369416e-02-6.00026885e-02j, -4.19679158e-02+6.04049319e-02j, 2.94658418e-02-2.07003282e-02j, 8.51945088e-02+8.19217414e-02j, -1.40734017e-01+7.52647297e-02j, 2.42289626e-01-1.27759422e-02j, -9.38154491e-02-1.26465660e-01j, -8.95541629e-03-1.42613529e-02j, 8.03314780e-03+1.60930516e-01j, -4.88653862e-02+1.17749379e-01j, -7.39379399e-02+8.62428712e-02j, -2.59414228e-03-7.84326485e-03j, 2.00269020e-01+9.58856720e-03j, -1.19645441e-02+4.34306329e-02j, 6.09717160e-03-1.54242927e-01j, 1.08644840e-01-7.83434868e-02j, -1.45600371e-01-5.53383550e-02j, 6.95876462e-02-3.75146138e-02j, -1.01317383e-01-3.44359913e-03j, -4.61204619e-02-9.77882682e-02j, 7.60823182e-02-1.37389279e-01j, 4.87149823e-02+9.94095931e-03j, - -4.76778208e-02+3.06934398e-02j, 1.34616868e-01-3.35001866e-02j, 9.42819618e-03-7.70997443e-02j, -1.58872569e-01-8.51718385e-02j, -1.08323340e-02-3.58830573e-02j, -9.44807628e-02+1.04462576e-01j, -5.12024697e-02+8.95696029e-02j, -1.23263290e-01-2.11365137e-02j, -6.23407814e-02+5.27129163e-02j, 1.84350076e-01-6.48454604e-02j, 4.47048643e-02+9.55835619e-02j, 3.04136984e-02-1.61047348e-01j, 5.35742906e-02-8.89771961e-02j, 5.21798913e-03-1.01652683e-01j, 9.81082670e-02+6.78883376e-02j, 4.51160517e-02+4.08974261e-02j, 7.24547188e-02+1.43396898e-02j, 1.34520732e-01+7.64023876e-02j, -2.44439308e-02+1.93019446e-01j, 4.70632798e-02+5.40126182e-02j, 1.44082445e-01-6.94027082e-02j, 1.10724758e-01-4.81811556e-02j, 1.75840970e-01+1.16857338e-01j, -1.38125661e-01-1.28426487e-01j, 1.67653981e-01+6.10401648e-02j, -9.27944162e-02-4.45898489e-02j, -6.36024967e-02-1.32504351e-01j, -3.83547731e-02-4.80351172e-02j, 2.87039348e-03+1.86993497e-01j, -8.06227067e-02-8.55853307e-02j, - 1.98050483e-01-5.65883695e-02j, -6.61066167e-02-1.71061740e-01j, -3.88695750e-02+1.09338522e-01j, -7.49700094e-02+9.33229878e-02j, -1.57544410e-02+5.63796550e-02j, 9.53506257e-02-6.37602365e-02j, 2.75211340e-03+7.79446442e-02j, 1.39113602e-01-1.36189229e-01j, 1.17220189e-01+9.46405945e-02j, -1.81301425e-02-2.48995711e-02j, -9.81095323e-02+1.42902852e-01j, 1.41212310e-01-1.26684189e-01j, -5.05751207e-02+9.51904702e-02j, 1.04859322e-01-2.04087816e-02j, -1.21826474e-01-1.07626674e-02j, -9.57058985e-03+1.37576990e-03j, -4.74540116e-02+1.96568999e-01j, -1.38789725e-01+5.29123729e-02j, -1.06381314e-02+7.45998022e-02j, 7.06297513e-02-7.13617157e-03j, -1.75797263e-03+1.12692942e-02j, -1.08418056e-01+7.80141453e-02j, 7.95831370e-02+5.43897927e-02j, -4.77081927e-02-1.65112693e-02j, -3.03381357e-02+8.08941075e-03j, -8.23004681e-02+1.05759705e-02j, -6.56969750e-02-1.79256431e-01j, -3.76059369e-02+1.78724732e-01j, -3.13850703e-02+9.23421858e-03j, -3.23711459e-02+8.23655512e-02j, - -5.52695718e-02-2.86257551e-02j, -8.21930608e-02+2.84104439e-02j, 6.88034715e-02+7.91090633e-02j, -9.58878856e-02+1.62110597e-02j, 1.85489072e-02+7.72518030e-02j, -8.47308705e-02+1.15419402e-01j, -1.27165710e-02-1.47844195e-01j, -3.31225492e-02-1.12256225e-01j, 4.38928408e-02+3.01083140e-02j, 1.49664011e-02-3.23579402e-02j, 6.18136699e-02-3.20311892e-02j, -2.00715491e-02+3.36952165e-02j, 3.84726438e-02-1.47570105e-01j, 5.66270826e-02+1.60052582e-03j, -4.30699454e-03+7.36300298e-02j, 1.17987394e-01+4.71108745e-02j, -6.17743138e-02-7.33753780e-02j, -2.90245523e-02-2.72610689e-02j, 1.91805045e-02+7.28153549e-02j, -2.42663866e-02+1.76970283e-01j, 1.34153427e-01-6.33407243e-02j, 2.80424444e-02+7.13200467e-02j, -1.89628021e-01+3.08308998e-02j, 8.30657938e-02-1.92419259e-01j, 7.56007039e-02+1.32593910e-01j, 4.03658952e-02+9.28689978e-02j, 2.32661487e-01+5.37620195e-02j, 9.71324362e-03+1.55793479e-01j, -7.90003403e-02-9.01055799e-02j, -7.19042248e-03+4.98522998e-02j, - -7.89912325e-03-9.22331480e-02j, -1.52218111e-01-2.70308556e-02j, 1.52204585e-01-1.04355797e-01j, -9.58268719e-02-2.66039347e-02j, -5.85839839e-02-8.45115184e-02j, -7.67554648e-02+4.09816179e-02j, -1.23737409e-02+6.27494390e-02j, 1.76544689e-02+2.91020457e-02j, 7.88970104e-02-3.84634885e-02j, 1.46944340e-01+4.22569979e-02j, 9.45664458e-02+1.75073953e-01j, -7.43530291e-02+5.39858529e-02j, 5.30273947e-02-2.04301186e-02j, 9.01691091e-02-1.37635743e-01j, 5.17323825e-02-4.42395728e-02j, 4.51065835e-02+1.55587162e-01j, -4.32070922e-02-8.47367622e-03j, 8.89766181e-02+7.27808224e-03j, -3.05321402e-02+4.01867117e-02j, 9.02139365e-02-1.02921926e-01j, -9.68996356e-02-5.57902239e-02j, 1.86882008e-01-3.65138998e-03j, -3.56735640e-02-5.38393441e-03j, 1.03631981e-02+6.62353454e-02j, 1.39301908e-02-3.82579866e-02j, 1.29806843e-02+1.15547571e-01j, -7.78767617e-02+1.17577632e-01j, -6.55156854e-02-3.75568378e-02j, -1.16185770e-01-9.97472455e-02j, 1.13027024e-01-1.71188329e-02j, - -6.23765584e-02+9.71995127e-02j, 1.98853369e-02+4.41168144e-02j, 5.16372259e-02+1.04020291e-01j, 2.45487579e-02-7.07505804e-02j, -5.66916759e-03+1.79107188e-01j, 1.34919009e-01-3.38433266e-02j, -9.26335780e-02-2.41450966e-02j, -5.93110207e-02-1.13009956e-01j, -1.12473035e-01-1.02705305e-01j, -4.54029970e-02-8.46187294e-02j, -6.23708588e-02+4.57479972e-02j, 1.03992622e-02+1.00980439e-01j, 1.23694781e-01+1.22523548e-01j, 1.75959124e-01+6.68614671e-02j, 1.27580207e-01-7.10524199e-02j, -2.21112630e-02-3.48999085e-02j, -2.89686819e-02-1.38112449e-01j, -4.03154317e-02+1.30278763e-01j, -9.87558643e-03+2.11808797e-01j, 5.51166437e-02+7.28637045e-02j, -1.08116027e-01-1.25165016e-01j, -3.86238981e-02+8.93334399e-02j, 1.05216928e-01+6.44215494e-02j, 8.30120047e-02+1.60173664e-01j, -1.61665814e-01+1.33604609e-01j, -1.07929918e-01-2.27824193e-02j, 7.55794397e-02+5.35699856e-02j, 6.46640729e-02+6.77207472e-02j, -7.58619365e-02-1.36147809e-02j, 1.13368566e-01+1.41535454e-02j, - 1.16562600e-02+1.40637360e-01j, -3.48865452e-02-3.87334493e-02j, 2.84836458e-02+4.90837454e-02j, -3.44567796e-02+7.63272004e-02j, 1.61636226e-01-1.05180549e-01j, -4.75623594e-02+6.52991698e-02j, 4.99185253e-02+1.14465223e-01j, -5.40773631e-02-8.42919215e-02j, -1.14147601e-01+7.66188244e-02j, -1.40176445e-02+1.81528191e-01j, 4.35191919e-03+4.15940186e-02j, 1.27180295e-01+1.33144935e-01j, 9.06497753e-02-8.52809907e-03j, -1.26885003e-01-1.51045190e-01j, 1.02171723e-01-2.10818775e-02j, -2.98553434e-02+5.76845178e-03j, -1.60706438e-01-2.00370478e-01j, 1.51384923e-02-1.26679865e-01j, 7.55024672e-02+1.00895062e-01j, -7.45007080e-03-7.05098188e-02j, -2.88191949e-04-3.68919966e-02j, 5.62265696e-02+3.61613198e-02j, 4.24155733e-02-1.35428909e-01j, -7.53735593e-02-1.13686296e-02j, -1.16745754e-01+7.74921732e-03j, -6.94457624e-02-7.72663319e-02j, 3.74783331e-02+4.85062269e-02j, 6.52243264e-02-1.18436957e-01j, 1.17192626e-01+2.15233561e-02j, 1.02189810e-02-2.93259136e-01j, - 1.20140155e-02-6.63128933e-02j, -7.59536948e-02+6.71887612e-02j, 1.03744562e-02-1.21868885e-01j, 2.44016980e-02+6.89084519e-02j, -4.65470072e-02+1.22685320e-01j, -4.86962360e-02-4.88161112e-02j, -2.34017454e-02-5.77271045e-02j, 1.13502743e-02+4.16363888e-02j, -1.23278700e-01+1.12353134e-01j, -1.00881756e-01+1.17893431e-02j, 1.43470161e-01-3.29644042e-02j, -6.02563150e-02-4.45108227e-02j, 2.08219274e-01-1.67238564e-02j, 1.17121095e-02-6.33598388e-02j, 1.02538269e-01+3.22547888e-02j, 2.06012703e-03+1.07778634e-01j, 2.65464923e-02-3.46848652e-03j, 1.26264949e-02-7.16205403e-02j, 1.88694092e-02+9.58433324e-03j, -1.35215533e-01+2.75775658e-02j, 8.38743345e-02-3.94921696e-03j, 7.32804883e-02+4.21473224e-02j, 9.07604721e-02+1.45926883e-02j, -6.18641521e-02+7.52679281e-02j, 3.77612246e-02+2.95629420e-02j, -1.09369090e-01+3.64775541e-02j, -8.08080517e-02-8.08179068e-02j, 1.25920478e-01+1.02020075e-01j, 1.48976545e-01-3.02271686e-02j, -6.94345873e-02-9.09390945e-03j, - 1.31215815e-01-4.81602495e-03j, -2.05577715e-01+1.85648890e-01j, -4.20038791e-02-6.79461932e-03j, -4.21802223e-02+3.20414345e-02j, -3.87813853e-02+8.90865396e-02j, -4.21262137e-03-2.67890619e-02j, 6.79636786e-02-1.01093511e-01j, 1.40097339e-01+1.13907091e-02j, -1.88534819e-02+1.86465325e-01j, 2.71881881e-02-3.96160387e-02j, -6.42435188e-02-5.92185512e-03j, -4.89365496e-02-5.43585428e-02j, -4.57530970e-02-4.59613671e-02j, -3.61926650e-02+6.52346667e-02j, -9.61553968e-02-1.04451040e-02j, 9.04112402e-02-1.17533502e-01j, 1.74545444e-02-4.57240195e-02j, -4.89015824e-02+7.55148764e-02j, -1.42395993e-01-2.07951667e-02j, -1.04312418e-01+1.84020305e-02j, 1.04123907e-01-2.12641676e-02j, 1.81621294e-02-1.38150470e-01j, 6.90749445e-02-5.41908577e-02j, 1.25242285e-01+6.69590747e-02j, -1.12044943e-01+7.01709827e-02j, 1.18559009e-01+6.36320518e-03j, -4.09721959e-02-7.48052629e-02j, 2.11912964e-01+6.98119674e-03j, -5.53338736e-02+3.84548615e-02j, -1.73475512e-02+4.66847305e-03j, - -1.39453707e-01+3.59052683e-02j, 5.65519475e-02+1.33581775e-01j, 9.24610673e-02+9.71550192e-04j, 1.01271681e-01+2.91580010e-02j, 5.65757574e-02-5.63073301e-02j, -6.89138190e-02+8.79709939e-02j, 1.32780848e-01+1.15842424e-01j, 5.74757429e-02+4.60581605e-02j, 1.30747705e-01-1.09382867e-01j, -6.81587412e-02+7.23700700e-02j, -4.77640537e-02-8.69425608e-02j, 5.41468987e-02+4.70866972e-02j, -5.45249768e-02+1.28327565e-01j, 3.88602977e-03+1.11946956e-01j, 2.58870901e-02-1.91503109e-01j, -3.66945777e-02-1.10208009e-01j, -2.56790612e-02+1.58065038e-01j, -1.90786566e-01+1.14107636e-01j, -5.60322067e-02-1.21127263e-02j, 1.08860290e-02+1.24596622e-01j, -1.48768362e-01+2.37695281e-04j, -1.47649036e-02-1.64313895e-01j, -4.79489441e-02-2.08483452e-01j, -8.71341644e-03-2.32533010e-02j, 7.23197740e-04-1.45104996e-01j, -1.03649950e-01+5.46849449e-02j, -1.40039869e-02+1.54117586e-02j, 1.34270729e-01+7.10254799e-02j, -1.62944885e-02-6.79478047e-02j, 3.02355044e-02+9.34069481e-02j, - -4.19572996e-02-2.36984771e-03j, 5.19461879e-02+1.37769363e-02j, -1.56996645e-01-1.34660692e-01j, -4.48308181e-02-3.38817723e-02j, 5.73788104e-02+1.42412043e-01j, -1.15377475e-01-3.01131028e-02j, -7.77514856e-03+8.05802903e-02j, -1.80121894e-02-4.97689832e-02j, 2.74606415e-02+1.48966719e-01j, -1.17119892e-01+8.81288551e-02j, 7.95268357e-02-3.87759152e-02j, -1.66297510e-02-7.62547866e-02j, 4.37512230e-02-4.07918510e-03j, -7.00709466e-02-1.80395743e-02j, 1.17198057e-01-7.79683242e-03j, 1.75402728e-01-1.75827182e-02j, 5.42956130e-02-3.91441862e-04j, 1.01465093e-01+9.25475158e-02j, 5.36093332e-02+8.63715906e-02j, 3.05460006e-03+4.52463764e-02j, -1.46059785e-01-1.29686001e-02j, 1.80571255e-02+1.12753039e-01j, -8.21657514e-02-4.73360574e-02j, -1.10948811e-02-8.29924942e-02j, 8.52411894e-02+5.18029751e-02j, -8.02700769e-02+1.90210044e-01j, -2.34714253e-02-2.31241051e-02j, -3.19869719e-01+4.57770182e-02j, -4.75928400e-02+1.12895685e-02j, -3.75738567e-02+6.21213961e-02j, - -1.14920013e-01-2.12107989e-03j, 4.77491260e-02-5.19463759e-02j, 1.03806006e-01+7.16366977e-03j, -8.27636909e-02-5.08812397e-02j, 2.22322180e-02+1.43361348e-02j, 3.14670279e-02+1.39911830e-02j, 8.48418379e-02+1.81601566e-01j, -7.46942903e-02+7.89752532e-02j, 7.08970727e-02-6.91124197e-02j, -1.13741776e-02+1.23825472e-01j, -6.59798634e-02+1.24967591e-01j, -6.33113532e-02-1.64307450e-01j, 1.14099231e-01+3.41222046e-03j, -4.61570543e-03-2.19001396e-01j, 2.84759810e-02-7.17797193e-02j, -5.39314225e-02-1.64591007e-01j, -1.16438285e-01+6.52426253e-02j, 5.86854248e-02-4.05905194e-02j, 1.47438624e-02+5.30606235e-02j, -1.90230877e-02+4.63842878e-02j, 8.00044760e-03+1.58689396e-01j, 4.42361550e-02+5.13313063e-02j, 2.55319954e-02-9.75583568e-02j, 3.01793771e-02+1.11081312e-01j, 1.27308954e-01+1.69452356e-01j, -4.94643829e-02-3.50989191e-02j, 2.42630119e-01-3.22834423e-02j, -9.43879468e-03+1.54569386e-02j, -1.26451530e-01+1.07634561e-02j, 6.53072639e-02+1.64004515e-01j, - 4.73037239e-02+6.72621484e-02j, 7.86355859e-02+1.37091046e-01j, 3.48468450e-02+5.01002189e-03j, -4.96409372e-02-1.79874187e-02j, -8.08977821e-03-1.60325464e-02j, -6.18986724e-02-9.03950614e-02j, -8.57358123e-03-1.05211425e-01j, -1.19635684e-01-9.84001742e-04j, -9.29477188e-02-8.10903125e-02j, -6.60847827e-02+1.07380011e-01j, 6.65522847e-02+2.25450350e-01j, -8.20410767e-04-1.28445752e-01j, 6.14568901e-02-4.79238345e-02j, -1.06893529e-01+1.36044214e-01j, 1.15138674e-02-4.90252547e-02j, -2.76216857e-02+6.76507128e-03j, -1.09382658e-01-5.30334315e-02j, 7.08950419e-02+3.44793514e-02j, -7.60439516e-03-1.03572965e-01j, -5.88875512e-02-1.16117780e-02j, -1.76441304e-02+1.51394952e-01j, 1.31994928e-01+4.65974993e-02j, -5.68107027e-02-3.38323177e-02j, -1.00658392e-01+9.28555205e-04j, -7.05082372e-02-1.20465449e-01j, 6.60549798e-02-1.08205211e-01j, 1.56747849e-01+1.21419663e-01j, -1.92613366e-01-1.52102819e-01j, 1.13592085e-02+2.83411765e-02j, 5.99946763e-02+1.22827499e-02j, - 6.29184081e-02+1.00151916e-01j, 2.10898432e-03-1.59215144e-02j, 1.66631398e-02+1.18954419e-01j, 8.45398912e-02-1.10186016e-01j, -1.19940961e-01+9.68249560e-02j, 4.70304208e-02+7.70342680e-02j, -1.22124543e-01+4.39697557e-02j, -9.96175775e-02+1.38251492e-01j, 6.97555402e-02+1.33210859e-02j, 2.56989939e-01+1.26134536e-01j, -3.26770849e-02-1.47901277e-02j, 2.42109734e-02-1.35712836e-01j, -1.47972097e-01+4.14172508e-02j, -5.11927028e-02+1.22448971e-01j, 6.62366501e-02+5.95513442e-02j, -5.32415834e-02+3.72035869e-02j, -1.52278830e-03+1.27320604e-01j, 6.50991303e-02-1.55212986e-01j, 4.34075807e-02+1.02149453e-02j, 4.30717490e-02+9.20139462e-02j, 1.16886206e-02-1.87138194e-01j, -6.64847366e-02+1.09856866e-01j, -3.67840574e-02+6.02029631e-02j, -9.81671194e-02-7.20999183e-02j, -6.04451121e-02+7.52633656e-02j, 2.81976119e-03+1.06633536e-01j, 5.26129880e-02-3.98349053e-02j, -2.87998493e-02-7.12947090e-03j, -3.94344408e-02-1.20091657e-01j, 8.38152379e-02+5.55474575e-02j, - 9.41964471e-02+2.98721048e-02j, 8.16069823e-02-2.59474209e-02j, 1.55022162e-01+1.57407270e-01j, -5.67424378e-02-1.25923094e-01j, -2.06889103e-02+1.23693612e-01j, 8.49745423e-02+6.37954576e-02j, 7.18887232e-02+1.75903579e-01j, -6.08588164e-03+2.03191283e-01j, 6.86348025e-02-2.78848587e-01j, -4.14352560e-02-7.92352365e-02j, 1.99800580e-02-1.07011810e-01j, -4.77750533e-02-4.29164779e-02j, -9.80129418e-02+2.26179330e-01j, 2.44211579e-03+8.87315263e-02j, -2.48518186e-04-2.58477922e-02j, 1.46163656e-02+2.66665629e-02j, -1.08518799e-01-1.22626080e-01j, -4.62433206e-02+6.55029395e-02j, -9.33013316e-02-1.22087077e-01j, -1.31539219e-01-2.41402172e-02j, 2.25238757e-01-4.21429135e-02j, 6.27985064e-03-1.07195959e-01j, 4.34640320e-02+5.35187773e-03j, 7.32060940e-02-8.45846618e-02j, 1.83126542e-01-1.06954649e-01j, 2.22212559e-03-1.29315970e-01j, 6.01963053e-03-3.51904776e-02j, 1.02955536e-01-3.85218206e-02j, 9.46926580e-02-7.37961277e-02j, -8.61772814e-02+1.07443737e-01j, - 2.04379335e-03+5.94079303e-02j, 8.23537953e-02-1.41231083e-02j, -8.33955001e-02-7.33002238e-02j, -4.63586972e-02-7.49582675e-02j, 1.44258446e-01+5.05833339e-02j, -7.26785087e-02+7.99070748e-03j, 9.65967758e-02+2.55373847e-03j, 4.56168318e-02-6.98355136e-02j, 1.34466635e-01+9.33168643e-03j, 1.35620410e-01-3.63893984e-02j, -2.18310783e-01-9.07642078e-03j, 2.41046715e-02+8.68133750e-02j, 8.46941220e-02-9.87087721e-02j, 2.32699075e-02+7.70324105e-02j, -6.83066191e-02+6.26029815e-02j, 3.96917401e-03+3.19047344e-02j, -1.93167112e-02-5.87602583e-02j, 6.40947853e-02+3.49325001e-02j, -8.48481277e-02+1.00080104e-01j, 1.43703227e-01-2.70626163e-02j, -1.56896525e-01-4.98153190e-02j, -1.06529060e-01+1.09204216e-01j, 1.34564483e-02-2.22232431e-01j, -5.20802942e-02-5.67593041e-02j, 6.29414647e-02-1.10240712e-01j, -1.54707424e-02-6.35737164e-02j, 8.94634583e-03-1.06767329e-02j, -4.21134431e-02-3.53658066e-02j, 2.41746297e-02-3.68212148e-02j, -9.21559781e-02-2.99118897e-02j, - -5.89654642e-02-2.28852318e-02j, -5.20985361e-02-1.16771130e-01j, 5.35843151e-02-1.32214156e-02j, 4.58936445e-03+3.34103858e-02j, -1.46128686e-03-7.50434059e-03j, -1.37118260e-01-2.96979592e-02j, -4.28133426e-02+3.29193671e-02j, 1.22565726e-01-6.37325294e-02j, -5.96435200e-02+6.19807323e-02j, 8.28472218e-02+1.93521885e-02j, -8.88354299e-03-1.16922356e-01j, 1.17046722e-01+7.55087525e-02j, 1.11458497e-01-4.97578367e-03j, 3.03775840e-02-6.26278785e-02j, 9.34835767e-02-8.35671209e-02j, 1.92817644e-01+6.09168886e-02j, 1.55965719e-02-3.49551218e-02j, -9.23258088e-02+2.02094665e-01j, 7.07259110e-02+6.29610500e-02j, 2.65355792e-02-1.45360966e-01j, -8.38484133e-02-2.25673551e-02j, -5.99920073e-02+1.19442828e-01j, 3.08096147e-02+2.05383373e-01j, 1.46680157e-01-1.34303106e-01j, 1.78416469e-01-2.56761475e-02j, -7.04073547e-03-4.26410412e-02j, 5.92741489e-03+2.73194162e-02j, 3.28330300e-02+1.38975663e-01j, 1.36088703e-01-7.00656141e-02j, -7.16088585e-02-5.01751384e-02j, - 1.07261982e-01-6.08676344e-02j, 3.29984881e-02-4.11527154e-02j, -1.22180830e-01-1.79219988e-01j, 1.52540838e-01-3.98900946e-02j, -6.59340891e-02-1.13945351e-01j, 3.26860116e-02+7.75988849e-02j, 1.84680188e-03-7.15874930e-02j, 5.75188825e-02-1.59627565e-01j, -1.45799524e-02+1.40916322e-02j, -1.89600216e-02+2.20952202e-01j, 3.67478575e-02+1.30282642e-01j, -9.75462649e-02+1.15756251e-01j, 1.16468796e-02+1.17487817e-01j, -2.76444195e-03+7.54195399e-02j, 1.01904254e-01+1.43117381e-02j, 6.03665982e-02-8.65537954e-03j, -1.32384893e-01-5.91759860e-02j, -1.26867457e-01-1.99641121e-02j, -7.35718904e-02+7.37721086e-02j, -4.37046524e-02-5.73821921e-02j, -4.88920306e-02+4.85533481e-02j, -2.58084890e-01-4.52105731e-02j, 8.83268017e-02-3.24794517e-02j, 3.97109460e-02+2.31464221e-02j, -8.74443503e-02+5.05459657e-02j, 3.49357665e-02+5.74013249e-02j, 7.76023292e-02+1.24157281e-01j, 4.67657992e-02+8.54501007e-02j, -2.73903139e-02+3.20710850e-02j, -7.22744938e-02+2.98218349e-02j, - -1.66836536e-02-5.55139728e-02j, -1.00817364e-01+1.98738235e-02j, 1.06000799e-01-4.17864489e-02j, 2.47089963e-02-6.89030059e-02j, 1.02071912e-02+1.40803829e-03j, -4.29064727e-02+1.48247071e-01j, 8.86549012e-02-1.49688762e-01j, -1.37487726e-01-6.88685909e-02j, 9.74446290e-02+3.34782789e-02j, 3.09376006e-02-8.18948969e-03j, -6.07821142e-02+2.05709303e-02j, 6.20301019e-03-1.07661389e-01j, 2.66360798e-02-1.95200123e-02j, -8.70121352e-03+6.27192787e-03j, 5.67467889e-03-4.71688645e-03j, -3.96568337e-02+2.60335168e-03j, 1.26272851e-01-7.88612171e-02j, 2.39896969e-02-1.94449288e-01j, 1.01939995e-01+5.40381344e-02j, 3.38010121e-02-1.07535239e-01j, 1.01694129e-01+1.58769881e-01j, -1.60525228e-01+1.61402777e-02j, 2.46147533e-02+1.84478112e-01j, -2.24323874e-02+1.44766330e-01j, -7.44818491e-02+1.10475796e-01j, -7.03647417e-03-7.89877995e-03j, -7.12605582e-02-6.00421868e-02j, 8.19735532e-02+3.10232290e-02j, 1.29199728e-01+8.64579318e-03j, 1.04093008e-01-2.16880641e-02j, - 2.62815057e-02-3.82377454e-02j, -1.62557224e-01-1.01320720e-01j, -5.68005830e-02-6.94736514e-03j, -1.49055391e-01+5.18207090e-02j, 6.27178782e-02+1.01489809e-02j, 1.25981379e-01-8.58405608e-02j, -8.20377419e-02+8.24372614e-02j, 6.37946588e-02+8.57050701e-03j, 6.54024538e-02+4.63840214e-02j, 6.18224834e-02-2.22489702e-02j, 1.17291795e-01-7.38374742e-03j, 1.48954910e-02-3.86650743e-02j, -3.77589928e-02-1.39936721e-01j, 4.52316221e-02-1.57936117e-01j, -6.23943129e-02+4.81748404e-02j, -1.92620084e-02-2.15996053e-02j, 1.71279612e-01+7.73412683e-02j, 2.23232062e-02-5.61065685e-02j, 1.57779087e-01+7.85148897e-02j, 1.40230327e-03+6.35368648e-02j, 8.38305347e-02+1.63118880e-02j, -9.03278369e-02+1.01139458e-02j, 3.54020248e-02+1.78314505e-02j, -1.70735336e-01-1.07777517e-01j, -3.34738370e-02+7.44591431e-02j, -2.16874208e-02-2.16863527e-02j, 1.15546757e-01-1.47632133e-01j, -1.64688932e-01+4.66255948e-02j, 5.97823744e-04-2.02720511e-02j, 2.98168578e-02-9.41198035e-02j, - 6.21270773e-02+6.40834784e-02j, 2.58933539e-02-2.42667870e-01j, 5.70136258e-02-3.77350337e-02j, 1.98579632e-01-9.20701075e-02j, 9.55640150e-02+3.54843433e-02j, 7.45928560e-02+4.26588872e-02j, 6.09447733e-02+3.16539556e-02j, -1.80171093e-01+5.60133264e-02j, 9.40854193e-02+4.31389113e-02j, 3.03850816e-04-2.85530728e-02j, 5.41410801e-02-6.13161714e-02j, 9.12148494e-02+1.80281943e-01j, 5.09948266e-02-3.86997536e-02j, -1.91113131e-02+1.94498984e-01j, 2.08692927e-01+6.43547140e-03j, 5.20633056e-03-1.90022093e-03j, 3.62398834e-02+1.08762806e-01j, 1.33590408e-01-1.61775350e-02j, -9.28966408e-02-5.91354052e-02j, 3.90924936e-02+3.49619784e-02j, -1.10597598e-02+1.62593761e-01j, -1.19019882e-01+1.11694210e-01j, 7.64944486e-02+8.29783985e-02j, 3.19470164e-02-2.07941529e-01j, -6.16504642e-02-5.17749153e-02j, -9.19641302e-02+1.26001118e-01j, 7.48796227e-02-5.35446337e-02j, 8.61395046e-02+7.66827772e-02j, 5.67446200e-02-1.44510489e-01j, -3.64513131e-02-9.95038225e-02j, - -5.23694938e-02+1.68673670e-01j, -9.98489889e-02+4.49214566e-02j, -2.62137478e-03+5.31844467e-02j, -1.97293197e-02-1.01779130e-02j, 6.56118297e-02-1.39819961e-01j, 1.07078888e-01-9.60455951e-02j, 4.04114157e-02-2.75185153e-02j, -1.06731160e-01+2.45576423e-02j, 3.97224538e-02+4.80422979e-02j, -1.41155662e-01+5.37056668e-02j, 3.94804097e-02-5.91553615e-02j, 1.02421169e-01+1.97936296e-01j, -1.01728301e-01-1.38399695e-02j, 8.76776513e-02+1.40003856e-02j, -1.53801875e-02+2.04027278e-02j, -8.81370764e-02+7.21575549e-02j, 2.88433274e-02-1.42749089e-01j, -6.16490703e-02-2.20430462e-01j, -1.98880578e-02-7.67322432e-02j, 5.79127107e-02-1.00419699e-02j, -1.09662385e-02+1.26745293e-01j, 7.36261795e-03-1.62045074e-02j, -1.45951390e-01-8.98045669e-02j, 1.04518882e-01+7.87311257e-02j, 1.84677017e-01+2.57397149e-02j, 9.20387231e-02+4.51211489e-02j, -8.11699179e-02+6.13269405e-02j, -7.54782810e-02-1.53812051e-02j, -2.27439779e-02+5.40599197e-02j, 5.27509423e-02+4.94672673e-02j, - 6.01908515e-02+7.08980366e-02j, 7.29386254e-03-4.35495079e-02j, 2.59865264e-02+5.23991312e-03j, -2.80790961e-02-3.17079888e-02j, 3.06137050e-02+7.10525322e-02j, 1.98725682e-01+1.63806997e-01j, -3.85808044e-02+3.17497500e-02j, -8.38991266e-02-8.29634220e-02j, 1.14568111e-01-2.51524437e-01j, 1.89161580e-01+1.22405055e-01j, 2.67369898e-02-6.29372223e-02j, -5.55112811e-03+8.24912321e-02j, 3.06911272e-02+1.24362478e-01j, 6.90052196e-02+4.78403406e-02j, 3.32511878e-02-5.54954803e-02j, -6.83065225e-02-9.83139293e-02j, -2.24205878e-03-1.08330998e-01j, 1.32158911e-01+6.21895108e-02j, 6.04041228e-02+2.26998786e-02j, 1.19910251e-03+2.40133006e-02j, 1.95384495e-02+7.25223079e-02j, -7.51114128e-02+7.50023940e-03j, -6.91753048e-02-1.84426984e-01j, 8.93361350e-02+6.14020197e-02j, -1.11027212e-02-2.73006053e-02j, -1.58027594e-01+1.12196684e-01j, 6.13191254e-02+2.98921562e-02j, 9.36940475e-02+1.74832860e-01j, 3.54488913e-02-1.86012865e-02j, 1.18886717e-01-5.60421606e-03j, - -5.08023225e-02+1.58187433e-01j, 2.05543121e-02+2.36229478e-02j, 7.56607990e-02-9.20635412e-03j, 3.04571802e-02-5.32735635e-02j, 1.05681520e-02+7.99310770e-02j, 1.00900200e-01+3.39036295e-02j, 6.00254366e-02+1.29251252e-01j, 1.73747341e-01-3.50700834e-02j, 8.68889594e-02+4.32124921e-02j, 1.20809063e-01-9.57225859e-02j, -5.08827469e-02-1.56682461e-01j, -5.51578706e-02-1.60825072e-01j, 7.75492052e-03+3.62310778e-02j, 2.70830573e-02+3.42352710e-03j, -3.35299324e-02-3.07678678e-03j, -2.09542652e-02-8.28876236e-02j, 1.67136215e-03+9.77623412e-02j, -8.33024445e-02+9.68319454e-03j, -1.27694754e-01-3.43756377e-02j, -1.05215118e-03+1.09484097e-01j, 5.77644996e-02+2.26376332e-02j, -2.27042043e-02+4.64923429e-02j, -7.52065556e-03+8.32320454e-02j, -3.45650834e-02-9.36227416e-02j, 1.58893895e-02-5.88622612e-02j, 6.75234381e-02+1.17750436e-01j, 9.91136713e-02-4.90548054e-02j, 1.14744296e-03-2.03805309e-01j, 1.26681748e-01+7.20946491e-02j, 1.72091738e-01+9.45687729e-02j, - -2.23781476e-02-3.05658385e-02j, -4.79846553e-02-9.53644599e-02j, 8.98978713e-02+3.73340639e-02j, 9.71904756e-02-5.07401492e-03j, 4.70042328e-03+2.98136201e-02j, 3.20602243e-02+8.90046751e-03j, 2.91870381e-01+1.56310942e-02j, 1.47571000e-02+1.74082211e-01j, 1.98727480e-01+1.81545936e-02j, 5.76140047e-02-1.37512019e-01j, 2.84157891e-02-8.90169341e-02j, 2.58144712e-02-8.66533513e-02j, 1.26007423e-01-1.42353852e-04j, 1.22011887e-02-1.50599335e-01j, -1.03678605e-01+1.77343389e-02j, 1.01880582e-01+1.02053135e-01j, -6.89911020e-04-1.34757213e-01j, -4.67669409e-02+5.62588217e-02j, 5.42306518e-02-4.70868860e-02j, 1.87819392e-02+5.88306140e-02j, -1.39180077e-01-5.74473723e-02j, -7.71319085e-02+1.05052464e-01j, -1.76084377e-01+4.53754001e-02j, 5.78987630e-02-1.39030598e-01j, -1.36379204e-03+1.03197101e-01j, -1.29842079e-01+6.46203124e-02j, 3.63331025e-03-1.52651696e-03j, -9.63370297e-02-5.23631453e-02j, 7.11523907e-02-7.71438142e-02j, -3.33129359e-02+4.04006262e-02j, - 2.49142373e-02+1.48066271e-01j, -2.26183059e-02+7.66734818e-02j, -5.45495074e-03-1.19942778e-01j, 9.13909578e-02+4.79952618e-02j, -5.35918216e-02-1.60654037e-02j, 5.98871312e-02-1.87532022e-02j, -1.12910440e-01-2.78610231e-02j, 1.46838755e-01+9.92565647e-02j, -4.13814974e-02+7.56087587e-02j, -4.88973691e-02+3.13114227e-02j, 7.56532879e-03+9.34644447e-02j, -2.67290794e-02-3.42410745e-02j, 8.46376955e-02-1.22432585e-01j, -3.13201588e-02-3.59657622e-02j, 1.52126152e-01+9.91205244e-02j, -9.45677226e-02-8.05276033e-03j, 5.46044728e-02-2.63756752e-01j, 1.95345701e-01+1.33669072e-02j, -3.25932513e-03-5.43829049e-02j, 1.53950498e-01-1.42848111e-01j, 1.48524300e-01+8.79890137e-03j, 1.17396603e-01+2.64318281e-02j, -2.62384138e-02+1.38751108e-01j, -9.52598923e-02+7.62648401e-02j, -1.80631676e-01-1.35669199e-01j, 8.51086298e-03-1.10183317e-01j, -8.83923576e-02+1.37131346e-01j, -3.89492392e-02-8.90366047e-02j, 1.90119483e-02+4.19438222e-02j, 1.12797080e-01+7.86580908e-02j, - 7.80716814e-02-9.09945481e-02j, 8.64121030e-02-7.22343210e-02j, -6.86716918e-02+1.03223441e-01j, 9.38556460e-02+7.85191865e-02j, 3.12389310e-02-8.62865526e-02j, 1.19593208e-02+6.74798173e-02j, -9.97752646e-02+4.73740307e-02j, 8.50920494e-02+1.21420677e-01j, -3.36867683e-02+7.31079808e-02j, 7.80684211e-02-1.11358256e-01j, -1.03606051e-01-1.00017901e-01j, 7.46662567e-02-4.58176146e-02j, -1.77215554e-01+5.14045000e-03j, -7.35851406e-02-5.88169005e-02j, -2.34091949e-02+5.56784850e-02j, -1.92734776e-01+5.23357550e-02j, 1.20534005e-01+6.92412538e-02j, -3.03040274e-02-2.43467856e-02j, 1.60451360e-01-1.02238503e-02j, 6.15204165e-02-1.94133488e-03j, -2.33847089e-02-8.66114982e-02j, 4.19745705e-02-4.99401327e-02j, -1.03928808e-02+8.20517312e-02j, -1.72244615e-03-4.42743317e-02j, 1.67168913e-01-3.07829598e-02j, -9.92849889e-02+4.65088178e-02j, -5.21084550e-02+2.70599004e-02j, -1.44242685e-01+1.42099698e-01j, 1.31564015e-01+6.03947617e-02j, 7.79295470e-02+1.16599297e-01j, - -1.44508140e-01+3.90326398e-02j, -1.63189060e-01-4.80102773e-02j, -4.23892524e-02+7.24586719e-02j, -1.08354291e-01+2.46926730e-02j, -3.31000925e-02-2.02469979e-02j, -1.06440911e-01+5.74076867e-02j, 2.98674990e-02-2.56460099e-02j, 3.27784317e-02-1.09277698e-01j, -1.11743589e-01-5.16542702e-02j, -4.38449856e-03+1.25111334e-02j, 4.20069024e-02+6.10391773e-02j, -8.31398473e-02-3.81548729e-02j, 1.09141869e-01+1.50926344e-01j, -4.57654467e-02-6.46747717e-02j, -8.54458173e-02+1.86067568e-01j, 6.94294608e-02-8.10150126e-02j, -5.70344424e-02+7.83521518e-04j, 3.21090931e-02+9.47319893e-03j, -6.02959548e-02-1.01689715e-01j, 1.25328049e-01+1.14694700e-02j, -3.84840481e-02-8.31927703e-02j, -6.76446553e-02-1.86440782e-01j, -9.65863639e-02+4.30146576e-02j, 1.86429327e-01+1.77285461e-02j, -2.79125197e-02+1.55599615e-02j, 9.66942708e-02+5.05933675e-02j, -1.96844343e-01-9.05549515e-02j, -1.06330695e-01-1.29754415e-01j, 9.69592860e-02+7.87237719e-02j, -3.20763173e-03-6.01830255e-03j, - -5.75846436e-02-3.07527027e-02j, -2.15090340e-02-1.13335909e-01j, 2.05999323e-02-1.64092718e-02j, 6.20217109e-02-7.21962400e-02j, 2.52569512e-02+8.67133723e-02j, 6.73469570e-02+5.06801423e-02j, -4.47799880e-02-1.27433227e-01j, -2.43147056e-02-4.19481682e-02j, -3.99145646e-02+1.36650217e-01j, -1.17600891e-02-3.67255385e-02j, -2.41082251e-02-1.48703792e-01j, 1.45917987e-01-2.09551629e-02j, 1.12455567e-01+4.32809709e-02j, -1.41748964e-01+8.50598353e-02j, -3.11770116e-02-5.18172723e-02j, 1.83579810e-01-7.06905345e-03j, 9.71116808e-02-7.25783826e-03j, -6.06413346e-02+1.83309774e-02j, 1.32067152e-01-8.04329623e-02j, -3.70830182e-02+3.25924415e-02j, 5.99945661e-02+1.39581640e-01j, 4.95057896e-02+1.41585780e-03j, 1.27163533e-01-2.79494886e-02j, -1.12806297e-01-1.38597417e-01j, -1.70331848e-01-6.41623156e-02j, 1.13320890e-01+4.80817353e-02j, 2.35832464e-01-5.92082391e-02j, 8.74837897e-02-2.86661849e-02j, 6.11698809e-02+6.06877492e-02j, 4.24028809e-02-6.62392146e-02j, - 4.30315505e-02-2.17789106e-01j, -2.72931426e-02+1.52670758e-02j, -3.82654806e-02+9.56802873e-02j, 2.43401149e-02-1.78124583e-02j, 9.02901686e-03-1.65710546e-01j, 8.04870293e-02+5.50553769e-02j, -4.69870057e-02+3.41343271e-02j, -3.50577896e-02+7.23143438e-02j, 1.10225646e-01-2.15752004e-03j, -9.61299965e-02-4.18347593e-02j, 8.68479349e-02+4.70126112e-02j, -1.07545082e-01+2.49148829e-02j, -4.53040726e-02-1.06734716e-01j, -1.59436033e-02+8.10286351e-02j, 2.02915812e-02-6.81132744e-02j, -6.08982393e-02+8.40773887e-02j, 1.50191978e-01-6.42097008e-02j, 1.35274591e-01+1.57431907e-01j, 3.53273620e-02+7.14369281e-02j, 1.81320909e-02+7.20914621e-02j, 6.03721972e-02+1.96226127e-01j, -3.18042660e-02-3.39904414e-02j, -1.19303840e-01+6.14160382e-02j, -1.76524156e-02-8.04986522e-02j, 1.76157967e-02-1.36875912e-02j, -4.49031451e-02-1.89495355e-01j, 1.26341022e-02-4.84818365e-02j, 7.93666935e-02-1.20859425e-01j, -9.00060617e-02+7.53951193e-02j, 6.15384669e-02+1.81702718e-01j, - -1.96562939e-02+6.02270326e-02j, -1.53637264e-01-3.42216746e-02j, 5.82845366e-02+1.35589726e-01j, -9.69854953e-02+7.81307161e-02j, 9.47424015e-03-7.67839223e-02j, -5.21777176e-02+1.18463908e-01j, 1.08597440e-02+7.34720754e-02j, 1.25753709e-02-4.59227875e-02j, 4.66065304e-03+3.16832178e-02j, -1.70642799e-01+1.09175443e-01j, -1.07616067e-01-6.77062304e-02j, -4.94690131e-02-1.33454471e-02j, -1.13671465e-01-1.13124774e-02j, 1.79311462e-01+1.36206373e-02j, -5.44546549e-02+2.39954931e-01j, 1.53720058e-01+8.17470362e-02j, -1.65785647e-01+4.99276923e-02j, 1.24051085e-01+2.08575029e-02j, -1.27344695e-02-1.00323698e-01j, 1.26323841e-01-1.75232843e-01j, 1.42829963e-02+9.51676108e-02j, -1.36837621e-02-5.10102254e-02j, -1.09035252e-01+3.04699753e-02j, -5.73977327e-02-9.67364763e-02j, -4.18955867e-02-7.26363284e-03j, -1.11110425e-01+9.11072318e-02j, -3.33402440e-03-9.81640668e-02j, 5.00153545e-02+2.96772715e-02j, 8.34464143e-02-1.07141828e-01j, 1.66627515e-02-1.76768451e-01j, - 3.01046178e-03+4.29920679e-02j, 3.90382225e-02+6.48627085e-02j, -1.29633542e-01-1.21639020e-01j, -1.81455901e-02+1.81332342e-02j, 1.70046497e-01+9.18523538e-02j, -7.49819636e-04+2.57010470e-02j, 6.14006255e-03-7.49534371e-02j, 5.73079131e-02+6.45021320e-02j, -1.25906199e-01+3.61504866e-02j, -4.14229989e-02-2.91283203e-02j, 3.22455405e-02+8.63451878e-02j, 1.23237528e-01-1.89968509e-01j, -3.05088062e-02+1.73009137e-02j, 2.14194747e-03+5.29985319e-02j, 6.96329432e-02+2.60627319e-02j, 1.57695179e-01+8.59454119e-03j, 7.26680354e-02+7.21484481e-02j, 7.00651142e-03-2.90372350e-03j, 2.90015482e-02-5.68542701e-02j, -1.27693027e-01-1.14964625e-01j, 1.50753348e-02-1.36610446e-01j, -1.47676083e-01+8.13290718e-02j, 9.24954421e-02+3.54388660e-02j, 1.81954041e-01+1.07582710e-01j, 1.15127848e-01+5.98445734e-02j, -6.47767365e-02+1.22084642e-01j, 5.54779597e-02-2.11336155e-01j, 2.33200724e-02+3.44422083e-02j, -3.99506520e-02-1.46402335e-01j, -3.39094996e-02-2.32080319e-02j, - 6.38032383e-02+4.58309555e-02j, 9.80627186e-02+6.74309177e-02j, 2.09243817e-01-9.21844569e-02j, 1.16068394e-01+3.58375950e-02j, 2.34470731e-02+1.34662899e-02j, -4.87953052e-02-3.39548474e-02j, 1.77551778e-02-7.33967642e-02j, -4.28970865e-02+2.14591815e-02j, 1.36029417e-01-9.66574708e-02j, -3.16822200e-02+1.06454016e-01j, -1.93320117e-01+1.76505036e-02j, 1.09916758e-01+1.27398554e-01j, -1.65850940e-01+7.04898942e-03j, -6.53608621e-02-1.87281647e-01j, -1.57179762e-02+3.65905427e-02j, -4.77377390e-02+5.01770606e-02j, 7.38286054e-02+5.86402502e-02j, 2.00220886e-01+2.14556567e-02j, -7.99321902e-02+1.20661845e-01j, 2.25130739e-02-7.92813095e-02j, 9.39404226e-02+4.23514982e-02j, 5.59759953e-02+5.29013915e-03j, 1.42272381e-01-2.03889918e-02j, -7.70692925e-02+2.18788591e-02j, 9.46416245e-02-5.40567083e-02j, -1.16864668e-01-1.17453747e-02j, -6.80245475e-02-8.85472661e-03j, -5.07648557e-02-1.41856238e-02j, -6.57054741e-02+4.87753999e-02j, 6.79140250e-02+7.57999993e-02j, - 8.31558858e-02+4.88031390e-02j, 7.04245127e-02+5.11799739e-02j, 1.92019820e-01+1.63346011e-01j, -1.08430098e-01+2.88148366e-02j, 2.15534804e-02-2.40090002e-02j, -2.83413932e-02+7.28009270e-02j, 2.77128550e-02-7.17129530e-02j, 4.43451848e-02+4.62015889e-02j, 2.29868386e-02-1.58564488e-01j, -1.80745027e-01-3.09626852e-02j, -5.25473622e-02-5.09485093e-02j, 4.13635441e-02+2.95240616e-03j, 3.46266625e-02+3.40501706e-02j, -1.36957085e-01+5.93795536e-02j, 1.71716569e-01+6.62369454e-02j, 2.00789628e-02+1.02579168e-01j, -2.49268976e-04+4.05793649e-03j, -8.70948659e-02+2.67855934e-02j, 9.58058704e-02-3.92343326e-02j, 6.37344353e-02+2.91954856e-02j, -1.62573041e-02+1.44050769e-01j, -2.12950381e-01+1.05380057e-01j, 1.54420103e-02-1.58531345e-02j, 4.62275644e-02-1.44131724e-02j, 9.63943826e-03+1.43294871e-01j, -6.82715621e-02+7.72801050e-02j, 1.19392259e-01-4.32006940e-02j, -9.25898691e-02+1.73642675e-01j, 7.87258333e-02-5.00345685e-02j, 6.74252100e-02-3.22021492e-03j, - -1.05938764e-02-4.80682200e-02j, -3.79109088e-02-7.18862647e-02j, -7.85329094e-03+5.08832953e-02j, -1.22207965e-01-2.08985568e-01j, 3.86004176e-02+9.75474606e-02j, 5.47838699e-02-2.51857867e-03j, 7.32135146e-02-2.02847686e-02j, -9.54663596e-02-1.51302713e-01j, 1.17232603e-01-8.67695572e-04j, 1.13627781e-02-2.45710953e-01j, 1.21005570e-01-1.25331270e-01j, -4.93568188e-02-6.26654349e-02j, -1.10411812e-01+1.72674386e-02j, 7.51406502e-02+1.35621387e-01j, -9.34619657e-03+4.06835362e-02j, -1.69436966e-01+2.11265428e-02j, 9.44593750e-02+9.45454295e-02j, 6.29973849e-02+7.81106789e-03j, -2.31884880e-02-6.08022409e-02j, -1.28506085e-02+4.57155954e-02j, -1.78724877e-01-8.40636436e-02j, -2.74516446e-03+6.87567686e-02j, 1.66154851e-01+2.97763171e-03j, 8.62945953e-02+1.33624387e-01j, -1.23971712e-01+1.06764084e-01j, -8.40377309e-02-4.45037883e-02j, -3.26308419e-02-1.03329380e-01j, -1.06682028e-01+9.15113745e-02j, 1.13743906e-01-7.02685477e-02j, -1.06680734e-01-1.29465759e-02j, - -6.97277691e-02-1.31064309e-01j, -1.10091153e-02+2.23611713e-01j, -4.61136052e-02-8.17268905e-03j, -1.69987303e-02-9.10722748e-02j, 2.79034389e-02-4.16172595e-02j, 1.24405356e-01-5.92755001e-02j, 3.02072420e-02+3.43359378e-02j, 1.10650997e-01+6.44841711e-02j, -9.59093007e-02-1.11423798e-02j, -5.96787368e-02-7.04578949e-02j, 3.28918399e-03+1.32284061e-01j, -3.72764227e-02+1.55273833e-01j, 2.06921775e-02+1.00442523e-01j, 7.21325549e-03+5.71288626e-02j, -2.14453527e-02-4.68398310e-02j, -6.82026389e-02-1.12497749e-02j, 4.92381808e-02+6.02284521e-03j, 7.83207240e-02+2.07448764e-02j, -5.05939363e-02-3.85781833e-02j, -3.35242535e-03-2.19084108e-02j, -3.49651101e-02+1.07847538e-01j, -2.45290850e-03-6.24826573e-02j, -1.51023459e-02+5.37010336e-02j, 6.37016602e-02-1.23760494e-01j, 2.91215038e-02-2.81493758e-02j, -3.39612485e-02+8.42272097e-02j, 7.35061854e-03+4.18985182e-02j, 1.12694901e-01+3.44174546e-02j, 2.75030448e-02-1.15362720e-02j, -6.56825803e-02+7.69914664e-02j, - 2.45522893e-01+1.94445453e-01j, 1.95565169e-02-6.02333458e-02j, -4.23341023e-02-4.08553715e-02j, -1.65720107e-02+1.11636285e-01j, 6.43254764e-02+5.20975294e-02j, 1.16324230e-01+4.30064237e-02j, -2.35493523e-04+7.94067955e-02j, -3.13234546e-02+3.31928019e-03j, -1.21907959e-01+8.94697709e-03j, -5.86229364e-02+5.00083180e-02j, 1.68440179e-01+1.58008999e-01j, -1.09277389e-02-5.63942582e-02j, -4.33874746e-02-9.18770776e-02j, -3.70318230e-02+2.10558944e-02j, 7.28110664e-02-4.99081181e-02j, 1.31921880e-01-4.54760418e-03j, 3.94635300e-02-8.20549821e-02j, 1.48897886e-01-1.45917759e-01j, -1.18265542e-01+3.70289451e-03j, 3.85086358e-03+1.91440435e-01j, 7.03135105e-02+2.60050811e-02j, -4.21039425e-02+3.01867113e-02j, -1.39706071e-01-2.85504702e-02j, 1.81921714e-03-1.40860236e-01j, 4.20339153e-02+1.95430738e-01j, -2.30135850e-02+3.09767448e-02j, 1.29258195e-01+9.14976478e-02j, -1.58756793e-01+1.28822164e-01j, -3.50036492e-02+8.00893734e-02j, 3.02776094e-02+1.42172163e-03j, - 2.57023140e-03-1.85433098e-02j, 3.72525284e-02+1.05139165e-01j, -9.12678942e-02+2.18607649e-01j, -1.46180909e-01-5.56793105e-02j, -6.56707703e-02-3.19916670e-02j, -7.38160928e-02-1.34669909e-02j, 3.23396348e-02-2.36520392e-01j, 3.30483293e-02-1.02266954e-01j, -4.19639544e-03-6.59678771e-02j, -8.19179151e-02+4.51704171e-02j, 3.09570371e-02-5.32005536e-02j, -5.22790586e-02-3.26500699e-02j, 1.56455025e-01-1.25231125e-01j, -5.05761174e-02+8.32852024e-02j, -2.59554971e-02+4.37847037e-02j, 2.16226296e-01-1.45471321e-01j, 2.65695033e-02+1.26666001e-01j, 4.68381033e-02+1.99629530e-01j, -1.50825778e-02+3.50747365e-02j, 1.26681152e-01-9.75019945e-02j, -1.71499088e-02-2.09581248e-02j, 1.61066501e-01+9.30902661e-02j, 2.60354119e-02+4.88141211e-02j, -6.21761636e-03-4.91509192e-03j, 1.70671987e-03-1.58639200e-02j, 9.95150572e-02-1.68503093e-02j, -3.98240701e-02-2.10542532e-02j, -7.76479029e-02+7.39797509e-03j, -5.77613183e-02+1.49932253e-01j, -1.67637878e-01+2.32658756e-01j, - 4.10173784e-02-4.51688638e-02j, 8.65002182e-02-1.06406855e-01j, 8.46830254e-02-1.72799554e-01j, 1.45422299e-02+2.59367720e-02j, 4.41673701e-02+1.11838918e-01j, 3.26970392e-02+4.00980128e-02j, -5.24772172e-02-7.49030751e-03j, -8.86683859e-02+1.79684474e-02j, -7.43158293e-02+1.44772160e-01j, -1.15935800e-01+6.86790801e-02j, 1.00946401e-02-5.68803310e-02j, 1.40177229e-01-1.19713358e-01j, -1.95130289e-01+5.29709085e-02j, 1.35467559e-01-2.15847353e-02j, 7.09552640e-02-7.66496576e-02j, -8.57302586e-02-1.37409094e-01j, -5.84144286e-02+4.22725006e-02j, -1.13523127e-01-2.08960999e-02j, -1.27785798e-01+2.27385357e-01j, 1.56444767e-03+1.48328917e-02j, 1.82904744e-02+9.01221738e-03j, -4.38128497e-03+4.96827820e-03j, -6.21944033e-02-7.90469632e-02j, 3.44125896e-04-4.79139098e-02j, 8.43927403e-03+4.11354177e-02j, 5.77038887e-02+8.29289688e-02j, 1.22039812e-01+1.12839590e-01j, -1.05530964e-02-1.15582561e-01j, -8.10699111e-02-1.07817350e-01j, -1.20022792e-01+6.78991377e-02j, - 6.48498574e-02-1.02145011e-01j, 2.90657255e-02+3.23596981e-02j, -1.43699949e-02+3.12920727e-02j, 1.71904194e-01-1.42590729e-01j, -5.09140335e-02+3.29766258e-02j, -3.01653038e-02+6.95227171e-02j, -3.76048324e-02-7.94865380e-02j, 6.51687233e-02+1.42580112e-01j, -1.39256310e-01-1.85980964e-02j, -1.10957689e-01-8.32129945e-02j, -1.22937408e-01+1.05433745e-01j, 2.32827863e-01-7.84040766e-02j, 9.68891514e-02+5.50536106e-02j, -7.66146565e-02-1.07485097e-01j, 3.75854655e-02+1.78256175e-02j, -1.05510057e-01+5.39334433e-02j, 2.59293770e-02+5.25056351e-02j, 4.17658585e-02+2.16550525e-02j, 1.79434516e-02-3.79639158e-02j, 4.54758271e-02-1.62169263e-01j, -9.15537346e-02-4.55546358e-02j, -2.87057950e-02-1.51850321e-01j, -4.73431627e-02-4.27936002e-02j, -7.34456848e-02+1.14503191e-01j, 3.21215086e-02-1.16222983e-01j, -1.86452641e-03-1.97148035e-02j, 9.35736392e-02+6.43359360e-03j, 9.90720039e-02+6.49407638e-02j, -1.30861723e-01-1.10397435e-01j, -6.06187143e-02+4.34780133e-03j, - -2.59141536e-02-8.36660746e-03j, 7.99764395e-02+2.05827485e-03j, -6.79710115e-02+2.19632538e-01j, -8.17267130e-03+1.30090034e-01j, 2.42203491e-02-1.18482312e-01j, -9.65525880e-03-7.27160937e-02j, 1.71710961e-02+3.97131195e-02j, 2.44032297e-02+1.55142147e-01j, -6.95618609e-02+1.14777484e-01j, -3.04082242e-02-2.56808488e-01j, -3.31333938e-02-4.42257523e-02j, 9.09829518e-02-6.41355665e-02j, 1.86082355e-01+8.21534305e-02j, 4.98683358e-02+2.30843433e-02j, 8.69232620e-02-5.72734258e-02j, 9.65089746e-02+4.63738692e-02j, 1.29934009e-01+6.98672714e-03j, -9.55106837e-02-2.11435206e-02j, -1.07437846e-01-4.34196605e-02j, 5.95822062e-02-1.60023155e-01j, 1.45094000e-01+3.62098607e-02j, -4.08020893e-02-3.54469118e-02j, -6.41922431e-02-1.50165876e-01j, 1.37778604e-01+1.57148644e-01j, 1.29772868e-01+3.87413012e-03j, -3.85445235e-04+9.15633467e-02j, 1.46217004e-02-7.02722233e-02j, -9.12225513e-02-1.34467186e-01j, -3.51468484e-02+4.68272859e-02j, -5.28148474e-02-7.05527841e-03j, - 9.85502435e-02-1.44725584e-01j, 4.52535985e-04-4.44306972e-02j, 1.03723988e-01+1.65607843e-01j, -4.21749097e-02-5.54886967e-02j, -9.10799975e-02+7.58681664e-02j, -2.17843207e-02+9.52639644e-02j, -3.30284395e-02+5.94376825e-02j, 9.26534994e-02+2.66802719e-02j, 1.03979128e-02-1.37706931e-02j, 2.33812820e-01+8.59946927e-02j, 6.98746888e-02+9.14639956e-02j, -1.08516120e-01+8.58234842e-02j, 4.21850071e-03+8.71853039e-02j, 6.36273247e-02+7.74673226e-02j, -3.91881255e-02+1.50528746e-01j, 1.09723495e-01+1.04344141e-01j, 7.43803264e-02-1.19685892e-01j, 2.19504862e-02+1.67527045e-01j, -1.60452930e-02-2.00978073e-02j, 6.55173044e-02+2.93255757e-02j, -8.85404950e-02-1.20757531e-02j, 1.14761440e-01-4.57840469e-02j, -5.41528486e-02-5.53916169e-02j, 4.21003566e-02-1.93226229e-02j, 3.45660820e-02-3.52093150e-02j, 1.17626157e-01-1.16988622e-01j, 8.56072498e-02-3.37517615e-02j, -5.90244905e-02-5.24335807e-02j, -5.65206254e-02-2.43446279e-02j, 1.20279495e-01+3.42123716e-03j, - -3.05654890e-02+1.98042481e-01j, 1.08387964e-02+2.84799289e-03j, -9.91462670e-02-3.82499265e-02j, 5.61732300e-02-2.25129588e-02j, 8.25340529e-02-1.45756514e-02j, -4.43017854e-02-1.98422787e-02j, -2.75902371e-02+2.17979919e-02j, -1.90295706e-02+4.21368188e-02j, -8.80691660e-02+1.15852296e-01j, -3.90388495e-02-2.17922247e-02j, 8.14551313e-02-6.28102543e-03j, 2.79352673e-02+6.35843316e-02j, -3.36457227e-02+1.90578786e-02j, -1.45100657e-02+3.63295744e-02j, -7.00631811e-03-7.40466939e-02j, -2.90520577e-02+7.81154295e-02j, -7.99312633e-02-5.37780863e-02j, 2.30177660e-01-1.83888371e-01j, -2.98717843e-02-1.13899232e-01j, -2.05273534e-02-1.81141663e-02j, 2.96813771e-02+5.94044596e-02j, -3.18971173e-02+7.22385762e-02j, 9.83167960e-02-8.92023743e-02j, 4.25608743e-03+9.09134290e-02j, 1.56893561e-01-4.23935738e-02j, 9.05556547e-02+3.59624971e-02j, 3.15980257e-02-5.46643490e-02j, -1.15196957e-01-8.82593135e-02j, -1.61272928e-01+1.78448561e-01j, 4.00567109e-03+1.76993307e-02j, - 1.17540437e-01-1.36239393e-01j, -6.69383706e-04+5.79926839e-02j, -1.12770659e-01-5.62223146e-02j, -6.21953015e-03-5.98234743e-02j, -4.10342219e-02-5.59744623e-02j, -5.66841235e-02+4.25833208e-03j, -8.23118814e-02+5.33394692e-02j, -1.34412900e-01-1.45272792e-01j, 1.15702329e-01+1.02297961e-01j, -3.19323625e-02+1.39788468e-01j, -2.24923180e-02-6.37168336e-02j, 1.39975574e-01+2.96315967e-02j, -2.05526833e-01-8.05348577e-02j, 1.20419312e-02+1.04877206e-01j, -5.36581838e-03-2.21242391e-01j, 1.43312392e-01+9.03085637e-02j, 1.50230560e-01+9.50231348e-02j, -4.59445185e-03+1.12399647e-02j, 5.16547174e-02+8.01461708e-02j, -9.43895891e-02-3.75397968e-03j, -4.73242216e-02-1.01945370e-01j, 3.44673025e-02+1.96628490e-01j, -9.88840012e-02+8.85464110e-02j, -7.92955362e-02-2.28998407e-02j, 1.69410571e-01+7.44974887e-02j, 6.20173928e-02+1.38106734e-01j, 8.52039046e-02-1.21666670e-01j, 6.84100368e-02-1.00904176e-01j, -1.42596295e-03+1.64268960e-01j, -1.24100632e-01-1.61368165e-02j, - 1.35519012e-02-2.59310892e-02j, 9.05490250e-02+4.84747479e-02j, -4.58662366e-02+1.34930496e-01j, -1.40646551e-01-1.69831134e-01j, -3.16239770e-02-1.48493455e-01j, 1.29115221e-02-4.76191420e-02j, 1.02846452e-01-1.15790746e-01j, 1.59952958e-01+3.50029230e-02j, 5.52164979e-02+5.58300761e-02j, -2.34098143e-02+1.20508448e-01j, -4.62940339e-02-1.16252123e-01j, 7.14945735e-02+8.50853849e-02j, 1.90523893e-02+1.82220632e-01j, 8.47593047e-02-3.87876272e-02j, -1.55367396e-01+9.11388648e-02j, -8.67503920e-02+3.87326858e-02j, -7.47073348e-02+1.13616928e-01j, -8.05356534e-02+7.50838943e-02j, -4.42508043e-02+1.04776551e-04j, 1.91365405e-02+4.59602654e-03j, -5.53849081e-02+9.81402899e-02j, 5.65523118e-02-1.28923219e-01j, 1.09708674e-02-7.17405169e-02j, 5.10870804e-02-4.18029754e-02j, -2.35923190e-02-3.54344675e-02j, 1.05632412e-01-1.52723227e-01j, 2.29356400e-02+1.72003014e-01j, -7.77818089e-02-8.58774571e-02j, -4.12300311e-02-1.40778154e-02j, 3.85331791e-02+1.34956847e-01j, - 9.08599023e-02-2.22765047e-02j, -6.47141773e-02+5.39631501e-02j, 3.78096842e-02+1.20010133e-02j, 6.56218844e-02-6.51650219e-02j, 9.31690801e-04-8.33640650e-02j, -1.79665558e-01+5.36828027e-02j, -7.18696825e-02+5.98082781e-02j, -7.60979310e-02+2.96533884e-02j, 8.38090767e-02+4.64776836e-02j, -1.90640176e-01-2.67445829e-03j, -3.33244747e-02+1.46650575e-01j, -2.87164842e-02-2.38484574e-02j, -1.31368281e-01+8.97392419e-02j, 1.70551482e-01-3.06077010e-02j, -1.23763743e-02-7.87055709e-02j, 1.03033690e-01-1.32308263e-01j, 4.89975988e-02-1.35921611e-01j, 9.42844960e-02+4.92092484e-02j, 1.25975887e-01-6.46248221e-02j, 2.04355365e-02+1.39811567e-01j, -8.13697343e-02+1.30030354e-01j, 1.44452639e-01-4.59256835e-02j, 8.30262490e-02-1.07582941e-01j, -1.01352710e-01+2.50968168e-02j, 3.80275778e-02+7.06296634e-02j, 1.01240183e-01-1.09841276e-01j, 7.93654229e-02+4.00721967e-02j, -1.27232823e-01+1.45125955e-01j, -1.63935684e-01-5.06866305e-02j, -3.33110180e-02+6.38573847e-02j, - 8.29906205e-02+2.45941583e-02j, 7.72777568e-02-2.18729918e-02j, -2.52670750e-02-1.33657547e-02j, 1.23713405e-01+6.60009234e-02j, 1.76105250e-03-5.13327294e-02j, 4.14606615e-02-1.08656071e-01j, -6.28912224e-02-1.07107702e-01j, 1.78069853e-01-3.95319222e-03j, -1.45753269e-03+7.84868919e-02j, 2.06813821e-02-4.02431446e-02j, 9.90237621e-02+1.96007825e-02j, 5.95901068e-02-2.92985389e-02j, 8.53920666e-02+9.47685100e-02j, -9.07144863e-02-2.48034646e-02j, -7.01707091e-02+1.05577150e-01j, -1.42941920e-01+1.06365145e-02j, -1.07249613e-01+2.31065721e-02j, -2.88007686e-05+1.70984097e-01j, -1.33993560e-01+4.60814975e-02j, 6.46602337e-02-1.73007798e-01j, 1.06092053e-02+1.77117336e-01j, -7.41235355e-02+6.72405741e-02j, -4.45379901e-02-2.75973792e-02j, 4.40770486e-02-4.07231141e-02j, 7.43855652e-02+3.34408901e-02j, 2.40780172e-02+7.63837816e-02j, -1.23431650e-02-2.96942615e-02j, -5.36958281e-02-9.09460148e-03j, 4.83507887e-02-3.64673587e-02j, -3.15949181e-03-6.78532281e-02j, - 1.49790019e-01+7.14330627e-02j, -2.59849469e-03+1.08797910e-02j, 2.39996357e-02-2.49046686e-02j, -1.70855065e-02-1.66572246e-01j, 2.50384745e-02-1.73555395e-03j, -8.79488783e-02-4.43380740e-02j, 4.04368200e-02-1.43535828e-01j, 6.99699704e-02+5.53061802e-02j, 1.06809669e-01+3.35034661e-03j, 2.35091058e-01+1.76495810e-01j, -1.04838058e-01+1.73042549e-02j, -1.79707883e-01-4.28597418e-02j, 1.06487618e-01+6.53314431e-02j, -7.12396824e-02-1.91412368e-03j, 1.75034759e-01+7.74238869e-02j, -2.80836905e-02+6.22152256e-02j, -9.72723299e-02-6.42131837e-02j, 1.28855782e-01-8.94346738e-02j, -6.34807923e-02-8.95849148e-02j, -1.76639575e-01+4.70857161e-02j, -8.66457034e-02+8.75818452e-02j, -9.89288233e-05+9.88579156e-02j, -8.42255352e-02+2.32390595e-02j, 5.68654338e-02+9.42482354e-02j, -7.55075952e-02-3.11797796e-02j, -1.77843576e-01+3.45449165e-03j, 5.22159678e-02+1.35185694e-01j, -4.83698045e-02+3.87913053e-03j, -1.51332382e-01-5.08730574e-02j, 9.19052718e-02+8.92932328e-02j, - -1.04864609e-01+1.59277075e-02j, 1.96860199e-01-1.54596648e-02j, -1.57519029e-01+8.28875556e-02j, 5.32027166e-02+1.80537329e-02j, -5.28489142e-02+4.64273257e-02j, 9.67687293e-02+5.45402170e-02j, -1.09668159e-01-1.19911498e-01j, 1.22173698e-01+7.19935237e-02j, -7.36173466e-02+1.19121401e-01j, 2.12661940e-01+8.30574676e-02j, 1.23393312e-01-1.96849020e-01j, 1.12986422e-01-1.66096746e-01j, -1.11544289e-01-9.50296086e-03j, 1.18875205e-01-9.74865066e-03j, -2.66898723e-02-6.04765594e-02j, 4.87295234e-02-3.00176126e-02j, -1.83928516e-02-1.56550584e-01j, -8.42099875e-02-1.94351327e-02j, 1.64034367e-01-1.73681939e-01j, 1.10112511e-01-7.38060195e-02j, 5.57965855e-02+1.27055482e-02j, 2.16746832e-02+3.08951640e-02j, -1.42130558e-02-2.70500110e-02j, -6.24735154e-02+1.00099685e-01j, -1.50431500e-03+1.77847451e-01j, 1.79109657e-01+4.53034157e-02j, 2.48493244e-01-1.15072362e-01j, 7.02539989e-02-8.21793869e-02j, 5.26929496e-02-4.78438510e-03j, 1.32560795e-02-2.04357332e-02j, - -1.65817978e-02-3.27041521e-02j, 1.45683239e-02+5.08346595e-02j, -2.16494395e-02-4.55596860e-02j, -1.19823818e-01-7.82211212e-02j, 5.69451958e-02-1.04748797e-01j, -7.35412255e-02-1.04581354e-01j, -1.12094932e-02+9.56866013e-03j, 1.07333598e-01-5.03504846e-02j, 3.98839186e-02+4.91837612e-02j, 1.24111729e-03+5.80244038e-02j, -8.12136032e-02-1.25906033e-01j, -1.47795068e-02-1.41661383e-01j, 7.28039351e-02-1.53666294e-01j, -1.44006427e-02-1.07568591e-01j, 2.89558773e-02+5.20172567e-02j, -3.64643948e-02-1.80813430e-01j, -6.77284194e-02-2.19340382e-02j, -1.51800732e-01+1.26354418e-01j, -2.73948963e-02-8.30809951e-02j, -1.23354114e-01+7.76964520e-02j, -2.26546949e-02-1.00472928e-01j, -4.60740997e-02+2.85918430e-02j, 4.98523677e-02+2.73595143e-02j, 6.84538848e-02-4.23015752e-02j, -1.23786500e-01-1.03759657e-01j, -4.63580185e-02-4.20827278e-02j, 5.00822284e-02+2.97891211e-02j, 1.20486086e-01-1.05685993e-01j, -4.83546445e-02-1.50608054e-01j, 4.41121465e-02+6.52452726e-02j, - -8.48704931e-02+1.00099989e-01j, 3.64618144e-02-5.84049288e-02j, 1.22257358e-01-2.46209538e-02j, -3.55664948e-02+3.00069552e-02j, -3.74424330e-02+1.03840630e-01j, 6.62161956e-02-1.24088728e-01j, -1.74591936e-02-6.08432847e-02j, -4.30903776e-02+2.28280325e-02j, -1.32783585e-01+2.54915665e-02j, 7.19465639e-02+7.60218114e-02j, 6.47195234e-02-6.25988897e-02j, 4.43633032e-02+1.13628071e-01j, -9.61062592e-02-1.10626660e-01j, 5.02086545e-03+1.71097394e-01j, 2.79457756e-01+3.62937257e-02j, 7.00690199e-02-7.77637776e-02j, 1.79011229e-01-8.68805824e-03j, 1.11655273e-01+1.15277003e-01j, 6.95789332e-02+7.61278729e-02j, 5.46339890e-02+4.89518665e-02j, 4.17643112e-02-9.89158287e-03j, 4.33563805e-02+8.13926965e-02j, -1.21887314e-01-2.12994079e-01j, 6.62822033e-02-9.28126086e-02j, 1.19584184e-01+5.96549891e-02j, -8.66323535e-02-6.73417091e-02j, -1.10895596e-01+1.63722633e-02j, 1.07332452e-01-2.05194027e-02j, 2.33547227e-02+2.92104674e-02j, 1.63241181e-01-3.72177572e-02j, - -8.50373601e-02-4.58981785e-02j, 1.30399262e-01+6.79769702e-02j, -3.88839698e-02-2.80027695e-02j, -1.42123694e-02-1.13992336e-02j, -3.91191271e-03-8.38363973e-02j, -3.00525620e-02-4.84482749e-02j, -7.07061618e-02+3.40883522e-02j, -2.65451649e-02+7.82186705e-02j, 7.06263189e-02+1.90006089e-01j, -1.06830313e-01+3.57336561e-02j, -1.83318787e-02-2.98391334e-02j, -1.26094265e-01-2.95955671e-02j, 6.69916734e-03-3.29056342e-02j, -4.56437407e-02-3.00362417e-02j, -1.97638423e-02-4.53695081e-02j, 5.62720421e-03+6.57464963e-02j, 1.62152741e-02+5.08849146e-02j, 7.15579817e-03-1.46367176e-01j, -3.66457634e-02-7.32904103e-02j, 1.47588967e-02+1.42117835e-01j, -4.15077413e-02+5.32471543e-02j, 1.81074012e-01-2.15788297e-01j, 1.37761481e-01+1.98205227e-02j, -5.49664338e-02+1.98201091e-01j, 1.06526105e-01+4.25454460e-02j, -1.11587932e-01-1.46278311e-02j, -5.20473894e-03+3.93591568e-02j, -3.98053192e-03-2.77757585e-02j, 8.01758751e-02+5.52518513e-02j, -1.89902375e-02-7.50263130e-02j, - 1.02340693e-01-1.07484115e-01j, 5.97194024e-02+2.99637326e-02j, 4.97079433e-02+9.42118947e-02j, -1.21749063e-01+5.12413635e-02j, 8.86514824e-02+2.02168637e-01j, -6.29512938e-02-5.10894134e-02j, 1.72194219e-02-1.39583523e-01j, -5.59939033e-02-7.47071549e-02j, 5.46002846e-02+1.44836673e-01j, -2.74093589e-02-4.62528590e-02j, -2.06132176e-02+2.54445042e-02j, 5.49369216e-02+1.13085624e-01j, 5.31450092e-02-5.77602131e-02j, 9.76193562e-02+1.59068016e-01j, -2.98195751e-02+4.85882645e-02j, 1.73318274e-02-9.95944267e-02j, 4.46831226e-02-8.05748385e-02j, 1.55069124e-01+1.85506946e-03j, 1.74618570e-01+7.88387737e-02j, 4.88827187e-02-6.57641635e-02j, -4.83705302e-04-3.66495970e-02j, -6.84625471e-03+9.00931899e-03j, 5.99085139e-02+9.55878693e-02j, 4.53412056e-03+4.82660251e-02j, 3.32400505e-02-7.24208945e-02j, 6.90343685e-02+5.16744895e-02j, 2.55541118e-02+2.68896192e-02j, -7.11313208e-03+5.40454970e-02j, -7.37568243e-02+3.56452181e-02j, -1.51159026e-01-3.32725818e-02j, - 2.76447397e-01-9.71246013e-02j, 1.40445833e-01-1.63819214e-01j, -7.47529467e-02+3.29702300e-02j, -5.24187826e-02+1.18661825e-01j, 8.31870820e-02-1.44188935e-01j, -9.53324502e-02+1.03506147e-01j, 3.50388013e-02-2.05399091e-02j, 5.87599572e-02-1.22481738e-01j, 1.06554427e-01+1.09594224e-02j, -2.37403722e-02-4.05386383e-02j, 1.30906014e-01+2.30293496e-02j, 3.42586203e-03+7.21644220e-02j, 4.28718087e-02-1.63183726e-03j, -9.74581387e-02-2.17171279e-02j, 4.79794062e-03+9.69996568e-02j, -2.81152594e-02+3.64640848e-02j, 1.41057044e-01-8.55610176e-02j, 1.13579799e-01-6.86894625e-02j, 3.26039112e-02-3.18036182e-02j, -1.03442985e-01+7.34067502e-03j, 2.45074328e-01-8.02551876e-02j, -9.95980284e-03-1.25597027e-01j, -1.13072351e-01+5.84716931e-02j, -2.91466791e-02-1.12346923e-01j, 1.39940920e-01+4.33022175e-02j, 9.62152966e-02+6.44762437e-02j, -1.78502974e-02+3.61510360e-02j, 1.58364304e-01-4.44919730e-02j, 5.56087485e-02-7.78226361e-02j, -1.28642124e-01+9.25199650e-02j, - -1.37827615e-02+8.63485029e-03j, -5.90489222e-02-6.21678061e-02j, -8.97089270e-02-5.55332554e-02j, 4.60473118e-04-7.44873712e-03j, -3.01789780e-02+2.62505348e-01j, -5.24922624e-02-1.16998291e-01j, -4.48619660e-02+7.75534691e-03j, -2.16942247e-02-1.32529990e-01j, 2.06845106e-01-3.99952263e-02j, 4.21013041e-03+3.75442281e-02j, 2.08877999e-02+4.65784759e-03j, 1.10316161e-01-1.85375840e-01j, 1.10518071e-01-5.97296649e-02j, 6.06210473e-02+4.13367885e-02j, -3.90943334e-02-8.60356454e-04j, 3.38772694e-02+2.12803762e-03j, 5.50896120e-02-2.37097732e-02j, -9.23532584e-03-2.15778018e-01j, -5.35860008e-02-4.10930146e-02j, 5.10150050e-02-9.19891264e-02j, -3.12179156e-02+5.16581942e-02j, -4.79608112e-02-9.76871529e-02j, -2.24134346e-02+1.11195765e-01j, 1.61216262e-01-9.33898111e-02j, 7.84476912e-03-1.25747019e-01j, -1.28241441e-02+1.46830948e-01j, 1.66002493e-01+6.78124856e-02j, 2.38609868e-01-1.74669970e-01j, 1.00056091e-01-1.91285012e-02j, 4.36951377e-02+3.92636206e-02j, - -6.33700025e-02+1.00688791e-01j, -9.01457033e-02-5.55666105e-02j, -2.74920713e-02-5.60945304e-02j, -1.12460738e-01+2.08926976e-01j, 1.47746830e-01+3.73544016e-02j, -1.18480516e-01+7.28623868e-02j, 4.33540648e-02+6.69355465e-02j, 4.12853021e-02-5.74198610e-02j, -5.08905281e-02-2.89177495e-02j, 4.39371436e-02+3.64541436e-02j, -1.86339121e-02+2.31353377e-02j, 9.01016810e-02+5.74020539e-02j, -1.46629405e-01-8.14734300e-02j, 8.38912755e-03+8.15995264e-02j, 4.11653085e-02-2.59878024e-02j, -5.12357023e-02+2.53150165e-04j, 1.36426369e-02+2.64118687e-03j, -1.95895595e-02+5.62617047e-02j, 2.47361159e-02-1.29518847e-01j, 3.88829366e-02+2.03908544e-02j, 3.41960599e-03-5.46266792e-02j, 7.46357033e-02-7.37336342e-02j, 2.42879656e-02-8.25850576e-02j, -1.30434368e-02+5.12158348e-02j, -5.86799503e-02-1.20936502e-01j, -3.64627451e-02-1.14700770e-01j, 8.79969190e-02+1.08108855e-01j, 2.86271051e-03+1.42659207e-02j, -4.16354582e-02+8.06660296e-02j, 4.15301680e-02+1.79575574e-02j, - -1.86461656e-01-2.42490106e-02j, 8.35776870e-02+5.65352490e-02j, 5.17627809e-02-2.14815383e-03j, 6.94949108e-02-1.12716819e-01j, 1.24952171e-01+5.87906220e-02j, 7.17725463e-02-1.19516974e-02j, 1.38777023e-01+1.91666559e-02j, -7.70714927e-02-8.45921195e-02j, -5.50990910e-02+1.88816346e-02j, -4.52069047e-02+9.92559466e-02j, 1.52931927e-01+2.18224356e-03j, 6.36110833e-02-1.49446746e-01j, -1.04306099e-01+2.55936479e-02j, -2.43190570e-02-1.24642498e-01j, 1.07908919e-01-5.24542844e-02j, 1.18023420e-01+1.82251949e-01j, -9.87945471e-04+2.24670038e-02j, 6.88747033e-02+3.88424142e-02j, 4.65620995e-02+6.84585535e-02j, 4.55186370e-02-1.10679652e-02j, 2.45232445e-01+1.21957784e-01j, -1.46216991e-01-6.73000332e-03j, 1.88431703e-01-7.71881296e-02j, 1.64320240e-01+5.78847160e-04j, 9.79316716e-02+4.54526962e-02j, 3.20288139e-03+1.55014950e-01j, 5.47467470e-02+4.35107341e-03j, -2.08130010e-01-5.64307911e-03j, -1.10232566e-01+7.32351151e-02j, 1.35941251e-01+1.38078108e-02j, - -7.56788025e-02+3.73517234e-02j, 2.04679302e-01+3.90147242e-02j, 1.08785662e-01-6.94594148e-02j, 7.20045941e-02+2.78459276e-02j, 1.92400736e-01-1.50979597e-01j, -1.58869068e-01-8.22425262e-02j, -2.98171534e-02+1.71665472e-03j, -3.06886027e-02-8.02964429e-03j, -4.25762489e-02+3.23637065e-02j, -2.79618445e-02-2.07485498e-02j, 1.18857251e-02-1.75486789e-02j, -4.36645926e-02+6.80482134e-02j, 7.37583273e-03+1.26666694e-01j, 3.95626865e-02-9.77189985e-02j, -1.48716204e-01+2.68786987e-01j, -3.72800597e-02+5.71237210e-02j, 7.41890650e-02-7.52430682e-02j, 3.90385347e-02-2.07079317e-02j, 3.84685342e-02+5.01376534e-02j, -5.27350224e-03+1.47858994e-01j, 3.90452488e-02-8.37384564e-02j, -7.98233712e-02-1.79529336e-02j, 1.33565706e-01+4.92479091e-02j, 3.72930254e-02+1.73346346e-02j, -8.85513745e-02-3.44914310e-02j, -2.55952093e-03+1.10740235e-01j, 1.22295953e-01-6.26298383e-02j, 1.07479323e-01+4.08024277e-02j, 1.94989868e-02+4.87243296e-02j, 1.43449277e-01-1.01261533e-01j, - -2.16939069e-02-4.18289269e-02j, 6.07804273e-02+9.37183963e-02j, -4.85826992e-02+4.34844713e-02j, -2.86068223e-02+1.03414084e-02j, -6.82958979e-02+7.45791847e-02j, 9.92759338e-03-1.01013890e-01j, 4.46668242e-02+5.34278176e-02j, 2.05957081e-01-8.43994442e-02j, -3.17105069e-02-2.64039322e-02j, -1.23137159e-02-1.67162172e-02j, -7.10187538e-02+1.11568931e-01j, 4.83956551e-02+1.38122479e-01j, 1.06745393e-01+3.55201390e-02j, 5.36566000e-02-1.64529636e-01j, -3.22813703e-02-4.03551165e-02j, -8.16829634e-02-1.59310035e-02j, 9.19194280e-02-1.87254021e-03j, 5.39877612e-02-1.41864131e-01j, -9.76301436e-02-1.21547018e-01j, -9.20678092e-02+1.74387849e-01j, 1.40685348e-01-1.27548000e-01j, 2.96123871e-02-1.02922618e-01j, 1.11352902e-01-8.62467830e-02j, -1.09712727e-01-3.89440732e-02j, 1.18222416e-01+5.77362689e-02j, -6.58226250e-02-1.00553320e-01j, -7.08216359e-02-3.82394234e-02j, 5.22392245e-02-9.90544241e-02j, 1.04343923e-01-2.21400076e-02j, -1.50119333e-01-2.08365776e-03j, - -2.00031377e-03+5.81542663e-02j, 3.83065634e-02+1.08315594e-01j, -1.52024028e-01+1.13697356e-01j, 5.98038406e-02-4.82362581e-02j, 8.65636860e-02-6.35096970e-02j, 7.72958756e-02-2.56093728e-02j, 2.29512769e-02+9.62400436e-03j, 4.45398156e-02+8.80887704e-02j, 9.49028759e-03-2.35771406e-02j, -2.36791919e-03-7.62382381e-02j, 1.19090719e-01-8.93309279e-02j, 5.19314568e-02+3.85447831e-02j, -3.87628280e-02+7.77506760e-02j, -3.26884566e-02+1.91066264e-02j, 1.43129957e-01+5.06655538e-02j, -8.14216372e-02-1.24857868e-01j, 4.08149916e-03+3.39964438e-02j, -3.18000514e-02+4.94502870e-02j, -8.59753841e-02-6.05242613e-02j, -7.02375587e-03-7.23709227e-02j, -5.90808602e-02-5.10396991e-03j, -3.99358436e-02+1.54029042e-01j, -1.48939165e-01-2.30986046e-02j, -1.36109697e-02+6.09298717e-02j, 3.36241127e-02-2.08250661e-01j, -6.48593373e-02-2.60921265e-02j, 4.78423392e-02+1.56280882e-01j, -3.67274730e-02-8.41030956e-02j, -1.44975443e-02+7.80523865e-02j, -1.13469394e-01-6.74622693e-02j, - 4.70147160e-02+3.56008433e-02j, 1.80886023e-01+6.94462782e-02j, 2.01441028e-01-2.41069795e-02j, -1.77832245e-01+1.67730057e-01j, -1.72926391e-01+8.72396028e-02j, 1.05716876e-01+7.93440128e-02j, -7.17398366e-02+2.39715722e-02j, 9.40991385e-02+9.48572465e-02j, 7.56374392e-02+1.26422068e-02j, -3.42567574e-02+6.57554524e-03j, -9.80583679e-02-2.48742400e-01j, 1.94821099e-03-4.61412351e-02j, -1.15171892e-01+4.23163024e-02j, 9.55046504e-02-2.85351271e-02j, 6.87501834e-02-9.09245253e-02j, 8.69873372e-02-1.36599865e-01j, 8.72279542e-03+1.71002218e-01j, -1.47382708e-01+1.48146962e-02j, -4.20312282e-03+1.48338430e-01j, 9.18441565e-02-1.67967981e-03j, 1.16613728e-01+1.50842236e-01j, 3.91945313e-02-1.54576297e-01j, -1.04976187e-02+6.29468802e-02j, 1.25177984e-02-8.77763898e-02j, 4.89867798e-02-5.41877145e-03j, 1.09219986e-01+4.12706256e-03j, 4.09641507e-02-2.21297934e-02j, -2.48745776e-02+1.70792444e-01j, -1.24622984e-01-5.47605581e-02j, -6.76718048e-02+5.83777721e-02j, - 1.08185457e-01-1.27066585e-02j, -4.14109909e-02-3.11627607e-03j, 9.79107799e-03+1.12951585e-01j, -4.09954965e-02+4.97455619e-02j, -1.01938277e-01-1.20867638e-01j, 5.94627844e-02+5.46678428e-02j, -2.22617431e-02-1.00320800e-01j, -5.28175862e-02-8.33668982e-02j, 5.18586133e-02+1.16558179e-02j, -6.29728280e-02+1.05923649e-01j, -5.99212755e-02+1.94190572e-02j, 6.94771130e-02-1.55683386e-01j, 5.19897813e-02+6.27034419e-02j, 7.90956993e-02-9.01446300e-02j, 1.88130641e-02-1.49956110e-02j, -4.23517166e-02-8.81984045e-02j, -8.63174858e-03-1.60373942e-01j, -8.74400710e-02+1.35436105e-01j, 1.05708057e-01-4.90293166e-02j, -8.38220286e-02+6.93173211e-02j, -9.44596245e-02+1.41396701e-02j, 1.44384840e-01-5.37706430e-03j, -1.41297717e-02+2.07240685e-01j, -8.91091924e-03+2.76415024e-02j, -5.69003223e-02-1.87856438e-02j, -3.10382650e-02-9.69041662e-02j, -8.46753743e-02-4.51121121e-02j, 2.13287292e-01+2.96795365e-02j, -6.78000993e-02-7.27014711e-02j, -5.24643121e-02+1.97358995e-02j, - 8.62181411e-03+1.79870726e-01j, 1.52898138e-01-9.88048051e-02j, 4.74521169e-02-3.56121574e-02j, 9.22896695e-02+1.40223845e-02j, 4.68319387e-02-7.26391162e-03j, 5.92394125e-03-4.79254400e-02j, 2.16269967e-01+5.54358310e-03j, -4.27515151e-02-1.23614667e-02j, 9.83446073e-02+8.83227942e-02j, -1.09197854e-01+4.99396436e-02j, -8.15404308e-02+2.55541009e-02j, 7.39865612e-02+6.55508075e-02j, 6.63286555e-04+1.54249963e-01j, 9.27110573e-02+3.41628715e-02j, 1.45527728e-01-1.41080682e-01j, -1.41359130e-02-6.02124272e-02j, -1.70089668e-01-9.50888884e-03j, -5.90907847e-02+9.90858589e-02j, 1.20282993e-01+1.63169966e-02j, -6.01831403e-02+4.99282270e-02j, 1.48186487e-02-1.19425802e-02j, 1.58460014e-01-4.80879586e-02j, 1.74692437e-01+1.32829541e-01j, -7.74148211e-02-3.37385643e-02j, 9.17695643e-02-3.98154413e-02j, 2.37156746e-02+9.59269352e-02j, 2.12142259e-01+2.79772767e-02j, 1.07204688e-01+7.30996249e-02j, -1.02045757e-01+1.90798954e-01j, -1.41858107e-01-1.07587269e-01j, - -1.43454403e-01+3.73650281e-02j, 2.32833516e-02-1.36078422e-02j, 8.83472839e-02+2.71852498e-02j, 1.19513218e-01+5.01626287e-03j, -5.92568345e-02+4.09442957e-04j, -8.14238995e-03+1.83183640e-02j, -6.61149944e-03+7.80984936e-02j, -1.12162965e-01-1.19962828e-01j, 5.48458766e-03+1.00469491e-01j, 2.73708801e-02-5.82827636e-03j, -1.19046015e-02-3.82564125e-02j, 7.29885631e-02-9.01451280e-03j, -4.94120509e-02+8.26467259e-02j, -5.51635770e-02+5.15768294e-02j, 3.20117208e-02+5.85584915e-03j, 1.06872987e-01-4.31353939e-02j, 4.40304662e-02+2.91857939e-02j, 1.68500095e-01-2.82738129e-02j, -2.03371967e-02-1.26195722e-01j, 2.83846022e-02+8.17355207e-02j, -1.51547265e-02+1.12602067e-01j, 7.81649864e-02-2.38189548e-01j, -1.35224365e-02+3.19631898e-02j, 1.17490585e-01+4.01554664e-02j, -4.72704834e-03-3.99565213e-02j, -8.84904826e-02-4.28727274e-02j, -1.22198482e-01-2.42786041e-02j, -1.12897707e-03-6.94497623e-03j, -2.19884514e-02+8.55486354e-02j, 8.70638696e-02-1.07127798e-01j, - -2.29371995e-02+4.63320598e-02j, 1.93873091e-02+1.86337449e-01j, -1.25468921e-02-5.18952165e-02j, -7.45890764e-03-8.03295372e-02j, -3.56745327e-02-6.25638362e-02j, -4.75510121e-02-7.83464611e-02j, -1.39534894e-01+8.16425405e-02j, 7.70005031e-02+8.69423266e-02j, 1.43911987e-02-1.33546977e-01j, -1.47102056e-01+1.15681347e-01j, -1.33126375e-01+1.02235868e-02j, -1.45122855e-01-2.89314423e-02j, 1.11563142e-02+3.69740758e-02j, 1.00779242e-01-3.90064124e-02j, 1.26325368e-01+6.71845381e-02j, 3.24794315e-02+1.38737288e-02j, 6.81836122e-02+1.40750598e-01j, 3.44546719e-02-5.21553657e-02j, -4.57601524e-02-3.27555405e-02j, 8.24373398e-02-8.90390790e-02j, -1.16860314e-01+1.25653018e-01j, 1.46493260e-01+1.41194112e-01j, -1.45396010e-01-1.32885959e-01j, -7.73293855e-02-6.72724685e-02j, 1.49309687e-01+6.97139456e-02j, 1.91464376e-01+3.82211888e-03j, -3.63957571e-02-1.31754413e-01j, -2.46974881e-02+1.39206134e-01j, 5.83769856e-02-3.77826253e-02j, -6.72768215e-02+2.28114923e-02j, - 2.55957644e-02+4.21858672e-02j, -5.88391848e-02+1.42670909e-01j, -7.05483919e-02-3.98423804e-02j, -7.02652206e-02+1.00856608e-01j, -1.41224511e-01+4.66217961e-02j, 1.07977589e-01+2.05966808e-01j, 1.27139331e-01-9.33860861e-02j, -5.36280638e-04-3.59555623e-02j, 2.38548900e-03+1.08390515e-01j, 5.57620979e-02+2.13967089e-01j, 2.14044445e-02-6.81976237e-02j, 1.33050862e-01+9.78079190e-02j, 9.59093734e-02-1.86488160e-02j, 6.43843748e-02-1.00325395e-01j, -3.78896000e-02-5.56830122e-02j, -9.49734363e-02+1.78783106e-01j, 8.92016398e-02-5.73330404e-02j, -1.49081326e-01-8.02418770e-02j, 1.29000520e-02+2.00740628e-01j, 9.56015376e-02-7.84317559e-02j, 7.74367443e-02+1.73620000e-02j, 6.30112118e-02-2.32571601e-01j, 3.00303803e-02-9.83705381e-02j, 1.61844259e-01+1.05485097e-01j, 2.40291349e-01-4.01070715e-02j, 1.18754377e-01+4.31127547e-02j, -2.18267030e-03+2.88200832e-02j, 1.17227459e-01+1.26467873e-01j, -8.49409061e-02+4.97160270e-02j, -1.63005455e-03-4.99396218e-03j, - 8.44483610e-02+7.05728728e-02j, 1.24861205e-02-2.58181667e-02j, -5.50187440e-02-4.48743334e-02j, 2.80015656e-03-4.82029670e-02j, 4.06373407e-02+1.17659005e-01j, 6.92546145e-02+5.26651932e-02j, 4.41971443e-02-7.53547930e-03j, 1.58836470e-01+1.43051517e-01j, 1.75841588e-01-9.63643389e-02j, -8.17547660e-02-3.31679339e-02j, -3.90876419e-02-9.54602863e-02j, -5.27660299e-02-4.52618847e-02j, -3.29940397e-02-7.32188040e-04j, 1.33182711e-01-3.30125326e-03j, -1.73800247e-01+7.37850658e-02j, -9.03044053e-03-5.62976198e-02j, -7.23873677e-03-5.29735141e-02j, 2.81516307e-03+5.96141674e-03j, 3.40919441e-02-4.95963107e-02j, -5.85547763e-02+1.19710083e-01j, 3.71410507e-02-1.14337865e-01j, -3.28786435e-02-1.31582104e-01j, -3.11008227e-02-1.06387141e-01j, 5.70725503e-02-5.01012877e-02j, -5.67037266e-02-1.45846038e-01j, 5.12987918e-02-5.27321657e-02j, -2.91698456e-02+7.36045193e-02j, -1.78732183e-03+3.56761928e-02j, -4.22088087e-02-2.10621398e-02j, -4.93624568e-02+1.57929069e-02j, - -7.57986052e-02+1.05462121e-01j, 9.12211212e-02-2.55913922e-02j, 1.65492733e-01+1.11378639e-01j, 1.23643907e-01-6.70361505e-02j, 8.91758326e-02+8.21455575e-02j, -5.05051969e-02+5.59456241e-03j, -1.26290743e-01-5.67854069e-03j, -1.18931736e-01+1.53843733e-01j, -7.50296683e-02-1.07846045e-01j, -1.21333537e-01+4.07381039e-02j, -8.52090624e-02+1.29604666e-01j, 8.09572029e-02+5.23771628e-04j, -5.44002980e-02+1.27113581e-01j, 5.79705919e-02-4.22805852e-02j, 1.26732210e-01+1.50354241e-03j, -4.77950234e-02+1.99087102e-02j, 1.03424607e-01+3.40027024e-02j, -5.83845975e-02+1.59746122e-01j, -2.17388369e-01+6.74992723e-03j, 1.42500131e-01+5.05071268e-02j, 5.45543560e-02+3.92456147e-02j, 2.18488301e-02-6.14267392e-03j, -5.57776866e-02+8.26003743e-02j, 3.49894774e-02+1.41336726e-01j, 6.69241650e-03-1.04471824e-01j, 1.21772946e-01+1.91210500e-01j, 1.19217589e-01-5.38115139e-02j, 1.88246371e-02-1.83004726e-02j, 2.08866104e-03-7.33113093e-02j, -8.12529253e-02+4.61430645e-02j, - -4.46184815e-02-3.01757956e-02j, -1.35634714e-02+3.38777008e-02j, 4.94210365e-02-2.07529226e-01j, 8.74104130e-02-5.08970513e-02j, 1.53550582e-02-9.11243595e-02j, 8.84523103e-02-4.03101881e-02j, -2.23589887e-01-7.04136609e-02j, 1.23249442e-01+7.55507497e-03j, -1.36224452e-02+1.24659565e-01j, 2.28284552e-01-1.13277060e-01j, -5.96268468e-02-5.73745561e-03j, 1.29530326e-01-8.61904688e-02j, 8.54578487e-02-1.00686862e-01j, 2.70928472e-02-4.63967514e-03j, 1.48161107e-02-5.46569087e-02j, 2.85271880e-02+3.26964639e-02j, 7.96782967e-02+1.10891607e-02j, -1.34176030e-01+6.96277781e-02j, -3.29195127e-02+9.64297617e-02j, 3.03391090e-02+9.71757423e-02j, 5.29277338e-02+3.47785677e-03j, -6.26896146e-02+4.62296383e-02j, -7.85231220e-03+3.56225075e-02j, -1.59413042e-01-7.66033618e-02j, -8.52104081e-03-3.79146418e-02j, -8.48098551e-02-1.08488438e-01j, 6.84002684e-02-9.27612240e-02j, -6.64407275e-02+4.15485835e-02j, 6.08387005e-02+8.19913120e-02j, 1.00446088e-01+1.55852725e-01j, - 3.97609833e-02+1.00146008e-01j, -5.22778987e-02-8.21009007e-02j, -3.77077303e-02+5.13288886e-02j, 9.21346640e-02-1.02972511e-01j, -5.81472043e-02+9.22815026e-03j, -6.72925561e-02-4.11932180e-02j, 6.44503140e-02+1.29261896e-02j, -1.32762347e-01+9.23711163e-03j, -1.03599757e-01-4.56192544e-03j, 3.24505339e-02-2.45398116e-03j, 6.58694205e-02-3.21227618e-02j, 1.24036462e-01+1.47475323e-02j, 1.30152316e-02+1.35707105e-01j, 1.56039110e-01-5.18164633e-02j, -7.03152690e-02+3.12506934e-01j, 8.76117464e-02+1.17448220e-02j, -4.68448704e-02+4.10314253e-02j, -3.22028182e-03-1.22678955e-01j, -1.14178360e-01-6.71304826e-02j, 4.55256387e-02+3.82766596e-02j, 1.48401693e-01-5.47951986e-02j, -7.56378950e-02+1.20320511e-01j, 6.30532615e-02+1.01337916e-01j, -4.99127404e-02+1.37739974e-02j, 2.35931263e-02-3.96687088e-02j, 2.67108253e-02+6.13453731e-02j, 1.62891049e-01+7.84529123e-02j, 7.49086743e-02+1.10381126e-01j, 7.63873637e-02-1.19047306e-02j, 6.77266410e-02-3.28310781e-02j, - -8.53110808e-02-2.50184384e-02j, 3.83933170e-02+1.43491474e-01j, -8.86989164e-02+7.99727750e-02j, -7.37362920e-02-1.49473969e-01j, 6.43959171e-02+1.99276397e-02j, 6.27697475e-02-2.27116899e-02j, 8.40868521e-02-5.22837391e-02j, -1.12648545e-02-1.12680946e-01j, -1.32392949e-01+4.13293428e-02j, 1.14842189e-01+3.80617047e-02j, 4.67782370e-02+1.54746874e-01j, 8.23224982e-02+4.56644140e-02j, -2.82310492e-02+1.47896780e-01j, 6.71171984e-02+3.63367239e-03j, -1.30820895e-02-1.66233584e-02j, 1.56041973e-01-5.91053002e-02j, 9.72049576e-03+1.57604493e-01j, 3.99164787e-02-1.39203421e-01j, 1.33473022e-02-2.20465140e-02j, 8.28185122e-02-6.79543638e-02j, 3.82282405e-02-5.77487822e-02j, -1.55532854e-02-1.04539428e-01j, -5.91946563e-02-1.84369274e-02j, -3.82486186e-02+4.42172266e-02j, 1.18801889e-01-8.57833822e-02j, -2.51752531e-01-1.52096140e-01j, 1.55380879e-01+7.23105262e-03j, -1.01032533e-02+1.06962879e-02j, -1.31703458e-01+3.76881824e-02j, 1.60460085e-02+6.30850547e-02j, - 4.19255549e-02+3.92629725e-02j, 4.93357915e-02+4.62217751e-02j, -2.46551328e-02+9.18461625e-02j, 7.84824861e-03+3.42026930e-02j, 2.27842145e-02+1.02988705e-01j, 8.89143553e-02-1.32777071e-01j, -1.53255753e-01-5.64168441e-02j, 2.60864735e-02+6.83070308e-02j, 1.24089898e-01+1.46531300e-01j, 8.03861657e-02+8.44347212e-02j, -3.99675456e-02-4.13219148e-02j, 1.99496563e-02-1.68741956e-01j, -9.61656011e-02-9.85036805e-02j, 3.81645661e-02-1.58403405e-01j, -1.22222597e-01+2.27927369e-02j, -1.95541768e-01-3.26566021e-02j, 3.06440615e-02+3.05364521e-02j, -8.76411203e-02-1.79424422e-02j, -2.13722727e-02-1.46393081e-01j, 1.81898579e-02-1.17003644e-01j, 1.36627407e-01-1.57758323e-01j, -5.03748616e-02-1.47579680e-01j, -3.40991053e-02+2.60350260e-02j, 6.61586084e-02+1.13051859e-01j, 9.27199042e-03+6.76019455e-03j, 1.97908095e-01-7.26532762e-02j, 8.82218775e-03+6.06572679e-03j, -7.52454053e-02-6.42541289e-02j, -8.99883870e-02+4.02263836e-02j, -1.59753697e-02+1.71002481e-01j, - -2.61136199e-02-1.03271017e-01j, 1.56419876e-02+3.02378993e-02j, -1.06994379e-02-4.42494478e-02j, 7.02703110e-02+5.64923383e-02j, 5.07122277e-02+4.74081563e-02j, 7.67303013e-02-1.56906009e-02j, 9.16318724e-02-3.07214532e-02j, -5.18225692e-02+1.08506378e-02j, -7.67455403e-02+5.55639645e-02j, 6.64535546e-02-9.01565151e-03j, -9.14990010e-02+3.73538098e-02j, -7.28625453e-02-1.19186740e-01j, -2.77589055e-02-8.22322098e-02j, -3.22296245e-02+1.31757376e-01j, -3.50339775e-02+1.37913873e-01j, 3.84813010e-02+1.67884657e-01j, -7.00195023e-02-6.19230041e-03j, 8.02979751e-03+1.25547652e-01j, 3.81418938e-02-8.66550141e-02j, 6.66673422e-02-2.80517890e-02j, 1.47446194e-01-1.21608923e-01j, -1.06983782e-01+1.61685673e-02j, 1.45128417e-01-9.97579672e-02j, 4.78343409e-02-3.43103884e-02j, 5.46402843e-02+3.32975311e-02j, -1.17712449e-01+3.53043129e-02j, 6.17783098e-02+7.68043303e-02j, -4.12278356e-02+2.20803550e-01j, -1.27049166e-01+5.43901474e-02j, -3.76806434e-02+1.87060854e-01j, - -8.90334008e-02+4.81197426e-02j, -1.61805869e-01-5.83124248e-03j, -2.35021073e-01-1.36839690e-02j, 5.95583000e-02-8.53455811e-03j, -1.36475568e-02+1.02072032e-02j, 6.57874310e-04-5.54357406e-02j, -1.16075063e-02-1.88043201e-01j, -4.10593532e-02-1.25295385e-01j, -1.01181308e-02-1.83976177e-02j, 1.22655279e-01-1.17069920e-01j, 4.31446899e-02-6.57352962e-02j, -1.00119330e-01-1.39878527e-01j, 9.98658335e-02-4.26160789e-02j, -1.34536488e-01+9.74478087e-02j, -6.92874025e-02-8.13138795e-02j, 2.45163582e-02-1.76548089e-01j, 3.22174804e-02-5.65589817e-03j, 8.07679515e-03+6.33986691e-03j, -6.31184637e-02-4.41509650e-02j, 2.05374550e-02+4.76306825e-03j, -1.36800160e-01+3.66858887e-02j, 1.47490170e-01-1.20606391e-01j, 8.14807620e-02-2.11446690e-01j, -1.45202365e-02+8.19600273e-02j, -1.59974770e-01+4.89558755e-02j, 1.40694468e-01-3.31038214e-02j, 1.41222361e-02+1.88783167e-02j, -1.39964930e-04-7.90888896e-03j, 4.02400089e-02-1.91496498e-02j, -2.10975834e-02+2.55743635e-02j, - -1.24830235e-02-1.04506988e-01j, -7.83991128e-02+7.24495291e-02j, -7.67997026e-02+1.15793120e-01j, 7.71299789e-02+1.54784598e-02j, 1.00227939e-01+1.64355312e-01j, 8.14056190e-02+1.20896109e-01j, -5.07211511e-02-4.31177626e-03j, -5.98801754e-02+1.87757032e-01j, -5.58581009e-02+1.11035307e-01j, 8.64549886e-02+9.22623166e-02j, 1.33102211e-01-8.68358502e-02j, -4.38973116e-02+3.47998547e-02j, -1.51802312e-01-9.79580479e-02j, 2.32964551e-01-2.62447131e-01j, 5.48006171e-02-8.11579033e-02j, -1.74315936e-02+9.52579508e-03j, 1.17761070e-01+1.11200729e-01j, -8.00284541e-02+1.32515499e-01j, -1.49555446e-02+1.88069542e-01j, -7.57884206e-03-4.58967652e-02j, -9.50078367e-02-1.00631395e-01j, 1.72491605e-02+4.47670026e-02j, -2.03781472e-02+3.26250698e-02j, -9.59715607e-02-4.37484169e-03j, -9.58454167e-03+2.95792410e-02j, 1.05438691e-01-1.33092379e-01j, 3.09937517e-02-2.42140206e-04j, -1.44752997e-01-1.10462732e-01j, 3.59606533e-02-3.84511090e-02j, -3.56750817e-02+5.75093775e-02j, - -4.15723422e-02+5.09095742e-02j, -2.50051531e-02+3.74719107e-02j, -3.34371919e-02-2.69992518e-02j, 2.17278805e-02-1.59555220e-01j, -1.18390615e-01+3.06546257e-02j, 5.93851132e-04+6.14587651e-02j, 1.40201832e-01-1.17018742e-01j, 6.30594857e-03+5.45456872e-03j, -3.76289949e-02-1.52282039e-02j, 1.32512888e-01-1.48351173e-01j, -7.54453520e-02-4.61426234e-02j, -3.03461225e-02-5.67156398e-02j, -8.36462232e-02-1.37701819e-01j, 1.70123787e-02-2.07730468e-02j, 2.02734494e-01+6.52242080e-02j, 1.92557330e-02+1.00734613e-01j, 1.75343958e-01+8.81780749e-02j, -1.19044611e-02+5.91177580e-02j, 1.67539379e-02+4.06442164e-02j, -8.00636857e-02+7.89439667e-02j, -4.75474374e-02+2.83892572e-02j, 2.61253074e-02+1.39692416e-02j, 1.27684922e-01+1.17156954e-01j, 2.73419985e-03-8.15456779e-02j, 1.30767101e-01-7.98744725e-02j, -1.17162715e-02-1.65840395e-01j, -5.76548732e-02+5.87985325e-02j, 7.07963445e-02-1.79886324e-01j, -4.20474415e-02+1.08883511e-01j, -5.75618414e-02+5.21190462e-03j, - -7.21987996e-03-3.10182665e-02j, 5.50605465e-02-7.25079912e-02j, -5.35629253e-03-3.15994255e-02j, 1.45261311e-02+1.13362595e-01j, -2.76125254e-02-3.24502000e-02j, 3.91132852e-02+7.99084254e-02j, 1.36671884e-01-4.22167609e-02j, -2.78745524e-02+1.66604820e-01j, -5.79322711e-02+1.89892952e-01j, 5.80213545e-02-5.63300106e-02j, 4.21450402e-02-2.34111878e-01j, -9.04896655e-02+8.57572295e-02j, -1.03359661e-01-7.96324957e-02j, 6.02369786e-02-6.27833326e-02j, 1.19673196e-01+1.10677207e-02j, 8.30081547e-02-3.58778391e-02j, 6.11783668e-02+6.11887674e-02j, -7.68605931e-02-5.39948682e-03j, 1.21343778e-01-2.97186254e-02j, 1.29116081e-01+1.87106712e-01j, 5.15873038e-03+6.61919344e-02j, -1.83282876e-03-3.68731936e-02j, 1.17016771e-01+1.58222912e-01j, -3.87226282e-03-9.70371654e-04j, -1.79300200e-01-2.83260393e-02j, -1.41400483e-03+1.35331847e-02j, 5.72087458e-02-7.75475006e-02j, -1.58108785e-01-7.97071215e-02j, -3.31189056e-03-5.73357007e-02j, 4.13786706e-03+1.22780539e-01j, - -5.36931375e-02-6.72722822e-02j, 1.11920724e-01+1.29862093e-02j, -5.24987149e-02+4.76643575e-02j, 1.05637164e-01+8.27861165e-02j, -1.18864055e-01-1.74568296e-01j, 5.81192411e-03-4.04070185e-02j, -1.03430483e-01-1.69035282e-01j, -1.13502716e-02+8.34191056e-02j, 1.05325163e-01-4.76216714e-03j, -9.25772817e-02+1.50670237e-01j, 4.28140700e-02+3.46151756e-02j, 9.73338934e-02+7.53926315e-02j, -1.25555176e-01+4.50327447e-02j, 2.83269738e-02+2.14864449e-02j, 1.03088528e-01-1.14373265e-01j, -7.31401450e-02+1.77769898e-01j, -1.12535149e-02+4.78161974e-03j, 8.18570896e-02-3.81132366e-02j, -1.33295296e-01-9.10001207e-02j, 8.58276762e-02-1.41863647e-02j, 1.67874702e-01-1.33988434e-02j, -8.67651467e-02+1.32689953e-01j, -3.90355992e-02-3.43351624e-02j, 7.26507704e-02+2.64829915e-02j, 1.11678187e-01+3.90653261e-02j, 1.15906135e-01+1.76724059e-02j, 9.82619413e-02-6.25174727e-02j, -7.37921876e-03+2.82544110e-02j, 1.03018820e-01-6.28247854e-02j, 1.87003733e-01+3.37938203e-02j, - 4.85530302e-03+7.88810000e-02j, -9.36602683e-02+2.03654036e-01j, 6.70298724e-02-1.28682263e-02j, -2.54909646e-02-1.98646445e-02j, -1.98543086e-02+6.61216538e-02j, -8.48576080e-02-2.49620592e-02j, -6.71496603e-02+7.22095879e-02j, 4.76262959e-02+1.21009164e-01j, -4.58951514e-02-5.17531968e-02j, -6.47960010e-02-1.20728072e-01j, 1.60295792e-01-1.40473647e-01j, -1.63756748e-03+1.76260693e-01j, -2.14187214e-02-1.44486405e-01j, 1.38935677e-01+1.82433112e-02j, 2.72551076e-02-8.98792607e-02j, -1.71326545e-01-1.10489461e-01j, 2.59713517e-02+1.80210728e-01j, -1.13356997e-01-5.39655073e-02j, -1.15002327e-01+2.11468680e-02j, 1.22206680e-01+2.00740144e-01j, 5.31251355e-02+3.41911572e-02j, -2.85470406e-02+3.40588721e-02j, 1.62612378e-02-1.25619786e-01j, -5.56722710e-02+8.35975795e-02j, 9.53800031e-02-8.43482473e-02j, -1.09105819e-01+9.48804730e-02j, 4.77081838e-02+9.49219343e-02j, 8.11850606e-02+1.08680074e-01j, 1.22006741e-01+5.82741535e-02j, -2.29701893e-02+6.62232347e-02j, - 3.92315193e-02+6.55030120e-02j, 2.03376796e-01+9.27366361e-02j, 6.35392164e-02+3.23680200e-02j, -5.31622978e-02-2.88908372e-02j, -7.02426374e-03+6.75379556e-02j, -2.12237232e-02-1.83434699e-02j, -6.78967104e-02-5.80275574e-02j, 1.69828044e-01+9.49136570e-02j, -5.08448568e-02-5.19598149e-02j, -1.06691250e-01-9.62889583e-02j, 5.32046688e-02-1.90509591e-02j, -2.50194692e-02-9.29642044e-02j, 1.88093417e-02+7.48436505e-02j, -6.10298150e-02-3.20064291e-02j, 4.40991893e-02+8.70526883e-02j, -3.11373800e-02-7.99283258e-03j, -1.21129358e-03+6.04760979e-02j, 1.23181705e-01+3.86186523e-02j, -3.45111027e-02+4.90467351e-02j, -6.92065655e-02-3.02708167e-02j, 5.84411839e-02-4.52250729e-03j, -2.94612333e-02-1.11594151e-01j, -4.35060760e-02+3.08939714e-04j, 1.65268661e-01+1.78101296e-02j, -9.71783036e-02-9.50097168e-02j, 3.12533928e-02-1.60026912e-02j, -7.79738476e-03+4.88586564e-02j, -8.40499527e-02-6.37198817e-02j, 9.61353831e-02+1.26583069e-01j, -5.53354967e-02-2.40176823e-02j, - -1.15968617e-01+3.30895067e-02j, 1.62856623e-01-3.47484132e-02j, 1.63934966e-02-1.56508626e-01j, 1.64466893e-01-1.15467354e-01j, 3.63366559e-02-1.20918496e-02j, 5.57051607e-02-2.18319816e-01j, 6.95284985e-03+1.83828937e-01j, 4.11729400e-03-1.49751410e-01j, 1.16899770e-01+5.20485323e-02j, -5.34538311e-02-1.12893252e-02j, 2.25104422e-02+1.11501556e-01j, -4.55768609e-02+2.15601916e-02j, -1.94808270e-02-1.27154235e-02j, 2.91608554e-03-5.58722359e-03j, -1.03179399e-01+6.99009222e-02j, 1.13405865e-01-2.56399009e-02j, 3.13735506e-02-5.75109182e-02j, 3.65624418e-03+1.07627557e-01j, -2.24465012e-02+9.87669291e-02j, -9.35607749e-02-5.07987181e-02j, 5.79961983e-02+3.09445598e-02j, 2.97307432e-03+3.93021054e-02j, 2.11226275e-02-9.88357430e-03j, 3.13416632e-02+1.03456485e-01j, -1.01917192e-02+6.18006060e-02j, 2.71549373e-02+1.35561825e-01j, -7.68074153e-02-6.85512247e-02j, -1.17581867e-02-2.53829160e-02j, 9.28375780e-02-6.14954707e-02j, -1.41596614e-01+1.07188921e-02j, - -7.28860525e-03+2.43651634e-01j, -8.80650359e-02+1.43082304e-01j, -1.26341313e-03+8.32647482e-02j, 2.03115842e-01+6.89095479e-02j, 1.67115866e-01-4.60730662e-02j, -1.05755428e-01+1.22039239e-01j, -1.43352206e-01-2.39082798e-02j, -4.18043091e-02+8.97024776e-02j, -7.77240171e-02+2.19308414e-01j, -9.11640110e-03+8.65422721e-02j, -1.05457490e-01-1.84014637e-02j, 6.77892119e-02+2.28872910e-02j, 1.16564450e-02+4.25565495e-02j, 1.26894200e-01-1.70513750e-01j, -1.20932866e-02-1.23697146e-01j, -1.05797816e-01-7.67449744e-02j, 5.47589103e-03-1.90378815e-01j, -1.22361425e-01-3.64873506e-04j, -4.92975620e-02+2.03877639e-01j, -1.01416867e-01-2.20615975e-02j, -4.04668442e-02+1.54538885e-02j, -7.31195916e-02+1.47711186e-01j, 1.28543207e-02+3.67988918e-02j, 6.59874297e-02-2.20951499e-02j, -5.69867977e-02-2.77874616e-02j, -1.39863923e-02-3.92723193e-02j, 3.44966375e-02+9.17851631e-02j, -1.35718074e-01+3.35410957e-02j, 2.56668817e-01+3.62517597e-02j, 1.45008246e-03-1.67266042e-02j, - 7.23949189e-02+3.50058311e-02j, 2.95906913e-02-5.11673530e-03j, -2.89210703e-02-7.83260207e-02j, -3.95276055e-02+2.62070530e-02j, 1.89223565e-02-3.73511633e-03j, -1.49815586e-01-3.23024572e-02j, -2.76757428e-01+1.09794058e-01j, -1.55603333e-02-9.26240637e-02j, -8.34324290e-02+1.10717331e-01j, -8.49852684e-02+1.21096192e-01j, -2.34217533e-03-2.20533245e-02j, -4.05124372e-02+4.91544177e-02j, 2.21939474e-01+1.06585662e-02j, -1.14788852e-01-1.45670084e-02j, -2.31864711e-02+8.16787838e-02j, 1.05772073e-01-3.81363629e-02j, 1.06410310e-02+5.56535302e-02j, 7.49474640e-02-2.44079960e-01j, -1.14493374e-01+2.54362093e-03j, -9.10842184e-02+4.58644113e-03j, -1.50764400e-01+9.60854982e-02j, 1.17718269e-01-1.33115252e-02j, 2.88747212e-02+2.37461286e-02j, -1.41759597e-02+1.51999121e-02j, -2.47353248e-02+7.48763400e-02j, -3.83509977e-02-3.50842772e-04j, 2.44222600e-02+5.36360149e-02j, -4.15187177e-02+1.66291792e-02j, -6.98415077e-02+1.55027916e-01j, 1.75717100e-01+4.63332796e-02j, - 1.62118073e-01+1.44290350e-01j, 2.27418566e-01-1.45684285e-01j, 3.06208328e-02+4.27399784e-03j, 7.46468629e-02-2.60921832e-02j, 1.36523904e-01+4.44488001e-02j, 4.42830359e-02-8.76058694e-02j, -5.01048932e-02+1.06328634e-02j, 1.74182387e-02-7.92930529e-02j, 1.30387046e-01-5.77562670e-03j, 3.38661732e-03-2.66393819e-02j, -5.84555746e-02+7.24533139e-03j, 9.24386154e-03-7.38257239e-02j, -2.01353089e-01-1.54900117e-01j, -7.64397545e-02-2.64763460e-02j, -1.05638845e-02+4.79286399e-02j, 3.31547555e-02+1.82840041e-01j, 1.02455279e-01-3.22470454e-02j, -2.02968636e-02-1.20561400e-01j, -1.53201600e-03-4.86412356e-02j, -3.36622849e-02+1.23466127e-01j, -3.17666031e-02-5.30530230e-03j, 7.87856594e-02-1.10488726e-02j, -6.50752335e-02-1.53696600e-01j, 1.12242184e-01+9.63039070e-02j, 7.29070752e-03-6.12939915e-02j, -1.27887554e-01-5.27193958e-02j, 2.67746028e-02+1.70487967e-02j, -7.75381791e-02-8.27737207e-02j, -2.68419314e-02+3.52729473e-02j, 2.08583372e-02-4.61001172e-02j, - 1.35435125e-02+7.17668513e-03j, 7.51284375e-02+1.57659374e-01j, -1.16573329e-01+3.45952874e-02j, 1.16952561e-01-1.92810160e-01j, 8.91983080e-03-1.72847221e-01j, -1.37395165e-01-1.29769519e-01j, -5.57858716e-02-1.29509855e-01j, -3.78818453e-02+8.97323481e-03j, -9.26055477e-02-3.82225179e-02j, -1.02176844e-01+7.72429422e-02j, -2.77767386e-02-7.89175823e-02j, 1.08550789e-01-1.24801337e-01j, -7.51967666e-02+4.42884220e-02j, -3.84132813e-02-2.23818923e-02j, 2.10290591e-02-1.63910071e-02j, -1.55546281e-02+6.83243462e-02j, 7.04925956e-02+1.13334991e-01j, -7.80853320e-02+6.46462801e-02j, -3.21182665e-02+5.84735194e-03j, -1.01335631e-03+2.56732273e-01j, 4.63262263e-02-8.08179095e-02j, 3.58066672e-02+4.41791548e-02j, 6.73367098e-02-7.01266251e-02j, -8.73687243e-02+8.94059276e-02j, -7.39072106e-02-1.65025667e-01j, -7.66981818e-02-3.34616641e-03j, -4.22405675e-02-1.60785801e-01j, -4.05947796e-02-6.73805916e-02j, 2.08188645e-02+6.87961393e-02j, 1.67132980e-01+2.05388800e-02j, - 2.10096943e-02-7.14703997e-02j, -1.96928545e-02-2.18626018e-01j, 3.85125630e-02+7.57691532e-05j, 8.30529385e-02-2.07160668e-02j, 1.38867666e-02+1.41588611e-01j, -6.60239944e-02-2.31858478e-01j, -5.97977022e-02-1.57154782e-01j, 1.12189711e-01-1.18577658e-02j, -3.53731368e-02-7.82586039e-02j, 1.75438251e-02+8.76571977e-04j, 1.41945832e-01+9.28040164e-02j, 3.52110938e-02-1.77822589e-02j, 4.95572709e-02-2.87314727e-02j, -1.30143044e-01+5.82148327e-02j, 1.45779892e-01+5.21651803e-02j, -1.98968827e-02+4.94037736e-02j, 6.58149682e-02-6.44416128e-02j, 9.20102049e-02+3.04692222e-03j, -3.38008186e-02-5.63391322e-02j, 8.37698748e-03-3.59590496e-02j, -4.35261097e-02-3.87390686e-02j, 5.76792009e-02+3.44475463e-02j, 9.59522963e-02+2.15717502e-01j, 1.88552950e-02-4.53059574e-02j, 1.70086117e-01-2.64053284e-02j, 2.22595913e-02-7.30566035e-03j, -1.12054071e-02+1.22101799e-01j, -6.41573620e-02+1.66227099e-01j, -3.58693002e-02-2.83078773e-02j, -6.60688819e-02-2.56512600e-02j, - -4.86337540e-02-1.57859846e-01j, -1.25599279e-02-4.54959147e-02j, -2.03534357e-02-2.87431987e-02j, -1.27646849e-02-3.90012510e-03j, 3.47598092e-02+7.87069224e-02j, -3.62772635e-03+1.62428369e-01j, 3.62281855e-02+5.50061027e-02j, -5.70765622e-02-1.34000365e-01j, -9.44564719e-02+1.49567942e-01j, 1.21510992e-01+1.17693975e-01j, -6.62911619e-02-6.46359390e-02j, 7.09082700e-02+2.48476467e-02j, 1.57824600e-01+1.17066315e-02j, -8.44151788e-02+5.34910078e-02j, 8.22583660e-02-9.68421318e-02j, 8.59570275e-03-1.91844681e-01j, 3.00350172e-02+6.80688724e-02j, 8.21553079e-03+3.06162281e-02j, 9.23264499e-02+1.94905975e-01j, -4.14970965e-02+1.08064766e-01j, 2.58033773e-02-6.91497742e-02j, 1.55917773e-01-5.09599368e-02j, -3.65483160e-03+1.14380435e-01j, 5.51468816e-02-2.59419769e-02j, 1.70702211e-01-1.99296533e-01j, 1.47724497e-02-1.85515054e-02j, 2.72122021e-02+7.29287795e-02j, 1.49109842e-01+5.93069060e-02j, -1.66613542e-02-8.67137446e-02j, -1.20909604e-01-2.93675341e-02j, - -9.83917085e-02-1.84204761e-02j, 1.62814792e-01-1.35139306e-01j, 4.73460440e-02+1.31337461e-01j, 2.32713411e-01+2.88388028e-02j, -6.68972821e-02+2.22197631e-02j, 3.92719612e-02+1.52580203e-01j, 2.53776470e-02+7.74832234e-02j, -4.36193830e-02+4.24058557e-02j, 8.23322375e-02+1.76410134e-01j, 1.54890627e-01+5.32375276e-02j, 4.37512275e-02+4.15304821e-02j, -3.49403249e-03+1.52670688e-01j, -9.70650860e-02+1.44844260e-01j, -1.95678640e-03+1.99977290e-02j, -4.80695395e-02+1.94770744e-01j, 2.79827269e-02+9.91437026e-02j, -1.29906563e-02-1.00716455e-01j, 5.77525685e-02-1.30956086e-01j, 2.57358361e-02-6.44845883e-02j, 1.72803438e-02-8.23410272e-02j, 6.55852364e-02+2.73660529e-02j, 1.25689774e-03+5.70941527e-02j, -6.05442115e-02+8.50756711e-02j, -1.20872173e-01+1.94266740e-02j, 1.99440268e-02+6.12317022e-03j, -8.27951261e-02+2.42864309e-02j, -3.47486834e-02+9.66718780e-03j, -9.44474618e-03-1.29324625e-03j, 1.08077651e-01-7.63083493e-02j, 1.77039940e-01+1.34457007e-02j, - 1.02205651e-01-1.32673224e-03j, 2.00202803e-01-4.79903919e-02j, -4.07654990e-02+1.99179948e-02j, 6.65024855e-02+9.63731804e-02j, 6.17223649e-02-2.41440229e-02j, 6.21646020e-02-4.29251282e-04j, -1.19217377e-01-5.11233888e-03j, 5.00452355e-02+9.64116293e-02j, 6.72018105e-02+1.58383035e-02j, 1.04920585e-02-3.75171295e-02j, -5.15836453e-02+4.10383258e-02j, -4.50121432e-02-1.56393689e-01j, -3.69949558e-02-3.49941789e-02j, 4.24813266e-02+4.56446662e-02j, -1.40693525e-01+3.62119110e-02j, 3.54644935e-02+6.55820345e-02j, -1.15036248e-01-6.70995814e-02j, 1.74477980e-01-8.46266302e-02j, 5.63822416e-02+7.09389700e-02j, -6.32001141e-02+5.22351752e-02j, 4.98335744e-02+8.47202636e-02j, 4.63525184e-02-2.59316779e-03j, 1.21744758e-01-2.32443032e-02j, -2.57646251e-01-1.06662161e-01j, 2.17462637e-02+8.80639240e-02j, 9.00883144e-03-1.80037699e-02j, -4.06906387e-02-4.18911845e-02j, 9.21795940e-02-4.20689728e-03j, -6.49150463e-02-8.38487063e-04j, 2.29472275e-02-1.09014529e-01j, - -1.18350148e-01+4.08252745e-02j, 4.82206235e-02-1.43520408e-02j, 8.95036890e-02+1.93669906e-02j, -1.15319803e-01+1.36806111e-01j, -1.74398823e-02-2.77018578e-02j, 2.58644789e-02+5.38396709e-02j, 9.21745774e-02-7.13300386e-02j, 8.49353400e-02+1.58488850e-01j, 1.05015608e-01-3.77073810e-03j, 9.35912413e-03+1.63510644e-01j, -4.73810170e-03-5.70824705e-02j, 6.57060173e-03-1.96057621e-03j, -7.21801277e-02+1.52720724e-01j, 9.56171753e-02+1.17779754e-01j, 4.28275190e-02-3.45548941e-02j, -4.86463734e-02-1.09920637e-01j, -6.83698564e-02-3.81786068e-02j, 1.08564055e-01-1.99558529e-01j, 2.14653459e-01-4.88992080e-02j, -8.24321086e-02+6.30930070e-02j, 3.37396930e-02+8.09973287e-03j, 3.12656291e-02+2.90758576e-03j, 4.19413119e-02+1.76739590e-01j, -1.78314610e-02+1.95598017e-01j, -1.03324368e-02-5.77691340e-02j, 4.49029815e-02+6.21737213e-02j, -8.40076602e-02-9.83562420e-02j, 1.13326150e-01+9.91253684e-02j, 2.38893291e-02+1.12755456e-01j, -8.37705940e-02+1.55665879e-02j, - -4.29407233e-02-1.17518245e-02j, 5.13377269e-02-8.93171618e-02j, 1.20001217e-01+2.01425975e-01j, 1.90297138e-01-8.38967425e-02j, -3.87460366e-02+7.49288218e-02j, -1.24320906e-01+6.56743495e-02j, -6.02213153e-02+3.79364325e-02j, -2.18310318e-02+1.88705143e-02j, 4.26490839e-02-7.19299318e-02j, -9.25682258e-02+2.18607895e-01j, -1.01660296e-01+1.12017637e-01j, 1.51315515e-01+1.84926829e-02j, 8.57594723e-02-7.50221664e-02j, -1.98220124e-02-1.20395767e-01j, 1.27485048e-01-6.69181634e-02j, -2.73468470e-02+4.65786430e-02j, -7.72377306e-02-2.68279016e-02j, -4.41939063e-02-1.86501327e-01j, 3.79414469e-02+1.29131092e-01j, 1.93659647e-03-1.92419385e-01j, -4.08341014e-02+6.14073848e-02j, -3.84304585e-02+7.01256300e-02j, 5.60045546e-03+9.27319924e-02j, -2.27222077e-02-8.96927881e-02j, -5.53554102e-02+8.30322612e-02j, 1.00213142e-01-6.38125486e-02j, 5.47423951e-02-9.71559022e-02j, 3.82241837e-03+1.21289781e-01j, -4.04486610e-02+1.79941878e-02j, -1.03559368e-02-4.30334206e-02j, - 5.89578314e-02+4.00524147e-02j, 1.40916511e-01+6.67082696e-02j, 4.40418631e-02+3.70535594e-03j, -2.67797544e-01+8.62091694e-02j, -3.76648865e-02-2.31015760e-02j, -7.67526017e-02-8.08939654e-02j, 9.26572419e-02+2.16789139e-02j, -6.29159288e-02+1.04174588e-01j, -1.11529756e-01+5.62658454e-02j, 1.17951934e-02-1.61302278e-01j, -1.80869076e-03-6.34125495e-02j, 7.62696393e-02-7.90164136e-02j, -7.87952131e-02-1.39323485e-01j, 1.02348156e-02+5.51626383e-02j, -1.67469740e-02+1.83413897e-02j, -2.87239563e-02-5.06066118e-02j, 8.87510480e-02+8.98941416e-02j, -5.76729095e-02-3.50195824e-02j, -8.61756954e-02+3.10618350e-02j, 2.94118856e-01-7.48255388e-02j, 1.58173913e-02-1.09383861e-01j, 3.21889474e-02+1.12228748e-01j, -6.28360404e-02-1.16637975e-01j, 7.93730300e-03-1.09748836e-02j, 1.27800657e-01-9.16258515e-03j, 3.27511712e-02+1.01571073e-01j, 9.85438792e-02-5.31420117e-02j, 1.61275851e-02-2.80605417e-03j, -1.19686377e-01+1.32242066e-01j, 1.87543551e-01+2.38937126e-03j, - 1.16921884e-02+2.62848401e-02j, -9.86694177e-03+7.77981844e-02j, -9.85602566e-02+2.38507308e-02j, 2.35400707e-03-5.43592014e-02j, -7.23858021e-02-5.93465697e-02j, -1.58506446e-02-5.97662787e-02j, -8.75208135e-03+5.09418023e-02j, -3.08916406e-02-3.48724890e-02j, -1.60191352e-02+1.03111217e-01j, -5.68159068e-02+7.46244049e-02j, 9.23995849e-02-1.05567241e-01j, 1.02643630e-01-4.48982087e-02j, -2.37025557e-02+9.91981818e-02j, -1.51080851e-01-6.60829227e-02j, -1.27955345e-01-3.54218582e-02j, 6.68788444e-02+7.48446185e-02j, 1.25809616e-01+8.22238020e-02j, 5.76912904e-02-7.07594599e-02j, -8.78078680e-02+1.75702063e-02j, 2.23150487e-01+1.21618743e-01j, 3.68863819e-02-2.30063462e-01j, -2.78605009e-02+3.00439015e-02j, 4.76710874e-02-4.21785515e-02j, -2.06022674e-02-8.33240131e-02j, 1.53185096e-01+5.43462784e-02j, 1.10483025e-01-9.58798477e-02j, -1.64335314e-02-1.37741584e-02j, 1.26456713e-01-6.49290331e-02j, 7.02876284e-02+8.95977937e-02j, 8.45954555e-03+1.52604418e-01j, - -1.26458774e-01-1.00591188e-01j, -1.51082804e-01-7.07219691e-02j, 1.35312036e-02+2.42766701e-02j, -2.57820349e-03-5.82206445e-02j, 1.25394937e-02+1.54994794e-01j, 4.34303108e-02+1.67758088e-01j, 2.50193827e-02-1.68203339e-02j, -7.42770942e-03+1.19995245e-01j, -2.14668364e-01-1.80954136e-01j, -7.90535193e-02+7.86162084e-02j, 1.63419690e-02-6.09920610e-02j, -1.35407002e-01-1.56744993e-02j, 1.23914645e-01-4.03721439e-02j, 1.77204484e-03+2.66140087e-02j, 1.25716789e-01-3.78667856e-02j, -2.99746760e-02+4.86935208e-03j, 1.38225290e-02+7.04359534e-02j, 1.72072353e-01+1.31015253e-02j, -6.19101329e-02+1.24807440e-02j, 5.20454040e-02-2.47656886e-01j, 1.05189919e-01-2.88161306e-02j, -1.53992477e-02+7.55199009e-03j, 5.82505243e-03+1.20984659e-01j, -1.42134562e-01+1.12480596e-02j, -1.09111335e-01-1.54002884e-01j, 4.21553065e-02+5.76813852e-03j, -7.58350800e-03+2.26849903e-01j, 4.77762685e-02+3.40790650e-02j, 3.85152600e-03+1.26559590e-01j, -4.06218500e-02+1.26222670e-01j, - -1.28628510e-01-1.00489682e-02j, 7.45782354e-02+6.90716494e-02j, -1.39804487e-01-5.89119056e-02j, -3.13298452e-02-1.40520253e-01j, -3.01100745e-02-8.12306975e-02j, 9.58783144e-02+8.71888394e-02j, 8.17466446e-02-5.59117276e-02j, 8.32972084e-03+1.02402858e-01j, -5.98910605e-02+1.77552646e-01j, -1.62084309e-01+4.79064238e-02j, 4.56745968e-02+2.37759503e-03j, -1.73401279e-01+2.45332405e-02j, -1.08518076e-02-5.51290615e-02j, 1.61371652e-01+7.02663314e-02j, 5.77371628e-03+3.08382613e-02j, -5.23348517e-02+6.18789064e-02j, 6.05004292e-02-4.83654472e-02j, 1.26452871e-02-1.00891539e-01j, 3.01323647e-02+1.96240326e-01j, -5.92861632e-02+1.08424895e-01j, 1.07222615e-01+1.41348222e-01j, -3.52439375e-02+9.37165441e-03j, 2.68309794e-02-1.10349093e-01j, 1.94493578e-02+1.47608062e-01j, 6.93871662e-02-9.40535516e-02j, -6.68998398e-02+3.72529839e-02j, 7.31071439e-02+4.62749207e-02j, 8.22767275e-02+4.33738687e-03j, -1.27461890e-01+7.16800653e-02j, -2.59615938e-02-4.42029716e-02j, - 5.93603172e-02+8.00663553e-02j, -1.30433729e-01+1.22098338e-01j, 6.08017369e-02-7.05338115e-03j, -4.97809705e-02+1.42873842e-02j, -4.40948151e-03-3.62800038e-02j, -7.23446309e-03-2.28188194e-02j, 7.55706875e-02-1.69914898e-02j, 1.20151025e-01+9.98944293e-02j, -2.80746263e-02-5.48362337e-02j, -1.32263858e-01+9.17482255e-02j, -1.57415802e-03-1.08396653e-02j, 3.69312813e-02-2.91296460e-02j, -3.41443670e-02-7.03052603e-02j, -1.38221692e-02-3.27697123e-02j, 8.95111448e-02-3.25747369e-02j, 9.12661146e-02+7.88395467e-02j, 1.33323387e-02+8.39085279e-02j, 1.03179796e-01-2.57974091e-04j, -4.01998444e-02+1.51487692e-02j, -3.29247221e-02+2.28990460e-01j, 1.72097871e-02+3.03322059e-02j, 3.56471471e-02+3.53238951e-02j, -7.01989588e-02+1.25589194e-01j, -1.27727238e-01-2.56240149e-02j, 1.11420554e-01+1.79185848e-02j, -6.33720285e-02-5.24980027e-02j, 1.69408311e-02+2.10972901e-02j, 4.61900829e-02+2.30128229e-02j, 1.64914084e-01+9.53427779e-02j, -8.10370774e-02-4.02999617e-02j, - -2.28926173e-02+6.01414298e-03j, 4.15959537e-02-1.62844430e-02j, -1.04015567e-01-2.28197070e-01j, 5.70917647e-02+6.10634039e-02j, 1.86651786e-02-1.32786359e-01j, 3.52815399e-02+2.63096329e-01j, -5.20942911e-03+9.32562283e-02j, 6.02358871e-02-2.03967495e-01j, 3.07765966e-02+4.43833301e-02j, -1.25342748e-01+9.30307464e-02j, -8.02078208e-02-7.48545491e-02j, 4.41479684e-02+4.55319347e-02j, -1.30358039e-02+3.44938629e-02j, 2.59548001e-03+8.55018910e-02j, -7.24207391e-02+7.25371152e-02j, 4.75649287e-02+8.49041681e-03j, 7.98960425e-02-2.09135805e-02j, -8.16200773e-03+8.52944822e-02j, 5.76132389e-02+7.92413488e-02j, -7.86674994e-03-5.18220519e-02j, 1.61866259e-03+4.58226858e-02j, 2.10573498e-02+1.21302913e-02j, 1.50642093e-01+3.18694799e-02j, -5.11976007e-02+3.35902634e-01j, 1.30304319e-02+1.20557949e-02j, 1.93169643e-02-2.04117390e-02j, 4.21485086e-03+4.50653899e-02j, -6.99644728e-02-4.38648373e-02j, -5.57760973e-02+1.03144757e-01j, -2.77981225e-04-6.55103561e-02j, - -2.47429687e-02-5.56510136e-02j, -1.30487865e-01-2.53886778e-01j, -5.31332551e-02+1.83257653e-01j, 4.49553366e-02-1.27860901e-01j, -1.41877991e-01-9.17018436e-02j, 1.41319426e-01+9.76950302e-02j, 1.69036782e-02+4.32713109e-02j, -2.21736722e-02-1.35943321e-02j, 8.45566133e-02+1.56861643e-01j, 6.06872432e-02+1.10300630e-01j, 8.18810463e-03+4.90937472e-02j, 2.59253095e-02+2.16031285e-02j, 2.91014435e-04-1.31594533e-01j, -1.54684856e-02+2.54619375e-02j, -2.12487171e-02+3.36985235e-02j, -2.13034153e-01-3.81858886e-03j, -2.27912308e-02-3.15100249e-02j, 8.56614800e-02-4.73562392e-02j, -3.21653523e-03-1.00666344e-01j, 4.76758478e-02+1.13788672e-01j, 1.04992660e-01-7.19338205e-03j, 2.61845427e-02-1.95367436e-04j, -5.70545419e-02-8.24770580e-02j, 2.59511921e-02-1.47959999e-01j, 9.90365911e-02-1.07073452e-01j, 4.24238401e-02+6.83240999e-04j, -9.29305355e-03+2.57478648e-02j, 5.09306367e-02+5.17850540e-02j, -3.35412235e-02+5.12389402e-02j, 2.46636595e-02+1.52497496e-01j, - -3.69885214e-02-1.43051224e-03j, -6.34083688e-02+7.95585662e-02j, -7.63159733e-02-9.59472692e-02j, 1.37701675e-01+1.72715523e-02j, 4.43926374e-03+1.03978366e-01j, -9.76045082e-04+1.16177364e-01j, 9.75501498e-02+1.10711036e-01j, -8.61395371e-02+4.75590898e-02j, -1.86326972e-02-8.72703099e-02j, -3.98222506e-02-2.01927936e-03j, -4.56659343e-02+6.85048391e-03j, -8.52516866e-02-3.58323276e-03j, 6.43698794e-02+9.95628825e-02j, -4.39734955e-02+2.10779642e-02j, 1.14785069e-01+1.09119788e-01j, -1.80570955e-01-6.60318868e-02j, 1.82596842e-02+1.32847306e-01j, -1.25277200e-01+1.85473095e-02j, 3.61733437e-02+1.42379572e-02j, -8.92845204e-03+6.77236053e-02j, 1.58690519e-01+6.45710673e-03j, -1.24921492e-02-9.99208311e-02j, -1.91513019e-01+3.48823651e-02j, -9.84584655e-02+1.76559101e-02j, -8.56099318e-02+1.49766608e-01j, -6.12707229e-02+1.07577597e-02j, 1.16550002e-01-2.40802989e-01j, -1.23620543e-02+4.45149950e-02j, -1.76292863e-01-1.09460504e-01j, 3.85853397e-02-5.33685000e-02j, - -4.33475627e-02+6.06156460e-02j, -1.87846565e-02+1.14931789e-01j, -1.02013650e-01-2.29362151e-02j, 6.16651648e-02+7.99999963e-03j, -3.24185056e-01-1.48847542e-01j, -1.15048411e-02-5.67954670e-02j, -1.31298592e-01+9.40862751e-02j, -3.38096707e-02-4.96639503e-03j, 1.01303563e-01-1.20893708e-01j, 3.69567985e-02-7.34673617e-02j, 1.17120440e-01+1.46681717e-01j, -1.08104493e-01+4.59797898e-02j, 1.57388412e-02-9.05862553e-02j, 1.28683206e-01+1.36862876e-01j, 1.20579464e-01+4.56797568e-02j, 5.32546371e-03+2.00030811e-03j, -4.47207586e-02+6.84790769e-02j, -4.28425820e-03+7.32050329e-02j, -5.49771829e-02+3.00964687e-02j, -2.52478091e-02+1.04723922e-01j, -3.75356066e-03-1.20885506e-01j, 3.37046879e-02+4.44937988e-02j, -5.52111021e-02+4.18487207e-02j, 6.53305005e-02+2.24424425e-03j, -4.86068425e-02+1.00608085e-03j, 1.60271931e-01+6.63649255e-02j, 4.60478432e-02+3.98226836e-02j, 3.26150010e-02+1.82968788e-01j, -9.10672877e-02-1.11311630e-01j, 1.00893232e-02-1.39737503e-02j, - 2.71754161e-02-2.34544035e-02j, 9.15977387e-02+1.99426961e-02j, -1.97642710e-01+9.12888621e-02j, 4.74121316e-02-5.13504981e-02j, 5.07225943e-02+9.46633787e-02j, -9.53911293e-02-1.80654690e-01j, 1.64115127e-01-6.50378535e-02j, 1.09449061e-01+5.60124725e-02j, 1.53796325e-01+5.18189982e-02j, 5.17206905e-02+1.90530640e-01j, 7.50057667e-02-1.03567448e-01j, -3.82878661e-02-1.80075937e-01j, 4.01978788e-02-1.00698223e-01j, 1.03377853e-03-3.07692277e-02j, 1.20225227e-01+2.07456969e-01j, 1.04309283e-01-9.26611183e-02j, -1.03361361e-01+1.95889640e-02j, 2.58259256e-02+1.58281886e-01j, 7.75239291e-02-1.01311736e-01j, 9.15117078e-02-7.60188931e-03j, 1.14475846e-01-6.79271552e-02j, 5.44144608e-02-1.28520982e-01j, -9.52291620e-02-6.55706207e-02j, 3.43890303e-02-2.76969004e-02j, -1.02611436e-01-1.50417588e-01j, 3.21748176e-02-3.07119412e-02j, -3.86609986e-02+7.35572270e-02j, -5.24141267e-02-2.68636860e-02j, 1.15398753e-02+5.32210898e-02j, -1.73433735e-01-1.20650971e-01j, - 1.59124482e-01-1.31576336e-02j, 1.20225299e-01-1.52593103e-01j, -9.55610838e-02-6.95071254e-02j, 5.40075010e-03+3.80444187e-02j, -1.17110757e-02-3.28355329e-02j, -3.14854352e-02+9.13669332e-02j, -2.11449648e-02-7.11967389e-02j, -1.05950323e-02+1.75284874e-01j, 1.84744416e-02-6.85391690e-02j, 3.46360131e-02+4.62850612e-02j, 8.41213852e-02-1.24326928e-02j, 9.98813964e-02+2.08812494e-02j, 5.76777438e-03-5.35307536e-02j, -9.73557829e-02+2.03322351e-01j, -7.32834396e-03+3.51292305e-02j, 1.97020322e-01-3.69066750e-02j, -4.20662160e-02-1.01225755e-01j, 4.66345435e-02+4.48953960e-02j, -2.96526616e-02+2.70537698e-02j, -1.12505815e-01-4.81118731e-02j, 6.21206830e-02-7.15323882e-02j, -4.47070431e-02+1.45161193e-01j, 5.16437799e-02+1.48994784e-01j, -4.60222096e-02-9.52131423e-02j, 5.53010620e-02-4.16026288e-02j, 3.29589607e-01-8.01715204e-02j, 7.43597136e-02-8.52844592e-02j, -1.50760562e-02-1.18150067e-01j, 2.04861788e-01+5.84783818e-02j, 1.93288780e-02-2.43307354e-02j, - -1.99745724e-01+3.64362975e-02j, -3.43725281e-02-6.21676876e-02j, 3.63703503e-02-6.52874052e-02j, 8.94751529e-02+4.47611628e-02j, -6.65470145e-02-7.98519549e-02j, 1.01433775e-02-7.72488898e-02j, 1.06307469e-01+7.79035119e-02j, -4.78507257e-02-6.23415087e-02j, 3.78893691e-02+2.62410143e-02j, 1.73318720e-01-3.21495796e-02j, -1.65681634e-01+6.67285599e-02j, 1.94291731e-01-2.89109408e-02j, -4.54548567e-02+5.83158238e-02j, 5.61383335e-02+3.83324113e-02j, 1.21596304e-01+1.70747464e-01j, 1.27954274e-01-1.93444819e-03j, -8.37891724e-02-8.64889585e-02j, 3.80499478e-02+2.01027939e-02j, 9.43965724e-02-8.90623338e-02j, -4.79597835e-02+4.75603864e-02j, -8.61574607e-02+8.32130201e-02j, -1.55412399e-02-1.27006036e-02j, -7.42519286e-02-8.61685534e-02j, -8.10108175e-02-6.16012333e-03j, -7.37177736e-02-4.44450757e-02j, 1.43980441e-01+5.66282763e-02j, -7.16666783e-02-1.66644680e-01j, 1.52513989e-01+5.67736253e-02j, -7.22985818e-02+4.50107611e-03j, 8.57243393e-02+1.44598168e-01j, - 2.61325291e-03-1.17556073e-01j, 7.88519979e-02+6.74275525e-02j, 7.41806885e-02-4.95153472e-02j, -1.84676918e-03+3.29891980e-02j, 3.84952719e-02+1.48034075e-01j, 3.04972039e-02-7.37869287e-02j, 7.01507010e-02-2.44450088e-02j, 3.33009500e-03+1.05487204e-04j, -4.25430453e-02+5.86220817e-02j, -1.05973079e-01+7.39664382e-02j, 2.92878309e-02+5.28859984e-02j, 5.61329338e-02+1.69166909e-01j, 5.28499244e-02+3.45360084e-02j, -6.53900660e-02-8.61522262e-02j, 7.96946190e-02-3.41452511e-02j, 5.22770869e-02-7.40489497e-03j, -1.88772294e-01+3.96780063e-03j, -2.32936723e-02-5.37723356e-03j, -1.24854292e-01-1.40224821e-02j, 3.07904415e-02-3.15381949e-02j, -3.25235318e-02+8.42701028e-03j, 1.66862279e-01+1.19354852e-01j, 1.57978914e-01+3.63014900e-02j, 8.67807480e-02+1.40379161e-01j, -5.07193433e-02-1.40569523e-02j, -5.00888412e-02-2.23435528e-02j, -7.17048440e-02-9.81330153e-02j, -2.12409092e-02+5.45752543e-02j, 6.06474942e-02+5.88358912e-02j, 6.80174213e-02+3.30162415e-02j, - -6.07282111e-02+1.02939777e-01j, -1.87732930e-02+1.92200565e-02j, -1.16626047e-01+6.45786333e-02j, 1.37742795e-01+8.42180324e-02j, -1.20841908e-01+7.65002919e-02j, 3.46012372e-02-4.84411652e-02j, -1.01213514e-02+1.20822878e-01j, 1.20196281e-02-3.67275266e-02j, 3.92842430e-02+2.04356272e-02j, -3.50278977e-02+1.22347382e-01j, 1.91917372e-01-6.95304549e-02j, 9.29916189e-02+6.32480707e-02j, -1.40237138e-01+4.73312139e-02j, -5.46257907e-03-3.43833080e-02j, 5.25735063e-02+1.22349339e-02j, 5.55091124e-02+4.13346745e-02j, 3.80292721e-02+8.69044043e-02j, -1.57996649e-01-7.65619514e-02j, 1.75325367e-03-1.92975200e-02j, 4.93539327e-02+1.78264744e-01j, 1.02628124e-01-9.66824408e-02j, -3.21786689e-02+4.29915452e-02j, -8.65810365e-02+1.13052509e-02j, -3.85279691e-02+6.40545958e-02j, 1.08229295e-02-8.43402245e-02j, 1.79862749e-01+7.88074870e-03j, -2.87530932e-02+2.46179737e-01j, -1.27639034e-01+1.94348924e-04j, 8.38416209e-02+1.18533050e-01j, -9.80168967e-02-2.75891572e-02j, - -1.18741656e-01-1.12401688e-01j, 1.73015815e-01+3.17142696e-02j, -1.12689840e-01-6.31993322e-03j, -1.42069958e-01+1.71043064e-01j, -7.41914581e-02-1.51931975e-01j, -3.66012909e-02+2.39026896e-03j, 5.14718439e-02-1.03341673e-01j, -4.72099830e-02+1.26667668e-02j, 1.37512313e-02-2.60230700e-02j, -6.00589937e-02+2.54281176e-03j, -1.55002558e-02+6.29291268e-02j, -1.19615201e-01+6.77959328e-02j, 2.31292548e-02-1.08782093e-01j, -1.09964341e-01+1.25294910e-01j, -7.47861771e-02-5.98894488e-02j, 4.71331416e-02+1.43755876e-01j, -1.38666615e-02+1.01256745e-02j, -1.00179410e-02+1.11863487e-01j, 6.31224250e-02+1.19440718e-01j, -4.16177531e-02-4.36345510e-02j, -3.48014985e-02+8.85623335e-02j, 1.24650686e-01+1.48734266e-01j, -2.24549336e-02-1.00924355e-01j, -1.02751585e-01-2.12847917e-01j, -1.05847008e-01-5.29000688e-02j, -4.67909943e-02-1.36206316e-01j, -4.85632359e-02+1.42473156e-01j, -1.24246749e-01+6.42615904e-02j, 5.81696877e-03-4.96687519e-02j, -2.24424614e-02-3.88848488e-02j, - -7.74915273e-02+1.54367388e-02j, 4.34592454e-02-1.56021904e-01j, -8.56892132e-02+1.24030217e-01j, -4.89507658e-02+5.90317176e-02j, -1.25697664e-01-2.32861745e-02j, -1.61863374e-01+1.19418496e-01j, -2.90213516e-03-2.82791717e-02j, 4.50605390e-02-1.85114054e-01j, 1.02768328e-01-7.98889081e-02j, -8.15041765e-02+7.49613006e-02j, 7.62836130e-02-1.09942641e-01j, -2.43957305e-02+1.60075781e-02j, 1.25368088e-01-4.97508023e-02j, 4.32447252e-02-6.48555547e-02j, -2.64345140e-02-1.18679637e-01j, -5.49407140e-02+2.89175240e-02j, -4.47502071e-02+7.51395018e-02j, -4.99554424e-02-1.05535549e-01j, 7.47066390e-02+1.23133955e-01j, 1.03069754e-01-1.57446612e-01j, -2.38467760e-01+1.51184192e-01j, 3.55395997e-02-1.03355238e-01j, -2.32302845e-02+4.74672683e-02j, 8.73424064e-02+9.29539222e-03j, 1.37790158e-01-1.37543346e-01j, -9.47568754e-02+4.59808420e-02j, 1.41612817e-01-7.50145993e-02j, -1.21252993e-01+2.11071077e-02j, 5.93864166e-03-1.03518747e-01j, 1.00814386e-01-1.08636130e-01j, - 8.47764700e-02-1.36804644e-01j, -4.06295973e-02-3.17316929e-02j, -1.29388374e-01-1.13022235e-01j, 4.05034297e-02-1.51303513e-01j, 5.35895225e-02-9.81906501e-02j, 1.01307296e-02-6.14659966e-02j, 7.19860763e-03-7.87661099e-02j, 6.87236698e-03+7.01353724e-03j, 1.84117743e-01+1.14586080e-01j, 3.91942011e-02-1.67427533e-01j, -4.34340225e-02-2.41238971e-02j, -4.20038485e-02+5.76875010e-02j, 5.23551179e-02-3.79231514e-02j, 1.17465353e-01+1.19464437e-01j, -9.14539775e-02+9.32704953e-02j, -3.28255936e-02+2.00709680e-01j, -3.47973061e-02-6.96489860e-02j, 5.68759165e-02+4.46913265e-02j, -4.55834517e-02-6.49989637e-03j, 6.92236117e-02+6.31449747e-02j, -1.00908352e-01-7.69839513e-03j, 1.81960295e-02-3.79970705e-03j, 1.68374360e-02+1.05842359e-02j, 1.28460284e-01+6.09000930e-02j, -1.02077544e-01+6.69284634e-02j, -1.53969863e-02-1.52720337e-02j, 1.81218895e-01+3.16794729e-02j, -1.24806065e-01+2.26699104e-02j, -3.03130859e-02-2.23873943e-02j, -6.99493462e-02-7.03904849e-03j, - -3.67200875e-02+2.84145877e-02j, 9.43878591e-02+7.21251481e-02j, 6.58129601e-02-3.60549923e-02j, 6.61779478e-02-3.04054186e-02j, -6.13842814e-02-6.07921661e-02j, 8.98783698e-03-7.41166890e-02j, 1.16392800e-02-2.36748091e-02j, -1.10768989e-01+4.56420908e-02j, 3.72471227e-03-1.25668424e-03j, -1.29167025e-01+5.63022023e-02j, 1.05866530e-01+1.86155416e-02j, -6.67515779e-02+6.46395437e-02j, -1.03224770e-02-6.42898639e-02j, 6.21606257e-02-5.26347583e-02j, 2.57841919e-02+3.56828380e-02j, -8.55918562e-02+1.63670027e-01j, -4.31423671e-02+7.94041400e-03j, 8.59410574e-03+5.25343549e-02j, -1.33389296e-02+4.52481973e-03j, 7.58536209e-02+7.06748771e-02j, -4.14761871e-02-1.02294821e-01j, -6.50116056e-02-2.21306166e-02j, 2.33077150e-01+5.67852132e-02j, 4.86390845e-02-2.02001648e-03j, 7.53644961e-02-1.89453116e-02j, 2.08862978e-02-1.49855086e-02j, 1.33052297e-02+1.01522608e-01j, 1.51083846e-01+1.12903477e-01j, -1.62667787e-01+6.56239071e-02j, 1.45208158e-01-5.36623261e-02j, - -6.95826831e-02+1.39196707e-01j, 3.29916774e-02-6.75590243e-02j, 3.95917337e-02+5.93925052e-02j, -2.26219692e-02-2.87050486e-02j, -7.18277375e-02-2.33909540e-01j, 3.23958840e-02+6.33185484e-02j, 6.84165483e-02+1.09982301e-01j, -1.76022868e-02+1.67477409e-01j, 1.23647618e-01+5.72347084e-02j, 1.01034190e-01-2.91422180e-02j, -9.75792719e-02+6.92072056e-02j, 2.24926784e-02+4.92453456e-02j, 9.72881515e-02-1.19536229e-02j, -3.46137229e-02-2.17219106e-01j, 1.18110854e-01-2.25904054e-02j, 7.03378796e-02+3.42026266e-02j, -8.74713404e-02+8.22715157e-03j, -1.03981674e-01-1.24708617e-01j, 3.55529717e-02-3.88864430e-02j, -1.37342148e-01-9.40956813e-02j, 4.45450338e-02+2.39754202e-01j, 2.41743357e-02+2.06386810e-01j, 1.08491505e-01+8.89560185e-02j, 5.47927931e-02+4.36730443e-02j, -1.77677037e-01-1.15306877e-01j, 2.38957141e-02+1.47875042e-01j, 4.55000869e-02-2.62193008e-02j, 2.12153347e-01+1.42025329e-01j, -5.30709017e-02-7.21771704e-02j, -5.46350714e-02+5.94590117e-02j, - 4.20227987e-02+5.33808606e-02j, -5.44950519e-03-1.02152548e-01j, -8.52371557e-02+6.87526175e-02j, -9.88849806e-02+8.63653429e-02j, -3.29535337e-02+1.11468767e-01j, -8.91525767e-02-1.10460050e-01j, 8.65861644e-02+6.93102010e-04j, -9.60730971e-02+1.56945079e-01j, -5.14109278e-03-2.81513903e-02j, -1.40068665e-01+2.86562459e-02j, -9.83017425e-02+5.21354581e-02j, 4.69469551e-02-8.89922402e-02j, 2.21941752e-02-5.57626726e-03j, 1.66024586e-01-7.95503934e-02j, -1.38920743e-01+6.04827362e-02j, 8.25451438e-02-6.28766108e-02j, 4.25038037e-02+1.82529097e-02j, 2.62973135e-02-4.18821635e-02j, -1.45761903e-01-1.47286365e-01j, 9.89672045e-02-1.24387645e-01j, -5.78704218e-02-1.62675064e-02j, -4.71981727e-02+2.44048888e-01j, 3.99979719e-02-5.61776567e-02j, -5.90057528e-03-2.06685934e-02j, 1.00743108e-01+1.26113923e-01j, -8.30394273e-02-8.67700959e-02j, -2.42292161e-02+5.45664588e-02j, 1.03200164e-01+4.38793374e-03j, -1.29760046e-01-1.16149074e-01j, -4.06013934e-02-2.91615196e-02j, - -7.66643814e-02-2.82129167e-02j, 5.18827442e-02-9.09744909e-03j, 1.74289199e-02+1.30371358e-01j, -2.12748239e-01+8.60445151e-02j, -4.50027204e-02-4.68921603e-03j, -1.65936974e-02+9.74970666e-03j, 1.89314727e-02-1.52142208e-02j, 1.40710985e-03-7.24579715e-02j, -2.85195855e-02-4.64302487e-02j, 9.28808388e-02-5.38966974e-02j, -8.37647013e-02+3.87783304e-02j, -7.93612636e-02+5.52106771e-02j, -8.24627154e-02-7.29275080e-02j, -9.95466967e-02-2.55863384e-02j, -1.11330369e-01-1.07026510e-02j, 9.03801665e-02+7.48566039e-02j, -1.57610909e-02-2.11373355e-03j, -1.29136461e-01-1.57473543e-02j, 1.44036925e-01-1.17830341e-01j, -1.67628907e-02+1.06263346e-01j, -1.78654592e-02-1.01880945e-01j, -2.49916456e-02+4.60896420e-02j, 2.10042132e-01-7.70664131e-02j, -7.63588341e-02-3.73507331e-02j, -7.46108448e-02+1.98266460e-02j, 7.96343195e-03+3.98058310e-02j, 7.08286705e-02+5.89683331e-02j, 9.06570839e-03-1.68675820e-01j, -7.58415198e-02-1.61708205e-02j, 1.63594232e-01+1.06080863e-01j, - -5.27043428e-02+1.97776646e-01j, 1.68672907e-01+1.72692116e-01j, 1.20883554e-01-4.19624503e-02j, -4.06781283e-02-3.62701240e-02j, -1.81279165e-02-5.02802312e-02j, 1.06586105e-01-6.34529844e-02j, 2.24092969e-01-1.34142134e-02j, 4.64319738e-02-5.98185270e-03j, -7.72761980e-02+6.83240697e-02j, -2.47197188e-02-6.64142633e-02j, 6.12047543e-02-5.67342772e-02j, 6.89583775e-02-7.32779423e-02j, -9.73665566e-02-1.38092077e-01j, 9.42299578e-02-7.83134489e-02j, 4.66576304e-02+5.01211578e-02j, -5.84347124e-03+2.76985347e-02j, 2.32720197e-02-4.52208360e-03j, 1.03896607e-01-4.81745519e-02j, -2.53632308e-02-9.39062130e-02j, -1.33410903e-01+1.61699487e-01j, 1.41818815e-01+7.56963929e-02j, -1.38784180e-01+1.42229126e-01j, -7.82906496e-02+1.02452713e-01j, 1.62728062e-01+5.26600513e-02j, -4.70320160e-02+4.62832652e-02j, -1.34884657e-03+5.09580708e-02j, -1.21163909e-01+1.96909871e-01j, -2.72261417e-01-6.42506010e-02j, 2.86136429e-02+8.86315131e-02j, 5.31085101e-02-2.71828288e-02j, - -3.21727877e-02-5.77796931e-02j, -9.44638527e-02+1.37507662e-02j, -1.21657787e-01+8.65124885e-02j, -4.96839239e-03-2.97644254e-02j, -1.19540366e-01-1.34414909e-01j, 1.30160754e-01-1.26480898e-02j, -7.18591735e-02-2.46715270e-02j, 1.36140893e-01+4.14359423e-02j, -5.71317147e-03-1.18124735e-01j, 3.73988883e-02-2.36730347e-02j, 5.33823290e-02-8.47267547e-03j, 5.80851057e-02-3.92213264e-02j, 2.96021470e-02+1.06824598e-01j, 9.52300406e-02+8.04315308e-02j, -2.19648403e-02-8.28498260e-02j, -2.89222027e-02-9.84731848e-02j, 1.10461055e-01-1.58070614e-01j, 2.09076408e-01+3.68001449e-02j, -6.73813906e-02+9.16108413e-03j, 3.03631342e-02+2.95543290e-02j, -4.54437979e-03-3.18493443e-03j, -7.63023942e-02+1.55592989e-01j, -3.19220889e-02+4.73941064e-02j, 7.13699814e-02-5.69129591e-02j, -9.54995207e-02-3.92267051e-02j, -3.94296081e-02-1.51384146e-01j, 9.68318889e-02-7.70409747e-02j, 1.25939378e-02+3.18634620e-02j, -6.89127002e-02+7.07882363e-02j, 2.43254950e-02+1.16436448e-01j, - -9.91874227e-03-5.42893449e-02j, 1.23743411e-01+4.78200570e-02j, -5.85714409e-02+3.39221080e-02j, 3.65412457e-03-4.02554546e-03j, -2.05342433e-02+2.06713323e-01j, -3.02186741e-03+1.99788433e-02j, 1.16854339e-01-1.15247241e-01j, 9.62932923e-02+3.42143052e-03j, 4.26837528e-02+1.80563531e-01j, -1.23230416e-01+8.43397964e-02j, -1.66241403e-01-7.38559917e-02j, 8.12086119e-02-6.97547686e-03j, -7.31213186e-02+7.79960115e-02j, 2.85823841e-02-2.07511068e-02j, 8.27080727e-02+4.36355847e-02j, -1.10859884e-01-1.36676547e-02j, 1.28303434e-01-1.06149501e-02j, -1.46242136e-01+7.04963534e-02j, -8.26304595e-02-4.38762538e-02j, 1.71071748e-01+4.02667862e-02j, -1.35488426e-01-6.87212472e-02j, -4.67922162e-02-1.03931421e-02j, -2.44813702e-02-5.53092986e-02j, 4.73878499e-02+2.91459937e-02j, 1.98580413e-02-6.12412029e-03j, 1.10488978e-01-2.45764352e-02j, 8.00241132e-02-8.57174156e-02j, 1.03702916e-02-5.49489277e-02j, 3.93099516e-02+3.06121558e-02j, -3.02550594e-02+1.18718205e-01j, - -1.36619382e-01+2.34100763e-02j, -1.45312692e-01-2.24127604e-01j, -2.38248910e-02-1.11579180e-01j, 2.29159458e-02+6.19272697e-02j, 7.32380697e-02+1.36444819e-01j, -4.61302116e-02-2.18822134e-01j, -4.49007145e-02-2.24886131e-02j, -1.47568288e-01-2.04472654e-02j, 2.73175459e-02-2.19629877e-02j, 1.24524515e-01+9.26245193e-02j, -3.55583512e-02+5.09874867e-02j, 1.81713481e-01+8.06582753e-02j, 3.11561167e-02-1.22752357e-01j, -1.72074875e-01-1.29423169e-01j, 5.08999251e-02-6.26136051e-02j, 1.02390035e-01+8.45685534e-02j, 5.52593493e-02+3.68538488e-02j, -5.70061651e-02-4.25009402e-02j, -1.56072617e-02+8.62563257e-03j, -5.21205630e-02+2.36450605e-02j, -1.08956603e-01+5.57188609e-02j, -6.99571459e-02-3.51674530e-02j, 4.86802380e-02+3.37359307e-03j, -4.13618066e-02-2.12316403e-02j, -1.46621977e-01-4.74596174e-02j, -9.63426212e-02+1.72166337e-02j, 2.51705991e-02+3.21369206e-01j, 4.96769009e-02+3.48387702e-02j, -1.04762586e-02+1.56285574e-01j, -3.67404105e-03+7.68483799e-02j, - -4.46016110e-02+1.95201429e-02j, 4.38113722e-02+8.65962895e-03j, 7.74746787e-02+6.94607249e-02j, 2.47130647e-02-1.12600318e-02j, -7.48410468e-02+7.24300380e-02j, -3.77887553e-02-4.43488254e-02j, 1.32708760e-01+4.87164738e-02j, 1.63778016e-01+1.40758747e-01j, 8.20076371e-02-1.79740773e-01j, 5.49371276e-02+3.22196346e-02j, -2.37249431e-02-1.30833713e-01j, 1.19126218e-01+1.15211057e-01j, -8.03659026e-03+2.24442260e-02j, 9.06621949e-02+1.69073869e-02j, -9.84253648e-02-1.22959233e-01j, -1.13106787e-01-1.00708166e-02j] - - u1 = ql.Unitary("big6qubitone", matrix) - - - - def test_usingqx_sparseunitary(self): - num_qubits = 5 - p = ql.Program('test_usingqxsparseunitary', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [-0.11921901-0.30382154j, -0.10645804-0.11760155j, -0.09639953-0.0353926j , -0.32605797+0.19552924j, 0.0168262 -0.26748208j, -0.17808469+0.25265196j, -0.24676084-0.23228431j, -0.02960302+0.23697569j, - -0.12435741-0.07223017j, 0.00178745+0.14813263j, -0.11173158+0.26636089j, 0.27656908+0.05229833j, -0.02964214-0.01505502j, -0.26959616+0.23274949j, -0.18183627-0.04041783j, 0.05385991-0.05587908j, - 0.17894461-0.25668366j, -0.01553181-0.07446613j, 0.1876467 -0.49135878j, -0.18292006-0.04599956j, -0.01618695+0.21951951j, 0.06003169-0.12728871j, -0.04276406+0.08327372j, 0.30102765+0.18403071j, - -0.08122018-0.08375638j, -0.02971758+0.09096399j, 0.10753511-0.03359547j, -0.1596309 +0.20649279j, -0.13684564+0.29450386j, 0.20557421+0.24856224j, 0.0683444 +0.01780095j, -0.22317907-0.12123145j, - -0.0323504 -0.02668934j, 0.08743777-0.49956832j, -0.30202031-0.22517221j, -0.10642491-0.11883126j, -0.13756817-0.20632933j, 0.02593802+0.00583978j, 0.05130972+0.06678859j, -0.10426135-0.14411822j, - 0.12318252+0.28583957j, 0.04903179-0.31898637j, -0.07650819-0.07261235j, -0.22918932-0.28329527j, -0.26553775+0.04563403j, -0.07728053+0.14952931j, -0.10271285-0.00216319j, -0.09000117+0.09055528j, - -0.15385903+0.01767834j, 0.42229431-0.05610483j, -0.11330491-0.05458018j, 0.01740815-0.01605897j, -0.11908997-0.01830574j, 0.21139794-0.10602858j, -0.23249721-0.25516076j, -0.29066084-0.19129198j, - 0.21273108-0.14369238j, -0.20662513+0.14463032j, 0.2512466 -0.20356141j, 0.0869495 +0.24425667j, 0.09736427-0.03954332j, 0.1446303 +0.14263171j, -0.25679664+0.09389641j, -0.04020309-0.19362247j, - 0.12577257-0.14527364j, 0.00371525+0.14235318j, -0.22416134+0.02069087j, 0.03851418-0.05351593j, -0.00289848-0.33289946j, 0.15454716-0.126633j , -0.08996296-0.09119411j, -0.00804455-0.19149767j, - -0.13311475-0.47100304j, -0.13920624-0.16994321j, -0.05030304+0.16820614j, 0.05770089-0.15422191j, -0.23739468-0.05651883j, 0.19202883+0.03893001j, 0.48514604+0.01905479j, -0.01593819-0.06475285j, - 0.31543713+0.41579542j, -0.08776349+0.24207219j, -0.07984699-0.12818844j, 0.00359655+0.02677178j, -0.12110453-0.25327887j, -0.21175671-0.1650074j , -0.14570465-0.05140668j, 0.06873883-0.01768705j, - -0.13804809-0.16458822j, 0.15096981-0.02802171j, -0.05750448-0.18911017j, -0.01552104+0.03159908j, -0.0482418 +0.09434822j, 0.1336447 +0.22030451j, -0.3771364 -0.17773263j, 0.16023381+0.26613455j, - 0.12688452-0.07290393j, 0.14834649+0.08064162j, -0.06224533+0.04404318j, 0.03464369+0.19965444j, -0.38140629-0.18927599j, -0.19710535-0.178657j , -0.0507885 +0.19579635j, 0.11741615+0.13922702j, - 0.2673399 -0.01439493j, 0.10844591-0.19799688j, 0.01177533+0.031846j , -0.07643954+0.25870281j, 0.28971442-0.25385986j, -0.23713666+0.01838019j, 0.1731864 -0.09372299j, -0.36912353-0.02243029j, - 0.03562803-0.09449815j, 0.13578229-0.19205153j, 0.21279127+0.14541266j, -0.20195524+0.187477j , -0.06326783+0.0134827j , 0.26953438-0.11153784j, -0.28939961-0.08995754j, 0.20662437-0.15535337j, - -0.03615272+0.00848631j, 0.14124129-0.10250932j, 0.08990493-0.13010897j, -0.04547667+0.17579099j, -0.01292137+0.10354402j, -0.21338733-0.11928412j, 0.19733294+0.12876129j, 0.35162495+0.45226713j, - 0.17112722-0.18496045j, -0.34024071-0.09520237j, 0.18864652-0.07147408j, 0.31340662+0.24027412j, -0.0720874 -0.11081564j, 0.08727975+0.02830958j, -0.07584662-0.22555917j, 0.07086867-0.27714915j, - -0.19116148-0.02164144j, -0.24831911+0.1055229j , -0.09939105-0.24800283j, -0.15274706-0.12267535j, 0.05237777-0.09974669j, -0.18435891-0.1737002j , -0.20884292+0.1076081j , -0.31368958-0.02539025j, - 0.03436293-0.19794965j, 0.11892581-0.17440358j, -0.03488877+0.02305411j, 0.29835292-0.08836461j, 0.07893495-0.16881403j, 0.21025843+0.13204032j, 0.17194288-0.06285539j, -0.0500497 +0.35833208j, - -0.14979745-0.07567974j, 0.00193804+0.04092128j, -0.07528403-0.18508153j, -0.16873521-0.09470809j, 0.50335605+0.00445803j, 0.11671956+0.30273552j, 0.10253226-0.13365319j, 0.16676135+0.18345473j, - -0.10096334-0.24031019j, -0.18452241+0.05766426j, 0.18102499-0.13532486j, 0.06252468-0.18030042j, -0.00591499+0.07587582j, -0.35209025-0.12186396j, -0.25282963-0.26651504j, -0.13074882+0.14059941j, - 0.18125386-0.03889917j, 0.06983104-0.3425076j , 0.37124455-0.00305632j, 0.04469806-0.31220629j, 0.16501585+0.00125887j, 0.15895714-0.14115809j, -0.01515444+0.06836136j, 0.03934186+0.13425449j, - 0.0513499 +0.21915368j, 0.00089628-0.3044611j , 0.05443815-0.05530296j, 0.12091374-0.16717579j, -0.06795704-0.2515947j , -0.43324316+0.13138954j, 0.03753289-0.00666299j, 0.16823686-0.22736152j, - -0.00567807+0.05485941j, -0.11705816+0.39078352j, 0.29136164+0.18699453j, -0.09255109+0.08923507j, 0.11214398+0.00806872j, 0.02971631+0.05584961j, 0.2561 +0.22302638j, 0.12491596+0.01725833j, - 0.23473354-0.19203316j, -0.09144197-0.04827201j, -0.0630975 -0.16831612j, 0.01497053+0.11121057j, 0.1426864 -0.15815582j, 0.21509872-0.0821851j , 0.00650273+0.42560079j, -0.15721229+0.09919403j, - 0.18076365-0.05697395j, -0.10596487+0.23118383j, 0.30913352+0.24695589j, -0.03403863-0.01778209j, -0.07783213-0.25923847j, 0.06847369-0.2460447j , -0.24223779-0.10590238j, 0.15920784+0.21435437j, - 0.26632193-0.02864663j, 0.06457043+0.0577428j , -0.38792984+0.08474334j, 0.00944311+0.22274564j, 0.11762823+0.36687658j, -0.1058428 -0.2103637j , -0.12970051-0.27031414j, 0.12684307+0.08398822j, - 0.06711923+0.23195763j, -0.04537262+0.26478843j, 0.10253668-0.07706414j, -0.13531665-0.27150259j, -0.09124132-0.23306839j, -0.08631867+0.17221145j, 0.17654328-0.10341264j, 0.11171903-0.05824829j, - 0.04708668-0.13436316j, -0.10544253+0.07083904j, 0.04191629+0.28190845j, -0.4212947 -0.28704399j, 0.10278485+0.05713015j, 0.02057009-0.19126408j, 0.04856717+0.26648423j, 0.05388858-0.32433511j, - -0.09408669-0.12159016j, -0.01355394+0.04757554j, 0.10925003-0.0453999j , -0.02512057-0.23836324j, 0.31375479-0.0993564j , -0.14702106+0.33395328j, -0.1608029 +0.11439592j, -0.11028577-0.0093615j , - -0.08440005-0.12376623j, 0.12932188+0.09711828j, 0.18574716-0.06392924j, -0.13048059+0.0287961j , -0.29552716-0.08768809j, -0.02439943-0.01548155j, 0.07775135+0.00727332j, 0.1561534 -0.06489038j, - 0.46665242-0.07708219j, -0.05251139+0.37781248j, -0.3549081 -0.10086123j, 0.11180645-0.40408473j, 0.03031085+0.16928711j, 0.1190129 -0.10061168j, 0.0318046 -0.12504866j, 0.08689947+0.07223655j] - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.hadamard(0) - k.hadamard(1) - k.hadamard(2) - k.hadamard(3) - k.cnot(0, 1) - k.cnot(0, 2) - k.cnot(0, 3) - k.cnot(1, 2) - k.cnot(1, 3) - k.cnot(2, 3) - - k.gate(u1, [0, 1, 2, 3]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(0.0625*helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7] + matrix[8] + matrix[9] + matrix[10]+ matrix[11]+ matrix[12]+ matrix[13]+ matrix[14]+ matrix[15])), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[16] + matrix[17]+ matrix[18]+ matrix[19]+ matrix[20]+ matrix[21]+ matrix[22]+ matrix[23]+ matrix[24] + matrix[25]+ matrix[26]+ matrix[27]+ matrix[28]+ matrix[29]+ matrix[30]+ matrix[31])), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[32] + matrix[33]+ matrix[34]+ matrix[35]+ matrix[36]+ matrix[37]+ matrix[38]+ matrix[39]+ matrix[40] + matrix[41]+ matrix[42]+ matrix[43]+ matrix[44]+ matrix[45]+ matrix[46]+ matrix[47])), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[48] + matrix[49]+ matrix[50]+ matrix[51]+ matrix[52]+ matrix[53]+ matrix[54]+ matrix[55]+ matrix[56] + matrix[57]+ matrix[58]+ matrix[59]+ matrix[60]+ matrix[61]+ matrix[62]+ matrix[63])), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[64] + matrix[65]+ matrix[66]+ matrix[67]+ matrix[68]+ matrix[69]+ matrix[70]+ matrix[71]+ matrix[72] + matrix[73]+ matrix[74]+ matrix[75]+ matrix[76]+ matrix[77]+ matrix[78]+ matrix[79])), helper_prob(state.get(to_bitstring(4, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[80] + matrix[81]+ matrix[82]+ matrix[83]+ matrix[84]+ matrix[85]+ matrix[86]+ matrix[87]+ matrix[88] + matrix[89]+ matrix[90]+ matrix[91]+ matrix[92]+ matrix[93]+ matrix[94]+ matrix[95])), helper_prob(state.get(to_bitstring(5, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[96] + matrix[97]+ matrix[98]+ matrix[99]+ matrix[100]+ matrix[101]+ matrix[102]+ matrix[103]+ matrix[104] + matrix[105]+ matrix[106]+ matrix[107]+ matrix[108]+ matrix[109]+ matrix[110]+ matrix[111])), helper_prob(state.get(to_bitstring(6, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[112] + matrix[113]+ matrix[114]+ matrix[115]+ matrix[116]+ matrix[117]+ matrix[118]+ matrix[119]+ matrix[120] + matrix[121]+ matrix[122]+ matrix[123]+ matrix[124]+ matrix[125]+ matrix[126]+ matrix[127])), helper_prob(state.get(to_bitstring(7, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[128] + matrix[129]+ matrix[130]+ matrix[131]+ matrix[132]+ matrix[133]+ matrix[134]+ matrix[135]+ matrix[136] + matrix[137]+ matrix[138]+ matrix[139]+ matrix[140]+ matrix[141]+ matrix[142]+ matrix[143])), helper_prob(state.get(to_bitstring(8, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[144] + matrix[145]+ matrix[146]+ matrix[147]+ matrix[148]+ matrix[149]+ matrix[150]+ matrix[151]+ matrix[152] + matrix[153]+ matrix[154]+ matrix[155]+ matrix[156]+ matrix[157]+ matrix[158]+ matrix[159])), helper_prob(state.get(to_bitstring(9, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[160] + matrix[161]+ matrix[162]+ matrix[163]+ matrix[164]+ matrix[165]+ matrix[166]+ matrix[167]+ matrix[168] + matrix[169]+ matrix[170]+ matrix[171]+ matrix[172]+ matrix[173]+ matrix[174]+ matrix[175])), helper_prob(state.get(to_bitstring(10, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[176] + matrix[177]+ matrix[178]+ matrix[179]+ matrix[180]+ matrix[181]+ matrix[182]+ matrix[183]+ matrix[184] + matrix[185]+ matrix[186]+ matrix[187]+ matrix[188]+ matrix[189]+ matrix[190]+ matrix[191])), helper_prob(state.get(to_bitstring(11, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[192] + matrix[193]+ matrix[194]+ matrix[195]+ matrix[196]+ matrix[197]+ matrix[198]+ matrix[199]+ matrix[200] + matrix[201]+ matrix[202]+ matrix[203]+ matrix[204]+ matrix[205]+ matrix[206]+ matrix[207])), helper_prob(state.get(to_bitstring(12, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[208] + matrix[209]+ matrix[210]+ matrix[211]+ matrix[212]+ matrix[213]+ matrix[214]+ matrix[215]+ matrix[216] + matrix[217]+ matrix[218]+ matrix[219]+ matrix[220]+ matrix[221]+ matrix[222]+ matrix[223])), helper_prob(state.get(to_bitstring(13, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[224] + matrix[225]+ matrix[226]+ matrix[227]+ matrix[228]+ matrix[229]+ matrix[230]+ matrix[231]+ matrix[232] + matrix[233]+ matrix[234]+ matrix[235]+ matrix[236]+ matrix[237]+ matrix[238]+ matrix[239])), helper_prob(state.get(to_bitstring(14, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[240] + matrix[241]+ matrix[242]+ matrix[243]+ matrix[244]+ matrix[245]+ matrix[246]+ matrix[247]+ matrix[248] + matrix[249]+ matrix[250]+ matrix[251]+ matrix[252]+ matrix[253]+ matrix[254]+ matrix[255])), helper_prob(state.get(to_bitstring(15, size=platform_qubits), 0.)), 5) - - - def test_extremelysparseunitary(self): - num_qubits = 4 - p = ql.Program('test_usingqx_extremelysparseunitary_newname', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [-0.59111943+0.15726005j, -0. +0.j , -0.15509793+0.32339668j, -0. +0.j , -0.33317562+0.00860528j, -0. +0.j , -0.5566068 +0.27625195j, -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j - , -0. +0.j , -0.59111943+0.15726005j, -0. +0.j , -0.15509793+0.32339668j, -0. +0.j , -0.33317562+0.00860528j, -0. +0.j , -0.5566068 +0.27625195j, -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j - , -0.00563624-0.59423429j, 0. -0.j , 0.46013302+0.40732351j, 0. +0.j , -0.30528142-0.21246605j, 0. -0.j , 0.25389832+0.25771317j, 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j - , 0. -0.j , -0.00563624-0.59423429j, 0. +0.j , 0.46013302+0.40732351j, 0. -0.j , -0.30528142-0.21246605j, 0. +0.j , 0.25389832+0.25771317j, 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j - , 0.01676811-0.33500121j, 0. +0.j , -0.46028079-0.49188018j, 0. -0.j , -0.18833511+0.15673318j, -0. +0.j , 0.14043556+0.59492096j, 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j - , 0. +0.j , 0.01676811-0.33500121j, 0. -0.j , -0.46028079-0.49188018j, -0. +0.j , -0.18833511+0.15673318j, 0. +0.j , 0.14043556+0.59492096j, 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j - , 0.3733514 +0.14423137j, 0. +0.j , -0.18039476+0.08589294j, -0. +0.j , -0.80479128+0.20701926j, -0. +0.j , 0.06883732-0.32342174j, 0. +0.j , 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j - , 0. +0.j , 0.3733514 +0.14423137j, -0. +0.j , -0.18039476+0.08589294j, -0. +0.j , -0.80479128+0.20701926j, 0. +0.j , 0.06883732-0.32342174j, 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j - , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0.59111943+0.15726005j, -0. +0.j , -0.15509793+0.32339668j, -0. +0.j , -0.33317562+0.00860528j, -0. +0.j , -0.5566068 +0.27625195j, -0. +0.j - , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0.59111943+0.15726005j, -0. +0.j , -0.15509793+0.32339668j, -0. +0.j , -0.33317562+0.00860528j, -0. +0.j , -0.5566068 +0.27625195j - , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , -0.00563624-0.59423429j, 0. -0.j , 0.46013302+0.40732351j, 0. +0.j , -0.30528142-0.21246605j, 0. -0.j , 0.25389832+0.25771317j, 0. +0.j - , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0. -0.j , -0.00563624-0.59423429j, 0. +0.j , 0.46013302+0.40732351j, 0. -0.j , -0.30528142-0.21246605j, 0. +0.j , 0.25389832+0.25771317j - , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j , 0.01676811-0.33500121j, 0. +0.j , -0.46028079-0.49188018j, 0. -0.j , -0.18833511+0.15673318j, -0. +0.j , 0.14043556+0.59492096j, 0. +0.j - , 0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0.01676811-0.33500121j, 0. -0.j , -0.46028079-0.49188018j, -0. +0.j , -0.18833511+0.15673318j, 0. +0.j , 0.14043556+0.59492096j - , 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j , 0.3733514 +0.14423137j, 0. +0.j , -0.18039476+0.08589294j, -0. +0.j , -0.80479128+0.20701926j, -0. +0.j , 0.06883732-0.32342174j, 0. +0.j - , 0. +0.j , 0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , -0. +0.j , 0. +0.j , 0. +0.j , 0. +0.j , 0.3733514 +0.14423137j, -0. +0.j , -0.18039476+0.08589294j, -0. +0.j , -0.80479128+0.20701926j, 0. +0.j , 0.06883732-0.32342174j] - - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.hadamard(0) - k.hadamard(1) - k.hadamard(2) - k.hadamard(3) - k.cnot(0, 1) - k.cnot(0, 2) - k.cnot(0, 3) - k.cnot(1, 2) - k.cnot(1, 3) - k.cnot(2, 3) - - k.gate(u1, [0, 1, 2, 3]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(0.0625*helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7] + matrix[8] + matrix[9] + matrix[10]+ matrix[11]+ matrix[12]+ matrix[13]+ matrix[14]+ matrix[15])), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[16] + matrix[17]+ matrix[18]+ matrix[19]+ matrix[20]+ matrix[21]+ matrix[22]+ matrix[23]+ matrix[24] + matrix[25]+ matrix[26]+ matrix[27]+ matrix[28]+ matrix[29]+ matrix[30]+ matrix[31])), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[32] + matrix[33]+ matrix[34]+ matrix[35]+ matrix[36]+ matrix[37]+ matrix[38]+ matrix[39]+ matrix[40] + matrix[41]+ matrix[42]+ matrix[43]+ matrix[44]+ matrix[45]+ matrix[46]+ matrix[47])), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[48] + matrix[49]+ matrix[50]+ matrix[51]+ matrix[52]+ matrix[53]+ matrix[54]+ matrix[55]+ matrix[56] + matrix[57]+ matrix[58]+ matrix[59]+ matrix[60]+ matrix[61]+ matrix[62]+ matrix[63])), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[64] + matrix[65]+ matrix[66]+ matrix[67]+ matrix[68]+ matrix[69]+ matrix[70]+ matrix[71]+ matrix[72] + matrix[73]+ matrix[74]+ matrix[75]+ matrix[76]+ matrix[77]+ matrix[78]+ matrix[79])), helper_prob(state.get(to_bitstring(4, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[80] + matrix[81]+ matrix[82]+ matrix[83]+ matrix[84]+ matrix[85]+ matrix[86]+ matrix[87]+ matrix[88] + matrix[89]+ matrix[90]+ matrix[91]+ matrix[92]+ matrix[93]+ matrix[94]+ matrix[95])), helper_prob(state.get(to_bitstring(5, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[96] + matrix[97]+ matrix[98]+ matrix[99]+ matrix[100]+ matrix[101]+ matrix[102]+ matrix[103]+ matrix[104] + matrix[105]+ matrix[106]+ matrix[107]+ matrix[108]+ matrix[109]+ matrix[110]+ matrix[111])), helper_prob(state.get(to_bitstring(6, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[112] + matrix[113]+ matrix[114]+ matrix[115]+ matrix[116]+ matrix[117]+ matrix[118]+ matrix[119]+ matrix[120] + matrix[121]+ matrix[122]+ matrix[123]+ matrix[124]+ matrix[125]+ matrix[126]+ matrix[127])), helper_prob(state.get(to_bitstring(7, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[128] + matrix[129]+ matrix[130]+ matrix[131]+ matrix[132]+ matrix[133]+ matrix[134]+ matrix[135]+ matrix[136] + matrix[137]+ matrix[138]+ matrix[139]+ matrix[140]+ matrix[141]+ matrix[142]+ matrix[143])), helper_prob(state.get(to_bitstring(8, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[144] + matrix[145]+ matrix[146]+ matrix[147]+ matrix[148]+ matrix[149]+ matrix[150]+ matrix[151]+ matrix[152] + matrix[153]+ matrix[154]+ matrix[155]+ matrix[156]+ matrix[157]+ matrix[158]+ matrix[159])), helper_prob(state.get(to_bitstring(9, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[160] + matrix[161]+ matrix[162]+ matrix[163]+ matrix[164]+ matrix[165]+ matrix[166]+ matrix[167]+ matrix[168] + matrix[169]+ matrix[170]+ matrix[171]+ matrix[172]+ matrix[173]+ matrix[174]+ matrix[175])), helper_prob(state.get(to_bitstring(10, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[176] + matrix[177]+ matrix[178]+ matrix[179]+ matrix[180]+ matrix[181]+ matrix[182]+ matrix[183]+ matrix[184] + matrix[185]+ matrix[186]+ matrix[187]+ matrix[188]+ matrix[189]+ matrix[190]+ matrix[191])), helper_prob(state.get(to_bitstring(11, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[192] + matrix[193]+ matrix[194]+ matrix[195]+ matrix[196]+ matrix[197]+ matrix[198]+ matrix[199]+ matrix[200] + matrix[201]+ matrix[202]+ matrix[203]+ matrix[204]+ matrix[205]+ matrix[206]+ matrix[207])), helper_prob(state.get(to_bitstring(12, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[208] + matrix[209]+ matrix[210]+ matrix[211]+ matrix[212]+ matrix[213]+ matrix[214]+ matrix[215]+ matrix[216] + matrix[217]+ matrix[218]+ matrix[219]+ matrix[220]+ matrix[221]+ matrix[222]+ matrix[223])), helper_prob(state.get(to_bitstring(13, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[224] + matrix[225]+ matrix[226]+ matrix[227]+ matrix[228]+ matrix[229]+ matrix[230]+ matrix[231]+ matrix[232] + matrix[233]+ matrix[234]+ matrix[235]+ matrix[236]+ matrix[237]+ matrix[238]+ matrix[239])), helper_prob(state.get(to_bitstring(14, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.0625*helper_prob((matrix[240] + matrix[241]+ matrix[242]+ matrix[243]+ matrix[244]+ matrix[245]+ matrix[246]+ matrix[247]+ matrix[248] + matrix[249]+ matrix[250]+ matrix[251]+ matrix[252]+ matrix[253]+ matrix[254]+ matrix[255])), helper_prob(state.get(to_bitstring(15, size=platform_qubits), 0.)), 5) - - def test_sparse2qubitunitary(self): - num_qubits = 2 - p = ql.Program('test_usingqx_sparse2qubit', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [ 0.2309453 -0.79746147j, -0.53683301+0.15009925j, 0. +0.j , -0. +0.j - , 0.39434916-0.39396473j, 0.80810853+0.19037107j, 0. +0.j , 0. +0.j - , 0. +0.j , -0. +0.j , 0.2309453 -0.79746147j, -0.53683301+0.15009925j - , 0. +0.j , 0. +0.j , 0.39434916-0.39396473j, 0.80810853+0.19037107j] - - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.gate(u1, [0, 1]) - - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[4]), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[8]), 0, 5) # Zero probabilities do not show up in the output list - self.assertAlmostEqual(helper_prob(matrix[12]), 0, 5) - - - - def test_sparse2qubitunitaryotherqubit(self): - num_qubits = 2 - p = ql.Program('test_usingqx_sparse2qubitotherqubit', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [ 0.30279949-0.60010283j, 0. +0.j , -0.58058628-0.45946559j, 0. -0.j - , 0. +0.j , 0.30279949-0.60010283j, 0. -0.j , -0.58058628-0.45946559j - , 0.04481146-0.73904059j, 0. +0.j , 0.64910478+0.17456782j, 0. +0.j - , 0. +0.j , 0.04481146-0.73904059j, 0. +0.j , 0.64910478+0.17456782j] - - u1 = ql.Unitary("sparse2_qubit_unitary_other_qubit",matrix) - u1.decompose() - k.gate(u1, [0, 1]) - - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[4]), 0, 5) # Zero probabilities do not show up in the output list - self.assertAlmostEqual(helper_prob(matrix[8]), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[12]), 0, 5) - - - def test_sparse2qubitunitaryotherqubitcheck(self): - num_qubits = 1 - p = ql.Program('test_usingqx_sparse2qubitotherqubit_test', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [ 0.30279949-0.60010283j, -0.58058628-0.45946559j - , 0.04481146-0.73904059j, 0.64910478+0.17456782j] - u1 = ql.Unitary("testname",matrix) - u1.decompose() - k.gate(u1, [0]) - - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(helper_prob(matrix[0]), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(helper_prob(matrix[1]), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) # Zero probabilities do not show up in the output list - - - def test_sparse2qubit_multiplexor(self): - num_qubits = 2 - p = ql.Program('test_usingqx_sparse2qubit_multiplexor', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [ 0.30279949-0.60010283j, -0.58058628-0.45946559j, 0 , 0 - , 0.04481146-0.73904059j, 0.64910478+0.17456782j, 0 , 0 - , 0. +0.j , -0. +0.j , 0.2309453 -0.79746147j, -0.53683301+0.15009925j - , 0. +0.j , 0. +0.j , 0.39434916-0.39396473j, 0.80810853+0.19037107j] - u1 = ql.Unitary("multiplexor",matrix) - u1.decompose() - k.hadamard(0) - k.hadamard(1) - k.gate(u1, [0, 1]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - - self.assertAlmostEqual(0.25*helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] )), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.25*helper_prob((matrix[4] + matrix[5] + matrix[6] + matrix[7] )), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.25*helper_prob((matrix[8] + matrix[9] + matrix[10]+ matrix[11])), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.25*helper_prob((matrix[12]+ matrix[13]+ matrix[14]+ matrix[15])), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - - def test_decomposition_rotatedtoffoli(self): - num_qubits = 3 - p = ql.Program('test_usingqx_rotatedtoffoli', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = (np.exp(-1j*0.3*3.141562)*np.array([[1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 1, 0]])).flatten() - - u1 = ql.Unitary("rotatedtoffoli",matrix) - u1.decompose() - k.hadamard(0) - k.hadamard(1) - k.hadamard(2) - - k.gate(u1, [0, 1, 2]) - - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(0.125*helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7])), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[8] + matrix[9] + matrix[10]+ matrix[11]+ matrix[12]+ matrix[13]+ matrix[14]+ matrix[15])), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[16] + matrix[17]+ matrix[18]+ matrix[19]+ matrix[20]+ matrix[21]+ matrix[22]+ matrix[23])), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[24] + matrix[25]+ matrix[26]+ matrix[27]+ matrix[28]+ matrix[29]+ matrix[30]+ matrix[31])), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[32] + matrix[33]+ matrix[34]+ matrix[35]+ matrix[36]+ matrix[37]+ matrix[38]+ matrix[39])), helper_prob(state.get(to_bitstring(4, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[40] + matrix[41]+ matrix[42]+ matrix[43]+ matrix[44]+ matrix[45]+ matrix[46]+ matrix[47])), helper_prob(state.get(to_bitstring(5, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[48] + matrix[49]+ matrix[50]+ matrix[51]+ matrix[52]+ matrix[53]+ matrix[54]+ matrix[55])), helper_prob(state.get(to_bitstring(6, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[56] + matrix[57]+ matrix[58]+ matrix[59]+ matrix[60]+ matrix[61]+ matrix[62]+ matrix[63])), helper_prob(state.get(to_bitstring(7, size=platform_qubits), 0.)), 5) - - def test_decomposition_toffoli(self): - num_qubits = 3 - p = ql.Program('test_usingqx_toffoli', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = np.array([[1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0, 1], - [0, 0, 0, 0, 0, 0, 1, 0]]).flatten() - - u1 = ql.Unitary("rotatedtoffoli",matrix) - u1.decompose() - k.hadamard(0) - k.hadamard(1) - k.hadamard(2) - k.gate(u1, [0, 1, 2]) - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - self.assertAlmostEqual(0.125*helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7])), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[8] + matrix[9] + matrix[10]+ matrix[11]+ matrix[12]+ matrix[13]+ matrix[14]+ matrix[15])), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[16] + matrix[17]+ matrix[18]+ matrix[19]+ matrix[20]+ matrix[21]+ matrix[22]+ matrix[23])), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[24] + matrix[25]+ matrix[26]+ matrix[27]+ matrix[28]+ matrix[29]+ matrix[30]+ matrix[31])), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[32] + matrix[33]+ matrix[34]+ matrix[35]+ matrix[36]+ matrix[37]+ matrix[38]+ matrix[39])), helper_prob(state.get(to_bitstring(4, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[40] + matrix[41]+ matrix[42]+ matrix[43]+ matrix[44]+ matrix[45]+ matrix[46]+ matrix[47])), helper_prob(state.get(to_bitstring(5, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[48] + matrix[49]+ matrix[50]+ matrix[51]+ matrix[52]+ matrix[53]+ matrix[54]+ matrix[55])), helper_prob(state.get(to_bitstring(6, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[56] + matrix[57]+ matrix[58]+ matrix[59]+ matrix[60]+ matrix[61]+ matrix[62]+ matrix[63])), helper_prob(state.get(to_bitstring(7, size=platform_qubits), 0.)), 5) - - def test_decomposition_controlled_U(self): - num_qubits = 3 - p = ql.Program('test_usingqx_toffoli', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = np.array([[1, 0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0, 0], - [0, 0, 1, 0, 0, 0, 0, 0], - [0, 0, 0, 1, 0, 0, 0, 0], - [0, 0, 0, 0, 1, 0, 0, 0], - [0, 0, 0, 0, 0, 1, 0, 0], - [0, 0, 0, 0, 0, 0, 0.30279949-0.60010283j, -0.58058628-0.45946559j], - [0, 0, 0, 0, 0 ,0, 0.04481146-0.73904059j, 0.64910478+0.17456782j]]).flatten() - - u1 = ql.Unitary("arbitrarycontrolled",matrix) - u1.decompose() - k.hadamard(0) - k.hadamard(1) - k.hadamard(2) - k.gate(u1, [0, 1, 2]) - - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - print(state) - self.assertAlmostEqual(0.125*helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7])), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[8] + matrix[9] + matrix[10]+ matrix[11]+ matrix[12]+ matrix[13]+ matrix[14]+ matrix[15])), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[16] + matrix[17]+ matrix[18]+ matrix[19]+ matrix[20]+ matrix[21]+ matrix[22]+ matrix[23])), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[24] + matrix[25]+ matrix[26]+ matrix[27]+ matrix[28]+ matrix[29]+ matrix[30]+ matrix[31])), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[32] + matrix[33]+ matrix[34]+ matrix[35]+ matrix[36]+ matrix[37]+ matrix[38]+ matrix[39])), helper_prob(state.get(to_bitstring(4, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[40] + matrix[41]+ matrix[42]+ matrix[43]+ matrix[44]+ matrix[45]+ matrix[46]+ matrix[47])), helper_prob(state.get(to_bitstring(5, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[48] + matrix[49]+ matrix[50]+ matrix[51]+ matrix[52]+ matrix[53]+ matrix[54]+ matrix[55])), helper_prob(state.get(to_bitstring(6, size=platform_qubits), 0.)), 5) - self.assertAlmostEqual(0.125*helper_prob((matrix[56] + matrix[57]+ matrix[58]+ matrix[59]+ matrix[60]+ matrix[61]+ matrix[62]+ matrix[63])), helper_prob(state.get(to_bitstring(7, size=platform_qubits), 0.)), 5) - - def test_decomposition_mscthesisaritra(self): - num_qubits = 4 - p = ql.Program('test_usingqx_mscthesisaritra', platform, num_qubits) - k = ql.Kernel('akernel', platform, num_qubits) - - matrix = [0.3672 ,-0.3654 ,-0.3654 ,-0.2109 ,-0.3654 ,-0.2109 ,-0.2109 ,-0.1218 ,-0.3654 ,-0.2109 ,-0.2109 ,-0.1218 ,-0.2109 ,-0.1218 ,-0.1218 ,-0.0703 - ,-0.3654 , 0.7891 ,-0.2109 ,-0.1218 ,-0.2109 ,-0.1218 ,-0.1218 ,-0.0703 ,-0.2109 ,-0.1218 ,-0.1218 ,-0.0703 ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 - ,-0.3654 ,-0.2109 , 0.7891 ,-0.1218 ,-0.2109 ,-0.1218 ,-0.1218 ,-0.0703 ,-0.2109 ,-0.1218 ,-0.1218 ,-0.0703 ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 - ,-0.2109 ,-0.1218 ,-0.1218 , 0.9297 ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 ,-0.0703 ,-0.0406 ,-0.0406 ,-0.0234 - ,-0.3654 ,-0.2109 ,-0.2109 ,-0.1218 , 0.7891 ,-0.1218 ,-0.1218 ,-0.0703 ,-0.2109 ,-0.1218 ,-0.1218 ,-0.0703 ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 - ,-0.2109 ,-0.1218 ,-0.1218 ,-0.0703 ,-0.1218 , 0.9297 ,-0.0703 ,-0.0406 ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 ,-0.0703 ,-0.0406 ,-0.0406 ,-0.0234 - ,-0.2109 ,-0.1218 ,-0.1218 ,-0.0703 ,-0.1218 ,-0.0703 , 0.9297 ,-0.0406 ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 ,-0.0703 ,-0.0406 ,-0.0406 ,-0.0234 - ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 ,-0.0703 ,-0.0406 ,-0.0406 , 0.9766 ,-0.0703 ,-0.0406 ,-0.0406 ,-0.0234 ,-0.0406 ,-0.0234 ,-0.0234 ,-0.0135 - ,-0.3654 ,-0.2109 ,-0.2109 ,-0.1218 ,-0.2109 ,-0.1218 ,-0.1218 ,-0.0703 , 0.7891 ,-0.1218 ,-0.1218 ,-0.0703 ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 - ,-0.2109 ,-0.1218 ,-0.1218 ,-0.0703 ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 ,-0.1218 , 0.9297 ,-0.0703 ,-0.0406 ,-0.0703 ,-0.0406 ,-0.0406 ,-0.0234 - ,-0.2109 ,-0.1218 ,-0.1218 ,-0.0703 ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 ,-0.1218 ,-0.0703 , 0.9297 ,-0.0406 ,-0.0703 ,-0.0406 ,-0.0406 ,-0.0234 - ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 ,-0.0703 ,-0.0406 ,-0.0406 ,-0.0234 ,-0.0703 ,-0.0406 ,-0.0406 , 0.9766 ,-0.0406 ,-0.0234 ,-0.0234 ,-0.0135 - ,-0.2109 ,-0.1218 ,-0.1218 ,-0.0703 ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 , 0.9297 ,-0.0406 ,-0.0406 ,-0.0234 - ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 ,-0.0703 ,-0.0406 ,-0.0406 ,-0.0234 ,-0.0703 ,-0.0406 ,-0.0406 ,-0.0234 ,-0.0406 , 0.9766 ,-0.0234 ,-0.0135 - ,-0.1218 ,-0.0703 ,-0.0703 ,-0.0406 ,-0.0703 ,-0.0406 ,-0.0406 ,-0.0234 ,-0.0703 ,-0.0406 ,-0.0406 ,-0.0234 ,-0.0406 ,-0.0234 , 0.9766 ,-0.0135 - ,-0.0703 ,-0.0406 ,-0.0406 ,-0.0234 ,-0.0406 ,-0.0234 ,-0.0234 ,-0.0135 ,-0.0406 ,-0.0234 ,-0.0234 ,-0.0135 ,-0.0234 ,-0.0135 ,-0.0135 , 0.9922] - - u1 = ql.Unitary("mscthesisaritra",matrix) - u1.decompose() - k.hadamard(0) - k.hadamard(1) - k.hadamard(2) - k.hadamard(3) - k.gate(u1, [0, 1, 2, 3]) - - - p.add_kernel(k) - p.get_compiler().set_option('initialqasmwriter.cqasm_version', '1.0') - p.get_compiler().set_option('initialqasmwriter.with_metadata', 'no') - p.compile() - state = qxelarator.execute_file(os.path.join(output_dir, p.name+'.qasm')).state - - # less accuracy because of less accurate input - self.assertAlmostEqual(0.0625*helper_prob((matrix[0] + matrix[1] + matrix[2] + matrix[3] + matrix[4] + matrix[5] + matrix[6] + matrix[7] + matrix[8] + matrix[9] + matrix[10]+ matrix[11]+ matrix[12]+ matrix[13]+ matrix[14]+ matrix[15])), helper_prob(state.get(to_bitstring(0, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[16] + matrix[17]+ matrix[18]+ matrix[19]+ matrix[20]+ matrix[21]+ matrix[22]+ matrix[23]+ matrix[24] + matrix[25]+ matrix[26]+ matrix[27]+ matrix[28]+ matrix[29]+ matrix[30]+ matrix[31])), helper_prob(state.get(to_bitstring(1, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[32] + matrix[33]+ matrix[34]+ matrix[35]+ matrix[36]+ matrix[37]+ matrix[38]+ matrix[39]+ matrix[40] + matrix[41]+ matrix[42]+ matrix[43]+ matrix[44]+ matrix[45]+ matrix[46]+ matrix[47])), helper_prob(state.get(to_bitstring(2, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[48] + matrix[49]+ matrix[50]+ matrix[51]+ matrix[52]+ matrix[53]+ matrix[54]+ matrix[55]+ matrix[56] + matrix[57]+ matrix[58]+ matrix[59]+ matrix[60]+ matrix[61]+ matrix[62]+ matrix[63])), helper_prob(state.get(to_bitstring(3, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[64] + matrix[65]+ matrix[66]+ matrix[67]+ matrix[68]+ matrix[69]+ matrix[70]+ matrix[71]+ matrix[72] + matrix[73]+ matrix[74]+ matrix[75]+ matrix[76]+ matrix[77]+ matrix[78]+ matrix[79])), helper_prob(state.get(to_bitstring(4, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[80] + matrix[81]+ matrix[82]+ matrix[83]+ matrix[84]+ matrix[85]+ matrix[86]+ matrix[87]+ matrix[88] + matrix[89]+ matrix[90]+ matrix[91]+ matrix[92]+ matrix[93]+ matrix[94]+ matrix[95])), helper_prob(state.get(to_bitstring(5, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[96] + matrix[97]+ matrix[98]+ matrix[99]+ matrix[100]+ matrix[101]+ matrix[102]+ matrix[103]+ matrix[104] + matrix[105]+ matrix[106]+ matrix[107]+ matrix[108]+ matrix[109]+ matrix[110]+ matrix[111])), helper_prob(state.get(to_bitstring(6, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[112] + matrix[113]+ matrix[114]+ matrix[115]+ matrix[116]+ matrix[117]+ matrix[118]+ matrix[119]+ matrix[120] + matrix[121]+ matrix[122]+ matrix[123]+ matrix[124]+ matrix[125]+ matrix[126]+ matrix[127])), helper_prob(state.get(to_bitstring(7, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[128] + matrix[129]+ matrix[130]+ matrix[131]+ matrix[132]+ matrix[133]+ matrix[134]+ matrix[135]+ matrix[136] + matrix[137]+ matrix[138]+ matrix[139]+ matrix[140]+ matrix[141]+ matrix[142]+ matrix[143])), helper_prob(state.get(to_bitstring(8, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[144] + matrix[145]+ matrix[146]+ matrix[147]+ matrix[148]+ matrix[149]+ matrix[150]+ matrix[151]+ matrix[152] + matrix[153]+ matrix[154]+ matrix[155]+ matrix[156]+ matrix[157]+ matrix[158]+ matrix[159])), helper_prob(state.get(to_bitstring(9, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[160] + matrix[161]+ matrix[162]+ matrix[163]+ matrix[164]+ matrix[165]+ matrix[166]+ matrix[167]+ matrix[168] + matrix[169]+ matrix[170]+ matrix[171]+ matrix[172]+ matrix[173]+ matrix[174]+ matrix[175])), helper_prob(state.get(to_bitstring(10, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[176] + matrix[177]+ matrix[178]+ matrix[179]+ matrix[180]+ matrix[181]+ matrix[182]+ matrix[183]+ matrix[184] + matrix[185]+ matrix[186]+ matrix[187]+ matrix[188]+ matrix[189]+ matrix[190]+ matrix[191])), helper_prob(state.get(to_bitstring(11, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[192] + matrix[193]+ matrix[194]+ matrix[195]+ matrix[196]+ matrix[197]+ matrix[198]+ matrix[199]+ matrix[200] + matrix[201]+ matrix[202]+ matrix[203]+ matrix[204]+ matrix[205]+ matrix[206]+ matrix[207])), helper_prob(state.get(to_bitstring(12, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[208] + matrix[209]+ matrix[210]+ matrix[211]+ matrix[212]+ matrix[213]+ matrix[214]+ matrix[215]+ matrix[216] + matrix[217]+ matrix[218]+ matrix[219]+ matrix[220]+ matrix[221]+ matrix[222]+ matrix[223])), helper_prob(state.get(to_bitstring(13, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[224] + matrix[225]+ matrix[226]+ matrix[227]+ matrix[228]+ matrix[229]+ matrix[230]+ matrix[231]+ matrix[232] + matrix[233]+ matrix[234]+ matrix[235]+ matrix[236]+ matrix[237]+ matrix[238]+ matrix[239])), helper_prob(state.get(to_bitstring(14, size=platform_qubits), 0.)), 2) - self.assertAlmostEqual(0.0625*helper_prob((matrix[240] + matrix[241]+ matrix[242]+ matrix[243]+ matrix[244]+ matrix[245]+ matrix[246]+ matrix[247]+ matrix[248] + matrix[249]+ matrix[250]+ matrix[251]+ matrix[252]+ matrix[253]+ matrix[254]+ matrix[255])), helper_prob(state.get(to_bitstring(15, size=platform_qubits), 0.)), 2) - -if __name__ == '__main__': - unittest.main() - - diff --git a/tests/visualizer/deutsch-josza.py b/tests/visualizer/deutsch-josza.py deleted file mode 100644 index 9fa0c127b..000000000 --- a/tests/visualizer/deutsch-josza.py +++ /dev/null @@ -1,45 +0,0 @@ -from openql import openql as ql -import os -from random import random - -curdir = os.path.dirname(__file__) -output_dir = os.path.join(curdir, 'visualizer_example_output') - -#ql.set_option('log_level', 'LOG_DEBUG') -#ql.set_option('log_level', 'LOG_INFO') -ql.set_option('unique_output', 'yes') - -c = ql.Compiler("testCompiler") -#c.append_pass("sch.Schedule", "scheduler", {"scheduler_heuristic": "asap"}) -c.append_pass("ana.visualize.Interaction", "visualizer", {"config": "visualizer_config_example1.json", "interactive": "yes"}) -c.set_option("**.output_prefix", output_dir + "/%N") - -platformCustomGates = ql.Platform('starmon', os.path.join(curdir, 'hardware_config_cc_light_visualizer2.json')) -num_qubits = 2 -p = ql.Program("Deutsch", platformCustomGates, num_qubits, 0) -k = ql.Kernel("kernel", platformCustomGates, num_qubits, 0) -for q in range(num_qubits): - k.gate('prepz',[q]) -k.gate('x',[1]) -for q in range(num_qubits): - k.gate('h',[q]) -#cr = random() -cr=0.23 -if (cr < 0.25): - print("Balanced : IDENTITY") - k.gate('cnot',[0,1]) -elif (cr < 0.50): - print("Balanced : NOT") - k.gate('x',[0]) - k.gate('cnot',[0, 1]) - k.gate('x',[0]) -elif (cr < 0.75): - print("Unbalanced : RESET") -else: - print("Unbalanced : SET") - k.gate('x',[1]) -k.gate('h',[0]) -for q in range(num_qubits): - k.gate('measure',[q]) -p.add_kernel(k) -c.compile(p) diff --git a/tests/visualizer/visualizer_example2.py b/tests/visualizer/visualizer_example2.py deleted file mode 100644 index 1f5ecad1d..000000000 --- a/tests/visualizer/visualizer_example2.py +++ /dev/null @@ -1,64 +0,0 @@ -from openql import openql as ql -import os - -curdir = os.path.dirname(__file__) -output_dir = os.path.join(curdir, 'visualizer_example_output') - -ql.initialize() -ql.set_option('output_dir', output_dir) -ql.set_option('optimize', 'no') -ql.set_option('scheduler', 'ASAP') -#ql.set_option('log_level', 'LOG_DEBUG') -ql.set_option('log_level', 'LOG_INFO') -ql.set_option('unique_output', 'yes') -ql.set_option('write_qasm_files', 'no') -ql.set_option('write_report_files', 'no') - -platformCustomGates = ql.Platform('starmon', os.path.join(curdir, 'hardware_config_cc_light_visualizer.json')) -nqubits = 4 -p = ql.Program("testProgram1", platformCustomGates, nqubits, 0) -k = ql.Kernel("aKernel1", platformCustomGates, nqubits, 0) -k.gate('x', [0]) -for i in range(nqubits): - k.gate('prepz', [i]) -k.gate('wait', [1], 40) -k.gate('wait', [2], 40) -k.gate('wait', [3], 40) -k.gate('x', [0]) -k.gate('x', [0]) -k.gate('x', [0]) -k.gate('wait', [2], 40) -k.gate('h', [2]) -k.gate('cz', [3, 1]) -k.gate('cz', [2, 0]) -k.gate('cz', [2, 0]) -k.gate('wait', [3], 40) -k.gate('measure', [3]) -k.gate('measure', [0]) -k.gate('measure', [1]) -k.gate('measure', [2]) -#k.gate('measure', [3]) -p.add_kernel(k) - -#p.get_compiler().append_pass( - #'ana.visualize.Interaction', - #'visualize_interaction', - #{ - #'output_prefix': output_dir + '/%N_interaction', - #'config': os.path.join(curdir, "visualizer_config_example2.json"), - #'interactive': 'yes' - #} -#) - -p.get_compiler().append_pass( - 'ana.visualize.Circuit', - 'visualize_circuit', - { - 'output_prefix': output_dir + '/%N_circuit', - 'config': os.path.join(curdir, "visualizer_config_example2.json"), - 'waveform_mapping': os.path.join(curdir, "waveform_mapping.json"), - 'interactive': 'yes' - } -) - -p.compile() diff --git a/tests/visualizer/visualizer_example3.py b/tests/visualizer/visualizer_example3.py deleted file mode 100644 index 0b8f0c4b1..000000000 --- a/tests/visualizer/visualizer_example3.py +++ /dev/null @@ -1,63 +0,0 @@ -from openql import openql as ql -import os - -curdir = os.path.dirname(__file__) -output_dir = os.path.join(curdir, 'visualizer_example_output') - -ql.set_option('output_dir', output_dir) -ql.set_option('optimize', 'no') -ql.set_option('scheduler', 'ASAP') -#ql.set_option('log_level', 'LOG_DEBUG') -ql.set_option('log_level', 'LOG_INFO') -ql.set_option('unique_output', 'yes') -ql.set_option('write_qasm_files', 'no') -ql.set_option('write_report_files', 'no') - -platformCustomGates = ql.Platform('starmon', os.path.join(curdir, 'hardware_config_cc_light_visualizer.json')) -nqubits = 4 -p = ql.Program("testProgram1", platformCustomGates, nqubits, 0) -k = ql.Kernel("aKernel1", platformCustomGates, nqubits, 0) -k.gate('x', [0]) -for i in range(nqubits): - k.gate('prepz', [i]) -k.gate('wait', [1], 40) -k.gate('wait', [2], 40) -k.gate('wait', [3], 40) -k.gate('x', [0]) -k.gate('x', [0]) -k.gate('x', [0]) -k.gate('wait', [2], 40) -k.gate('h', [2]) -k.gate('cz', [3, 1]) -k.gate('cz', [2, 0]) -k.gate('cz', [2, 0]) -k.gate('wait', [3], 40) -k.gate('measure', [3]) -k.gate('measure', [0]) -k.gate('measure', [1]) -k.gate('measure', [2]) -#k.gate('measure', [3]) -p.add_kernel(k) - -#p.get_compiler().append_pass( - #'ana.visualize.Interaction', - #'visualize_interaction', - #{ - #'output_prefix': output_dir + '/%N_interaction', - #'config': os.path.join(curdir, "visualizer_config_example3.json"), - #'interactive': 'yes' - #} -#) - -p.get_compiler().append_pass( - 'ana.visualize.Circuit', - 'visualize_circuit', - { - 'output_prefix': output_dir + '/%N_circuit', - 'config': os.path.join(curdir, "visualizer_config_example3.json"), - 'waveform_mapping': os.path.join(curdir, "waveform_mapping.json"), - 'interactive': 'yes' - } -) - -p.compile()